From 9b18bc507f18c8717b6b17f727ad60ce6fe193e7 Mon Sep 17 00:00:00 2001 From: arne Date: Fri, 9 Dec 2022 16:01:08 +0100 Subject: [PATCH] Fix plotting closed shapes --- src/heyarne/line_us/gcode.clj | 101 ++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/src/heyarne/line_us/gcode.clj b/src/heyarne/line_us/gcode.clj index 16c609b..ff4b6f2 100644 --- a/src/heyarne/line_us/gcode.clj +++ b/src/heyarne/line_us/gcode.clj @@ -18,40 +18,56 @@ (map (fn [[x y z]] (str "G01 X" x " Y" y " Z" z)) gcode-verts)) +(defn- vertices* + "Wrapper around geom.core/vertices that makes sure calls for geometries + which don't support the resolution parameter don't fail." + [geom {:keys [res]}] + (try + (if res (g/vertices geom res) (g/vertices geom)) + (catch clojure.lang.ArityException _ + (g/vertices geom)))) + +(defn- vertices + "Return the vertices of the outline of a shape; if a geometry is closed, the + first and last vertex will be the same." + ([geom] (vertices geom {})) + ([geom opts] + (let [last-p (last (g/sample-uniform geom Double/MAX_VALUE true)) + vertices (vertices* geom opts)] + (cond-> vertices + (not= last-p (last vertices)) (conj last-p))))) + (defn- ->gcode-verts ([geom] (->gcode-verts geom {})) - ([geom {:keys [r]}] - (vertices->gcode-verts (try - (if r (g/vertices geom r) (g/vertices geom)) - (catch IllegalArgumentException _ - (g/vertices geom)))))) + ([geom {:keys [res]}] + (vertices->gcode-verts (vertices geom res)))) (def gcode-seq "Convert thi.ng.geom types into a sequence of G-Code to plot them. - An optional parameter `{:r 10}` can be used to adjust the sampling resolution - for the shape." + An optional parameter `{:res 10}` can be used to adjust the sampling resolution + for the shape, if the shape supports it." (comp gcode-verts->gcode-seq ->gcode-verts)) (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}" +;; (pr-str (c/circle 20)) ;; => "#thi.ng.geom.types.Circle2{:p [0.0 0.0], :res 20.0}" (defn scene->gcode-seq "Converts a scene into a sequence of G-Code instructions. A scene is an arbitrarily nested vector of geom instances and hiccup-like in that each object can be followed by a map of attributes. The map is currently ignored." ([scene] (scene->gcode-seq scene {})) - ([scene {:keys [r] :as opts}] + ([scene {:keys [res] :as opts}] (loop [[el & rs] scene result []] (cond (nil? el) result - (sequential? el) (recur rs (vec (concat result (scene->gcode-seq el opts)))) ;; recursively convert sequences - (geom? el) (recur rs (conj result (if r (gcode-seq el r) (gcode-seq el)))) ;; convert geoms - (map? el) (recur rs result))))) ;; ignore attribute maps + (sequential? el) (recur rs (vec (concat result (scene->gcode-seq el opts)))) ;; recursively convert sequences + (geom? el) (recur rs (conj result (if res (gcode-seq el res) (gcode-seq el)))) ;; convert geoms + (map? el) (recur rs result))))) ;; ignore attribute maps (comment ;; example usage: @@ -67,70 +83,97 @@ ;; "G01 X200.0 Y200.0 Z1000") ;; you can pass a second argument to increase or decrease resolution - (gcode-seq (c/circle) {:r 10}) + (gcode-seq (c/circle) {:res 10}) ;; => ("G01 X1.0 Y0.0 Z1000" ;; "G01 X1.0 Y0.0 Z0" + ;; "G01 X0.9510565162951535 Y0.3090169943749474 Z0" ;; "G01 X0.8090169943749475 Y0.5877852522924731 Z0" + ;; "G01 X0.5877852522924731 Y0.8090169943749475 Z0" ;; "G01 X0.30901699437494745 Y0.9510565162951535 Z0" + ;; "G01 X6.123233995736766E-17 Y1.0 Z0" ;; "G01 X-0.30901699437494734 Y0.9510565162951536 Z0" + ;; "G01 X-0.587785252292473 Y0.8090169943749475 Z0" ;; "G01 X-0.8090169943749473 Y0.5877852522924732 Z0" + ;; "G01 X-0.9510565162951535 Y0.3090169943749475 Z0" ;; "G01 X-1.0 Y1.2246467991473532E-16 Z0" + ;; "G01 X-0.9510565162951535 Y-0.30901699437494773 Z0" ;; "G01 X-0.8090169943749476 Y-0.587785252292473 Z0" + ;; "G01 X-0.5877852522924732 Y-0.8090169943749473 Z0" ;; "G01 X-0.30901699437494756 Y-0.9510565162951535 Z0" + ;; "G01 X-1.8369701987210297E-16 Y-1.0 Z0" ;; "G01 X0.30901699437494723 Y-0.9510565162951536 Z0" + ;; "G01 X0.5877852522924729 Y-0.8090169943749476 Z0" ;; "G01 X0.8090169943749473 Y-0.5877852522924734 Z0" - ;; "G01 X0.8090169943749473 Y-0.5877852522924734 Z1000") + ;; "G01 X0.9510565162951535 Y-0.3090169943749476 Z0" + ;; "G01 X0.9510565162951535 Y-0.3090169943749476 Z1000") + ;; `scene->gcode-seq` converts a tree of arbitrarily nested elements into a + ;; sequence of gcode drawing instructions - ;; `scene->gcode-seq` converts a tree of arbitrarily nested 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]) - [(c/circle [5 5] 10)] - (r/rect [20 20] [40 40])]] - {:r 10}) + [[(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]) + [(c/circle [5 5] 10)] + (r/rect [20 20] [40 40])]] + {:res 10}) ;; => [("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 Z0" + ;; "G01 X0.0 Y0.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 X0.0 Y0.0 Z0" + ;; "G01 X0.0 Y0.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 X5.0 Y5.0 Z0" + ;; "G01 X5.0 Y5.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 X20.0 Y20.0 Z0" + ;; "G01 X20.0 Y20.0 Z1000") ;; ("G01 X15.0 Y5.0 Z1000" ;; "G01 X15.0 Y5.0 Z0" + ;; "G01 X14.510565162951535 Y8.090169943749475 Z0" ;; "G01 X13.090169943749475 Y10.877852522924732 Z0" + ;; "G01 X10.877852522924732 Y13.090169943749475 Z0" ;; "G01 X8.090169943749475 Y14.510565162951535 Z0" + ;; "G01 X5.000000000000001 Y15.0 Z0" ;; "G01 X1.9098300562505264 Y14.510565162951536 Z0" + ;; "G01 X-0.87785252292473 Y13.090169943749475 Z0" ;; "G01 X-3.0901699437494727 Y10.877852522924734 Z0" + ;; "G01 X-4.510565162951535 Y8.090169943749475 Z0" ;; "G01 X-5.0 Y5.000000000000001 Z0" + ;; "G01 X-4.510565162951535 Y1.9098300562505228 Z0" ;; "G01 X-3.0901699437494763 Y-0.87785252292473 Z0" + ;; "G01 X-0.8778525229247327 Y-3.0901699437494727 Z0" ;; "G01 X1.9098300562505246 Y-4.510565162951535 Z0" + ;; "G01 X4.999999999999998 Y-5.0 Z0" ;; "G01 X8.090169943749473 Y-4.510565162951536 Z0" + ;; "G01 X10.87785252292473 Y-3.0901699437494763 Z0" ;; "G01 X13.090169943749473 Y-0.8778525229247336 Z0" - ;; "G01 X13.090169943749473 Y-0.8778525229247336 Z1000") + ;; "G01 X14.510565162951535 Y1.9098300562505237 Z0" + ;; "G01 X15.0 Y5.0 Z0" + ;; "G01 X15.0 Y5.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 X20.0 Y20.0 Z0" + ;; "G01 X20.0 Y20.0 Z1000")] + )