Restrict gcode api surface to gcode-seq and scene->gcode-seq

This commit is contained in:
arne 2022-12-08 10:58:17 +01:00
commit c88a4bedc8

View file

@ -2,48 +2,44 @@
"Provides functions to move from geometry types provided by thi.ng to gcode "Provides functions to move from geometry types provided by thi.ng to gcode
so you can plot them." so you can plot them."
(:require [thi.ng.geom.core :as g] (:require [thi.ng.geom.core :as g]
[thi.ng.geom.types] [clojure.string :as str]))
[thi.ng.geom.vector :as v]
[thi.ng.geom.circle :as c])
(:import [thi.ng.geom.types Line2 LineStrip2 Circle2]))
(defprotocol GCode ;; scroll down for a rich comment with usage examples
"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."))
(defn- point-seq->gcode [pts] (defn- vertices->gcode-verts [vertices]
(let [vertices pts (let [[f-x f-y] (first vertices)
[l-x l-y] (last vertices)] [l-x l-y] (last vertices)]
(conj (mapv (fn [[x y]] (concat
[x y 0]) vertices) [[f-x f-y 1000]]
[l-x l-y 1000]))) (mapv (fn [[x y]] [x y 0]) vertices)
[[l-x l-y 1000]])))
(defn gcode-seq->str [gcode-seq] (defn- gcode-verts->gcode-seq [gcode-verts]
(map (fn [[x y z]] (map (fn [[x y z]]
(str "G01 X" x " Y" y " Z" z)) gcode-seq)) (str "G01 X" x " Y" y " Z" z)) gcode-verts))
(extend-protocol GCode (defn- ->gcode-verts
Line2 ([geom]
(->gcode (vertices->gcode-verts (g/vertices geom)))
([_] (point-seq->gcode (:points _))) ([geom r]
([_ r] (->gcode _))) (vertices->gcode-verts (g/vertices geom r))))
LineStrip2 (def gcode-seq
(->gcode "Convert thi.ng.geom types into a sequence of G-Code to plot them. The G-Code
([_] (point-seq->gcode (:points _))) instructions are given as a sequence of vectors, where each vector is given
([_ r] (->gcode _))) as [x y z].
Circle2 Returns G01 movements on the x, y, and z axis. Z is constantly 1000 in the
(->gcode current implementation, but this might change in the future. The optional
([_] (point-seq->gcode (:points (g/as-polygon _)))) parameter `r` can be used to adjust the resolution."
([_ r] (point-seq->gcode (:points (g/as-polygon _ r)))))) (comp gcode-verts->gcode-seq ->gcode-verts))
(defn scene->gcode (defn geom? [x]
(str/starts-with? (pr-str x) "#thi.ng.geom."))
;; (pr-str (c/circle 20)) ;; => "#thi.ng.geom.types.Circle2{:p [0.0 0.0], :r 20.0}"
(defn scene->gcode-seq
"Converts a scene into a sequence of gcode instructions. A scene is an "Converts a scene into a sequence of gcode instructions. A scene is an
arbitrarily nested vector of geom instances. arbitrarily nested vector of geom instances.
@ -52,25 +48,86 @@
object." object."
[scene] [scene]
(loop [[el & rs] scene (loop [[el & rs] scene
res []] result []]
(cond (cond
(vector? el) (recur (scene->gcode el) res) (nil? el) result
(map? el) (recur rs res) (sequential? el) (recur rs (concat result (scene->gcode-seq el))) ;; recursively convert sequences
:else (if (seq rs) (geom? el) (recur rs (conj result (gcode-seq el))) ;; convert geoms
(recur rs (conj res (gcode-seq->str (->gcode el)))) (map? el) (recur rs result)))) ;; ignore attribute maps
(flatten res)))))
;; TODO: Resolution for scenes?
;; `g/vertices` fails when called with a second arg for `r/rect`
(comment (comment
;; example usage:
(require '[thi.ng.geom.line :as l])
(require '[thi.ng.geom.circle :as c]) (require '[thi.ng.geom.circle :as c])
(require '[thi.ng.geom.rect :as r])
;; convert a single element ;; `gcode-seq`` returns a sequence of gcode strings, where z=0 means "down"
(-> (gcode-seq (l/line2 [100 100] [200 200]))
(->gcode (c/circle) 10) ;; => ("G01 X100.0 Y100.0 Z1000"
(gcode-seq->str)) ;; "G01 X100.0 Y100.0 Z0"
;; "G01 X200.0 Y200.0 Z0"
;; "G01 X200.0 Y200.0 Z1000")
;; convert a tree of elements ;; you can pass a second argument to increase or decrease resolution
(scene->gcode (gcode-seq (c/circle) 10)
[(c/circle 10) ;; => ("G01 X1.0 Y0.0 Z1000"
[(c/circle [0 20] 10) ;; "G01 X1.0 Y0.0 Z0"
(c/circle [0 40] 10)]]) ;; "G01 X0.8090169943749475 Y0.5877852522924731 Z0"
;; "G01 X0.30901699437494745 Y0.9510565162951535 Z0"
;; "G01 X-0.30901699437494734 Y0.9510565162951536 Z0"
;; "G01 X-0.8090169943749473 Y0.5877852522924732 Z0"
;; "G01 X-1.0 Y1.2246467991473532E-16 Z0"
;; "G01 X-0.8090169943749476 Y-0.587785252292473 Z0"
;; "G01 X-0.30901699437494756 Y-0.9510565162951535 Z0"
;; "G01 X0.30901699437494723 Y-0.9510565162951536 Z0"
;; "G01 X0.8090169943749473 Y-0.5877852522924734 Z0"
;; "G01 X0.8090169943749473 Y-0.5877852522924734 Z1000")
;; `scene->gcode-seq` converts a tree of elements into a sequence of gcode drawing instructions
(scene->gcode-seq
[[(r/rect [0 0] [10 10]) {:attributes/ignored? true}]
(r/rect [0 0] [10 10])
[(r/rect [5 5] [15 15])
(r/rect [20 20] [40 40])
[(r/rect [5 5] [15 15])]
(r/rect [20 20] [40 40])]])
;; => (("G01 X0.0 Y0.0 Z1000"
;; "G01 X0.0 Y0.0 Z0"
;; "G01 X10.0 Y0.0 Z0"
;; "G01 X10.0 Y10.0 Z0"
;; "G01 X0.0 Y10.0 Z0"
;; "G01 X0.0 Y10.0 Z1000")
;; ("G01 X0.0 Y0.0 Z1000"
;; "G01 X0.0 Y0.0 Z0"
;; "G01 X10.0 Y0.0 Z0"
;; "G01 X10.0 Y10.0 Z0"
;; "G01 X0.0 Y10.0 Z0"
;; "G01 X0.0 Y10.0 Z1000")
;; ("G01 X20.0 Y20.0 Z1000"
;; "G01 X20.0 Y20.0 Z0"
;; "G01 X40.0 Y20.0 Z0"
;; "G01 X40.0 Y40.0 Z0"
;; "G01 X20.0 Y40.0 Z0"
;; "G01 X20.0 Y40.0 Z1000")
;; ("G01 X5.0 Y5.0 Z1000"
;; "G01 X5.0 Y5.0 Z0"
;; "G01 X15.0 Y5.0 Z0"
;; "G01 X15.0 Y15.0 Z0"
;; "G01 X5.0 Y15.0 Z0"
;; "G01 X5.0 Y15.0 Z1000")
;; ("G01 X20.0 Y20.0 Z1000"
;; "G01 X20.0 Y20.0 Z0"
;; "G01 X40.0 Y20.0 Z0"
;; "G01 X40.0 Y40.0 Z0"
;; "G01 X20.0 Y40.0 Z0"
;; "G01 X20.0 Y40.0 Z1000")
;; ("G01 X5.0 Y5.0 Z1000"
;; "G01 X5.0 Y5.0 Z0"
;; "G01 X15.0 Y5.0 Z0"
;; "G01 X15.0 Y15.0 Z0"
;; "G01 X5.0 Y15.0 Z0"
;; "G01 X5.0 Y15.0 Z1000"))
) )