Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
e5fcf0b10c Commit unstaged changes 2022-02-19 19:36:34 +01:00
2 changed files with 177 additions and 23 deletions

View file

@ -5,6 +5,7 @@
[cheshire.core :as json]
[net.cgrand.xforms :as x]
[thi.ng.geom.aabb :as aabb]
[thi.ng.geom.circle :as c]
[thi.ng.geom.vector :as v]
[thi.ng.geom.core :as g]
[thi.ng.geom.line :as l]
@ -16,6 +17,7 @@
[clojure.java.io :as io]
[clojure.string :as str]))
;; TODO: Implement camera
(def canvas (r/rect 0 0 500 500))
@ -74,7 +76,7 @@
(q/frame-rate (if debug 1 30))
(q/ellipse-mode :center)
(q/color-mode :hsb)
{:current-faces (rand-nth uploads)})
{:current-faces (last uploads)})
(defn find-index [xs x]
(first (keep-indexed (fn [idx item] (when (= x item) idx)) xs)))
@ -94,20 +96,37 @@
state))
(def scale 200)
(def line-length 5)
(def gap-size 10)
(defn draw [{:keys [current-faces]}]
(q/clear)
(q/background 40 80 255)
(q/stroke 4 120 255)
(q/no-fill)
(q/stroke-weight 1)
(q/background 40 5 255)
(q/with-translation [(/ (q/width) 2)
(/ (q/height) 2)]
;; draw face
(q/no-stroke)
(q/fill 0 0 190)
(doseq [face current-faces
[x y z] face
:let [d (* 5 (- 1 (+ 0.5 z)))]]
(q/ellipse (* scale x) (* scale y) d d))))
(q/ellipse (* scale x) (* scale y) 3 3))
;; draw dashed line
(q/stroke 140 60 240)
(q/stroke-weight 4)
(q/no-fill)
(let [dashes-y (map #(l/line2 0 % 0 (+ % line-length))
(range -160 160 (+ line-length gap-size)))
dashes-x (map #(l/line2 % 0 (+ % line-length) 0)
(range -160 160 (+ line-length gap-size)))]
(doseq [line dashes-y :let [[a b] (:points line)]]
(q/line a b))
#_(doseq [line dashes-x :let [[a b] (:points line)]]
(q/line a b)))))
#_:clj-kondo/ignore
(q/defsketch all-my-friends
@ -119,3 +138,123 @@
:key-pressed key-pressed
:draw draw
:size (:size canvas))
(comment
(require '[heyarne.line-us.connection :as line-us])
(require '[heyarne.line-us.gcode :refer [->gcode]])
;; paulas faces are the last two, there's only one face in the upload
(def smiling-paula
(-> (nth uploads (- (count uploads) 2))
(first)))
(def neutral-paula (first (last uploads)))
;; TODO: Validate all points before sending them to the line-us
(def plot-scale 900)
(def line-length 3)
(identity line-us/drawing-area)
;; => {:x [800 1700], :y [-900 900], :z [0 1000]}
;;
(defn invalid-in-gcode-seq [gcode-seq]
(let [{[min-x max-x] :x
[min-y max-y] :y
[min-z max-z] :z} line-us/drawing-area]
(keep-indexed (fn [idx [x y z]]
(when (or (< x min-x) (> x max-x)
(< y min-y) (> y max-y)
(< z min-z) (> z max-z))
[idx [x y z]]))
gcode-seq)))
(def face-gcode-seq
(into []
(comp
(map #(m/* % plot-scale))
;; we need to center horizontally
(map #(g/translate %
(v/vec2 (+ (first (:x line-us/drawing-area))
(* 0.5 (- (second (:x line-us/drawing-area))
(first (:x line-us/drawing-area)))))
0)))
(map (fn [[x y _]] (v/vec2 x y)))
(mapcat ->gcode)
#_#_ (mapcat (fn [[x y _z]]
(let [l (* 0.5 line-length)]
[(l/line2 (- x l) (- y l) (+ x l) (+ y l))
#_(l/line2 (- x l) (+ y l) (+ x l) (- y l))])))
(mapcat ->gcode))
neutral-paula))
(assert (empty? (invalid-in-gcode-seq face-gcode-seq)))
#_(def instructions (gcode-seq->str gcode-seq))
;; NOTE: Calibration works quite well with a 20 Euro-Cent and a 1 Euro-Cent coint
(defn plot! [gcode-seq]
(let [log (partial println "Line-us:")]
(with-open [line-us (line-us/connect "line-us.lan" 1337)]
(log (line-us/read-response line-us))
(Thread/sleep 1000)
(doseq [coords gcode-seq]
(log (line-us/send-movement! line-us coords)))
(Thread/sleep 1000)
(log "Done!"))))
(plot! face-gcode-seq)
(count face-gcode-seq) ;; => 1404
(def accents
(into [] (comp (partition-all 3)
(random-sample 0.1)
cat)
face-gcode-seq))
(count accents)
(plot! accents)
;; now we draw some extra circles
(def bounds
(reduce (fn [[[min-x min-y min-z]
[max-x max-y max-z]]
[x y z]]
[[(min min-x x) (min min-y y) (min min-z z)]
[(max max-x x) (max max-y y) (max max-z z)]])
[(first face-gcode-seq) (first face-gcode-seq)] (rest face-gcode-seq)))
(def plot-width (- (get-in bounds [1 0]) (get-in bounds [0 0])))
(def plot-height (- (get-in bounds [1 1]) (get-in bounds [0 1])))
(def circle-one (c/circle (first bounds) (/ plot-width 8)))
(def circle-two (c/circle (second bounds) (* (/ plot-width 8) 1)))
(def circle-gcode-seq
(mapcat ->gcode [circle-one circle-two]))
;; the following section is commented out because it might be skipped
;; NOTE: This should be empty!
#_(assert (empty? (invalid-in-gcode-seq circle-gcode-seq)))
#_(plot! circle-gcode-seq)
(def center-x (+ (ffirst bounds) (* 0.5 plot-width)))
(def dash-start-y (- (get-in bounds [0 1]) (* (/ 1 3) plot-height)))
(def dash-stop-y (+ (get-in bounds [1 1]) (* (/ 1 3) plot-height)))
(def dash-length 20)
(def dash-gap 40)
(def dashes
(->> (range dash-start-y dash-stop-y (+ dash-length dash-gap))
(map #(l/line2 center-x % center-x (+ % dash-length)))
(mapcat ->gcode)))
(assert (empty? (invalid-in-gcode-seq dashes)))
(plot! dashes)
)

View file

@ -2,29 +2,44 @@
"Provides functions to move from geometry types provided by thi.ng to gcode
so you can plot them."
(:require [thi.ng.geom.core :as g])
(:import [thi.ng.geom.types Line2 LineStrip2 Circle2]))
(:import [thi.ng.geom.types Line2 LineStrip2 Circle2]
[thi.ng.geom.vector Vec2]))
(defprotocol GCode
"Convert thi.ng.geom types into sequences of GCode to plot them. The GCode
instructions are given as a sequence of vectors, where each vector is given
as [x y z]."
(->gcode [_] [_ r]
"Returns G01 movements on the x, y, and z axis. Z is constantly 1000 in the
current implementation, but this might change in the future. The optional
parameter `r` can be used to adjust the resolution."))
(->gcode [_] [_ res]
"Returns G01 movements on the x, y, and z axis. Z=1000 means up, Z=0 means
down. The optional parameter `res` can be used to adjust the resolution if
the shape is not natively supported by the Line-us and has to be converted
into a polygon."))
(defn- point-seq->gcode [pts]
(defn- point-seq->gcode
"Turns a seq into a drawable seq of points, so that before and after the last
point in the seq the drawing arm is lifted."
[pts]
(let [vertices pts
[f-x f-y] (first vertices)
[l-x l-y] (last vertices)]
(conj (mapv (fn [[x y]]
(vec (concat [[f-x f-y 1000]]
(mapv (fn [[x y]]
[x y 0]) vertices)
[l-x l-y 1000])))
[[l-x l-y 1000]]))))
(defn gcode-seq->str [gcode-seq]
(comment
;; NOTE This is not actually needed. It makes more sense to work with vecs so
;; the coordinates can be verified to be within a valid range
(defn gcode-seq->str [gcode-seq]
(map (fn [[x y z]]
(str "G01 X" x " Y" y " Z" z)) gcode-seq))
(str "G01 X" x " Y" y " Z" z)) gcode-seq)))
(extend-protocol GCode
Circle2
(->gcode
([_] (point-seq->gcode (:points (g/as-polygon _))))
([_ r] (point-seq->gcode (:points (g/as-polygon _ r)))))
Line2
(->gcode
([_] (point-seq->gcode (:points _)))
@ -35,14 +50,14 @@
([_] (point-seq->gcode (:points _)))
([_ r] (->gcode _)))
Circle2
Vec2
(->gcode
([_] (point-seq->gcode (:points (g/as-polygon _))))
([_ r] (point-seq->gcode (:points (g/as-polygon _))))))
([_] (point-seq->gcode [_]))
([_ r] (->gcode _))))
(comment
(require '[thi.ng.geom.circle :as c])
(->
(->gcode (c/circle))
(gcode-seq->str)))
#_(gcode-seq->str)))