From d466da8a90a7678d844ed1f2b8c114e0fcbde5d9 Mon Sep 17 00:00:00 2001 From: Matt Adereth Date: Fri, 6 Mar 2015 15:26:01 -0800 Subject: Initial commit --- src/dactyl_cave/text.clj | 134 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/dactyl_cave/text.clj (limited to 'src/dactyl_cave/text.clj') diff --git a/src/dactyl_cave/text.clj b/src/dactyl_cave/text.clj new file mode 100644 index 0000000..db37bfd --- /dev/null +++ b/src/dactyl_cave/text.clj @@ -0,0 +1,134 @@ +(ns dactyl-cave.text + (:use [scad-clj.scad]) + (:use [scad-clj.model]) + (:import (java.awt Font RenderingHints) + (java.awt.font FontRenderContext) + (java.awt.geom PathIterator))) + +(def segment-type + {PathIterator/SEG_CLOSE :close + PathIterator/SEG_CUBICTO :cubic-to + PathIterator/SEG_LINETO :line-to + PathIterator/SEG_MOVETO :move-to + PathIterator/SEG_QUADTO :quad-to}) + +;; How many points are specified for each segment type +(def segment-length + {PathIterator/SEG_CLOSE 0 + PathIterator/SEG_CUBICTO 3 + PathIterator/SEG_LINETO 1 + PathIterator/SEG_MOVETO 1 + PathIterator/SEG_QUADTO 2}) + +(defn path-iterator->segments + "Converts a PathIterator into a sequence of segments of the form [segment-type [& points]]" + [^PathIterator path-iterator] + (if (not (.isDone path-iterator)) + (let [coords (double-array (* 2 (apply max (vals segment-length)))) + segment-code (.currentSegment path-iterator coords)] + (cons [(segment-type segment-code) + (take (segment-length segment-code) (partition 2 coords))] + (lazy-seq (path-iterator->segments (doto path-iterator (.next)))))))) + +(defn quad->fn + "Returns the parametric control equation f(t), 0 <= t <= 1 +for the quadratic interpolation of 3 points." + [cp p1 p2] + (fn [t] + (letfn [(interp [a b c] (+ (* (Math/pow (- 1 t) 2) a) + (* 2 t (- 1 t) b) + (* (Math/pow t 2) c)))] + [(apply interp (map first [cp p1 p2])) + (apply interp (map second [cp p1 p2]))]))) + +(defn cubic->fn + "Returns the parametric control equation f(t), 0 <= t <= 1 +for the cubic interpolation of 4 points." + [cp p1 p2 p3] + (fn [t] + (letfn [(interp [a b c d] + (+ (* (Math/pow (- 1 t) 3) a) + (* 3 t (Math/pow (- 1 t) 2) b) + (* 3 (Math/pow t 2) (- 1 t) c) + (* (Math/pow t 3) d)))] + [(apply interp (map first [cp p1 p2 p3])) + (apply interp (map second [cp p1 p2 p3]))]))) + +(defn segments->lines + "Takes a sequence of segments of the form [segment-type [& points]] +and transforms each segment into a sequence of interpolated points" + [segments] + (reductions (fn [prev-line-points [segment-type control-points]] + #_(println segment-type) + (condp = segment-type + :move-to control-points + :line-to control-points + :quad-to (map (apply quad->fn + (last prev-line-points) + control-points) + (range 1/10 11/10 1/10)) + :cubic-to (map (apply cubic->fn + (last prev-line-points) + control-points) + (range 1/10 11/10 1/10)))) + (last (rest (first segments))) + (rest segments))) + + +(defn path2d [points] + (let [path (doto (java.awt.geom.Path2D$Double.) + (.moveTo (-> points first first) + (-> points first second)))] + (doseq [point (rest points)] + (.lineTo path (first point) (second point))) + path)) + +(defn split-intersecting [paths] + (let [polygons (map path2d paths) + starting-points (map first paths)] + (reduce (fn [acc path] + (let [polygon (path2d path)] + (if (some #(.contains % (-> path first first) (-> path first second)) + (:polygons acc)) + (merge-with concat acc + {:difference [path]}) + (merge-with concat acc + {:polygons [polygon] + :union [path]})))) + {:polygons [] + :union [] + :difference []} + paths))) + +(defn text-polygon [font size text] + (let [frc (FontRenderContext. nil + RenderingHints/VALUE_TEXT_ANTIALIAS_DEFAULT + RenderingHints/VALUE_FRACTIONALMETRICS_DEFAULT) + path-iter (-> (Font. font Font/PLAIN size) + (.createGlyphVector frc text) + (.getOutline) + (.getPathIterator nil)) + paths (->> (path-iterator->segments path-iter) + (partition-by #(= (first %) :close)) + (take-nth 2) + (map segments->lines) + (map flatten) + (map (partial partition 2))) + split-paths (split-intersecting paths)] + (difference + (apply union (map polygon (:union split-paths))) + (apply union (map polygon (:difference split-paths)))))) + +(spit "/Users/madereth/text.scad" + (write-scad + (->> "Anonymous Pro" #_(str (java.util.Date.)) + (text-polygon "Anonymous Pro" 12) + (extrude-linear {:height 50 :twist 0 :convexity 0})))) + + + +(spit "/Users/madereth/text.scad" + (write-scad + (->> "Anonymous Pro" #_(str (java.util.Date.)) + (text-polygon "Anonymous Pro" 12) + (extrude-linear {:height 12 :twist 0 :convexity 0})))) \ No newline at end of file -- cgit v1.2.3