summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dactyl_cave/alternathumb.clj149
-rw-r--r--src/dactyl_cave/cave.clj337
-rw-r--r--src/dactyl_cave/core.clj6
-rw-r--r--src/dactyl_cave/key.clj81
-rw-r--r--src/dactyl_cave/text.clj134
-rw-r--r--src/dactyl_cave/thumb.clj173
-rw-r--r--src/dactyl_keyboard/dactyl.clj1240
7 files changed, 1240 insertions, 880 deletions
diff --git a/src/dactyl_cave/alternathumb.clj b/src/dactyl_cave/alternathumb.clj
deleted file mode 100644
index ddfb42a..0000000
--- a/src/dactyl_cave/alternathumb.clj
+++ /dev/null
@@ -1,149 +0,0 @@
-(ns dactyl-cave.alternathumb
- (:use [scad-clj.scad])
- (:use [scad-clj.model])
- (:use [unicode-math.core])
- (:require [dactyl-cave.key :as key])
- (:require [dactyl-cave.cave :as cave]))
-
-(defn- scoop [angle radius [x y :as direction] shape]
- (->> shape
- (translate [0 0 radius])))
-
-(defn thumb-x+x-column [shape]
- (let [α (/ π 12)
- radius (/ (/ key/pillar-depth 2)
- (Math/sin (/ α 2)))
- spin-shape (->> shape
- (translate [0 0 (+ (- key/full-height)
- (- radius))]))]
- (translate
- [0 0 (+ radius key/full-height)]
- (union
- spin-shape
-
- (->> spin-shape
- (rotate (- α) [1 0 0]))))))
-
-(defn thumb-2x-column [shape]
- (let [α (/ π 12)
- radius (/ (/ key/pillar-depth 2)
- (Math/sin (/ α 2)))
- spin-shape (->> shape
- (translate [0 0 (+ (- key/full-height)
- (- radius))]))]
- (translate
- [0 0 (+ radius key/full-height)]
- (union
- (->> spin-shape
- (rotate (* α -1/2) [1 0 0]))))))
-
-(defn thumb-2x-row [shape]
- (let [α (/ π 12)
- radius (/ (/ key/pillar-depth 2)
- (Math/sin (/ α 2)))
- spin-shape (->> shape
- (translate [0 0 (+ (- key/full-height)
- (- radius))]))]
- (translate
- [0 0 (+ radius key/full-height)]
- (union
- (->> spin-shape
- (rotate (* α 1) [1 0 0]))))))
-
-
-(defn spin-thumb [column shape]
- (let [β (/ π 36)
- radius (/ (/ (+ key/pillar-width 5) 2)
- (Math/sin (/ β 2)))]
- (->>
- (translate
- [0 0 (- (- radius key/full-height))]
- (->> shape
- (translate [0 0 (- radius key/full-height)])
- (rotate (* column β) [0 1 0])))
- (translate [key/pillar-width 0 0])
- (rotate (/ π 12) [0 0 1])
- #_(rotate (/ π -12) [0 1 0])
- #_(rotate (/ π 6) [0 0 1])
- (translate [-7 -47 35]))))
-
-(defn thumb-layout [shape]
- (union
- (spin-thumb 2 (thumb-x+x-column shape))
- (spin-thumb 1 (thumb-x+x-column shape))
- (spin-thumb 0 (thumb-2x-column shape))
- (spin-thumb 1/2 (thumb-2x-row shape))))
-
-(defn support [shape]
- (hull
- shape
- (extrude-linear {:height 10 :twist 0 :convexity 0}
- (project (hull shape)))))
-
-(defn thumb-support [shape]
- (union
- (support (union
- (spin-thumb 2 (thumb-x+x-column shape))
- (spin-thumb 1 (thumb-x+x-column shape))
- (spin-thumb 0 (thumb-2x-column shape))))
- (support (union
- (spin-thumb 0 (thumb-2x-column shape))
- (spin-thumb 1/2 (thumb-2x-row shape))))
-
-))
-
-(def bottom
- (translate [0 0 -100]
- (cube 2000 2000 200))
- )
-
-
-#_(def thumb-base
- (difference
- (hull
- (thumb-layout (translate [0 0 (/ key/pillar-height -2)]
- (scale [1 1 1/10] key/full-pillar)))
- (extrude-linear {:height 10 :twist 0 :convexity 0}
- (project (hull (thumb-layout key/full-pillar)))))
- bottom
- (thumb-layout key/keyswitch-full-hole)))
-
-(def thumb-base
- (union
- (thumb-support (scale [1 1 1/10] key/full-pillar))
- #_(->> (cube 150 150 50)
- (translate [150 75 25])))
-
- )
-
-(defn move-to-corner [shape]
- (translate [-265 -215 0] shape))
-
-(def thumb-cluster
- (difference
- (translate [0 0 -20]
- (difference
- (union
- (thumb-layout key/pillar)
- thumb-base)
- (thumb-layout key/keyswitch-full-hole)))
- bottom))
-
-(spit "alternathumb.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- #_thumb-cluster
- (union
- (mirror [1 0 0] (move-to-corner thumb-cluster))
- #_(->> (move-to-corner thumb-cluster)
- (mirror [1 0 0]))
- #_cave/base
- #_cave/fingers
- )
-
- #_(mirror [1 0 0]
- (difference
- (move-to-corner thumb-cluster)
- cave/base
- ))
- )))
-
diff --git a/src/dactyl_cave/cave.clj b/src/dactyl_cave/cave.clj
deleted file mode 100644
index 05bfaed..0000000
--- a/src/dactyl_cave/cave.clj
+++ /dev/null
@@ -1,337 +0,0 @@
-(ns dactyl-cave.cave
- (:use [scad-clj.scad])
- (:use [scad-clj.model])
- (:use [unicode-math.core])
- (:use [dactyl-cave.key]))
-
-(defn key-place [column row shape]
- (let [α (/ π 12)
- row-radius (+ (/ (/ pillar-depth 2)
- (Math/sin (/ α 2)))
- full-height)
- row-placed-shape (->> shape
- (translate [0 0 (- row-radius)])
- (rotate (* α (- 2 row)) [1 0 0])
- (translate [0 0 row-radius]))
- β (/ π 36)
- column-radius (+ (/ (/ (+ pillar-width 127/90) 2)
- (Math/sin (/ β 2)))
- full-height)
- column-offset (condp = column
- 2 [0 127/45 -254/45]
- 4 [0 (/ pillar-depth -3) 254/45]
- 5 [0 (/ pillar-depth -4) 254/45]
- [0 0 0])
- column-angle (if (<= column 4)
- (* β (- 2 column))
- (* β -3.25))
- placed-shape (->> row-placed-shape
- (translate [0 0 (- column-radius)])
- (rotate column-angle [0 1 0])
- (translate [0 0 column-radius])
- (translate column-offset))]
- (translate [0 0 127/18]
- (rotate (/ π 12) [0 1 0]
- placed-shape))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Limits
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(def bottom-limit
- (->> (cube (* pillar-width 17.75)
- (* pillar-depth 17)
- 508/9)
- (translate [(+ (/ pillar-width 2) 127/45)
- 0 -254/9])))
-
-(def back-limit
- (->> (cube (* pillar-width 9)
- (* pillar-depth 2)
- 254/3)
- (translate [pillar-width
- (+ (* pillar-depth 4.1))
- 254/9])))
-
-(def front-right-limit
- (->> (cube (* pillar-width 2)
- (* pillar-depth 2)
- 254/3)
- (translate [(+ (* pillar-width 4.125))
- (+ (* pillar-depth -3.25))])))
-
-(def front-left-limit
- (->> (cube (* pillar-width 2.5)
- (* pillar-depth 2)
- 254/3)
- (translate [(+ (* pillar-width -3))
- (+ (* pillar-depth -3))
- 254/9])))
-
-(def front-limit
- (->> (cube (* pillar-width 9)
- (* pillar-depth 2)
- 254/3)
- (translate [(* pillar-width 1/2) (+ (* pillar-depth -4.25)) 254/9])))
-
- (* (/ 25.4 90) pillar-depth (- 3.1 -3.2))
-
-
-(def left-limit
- (->> (cube (* pillar-width 1)
- (* pillar-depth 8)
- 254/3)
- (translate [(+ (* pillar-depth -3.25)) 0 254/9])))
-
-(def right-limit
- (->> (cube (* pillar-width )
- (* pillar-depth 8)
- 1016/9)
- (translate [(+ (* pillar-depth 5.5)) 0 254/9])) )
-
-(* (/ 25.4 90) (- (- (* pillar-depth 5.4) (* pillar-width 1/2))
- (+ (* pillar-depth -3.25) (* pillar-width 1/2))
- ))
-
-(def limits
- (union
- #_front-right-limit
- front-left-limit
- front-limit
- left-limit
- right-limit
- bottom-limit
- back-limit))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Base
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(def main-sphere
- (let [radius (/ (/ pillar-depth 2)
- (Math/sin (/ (/ π 36) 2)))]
- (->> (sphere radius)
- (translate [(* pillar-width 2.5) 0 (+ radius 127/90)]))) )
-
-(def base-cube
- (->> (cube (* pillar-width 7.75)
- (* pillar-depth 7)
- 508/9)
- (translate [(+ (/ pillar-width 2) 2921/450)
- 0 254/9])))
-
-(def base
- (difference
- base-cube
- main-sphere
- limits))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Walls
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-#_(def wall-sphere
- (let [radius (/ (/ pillar-depth 2)
- (Math/sin (/ (/ π 36) 2)))]
- (->> (sphere radius)
- (scale [1 2/3 1])
- (translate [(* pillar-width 2.5) 0 (+ radius 5 (* pillar-depth ))]))))
-
-(def wall-sphere
- (let [radius (/ (/ pillar-depth 2)
- (Math/sin (/ (/ π 36) 2)))]
- (->> (sphere radius)
- (scale [1 2/3 1])
- (translate [0 0 radius])
- (translate [0 0 127/18])
- (rotate (/ π 12) [0 1 0])
- (translate [0 0 (* pillar-depth 3/4)]))))
-
-(def wall-thickness 127/30)
-
-(def back-wall
- (difference
- (translate [0 (- wall-thickness) 0] back-limit)
- back-limit
- right-limit
- left-limit
- bottom-limit
- wall-sphere))
-
-(def walls
- (difference
- (union
- (translate [0 (- wall-thickness) 0] back-limit)
- (translate [(- wall-thickness) 0 0] right-limit)
- (translate [0 wall-thickness 0] front-limit)
- (translate [wall-thickness 0 0] left-limit)
- )
- wall-sphere
- limits))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Wire holes
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(def teensy-center [(* -1.6 pillar-width)
- (* 2.8 pillar-depth)
- 254/45])
-
-(def teensy-tray-slot
- (->> (cube (* 1.125 pillar-width)
- 40
- 508/45)
- (translate teensy-center)))
-
-(def hole-destination
- (->> (cube 5.7 5.7 5.7)
- (translate [(first teensy-center)
- (second teensy-center)
- 2.8 #_3.1])))
-
-(defn bottom-cube [column row]
- (->> (cube 6 6 6)
- (key-place column row)
- (project)
- (extrude-linear {:height 5.7 :twist 0 :convexity 0})
- (translate [0 0 2.8])))
-
-(defn wire-hole [column row]
- (union
- (hull
- (key-place column row (cube 6 6 keyswitch-height))
- (bottom-cube column row))
- (hull
- hole-destination
- (bottom-cube column row))))
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Full Model
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(def fingers
- (let [all-key-coords (for [column (range 0 6)
- row (range 0 5)
- ;; Removing bottom left key
- :when (or (not= column 0)
- (not= row 4))]
- [column row])
- middle-key-coords (for [column (range 0 6)
- row (range 1 4)
- ;; Removing bottom left key
- :when (or (not= column 0)
- (not= row 4))]
- [column row])
- top-key-coords (for [column (range 0 6)]
- [column 0])
- bottom-key-coords (conj (for [column (range 1 6)]
- [column 4])
- [0 3])
-
- ]
- (difference
- (union base
- #_walls
- (apply union
- (map #(key-place (first %) (second %)
- (->> (cube pillar-width pillar-depth
- (* 3 pillar-height))
- (translate [0 0 (/ pillar-height -2)])))
- all-key-coords)))
- (apply union
- (concat
- (map #(key-place (first %) (second %) keyswitch-full-hole)
- middle-key-coords)
- (map #(key-place (first %) (second %) keyswitch-bottom-hole)
- top-key-coords)
- (map #(key-place (first %) (second %) (mirror [0 -1 0] keyswitch-bottom-hole))
- bottom-key-coords)
- ))
- limits
- teensy-tray-slot)))
-
-
-(def wire-network
- (union
- (wire-hole 0 0)
- (wire-hole 1 0)
- (wire-hole 2 0)
- (wire-hole 3 0)
- (wire-hole 4 0)
- (wire-hole 5 0)
- (wire-hole 0 1)
- (wire-hole 0 2)
- (wire-hole 0 3)
- (wire-hole 0 4)
- (wire-hole 1 4)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Actual Output
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-#_(spit "key.scad"
- (write-scad (difference
- pillar
- )))
-
-(spit "key.scad"
- (write-scad (difference
- (union
- #_walls
- #_wall-sphere
- #_fingers
- (difference fingers wire-network)
- #_(mirror [-1 0 0]
- (difference fingers wire-network))
- )
- #_(cube 400 800 800)
- )))
-
-#_(spit "key.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- (difference
- (union
- #_walls
- #_wall-sphere
- #_fingers
- (difference fingers wire-network)
- #_(mirror [-1 0 0]
- (difference fingers wire-network))
- )
- #_(cube 400 800 800)
- ))))
-
-
-#_(spit "key.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- (difference
- fingers
- wire-hole-1
- wire-hole-2))))
-
-#_(spit "key.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- (differe
- #_wall
- #_base
- #_rim
- #_(mirror [1 0 0] fingers)
- fingers
- wire-hole-1))))
-
-#_(spit "key.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- (union
- fingers
- (->> fingers
- project
- (extrude-linear {:height 1 :twist 0 :convexity 0})
- (scale [1.5 1.15 1])
- )
- )
- )))
-
diff --git a/src/dactyl_cave/core.clj b/src/dactyl_cave/core.clj
deleted file mode 100644
index d07faa6..0000000
--- a/src/dactyl_cave/core.clj
+++ /dev/null
@@ -1,6 +0,0 @@
-(ns dactyl-cave.core)
-
-(defn foo
- "I don't do a whole lot."
- [x]
- (println x "Hello, World!"))
diff --git a/src/dactyl_cave/key.clj b/src/dactyl_cave/key.clj
deleted file mode 100644
index 13c46fd..0000000
--- a/src/dactyl_cave/key.clj
+++ /dev/null
@@ -1,81 +0,0 @@
-(ns dactyl-cave.key
- (:use [scad-clj.scad])
- (:use [scad-clj.model])
- (:use [unicode-math.core]))
-
-
-(def tw 13.969999999999999) ;; Top width
-(def smh 0.98044) ;; Side margin height
-(def pw 0.8128) ;; Peg width
-(def ph 3.5001199999999995) ;; Peg height
-(def pgh 5.00888) ;; Peg gap height
-
-(def keyswitch-height (+ smh ph pgh ph smh))
-(def keyswitch-width (+ pw tw pw))
-(def plate-height 254/45)
-
-(defn- flip-path [points] (map (partial map -) points))
-
-(def keyswitch-plate-hole-shape
- (polygon [[0.8128 0] [0.8128 0.98044] [0.0 0.98044] [0.0 4.48056] [0.8128 4.48056] [0.8128 9.48944] [0.0 9.48944] [0.0 12.98956] [0.8128 12.98956] [0.8128 13.969999999999999] [14.7828 13.969999999999999] [14.7828 12.98956] [15.5956 12.98956] [15.5956 9.48944] [14.7828 9.48944] [14.7828 4.48056] [15.5956 4.48056] [15.5956 0.98044] [14.7828 0.98044] [14.7828 0]]))
-
-(def keyswitch-plate-hole
- (->> keyswitch-plate-hole-shape
- (extrude-linear {:height plate-height :twist 0 :convexity 0})
- (translate (map #(/ (- %) 2) [keyswitch-width keyswitch-height 0]))
- (translate [0 0 1])))
-
-(def hole-height 127/18)
-
-(def pillar-width (+ keyswitch-width 127/45))
-(def pillar-height (+ hole-height (/ plate-height 2)))
-(def pillar-depth (+ keyswitch-height 127/30))
-
-(def keyswitch-full-hole
- (->>
- (union
- keyswitch-plate-hole
- (->> (cube (/ ph 2) pillar-depth (* plate-height 2))
- (translate [(* tw -1/4) 0 0]))
- (->> (cube (/ ph 2) pillar-depth (* plate-height 2))
- (translate [(* tw 1/4) 0 0]))
- (translate
- [0 0 (/ hole-height -2)]
- (cube keyswitch-width
- keyswitch-height
- hole-height)))
- (translate [0 0 hole-height])))
-
-(def keyswitch-bottom-hole
- (->>
- (union
- keyswitch-plate-hole
- (->> (cube (/ ph 2) (/ pillar-depth 2) (* plate-height 2))
- (translate [(* tw -1/4) (/ pillar-depth -2) 0]))
- (->> (cube (/ ph 2) (/ pillar-depth 2) (* plate-height 2))
- (translate [(* tw 1/4) (/ pillar-depth -2) 0]))
- (translate
- [0 0 (/ hole-height -2)]
- (cube keyswitch-width
- keyswitch-height
- hole-height)))
- (translate [0 0 hole-height])))
-
-(def full-pillar
- (->> (cube pillar-width pillar-depth
- pillar-height)
- (translate [0 0 (/ pillar-height 2)])))
-
-(def pillar
- (difference
- full-pillar
- keyswitch-full-hole))
-
-(def key-height 127/10)
-
-(def pillar-with-fake-key
- (union pillar
- (->> (cube (+ -0 pillar-width) (+ -0 pillar-depth) key-height)
- (translate [0 0 (+ (/ key-height 2) pillar-height 127/450)]))))
-
-(def full-height (+ pillar-height key-height 127/450))
diff --git a/src/dactyl_cave/text.clj b/src/dactyl_cave/text.clj
deleted file mode 100644
index db37bfd..0000000
--- a/src/dactyl_cave/text.clj
+++ /dev/null
@@ -1,134 +0,0 @@
-(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
diff --git a/src/dactyl_cave/thumb.clj b/src/dactyl_cave/thumb.clj
deleted file mode 100644
index 0dfce97..0000000
--- a/src/dactyl_cave/thumb.clj
+++ /dev/null
@@ -1,173 +0,0 @@
-(ns dactyl-cave.thumb
- (:use [scad-clj.scad])
- (:use [scad-clj.model])
- (:use [unicode-math.core])
- (:require [dactyl-cave.key :as key])
- (:require [dactyl-cave.cave :as cave]))
-
-(defn thumb-place [column row shape]
- (let [α (/ π 12)
- row-radius (+ (/ (/ key/pillar-depth 2)
- (Math/sin (/ α 2)))
- key/full-height)
- β (/ π 36)
- column-radius (+ (/ (/ (+ key/pillar-width 5) 2)
- (Math/sin (/ β 2)))
- key/full-height)]
- (->> shape
- (translate [0 0 (- row-radius)])
- (rotate (* α row) [1 0 0])
- (translate [0 0 row-radius])
- (translate [0 0 (- column-radius)])
- (rotate (* column β) [0 1 0])
- (translate [0 0 column-radius])
- (translate [key/pillar-width 0 0])
- (rotate (/ π 12) [0 1 0])
- (rotate (* π (- 1/4 1/16)) [0 0 1])
- (rotate (/ π 12) [1 1 0])
- (translate [254/45 127/15 1778/45]))))
-
-(defn thumb-2x-column [shape]
- (thumb-place 0 -1/2 shape))
-
-(defn thumb-2x+1-column [shape]
- (union (thumb-place 1 -1/2 shape)
- (thumb-place 1 1 shape)))
-
-(defn thumb-1x-column [shape]
- (union (thumb-place 2 -1 shape)
- (thumb-place 2 0 shape)
- (thumb-place 2 1 shape)))
-
-(defn thumb-layout [shape]
- (union
- (thumb-2x-column shape)
- (thumb-2x+1-column shape)
- (thumb-1x-column shape)))
-
-(defn support [shape]
- (hull
- shape
- (extrude-linear {:height 127/45 :twist 0 :convexity 0}
- (project (hull shape)))))
-
-(defn thumb-support [shape]
- (let [column-supports
- (union
- (support (thumb-2x-column shape))
- (support (thumb-2x+1-column shape))
- (support (thumb-1x-column shape)))]
- (union column-supports
- (support column-supports))))
-(fn [])
-(def bottom
- (translate [0 0 -254/9] (cube 5080/9 5080/9 508/9)))
-
-(def thumb-base
- (thumb-support (scale [1 1 1/10] key/full-pillar)))
-
-#_(defn move-to-corner [shape]
- (translate [-6731/90 -5461/90 0] shape))
-
-(defn move-to-corner [shape]
- (translate [(+ -6731/90 10) (- -5461/90 10) 0] shape))
-
-(/ -6731 90.0) -74.78888888888889
-(double -5461/90) -60.67777777777778
-
-(def thumb-cluster
- (difference
- (translate [0 0 -254/45]
- (difference
- (union
- (thumb-layout key/pillar)
- thumb-base)
- (thumb-layout key/keyswitch-full-hole)))
- bottom))
-
-(def connection-stems
- (difference
- (hull (union
- (->> (cylinder 127/90 508/9)
- (translate [-0 -2413/45 0]))
- (->> (cylinder 127/90 508/9)
- (translate [-127/3 -0 0]))
- (->> (cylinder 127/90 508/9)
- (translate [-2159/30 -127/5 0]))
- (->> (cylinder 127/90 508/9)
- (translate [-508/9 -381/5 0]))))
- bottom
- cave/main-sphere
- (translate [0 0 -254/45]
- (thumb-layout key/keyswitch-full-hole))))
-
-(def wire-network
- (apply union
- (for [[column row] [[0 -1/2]
- [1 -1/2]
- [1 1]
- [2 -1]
- [2 0]
- [2 1]]]
- (let [middle-hole (->> (thumb-place column row (cube 6 6 6))
- (translate [0 0 -127/9])
- move-to-corner)]
- #_(thumb-place column row (sphere 127/9))
- (union (hull (->> (cube 254/45 254/45 key/keyswitch-height)
- (thumb-place column row)
- move-to-corner)
- middle-hole)
- (hull middle-hole (cave/bottom-cube 0 4))
- (hull (cave/bottom-cube 0 4) cave/hole-destination))))))
-
-
-(spit "thumb.scad"
- (write-scad (difference
- (union
- (move-to-corner thumb-cluster)
- connection-stems
-
- #_cave/base
- #_cave/fingers)
- cave/base
- wire-network)))
-
-#_(spit "thumb.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- (mirror [-1 0 0]
- (difference
- (union
- (move-to-corner thumb-cluster)
- connection-stems
-
- #_cave/base
- #_cave/fingers)
- cave/base
- wire-network)))))
-
-#_(spit "thumb.scad"
- (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
- (mirror [-1 0 0]
- (difference
- (union
- (move-to-corner thumb-cluster)
- connection-stems
-
- #_cave/base
- #_cave/fingers)
- cave/base
- wire-network)))))
-
-
-
-
-(spit "one-piece.scad"
- (write-scad
- (mirror [-1 0 0]
- (union (difference cave/fingers cave/wire-network)
- (difference
- (union
- (move-to-corner thumb-cluster)
- connection-stems)
- cave/base
- wire-network)))))
diff --git a/src/dactyl_keyboard/dactyl.clj b/src/dactyl_keyboard/dactyl.clj
new file mode 100644
index 0000000..2e26ed2
--- /dev/null
+++ b/src/dactyl_keyboard/dactyl.clj
@@ -0,0 +1,1240 @@
+(ns dactyl-keyboard.dactyl
+ (:refer-clojure :exclude [use import])
+ (:require [scad-clj.scad :refer :all]
+ [scad-clj.model :refer :all]
+ [unicode-math.core :refer :all]))
+
+;;;;;;;;;;;;;;;;;
+;; Switch Hole ;;
+;;;;;;;;;;;;;;;;;
+
+(def keyswitch-height 14.4) ;; Was 14.1, then 14.25
+(def keyswitch-width 14.4)
+
+(def sa-profile-key-height 12.7)
+
+(def plate-thickness 4)
+(def mount-width (+ keyswitch-width 3))
+(def mount-height (+ keyswitch-height 3))
+
+(def single-plate
+ (let [top-wall (->> (cube (+ keyswitch-width 3) 1.5 plate-thickness)
+ (translate [0
+ (+ (/ 1.5 2) (/ keyswitch-height 2))
+ (/ plate-thickness 2)]))
+ left-wall (->> (cube 1.5 (+ keyswitch-height 3) plate-thickness)
+ (translate [(+ (/ 1.5 2) (/ keyswitch-width 2))
+ 0
+ (/ plate-thickness 2)]))
+ side-nub (->> (binding [*fn* 30] (cylinder 1 2.75))
+ (rotate (/ π 2) [1 0 0])
+ (translate [(+ (/ keyswitch-width 2)) 0 1])
+ (hull (->> (cube 1.5 2.75 plate-thickness)
+ (translate [(+ (/ 1.5 2) (/ keyswitch-width 2))
+ 0
+ (/ plate-thickness 2)]))))
+ plate-half (union top-wall left-wall (with-fn 100 side-nub))]
+ (union plate-half
+ (->> plate-half
+ (mirror [1 0 0])
+ (mirror [0 1 0])))))
+
+;;;;;;;;;;;;;;;;
+;; SA Keycaps ;;
+;;;;;;;;;;;;;;;;
+
+(def sa-length 18.25)
+(def sa-double-length 37.5)
+(def sa-cap {1 (let [bl2 (/ 18.5 2)
+ m (/ 17 2)
+ key-cap (hull (->> (polygon [[bl2 bl2] [bl2 (- bl2)] [(- bl2) (- bl2)] [(- bl2) bl2]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 0.05]))
+ (->> (polygon [[m m] [m (- m)] [(- m) (- m)] [(- m) m]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 6]))
+ (->> (polygon [[6 6] [6 -6] [-6 -6] [-6 6]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 12])))]
+ (->> key-cap
+ (translate [0 0 (+ 5 plate-thickness)])
+ (color [220/255 163/255 163/255 1])))
+ 2 (let [bl2 (/ sa-double-length 2)
+ bw2 (/ 18.25 2)
+ key-cap (hull (->> (polygon [[bw2 bl2] [bw2 (- bl2)] [(- bw2) (- bl2)] [(- bw2) bl2]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 0.05]))
+ (->> (polygon [[6 16] [6 -16] [-6 -16] [-6 16]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 12])))]
+ (->> key-cap
+ (translate [0 0 (+ 5 plate-thickness)])
+ (color [127/255 159/255 127/255 1])))
+ 1.5 (let [bl2 (/ 18.25 2)
+ bw2 (/ 28 2)
+ key-cap (hull (->> (polygon [[bw2 bl2] [bw2 (- bl2)] [(- bw2) (- bl2)] [(- bw2) bl2]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 0.05]))
+ (->> (polygon [[11 6] [-11 6] [-11 -6] [11 -6]])
+ (extrude-linear {:height 0.1 :twist 0 :convexity 0})
+ (translate [0 0 12])))]
+ (->> key-cap
+ (translate [0 0 (+ 5 plate-thickness)])
+ (color [240/255 223/255 175/255 1])))})
+
+;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Placement Functions ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def columns (range 0 6))
+(def rows (range 0 5))
+
+(def α (/ π 12))
+(def β (/ π 36))
+(def cap-top-height (+ plate-thickness sa-profile-key-height))
+(def row-radius (+ (/ (/ (+ mount-height 1/2) 2)
+ (Math/sin (/ α 2)))
+ cap-top-height))
+(def column-radius (+ (/ (/ (+ mount-width 2.0) 2)
+ (Math/sin (/ β 2)))
+ cap-top-height))
+
+(defn key-place [column row shape]
+ (let [row-placed-shape (->> shape
+ (translate [0 0 (- row-radius)])
+ (rotate (* α (- 2 row)) [1 0 0])
+ (translate [0 0 row-radius]))
+ column-offset (cond
+ (= column 2) [0 2.82 -4.5]
+ (>= column 4) [0 -5.8 5.64]
+ :else [0 0 0])
+ column-angle (* β (- 2 column))
+ placed-shape (->> row-placed-shape
+ (translate [0 0 (- column-radius)])
+ (rotate column-angle [0 1 0])
+ (translate [0 0 column-radius])
+ (translate column-offset))]
+ (->> placed-shape
+ (rotate (/ π 12) [0 1 0])
+ (translate [0 0 13]))))
+
+(defn case-place [column row shape]
+ (let [row-placed-shape (->> shape
+ (translate [0 0 (- row-radius)])
+ (rotate (* α (- 2 row)) [1 0 0])
+ (translate [0 0 row-radius]))
+ column-offset [0 -4.35 5.64]
+ column-angle (* β (- 2 column))
+ placed-shape (->> row-placed-shape
+ (translate [0 0 (- column-radius)])
+ (rotate column-angle [0 1 0])
+ (translate [0 0 column-radius])
+ (translate column-offset))]
+ (->> placed-shape
+ (rotate (/ π 12) [0 1 0])
+ (translate [0 0 13]))))
+
+(def key-holes
+ (apply union
+ (for [column columns
+ row rows
+ :when (or (not= column 0)
+ (not= row 4))]
+ (->> single-plate
+ (key-place column row)))))
+
+(def caps
+ (apply union
+ (for [column columns
+ row rows
+ :when (or (not= column 0)
+ (not= row 4))]
+ (->> (sa-cap (if (= column 5) 1 1))
+ (key-place column row)))))
+
+;;;;;;;;;;;;;;;;;;;;
+;; Web Connectors ;;
+;;;;;;;;;;;;;;;;;;;;
+
+(def web-thickness 3.5)
+(def post-size 0.1)
+(def web-post (->> (cube post-size post-size web-thickness)
+ (translate [0 0 (+ (/ web-thickness -2)
+ plate-thickness)])))
+
+(def post-adj (/ post-size 2))
+(def web-post-tr (translate [(- (/ mount-width 2) post-adj) (- (/ mount-height 2) post-adj) 0] web-post))
+(def web-post-tl (translate [(+ (/ mount-width -2) post-adj) (- (/ mount-height 2) post-adj) 0] web-post))
+(def web-post-bl (translate [(+ (/ mount-width -2) post-adj) (+ (/ mount-height -2) post-adj) 0] web-post))
+(def web-post-br (translate [(- (/ mount-width 2) post-adj) (+ (/ mount-height -2) post-adj) 0] web-post))
+
+(defn triangle-hulls [& shapes]
+ (apply union
+ (map (partial apply hull)
+ (partition 3 1 shapes))))
+
+(def connectors
+ (apply union
+ (concat
+ ;; Row connections
+ (for [column (drop-last columns)
+ row rows
+ :when (or (not= column 0)
+ (not= row 4))]
+ (triangle-hulls
+ (key-place (inc column) row web-post-tl)
+ (key-place column row web-post-tr)
+ (key-place (inc column) row web-post-bl)
+ (key-place column row web-post-br)))
+
+ ;; Column connections
+ (for [column columns
+ row (drop-last rows)
+ :when (or (not= column 0)
+ (not= row 3))]
+ (triangle-hulls
+ (key-place column row web-post-bl)
+ (key-place column row web-post-br)
+ (key-place column (inc row) web-post-tl)
+ (key-place column (inc row) web-post-tr)))
+
+ ;; Diagonal connections
+ (for [column (drop-last columns)
+ row (drop-last rows)
+ :when (or (not= column 0)
+ (not= row 3))]
+ (triangle-hulls
+ (key-place column row web-post-br)
+ (key-place column (inc row) web-post-tr)
+ (key-place (inc column) row web-post-bl)
+ (key-place (inc column) (inc row) web-post-tl))))))
+
+;;;;;;;;;;;;
+;; Thumbs ;;
+;;;;;;;;;;;;
+
+(defn thumb-place [column row shape]
+ (let [cap-top-height (+ plate-thickness sa-profile-key-height)
+ α (/ π 12)
+ row-radius (+ (/ (/ (+ mount-height 1) 2)
+ (Math/sin (/ α 2)))
+ cap-top-height)
+ β (/ π 36)
+ column-radius (+ (/ (/ (+ mount-width 2) 2)
+ (Math/sin (/ β 2)))
+ cap-top-height)
+ #_(+ (/ (/ (+ pillar-width 5) 2)
+ (Math/sin (/ β 2)))
+ cap-top-height)]
+ (->> shape
+ (translate [0 0 (- row-radius)])
+ (rotate (* α row) [1 0 0])
+ (translate [0 0 row-radius])
+ (translate [0 0 (- column-radius)])
+ (rotate (* column β) [0 1 0])
+ (translate [0 0 column-radius])
+ (translate [mount-width 0 0])
+ (rotate (* π (- 1/4 3/16)) [0 0 1])
+ (rotate (/ π 12) [1 1 0])
+ (translate [-52 -45 40]))))
+
+(defn thumb-2x-column [shape]
+ (thumb-place 0 -1/2 shape))
+
+(defn thumb-2x+1-column [shape]
+ (union (thumb-place 1 -1/2 shape)
+ (thumb-place 1 1 shape)))
+
+(defn thumb-1x-column [shape]
+ (union (thumb-place 2 -1 shape)
+ (thumb-place 2 0 shape)
+ (thumb-place 2 1 shape)))
+
+(defn thumb-layout [shape]
+ (union
+ (thumb-2x-column shape)
+ (thumb-2x+1-column shape)
+ (thumb-1x-column shape)))
+
+(def double-plates
+ (let [plate-height (/ (- sa-double-length mount-height) 2)
+ top-plate (->> (cube mount-width plate-height web-thickness)
+ (translate [0 (/ (+ plate-height mount-height) 2)
+ (- plate-thickness (/ web-thickness 2))]))
+ stabilizer-cutout (union (->> (cube 14.2 3.5 web-thickness)
+ (translate [0.5 12 (- plate-thickness (/ web-thickness 2))])
+ (color [1 0 0 1/2]))
+ (->> (cube 16 3.5 web-thickness)
+ (translate [0.5 12 (- plate-thickness (/ web-thickness 2) 1.4)])
+ (color [1 0 0 1/2])))
+ top-plate (difference top-plate stabilizer-cutout)]
+ (union top-plate (mirror [0 1 0] top-plate))))
+
+(def thumbcaps
+ (union
+ (thumb-2x-column (sa-cap 2))
+ (thumb-place 1 -1/2 (sa-cap 2))
+ (thumb-place 1 1 (sa-cap 1))
+ (thumb-1x-column (sa-cap 1))))
+
+(def thumb-connectors
+ (union
+ (apply union
+ (concat
+ (for [column [2] row [1]]
+ (triangle-hulls (thumb-place column row web-post-br)
+ (thumb-place column row web-post-tr)
+ (thumb-place (dec column) row web-post-bl)
+ (thumb-place (dec column) row web-post-tl)))
+ (for [column [2] row [0 1]]
+ (triangle-hulls
+ (thumb-place column row web-post-bl)
+ (thumb-place column row web-post-br)
+ (thumb-place column (dec row) web-post-tl)
+ (thumb-place column (dec row) web-post-tr)))))
+ (let [plate-height (/ (- sa-double-length mount-height) 2)
+ thumb-tl (->> web-post-tl
+ (translate [0 plate-height 0]))
+ thumb-bl (->> web-post-bl
+ (translate [0 (- plate-height) 0]))
+ thumb-tr (->> web-post-tr
+ (translate [0 plate-height 0]))
+ thumb-br (->> web-post-br
+ (translate [0 (- plate-height) 0]))]
+ (union
+
+ ;;Connecting the two doubles
+ (triangle-hulls (thumb-place 0 -1/2 thumb-tl)
+ (thumb-place 0 -1/2 thumb-bl)
+ (thumb-place 1 -1/2 thumb-tr)
+ (thumb-place 1 -1/2 thumb-br))
+
+ ;;Connecting the double to the one above it
+ (triangle-hulls (thumb-place 1 -1/2 thumb-tr)
+ (thumb-place 1 -1/2 thumb-tl)
+ (thumb-place 1 1 web-post-br)
+ (thumb-place 1 1 web-post-bl))
+
+ ;;Connecting the 4 with the double in the bottom left
+ (triangle-hulls (thumb-place 1 1 web-post-bl)
+ (thumb-place 1 -1/2 thumb-tl)
+ (thumb-place 2 1 web-post-br)
+ (thumb-place 2 0 web-post-tr))
+
+ ;;Connecting the two singles with the middle double
+ (hull (thumb-place 1 -1/2 thumb-tl)
+ (thumb-place 1 -1/2 thumb-bl)
+ (thumb-place 2 0 web-post-br)
+ (thumb-place 2 -1 web-post-tr))
+ (hull (thumb-place 1 -1/2 thumb-tl)
+ (thumb-place 2 0 web-post-tr)
+ (thumb-place 2 0 web-post-br))
+ (hull (thumb-place 1 -1/2 thumb-bl)
+ (thumb-place 2 -1 web-post-tr)
+ (thumb-place 2 -1 web-post-br))
+
+ ;;Connecting the thumb to everything
+ (triangle-hulls (thumb-place 0 -1/2 thumb-br)
+ (key-place 1 4 web-post-bl)
+ (thumb-place 0 -1/2 thumb-tr)
+ (key-place 1 4 web-post-tl)
+ (key-place 1 3 web-post-bl)
+ (thumb-place 0 -1/2 thumb-tr)
+ (key-place 0 3 web-post-br)
+ (key-place 0 3 web-post-bl)
+ (thumb-place 0 -1/2 thumb-tr)
+ (thumb-place 0 -1/2 thumb-tl)
+ (key-place 0 3 web-post-bl)
+ (thumb-place 1 -1/2 thumb-tr)
+ (thumb-place 1 1 web-post-br)
+ (key-place 0 3 web-post-bl)
+ (key-place 0 3 web-post-tl)
+ (thumb-place 1 1 web-post-br)
+ (thumb-place 1 1 web-post-tr))
+ (hull (thumb-place 0 -1/2 web-post-tr)
+ (thumb-place 0 -1/2 thumb-tr)
+ (key-place 1 4 web-post-bl)
+ (key-place 1 4 web-post-tl))))))
+
+(def thumb
+ (union
+ thumb-connectors
+ (thumb-layout (rotate (/ π 2) [0 0 1] single-plate))
+ (thumb-place 0 -1/2 double-plates)
+ (thumb-place 1 -1/2 double-plates)))
+
+;;;;;;;;;;
+;; Case ;;
+;;;;;;;;;;
+
+;; In column units
+(def right-wall-column (+ (last columns) 0.55))
+(def left-wall-column (- (first columns) 1/2))
+(def thumb-back-y 0.93)
+(def thumb-right-wall (- -1/2 0.05))
+(def thumb-front-row (+ -1 0.07))
+(def thumb-left-wall-column (+ 5/2 0.05))
+(def back-y 0.02)
+
+(defn range-inclusive [start end step]
+ (concat (range start end step) [end]))
+
+(def wall-step 0.2)
+(def wall-sphere-n 20) ;;Sphere resolution, lower for faster renders
+
+(defn wall-sphere-at [coords]
+ (->> (sphere 1)
+ (translate coords)
+ (with-fn wall-sphere-n)))
+
+(defn scale-to-range [start end x]
+ (+ start (* (- end start) x)))
+
+(defn wall-sphere-bottom [front-to-back-scale]
+ (wall-sphere-at [0
+ (scale-to-range
+ (+ (/ mount-height -2) -3.5)
+ (+ (/ mount-height 2) 5.0)
+ front-to-back-scale)
+ -6]))
+
+(defn wall-sphere-top [front-to-back-scale]
+ (wall-sphere-at [0
+ (scale-to-range
+ (+ (/ mount-height -2) -3.5)
+ (+ (/ mount-height 2) 3.5)
+ front-to-back-scale)
+ 10]))
+
+(def wall-sphere-top-back (wall-sphere-top 1))
+(def wall-sphere-bottom-back (wall-sphere-bottom 1))
+(def wall-sphere-bottom-front (wall-sphere-bottom 0))
+(def wall-sphere-top-front (wall-sphere-top 0))
+
+(defn top-case-cover [place-fn sphere
+ x-start x-end
+ y-start y-end
+ step]
+ (apply union
+ (for [x (range-inclusive x-start (- x-end step) step)
+ y (range-inclusive y-start (- y-end step) step)]
+ (hull (place-fn x y sphere)
+ (place-fn (+ x step) y sphere)
+ (place-fn x (+ y step) sphere)
+ (place-fn (+ x step) (+ y step) sphere)))))
+
+(def front-wall
+ (let [step wall-step ;;0.1
+ wall-step 0.05 ;;0.05
+ place case-place
+ top-cover (fn [x-start x-end y-start y-end]
+ (top-case-cover place wall-sphere-top-front
+ x-start x-end y-start y-end
+ wall-step))]
+ (union
+ (apply union
+ (for [x (range-inclusive 0.7 (- right-wall-column step) step)]
+ (hull (place x 4 wall-sphere-top-front)
+ (place (+ x step) 4 wall-sphere-top-front)
+ (place x 4 wall-sphere-bottom-front)
+ (place (+ x step) 4 wall-sphere-bottom-front))))
+ (apply union
+ (for [x (range-inclusive 0.5 0.7 0.01)]
+ (hull (place x 4 wall-sphere-top-front)
+ (place (+ x step) 4 wall-sphere-top-front)
+ (place 0.7 4 wall-sphere-bottom-front))))
+ (top-cover 0.5 1.7 3.6 4)
+ (top-cover 1.59 2.41 3.35 4) ;; was 3.32
+ (top-cover 2.39 3.41 3.6 4)
+ (apply union
+ (for [x (range 2 5)]
+ (union
+ (hull (place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (place (+ x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place x 4 web-post-bl)
+ (key-place x 4 web-post-br))
+ (hull (place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place x 4 web-post-bl)
+ (key-place (- x 1) 4 web-post-br)))))
+ (hull (place right-wall-column 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place 5 4 web-post-bl)
+ (key-place 5 4 web-post-br))
+ (hull (place (+ 4 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place 4 4 web-post-br)
+ (key-place 5 4 web-post-bl))
+ (hull (place 0.7 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (place 1.7 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place 1 4 web-post-bl)
+ (key-place 1 4 web-post-br)))))
+
+(def back-wall
+ (let [step wall-step
+ wall-sphere-top-backtep 0.05
+ place case-place
+ front-top-cover (fn [x-start x-end y-start y-end]
+ (apply union
+ (for [x (range-inclusive x-start (- x-end wall-sphere-top-backtep) wall-sphere-top-backtep)
+ y (range-inclusive y-start (- y-end wall-sphere-top-backtep) wall-sphere-top-backtep)]
+ (hull (place x y wall-sphere-top-back)
+ (place (+ x wall-sphere-top-backtep) y wall-sphere-top-back)
+ (place x (+ y wall-sphere-top-backtep) wall-sphere-top-back)
+ (place (+ x wall-sphere-top-backtep) (+ y wall-sphere-top-backtep) wall-sphere-top-back)))))]
+ (union
+ (apply union
+ (for [x (range-inclusive left-wall-column (- right-wall-column step) step)]
+ (hull (place x back-y wall-sphere-top-back)
+ (place (+ x step) back-y wall-sphere-top-back)
+ (place x back-y wall-sphere-bottom-back)
+ (place (+ x step) back-y wall-sphere-bottom-back))))
+ (front-top-cover 1.56 2.44 back-y 0.1)
+ (front-top-cover 3.56 4.44 back-y 0.13)
+ (front-top-cover 4.3 right-wall-column back-y 0.13)
+
+
+ (hull (place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
+ (place (+ left-wall-column 1) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place 0 0 web-post-tl)
+ (key-place 0 0 web-post-tr))
+
+ (hull (place 5 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (place right-wall-column 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place 5 0 web-post-tl)
+ (key-place 5 0 web-post-tr))
+
+ (apply union
+ (for [x (range 1 5)]
+ (union
+ (hull (place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (place (+ x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place x 0 web-post-tl)
+ (key-place x 0 web-post-tr))
+ (hull (place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place x 0 web-post-tl)
+ (key-place (- x 1) 0 web-post-tr)))))
+ (hull (place (- 5 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (place 5 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place 4 0 web-post-tr)
+ (key-place 5 0 web-post-tl)))))
+
+(def right-wall
+ (let [place case-place]
+ (union
+ (apply union
+ (map (partial apply hull)
+ (partition 2 1
+ (for [scale (range-inclusive 0 1 0.01)]
+ (let [x (scale-to-range 4 0.02 scale)]
+ (hull (place right-wall-column x (wall-sphere-top scale))
+ (place right-wall-column x (wall-sphere-bottom scale))))))))
+
+ (apply union
+ (concat
+ (for [x (range 0 5)]
+ (union
+ (hull (place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (key-place 5 x web-post-br)
+ (key-place 5 x web-post-tr))))
+ (for [x (range 0 4)]
+ (union
+ (hull (place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (place right-wall-column (inc x) (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (key-place 5 x web-post-br)
+ (key-place 5 (inc x) web-post-tr))))
+ [(union
+ (hull (place right-wall-column 0 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (place right-wall-column 0.02 (translate [-1 -1 1] (wall-sphere-bottom 1)))
+ (key-place 5 0 web-post-tr))
+ (hull (place right-wall-column 4 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (place right-wall-column 4 (translate [-1 1 1] (wall-sphere-bottom 0)))
+ (key-place 5 4 web-post-br)))])))))
+
+(def left-wall
+ (let [place case-place]
+ (union
+ (apply union
+ (for [x (range-inclusive -1 (- 1.6666 wall-step) wall-step)]
+ (hull (place left-wall-column x wall-sphere-top-front)
+ (place left-wall-column (+ x wall-step) wall-sphere-top-front)
+ (place left-wall-column x wall-sphere-bottom-front)
+ (place left-wall-column (+ x wall-step) wall-sphere-bottom-front))))
+ (hull (place left-wall-column -1 wall-sphere-top-front)
+ (place left-wall-column -1 wall-sphere-bottom-front)
+ (place left-wall-column 0.02 wall-sphere-top-back)
+ (place left-wall-column 0.02 wall-sphere-bottom-back))
+ (hull (place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
+ (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
+ (key-place 0 0 web-post-tl)
+ (key-place 0 0 web-post-bl))
+ (hull (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
+ (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
+ (key-place 0 0 web-post-bl)
+ (key-place 0 1 web-post-bl))
+ (hull (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
+ (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (key-place 0 1 web-post-bl)
+ (key-place 0 2 web-post-bl))
+ (hull (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (key-place 0 2 web-post-bl)
+ (key-place 0 3 web-post-tl))
+ (hull (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (thumb-place 1 1 web-post-tr)
+ (key-place 0 3 web-post-tl))
+ (hull (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (thumb-place 1 1 web-post-tr)
+ (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))))))
+
+(def thumb-back-wall
+ (let [step wall-step
+ top-step 0.05
+ front-top-cover (fn [x-start x-end y-start y-end]
+ (apply union
+ (for [x (range-inclusive x-start (- x-end top-step) top-step)
+ y (range-inclusive y-start (- y-end top-step) top-step)]
+ (hull (thumb-place x y wall-sphere-top-back)
+ (thumb-place (+ x top-step) y wall-sphere-top-back)
+ (thumb-place x (+ y top-step) wall-sphere-top-back)
+ (thumb-place (+ x top-step) (+ y top-step) wall-sphere-top-back)))))
+ back-y thumb-back-y]
+ (union
+ (apply union
+ (for [x (range-inclusive 1/2 (- (+ 5/2 0.05) step) step)]
+ (hull (thumb-place x back-y wall-sphere-top-back)
+ (thumb-place (+ x step) back-y wall-sphere-top-back)
+ (thumb-place x back-y wall-sphere-bottom-back)
+ (thumb-place (+ x step) back-y wall-sphere-bottom-back))))
+ (hull (thumb-place 1/2 back-y wall-sphere-top-back)
+ (thumb-place 1/2 back-y wall-sphere-bottom-back)
+ (case-place left-wall-column 1.6666 wall-sphere-top-front))
+ (hull (thumb-place 1/2 back-y wall-sphere-bottom-back)
+ (case-place left-wall-column 1.6666 wall-sphere-top-front)
+ (case-place left-wall-column 1.6666 wall-sphere-bottom-front))
+ (hull
+ (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (thumb-place 1 1 web-post-tr)
+ (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (thumb-place 1 1 web-post-tl))
+ (hull
+ (thumb-place (+ 5/2 0.05) thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
+ (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (thumb-place 1 1 web-post-tl)
+ (thumb-place 2 1 web-post-tl)))))
+
+(def thumb-left-wall
+ (let [step wall-step
+ place thumb-place]
+ (union
+ (apply union
+ (for [x (range-inclusive (+ -1 0.07) (- 1.95 step) step)]
+ (hull (place thumb-left-wall-column x wall-sphere-top-front)
+ (place thumb-left-wall-column (+ x step) wall-sphere-top-front)
+ (place thumb-left-wall-column x wall-sphere-bottom-front)
+ (place thumb-left-wall-column (+ x step) wall-sphere-bottom-front))))
+ (hull (place thumb-left-wall-column 1.95 wall-sphere-top-front)
+ (place thumb-left-wall-column 1.95 wall-sphere-bottom-front)
+ (place thumb-left-wall-column thumb-back-y wall-sphere-top-back)
+ (place thumb-left-wall-column thumb-back-y wall-sphere-bottom-back))
+
+ (hull
+ (thumb-place thumb-left-wall-column thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
+ (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 1 web-post-tl)
+ (thumb-place 2 1 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 0 web-post-tl)
+ (thumb-place 2 1 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 0 web-post-tl)
+ (thumb-place 2 0 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 -1 web-post-tl)
+ (thumb-place 2 0 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place thumb-left-wall-column (+ -1 0.07) (translate [1 1 1] wall-sphere-bottom-front))
+ (thumb-place 2 -1 web-post-tl)
+ (thumb-place 2 -1 web-post-bl)))))
+
+(def thumb-front-wall
+ (let [step wall-step ;;0.1
+ wall-sphere-top-fronttep 0.05 ;;0.05
+ place thumb-place
+ plate-height (/ (- sa-double-length mount-height) 2)
+ thumb-tl (->> web-post-tl
+ (translate [0 plate-height 0]))
+ thumb-bl (->> web-post-bl
+ (translate [0 (- plate-height) 0]))
+ thumb-tr (->> web-post-tr
+ (translate [-0 plate-height 0]))
+ thumb-br (->> web-post-br
+ (translate [-0 (- plate-height) 0]))]
+ (union
+ (apply union
+ (for [x (range-inclusive thumb-right-wall (- (+ 5/2 0.05) step) step)]
+ (hull (place x thumb-front-row wall-sphere-top-front)
+ (place (+ x step) thumb-front-row wall-sphere-top-front)
+ (place x thumb-front-row wall-sphere-bottom-front)
+ (place (+ x step) thumb-front-row wall-sphere-bottom-front))))
+
+ (hull (place thumb-right-wall thumb-front-row wall-sphere-top-front)
+ (place thumb-right-wall thumb-front-row wall-sphere-bottom-front)
+ (case-place 0.5 4 wall-sphere-top-front))
+ (hull (place thumb-right-wall thumb-front-row wall-sphere-bottom-front)
+ (case-place 0.5 4 wall-sphere-top-front)
+ (case-place 0.7 4 wall-sphere-bottom-front))
+
+ (hull (place thumb-right-wall thumb-front-row wall-sphere-bottom-front)
+ (key-place 1 4 web-post-bl)
+ (place 0 -1/2 thumb-br)
+ (place 0 -1/2 web-post-br)
+ (case-place 0.7 4 wall-sphere-bottom-front))
+
+ (hull (place (+ 5/2 0.05) thumb-front-row (translate [1 1 1] wall-sphere-bottom-front))
+ (place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (place 2 -1 web-post-bl)
+ (place 2 -1 web-post-br))
+
+ (hull (place thumb-right-wall thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (place 0 -1/2 thumb-bl)
+ (place 0 -1/2 thumb-br))
+ (hull (place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (place 0 -1/2 thumb-bl)
+ (place 1 -1/2 thumb-bl)
+ (place 1 -1/2 thumb-br)
+ (place 2 -1 web-post-br)))))
+
+(def new-case
+ (union front-wall
+ right-wall
+ back-wall
+ left-wall
+ thumb-back-wall
+ thumb-left-wall
+ thumb-front-wall))
+
+;;;;;;;;;;;;
+;; Bottom ;;
+;;;;;;;;;;;;
+
+
+(defn bottom [height p]
+ (->> (project p)
+ (extrude-linear {:height height :twist 0 :convexity 0})
+ (translate [0 0 (/ height 2)])))
+
+(defn bottom-hull [p]
+ (hull p (bottom 1 p)))
+
+
+(def bottom-key-guard (->> (cube mount-width mount-height web-thickness)
+ (translate [0 0 (+ (- (/ web-thickness 2)) -4.5)])))
+(def bottom-front-key-guard (->> (cube mount-width (/ mount-height 2) web-thickness)
+ (translate [0 (/ mount-height 4) (+ (- (/ web-thickness 2)) -4.5)])))
+
+(def bottom-plate
+ (union
+ (apply union
+ (for [column columns
+ row (drop-last rows) ;;
+ :when (or (not= column 0)
+ (not= row 4))]
+ (->> bottom-key-guard
+ (key-place column row))))
+ (thumb-layout (rotate (/ π 2) [0 0 1] bottom-key-guard))
+ (apply union
+ (for [column columns
+ row [(last rows)] ;;
+ :when (or (not= column 0)
+ (not= row 4))]
+ (->> bottom-front-key-guard
+ (key-place column row))))
+ (let [shift #(translate [0 0 (+ (- web-thickness) -5)] %)
+ web-post-tl (shift web-post-tl)
+ web-post-tr (shift web-post-tr)
+ web-post-br (shift web-post-br)
+ web-post-bl (shift web-post-bl)
+ half-shift-correction #(translate [0 (/ mount-height 2) 0] %)
+ half-post-br (half-shift-correction web-post-br)
+ half-post-bl (half-shift-correction web-post-bl)
+ row-connections (concat
+ (for [column (drop-last columns)
+ row (drop-last rows)
+ :when (or (not= column 0)
+ (not= row 4))]
+ (triangle-hulls
+ (key-place (inc column) row web-post-tl)
+ (key-place column row web-post-tr)
+ (key-place (inc column) row web-post-bl)
+ (key-place column row web-post-br)))
+ (for [column (drop-last columns)
+ row [(last rows)]
+ :when (or (not= column 0)
+ (not= row 4))]
+ (triangle-hulls
+ (key-place (inc column) row web-post-tl)
+ (key-place column row web-post-tr)
+ (key-place (inc column) row half-post-bl)
+ (key-place column row half-post-br))))
+ column-connections (for [column columns
+ row (drop-last rows)
+ :when (or (not= column 0)
+ (not= row 3))]
+ (triangle-hulls
+ (key-place column row web-post-bl)
+ (key-place column row web-post-br)
+ (key-place column (inc row) web-post-tl)
+ (key-place column (inc row) web-post-tr)))
+ diagonal-connections (for [column (drop-last columns)
+ row (drop-last rows)
+ :when (or (not= column 0)
+ (not= row 3))]
+ (triangle-hulls
+ (key-place column row web-post-br)
+ (key-place column (inc row) web-post-tr)
+ (key-place (inc column) row web-post-bl)
+ (key-place (inc column) (inc row) web-post-tl)))
+ main-keys-bottom (concat row-connections
+ column-connections
+ diagonal-connections)
+ front-wall (concat
+ (for [x (range 2 5)]
+ (union
+ (hull (case-place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (case-place (+ x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place x 4 half-post-bl)
+ (key-place x 4 half-post-br))
+ (hull (case-place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place x 4 half-post-bl)
+ (key-place (- x 1) 4 half-post-br))))
+ [(hull (case-place right-wall-column 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (case-place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place 5 4 half-post-bl)
+ (key-place 5 4 half-post-br))
+ (hull (case-place (+ 4 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (case-place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (key-place 4 4 half-post-br)
+ (key-place 5 4 half-post-bl))])
+ right-wall (concat
+ (for [x (range 0 4)]
+ (hull (case-place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (key-place 5 x web-post-br)
+ (key-place 5 x web-post-tr)))
+ (for [x (range 0 4)]
+ (hull (case-place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (case-place right-wall-column (inc x) (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (key-place 5 x web-post-br)
+ (key-place 5 (inc x) web-post-tr)))
+ [(union
+ (hull (case-place right-wall-column 0 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (case-place right-wall-column 0.02 (translate [-1 -1 1] (wall-sphere-bottom 1)))
+ (key-place 5 0 web-post-tr)
+ )
+ (hull (case-place right-wall-column 4 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (case-place right-wall-column 4 (translate [0 1 1] (wall-sphere-bottom 0)))
+ (key-place 5 4 half-post-br)
+ )
+ (hull (case-place right-wall-column 4 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
+ (key-place 5 4 half-post-br)
+ (key-place 5 4 web-post-tr)))])
+ back-wall (concat
+ (for [x (range 1 6)]
+ (union
+ (hull (case-place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (case-place (+ x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place x 0 web-post-tl)
+ (key-place x 0 web-post-tr))
+ (hull (case-place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place x 0 web-post-tl)
+ (key-place (- x 1) 0 web-post-tr))))
+ [(hull (case-place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
+ (case-place (+ left-wall-column 1) 0 (translate [0 -1 1] wall-sphere-bottom-back))
+ (key-place 0 0 web-post-tl)
+ (key-place 0 0 web-post-tr))])
+ left-wall (let [place case-place]
+ [(hull (place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
+ (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
+ (key-place 0 0 web-post-tl)
+ (key-place 0 0 web-post-bl))
+ (hull (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
+ (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
+ (key-place 0 0 web-post-bl)
+ (key-place 0 1 web-post-bl))
+ (hull (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
+ (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (key-place 0 1 web-post-bl)
+ (key-place 0 2 web-post-bl))
+ (hull (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (key-place 0 2 web-post-bl)
+ (key-place 0 3 web-post-tl))])
+ thumbs [(hull (thumb-place 0 -1/2 web-post-bl)
+ (thumb-place 0 -1/2 web-post-tl)
+ (thumb-place 1 -1/2 web-post-tr)
+ (thumb-place 1 -1/2 web-post-br))
+ (hull (thumb-place 1 -1/2 web-post-tr)
+ (thumb-place 1 -1/2 web-post-tl)
+ (thumb-place 1 1 web-post-bl)
+ (thumb-place 1 1 web-post-br))
+ (hull (thumb-place 2 -1 web-post-tr)
+ (thumb-place 2 -1 web-post-tl)
+ (thumb-place 2 0 web-post-bl)
+ (thumb-place 2 0 web-post-br))
+ (hull (thumb-place 2 0 web-post-tr)
+ (thumb-place 2 0 web-post-tl)
+ (thumb-place 2 1 web-post-bl)
+ (thumb-place 2 1 web-post-br))
+ (triangle-hulls (thumb-place 2 1 web-post-tr)
+ (thumb-place 1 1 web-post-tl)
+ (thumb-place 2 1 web-post-br)
+ (thumb-place 1 1 web-post-bl)
+ (thumb-place 2 0 web-post-tr)
+ (thumb-place 1 -1/2 web-post-tl)
+ (thumb-place 2 0 web-post-br)
+ (thumb-place 1 -1/2 web-post-bl)
+ (thumb-place 2 -1 web-post-tr)
+ (thumb-place 2 -1 web-post-br))
+ (hull (thumb-place 2 -1 web-post-br)
+ (thumb-place 1 -1/2 web-post-bl)
+ (thumb-place 1 -1 web-post-bl))
+ (hull (thumb-place 1 -1/2 web-post-bl)
+ (thumb-place 1 -1 web-post-bl)
+ (thumb-place 1 -1/2 web-post-br)
+ (thumb-place 1 -1 web-post-br))
+ (hull (thumb-place 0 -1/2 web-post-bl)
+ (thumb-place 0 -1 web-post-bl)
+ (thumb-place 0 -1/2 web-post-br)
+ (thumb-place 0 -1 web-post-br))
+ (hull (thumb-place 0 -1/2 web-post-bl)
+ (thumb-place 0 -1 web-post-bl)
+ (thumb-place 1 -1/2 web-post-br)
+ (thumb-place 1 -1 web-post-br))]
+ thumb-back-wall [(hull
+ (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (thumb-place 1 1 web-post-tr)
+ (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (thumb-place 1 1 web-post-tl))
+
+ (hull
+ (thumb-place (+ 5/2 0.05) thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
+ (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (thumb-place 1 1 web-post-tl)
+ (thumb-place 2 1 web-post-tl))
+ (hull
+ (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
+ (case-place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
+ (key-place 0 3 web-post-tl)
+ (thumb-place 1 1 web-post-tr))
+ ]
+ thumb-left-wall [(hull
+ (thumb-place thumb-left-wall-column thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
+ (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 1 web-post-tl)
+ (thumb-place 2 1 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 0 web-post-tl)
+ (thumb-place 2 1 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 0 web-post-tl)
+ (thumb-place 2 0 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place 2 -1 web-post-tl)
+ (thumb-place 2 0 web-post-bl))
+ (hull
+ (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
+ (thumb-place thumb-left-wall-column (+ -1 0.07) (translate [1 1 1] wall-sphere-bottom-front))
+ (thumb-place 2 -1 web-post-tl)
+ (thumb-place 2 -1 web-post-bl))]
+ thumb-front-wall [(hull (thumb-place (+ 5/2 0.05) thumb-front-row (translate [1 1 1] wall-sphere-bottom-front))
+ (thumb-place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (thumb-place 2 -1 web-post-bl)
+ (thumb-place 2 -1 web-post-br))
+ (hull (thumb-place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (thumb-place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (thumb-place 0 -1 web-post-bl)
+ (thumb-place 1 -1 web-post-bl)
+ (thumb-place 1 -1 web-post-br)
+ (thumb-place 2 -1 web-post-br))
+ (hull (thumb-place thumb-right-wall thumb-front-row (translate [-1 1 1] wall-sphere-bottom-front))
+ (thumb-place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
+ (thumb-place 0 -1 web-post-bl)
+ (thumb-place 0 -1 web-post-br))]
+ thumb-inside [(triangle-hulls
+ (thumb-place 1 1 web-post-tr)
+ (key-place 0 3 web-post-tl)
+ (thumb-place 1 1 web-post-br)
+ (key-place 0 3 web-post-bl)
+ (thumb-place 1 -1/2 web-post-tr)
+ (thumb-place 0 -1/2 web-post-tl)
+ (key-place 0 3 web-post-bl)
+ (thumb-place 0 -1/2 web-post-tr)
+ (key-place 0 3 web-post-br)
+ (key-place 1 3 web-post-bl)
+ (thumb-place 0 -1/2 web-post-tr)
+ (key-place 1 4 web-post-tl)
+ (key-place 1 4 half-post-bl))
+
+ (hull
+ (thumb-place 0 -1/2 web-post-tr)
+ (thumb-place 0 -1/2 web-post-br)
+ (key-place 1 4 half-post-bl))
+
+ (hull
+ (key-place 1 4 half-post-bl)
+ (key-place 1 4 half-post-br)
+ (case-place (- 2 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
+ (case-place 0.7 4 (translate [0 1 1] wall-sphere-bottom-front)))
+
+ (hull
+ (thumb-place 0 -1 web-post-br)
+ (thumb-place 0 -1/2 web-post-br)
+ (thumb-place thumb-right-wall thumb-front-row (translate [-1 1 1] wall-sphere-bottom-front))
+ (key-place 1 4 (translate [0 0 8.5] web-post-bl))
+ (key-place 1 4 half-post-bl)
+ )]
+ stands (let [bumper-diameter 9.6
+ bumper-radius (/ bumper-diameter 2)
+ stand-diameter (+ bumper-diameter 2)
+ stand-radius (/ stand-diameter 2)
+ stand-at #(difference (->> (sphere stand-radius)
+ (translate [0 0 (+ (/ stand-radius -2) -4.5)])
+ %
+ (bottom-hull))
+ (->> (cube stand-diameter stand-diameter stand-radius)
+ (translate [0 0 (/ stand-radius -2)])
+ %)
+ (->> (sphere bumper-radius)
+ (translate [0 0 (+ (/ stand-radius -2) -4.5)])
+ %
+ (bottom 1.5)))]
+ [(stand-at #(key-place 0 1 %))
+ (stand-at #(thumb-place 1 -1/2 %))
+ (stand-at #(key-place 5 0 %))
+ (stand-at #(key-place 5 3 %))])]
+ (apply union
+ (concat
+ main-keys-bottom
+ front-wall
+ right-wall
+ back-wall
+ left-wall
+ thumbs
+ thumb-back-wall
+ thumb-left-wall
+ thumb-front-wall
+ thumb-inside
+ stands)))))
+
+(def screw-hole (->> (cylinder 1.5 60)
+ (translate [0 0 3/2])
+ (with-fn wall-sphere-n)))
+
+(def screw-holes
+ (union
+ (key-place (+ 4 1/2) 1/2 screw-hole)
+ (key-place (+ 4 1/2) (+ 3 1/2) screw-hole)
+ (thumb-place 2 -1/2 screw-hole)))
+
+(defn circuit-cover [width length height]
+ (let [cover-sphere-radius 1
+ cover-sphere (->> (sphere cover-sphere-radius)
+ (with-fn 20))
+ cover-sphere-z (+ (- height) (- cover-sphere-radius))
+ cover-sphere-x (+ (/ width 2) cover-sphere-radius)
+ cover-sphere-y (+ (/ length 2) (+ cover-sphere-radius))
+ cover-sphere-tl (->> cover-sphere
+ (translate [(- cover-sphere-x) (- cover-sphere-y) cover-sphere-z])
+ (key-place 1/2 3/2))
+ cover-sphere-tr (->> cover-sphere
+ (translate [cover-sphere-x (- cover-sphere-y) cover-sphere-z])
+ (key-place 1/2 3/2))
+ cover-sphere-br (->> cover-sphere
+ (translate [cover-sphere-x cover-sphere-y cover-sphere-z])
+ (key-place 1/2 3/2))
+ cover-sphere-bl (->> cover-sphere
+ (translate [(- cover-sphere-x) cover-sphere-y cover-sphere-z])
+ (key-place 1/2 3/2))
+
+ lower-to-bottom #(translate [0 0 (+ (- cover-sphere-radius) -5.5)] %)
+ bl (->> cover-sphere lower-to-bottom (key-place 0 1/2))
+ br (->> cover-sphere lower-to-bottom (key-place 1 1/2))
+ tl (->> cover-sphere lower-to-bottom (key-place 0 5/2))
+ tr (->> cover-sphere lower-to-bottom (key-place 1 5/2))
+
+ mlb (->> cover-sphere
+ (translate [(- cover-sphere-x) 0 (+ (- height) -1)])
+ (key-place 1/2 3/2))
+ mrb (->> cover-sphere
+ (translate [cover-sphere-x 0 (+ (- height) -1)])
+ (key-place 1/2 3/2))
+
+ mlt (->> cover-sphere
+ (translate [(+ (- cover-sphere-x) -4) 0 -6])
+ (key-place 1/2 3/2))
+ mrt (->> cover-sphere
+ (translate [(+ cover-sphere-x 4) 0 -6])
+ (key-place 1/2 3/2))]
+ (union
+ (hull cover-sphere-bl cover-sphere-br cover-sphere-tl cover-sphere-tr)
+ (hull cover-sphere-br cover-sphere-bl bl br)
+ (hull cover-sphere-tr cover-sphere-tl tl tr)
+ (hull cover-sphere-tl tl mlb mlt)
+ (hull cover-sphere-bl bl mlb mlt)
+ (hull cover-sphere-tr tr mrb mrt)
+ (hull cover-sphere-br br mrb mrt))))
+
+(def io-exp-width 10)
+(def io-exp-height 8)
+(def io-exp-length 36)
+
+(def teensy-width 20)
+(def teensy-height 12)
+(def teensy-length 33)
+
+(def io-exp-cover (circuit-cover io-exp-width io-exp-length io-exp-height))
+(def teensy-cover (circuit-cover teensy-width teensy-length teensy-height))
+
+(def trrs-diameter 6.6)
+(def trrs-radius (/ trrs-diameter 2))
+(def trrs-hole-depth 10)
+
+(def trrs-hole (->> (union (cylinder trrs-radius trrs-hole-depth)
+ (->> (cube trrs-diameter (+ trrs-radius 5) trrs-hole-depth)
+ (translate [0 (/ (+ trrs-radius 5) 2) 0])))
+ (rotate (/ π 2) [1 0 0])
+ (translate [0 (+ (/ mount-height 2) 4) (- trrs-radius)])
+ (with-fn 50)))
+
+(def trrs-hole-just-circle
+ (->> (cylinder trrs-radius trrs-hole-depth)
+ (rotate (/ π 2) [1 0 0])
+ (translate [0 (+ (/ mount-height 2) 4) (- trrs-radius)])
+ (with-fn 50)
+ (key-place 1/2 0)))
+
+(def trrs-box-hole (->> (cube 14 14 7 )
+ (translate [0 1 -3.5])))
+
+
+(def trrs-cutout
+ (->> (union trrs-hole
+ trrs-box-hole)
+ (key-place 1/2 0)))
+
+(def teensy-pcb-thickness 1.6)
+(def teensy-offset-height 5)
+
+(def teensy-pcb (->> (cube 18 30.5 teensy-pcb-thickness)
+ (translate [0 0 (+ (/ teensy-pcb-thickness -2) (- teensy-offset-height))])
+ (key-place 1/2 3/2)
+ (color [1 0 0])))
+
+(def teensy-support
+ (difference
+ (union
+ (->> (cube 3 3 9)
+ (translate [0 0 -2])
+ (key-place 1/2 3/2)
+ (color [0 1 0]))
+ (hull (->> (cube 3 6 9)
+ (translate [0 0 -2])
+ (key-place 1/2 2)
+ (color [0 0 1]))
+ (->> (cube 3 3 (+ teensy-pcb-thickness 3))
+ (translate [0 (/ 30.5 -2) (+ (- teensy-offset-height)
+ #_(/ (+ teensy-pcb-thickness 3) -2)
+ )])
+ (key-place 1/2 3/2)
+ (color [0 0 1]))))
+ teensy-pcb
+ (->> (cube 18 30.5 teensy-pcb-thickness)
+ (translate [0 1.5 (+ (/ teensy-pcb-thickness -2) (- teensy-offset-height) -1)])
+ (key-place 1/2 3/2)
+ (color [1 0 0]))))
+
+(def usb-cutout
+ (let [hole-height 6.2
+ side-radius (/ hole-height 2)
+ hole-width 10.75
+ side-cylinder (->> (cylinder side-radius teensy-length)
+ (with-fn 20)
+ (translate [(/ (- hole-width hole-height) 2) 0 0]))]
+ (->> (hull side-cylinder
+ (mirror [-1 0 0] side-cylinder))
+ (rotate (/ π 2) [1 0 0])
+ (translate [0 (/ teensy-length 2) (- side-radius)])
+ (translate [0 0 (- 1)])
+ (translate [0 0 (- teensy-offset-height)])
+ (key-place 1/2 3/2))))
+
+;;;;;;;;;;;;;;;;;;
+;; Final Export ;;
+;;;;;;;;;;;;;;;;;;
+
+(def dactyl-bottom-right
+ (difference
+ (union
+ teensy-cover
+ (difference
+ bottom-plate
+ (hull teensy-cover)
+ new-case
+ teensy-cover
+ trrs-cutout
+ (->> (cube 1000 1000 10) (translate [0 0 -5]))
+ screw-holes))
+ usb-cutout))
+
+(def dactyl-bottom-left
+ (mirror [-1 0 0]
+ (union
+ io-exp-cover
+ (difference
+ bottom-plate
+ (hull io-exp-cover)
+ new-case
+ io-exp-cover
+ trrs-cutout
+ (->> (cube 1000 1000 10) (translate [0 0 -5]))
+ screw-holes))))
+
+(def dactyl-top-right
+ (difference
+ (union key-holes
+ connectors
+ thumb
+ new-case
+ teensy-support)
+ trrs-hole-just-circle
+ screw-holes))
+
+(def dactyl-top-left
+ (mirror [-1 0 0]
+ (difference
+ (union key-holes
+ connectors
+ thumb
+ new-case)
+ trrs-hole-just-circle
+ screw-holes)))
+
+(spit "things/dactyl-top-right.scad"
+ (write-scad dactyl-top-right))
+
+(spit "things/dactyl-bottom-right.scad"
+ (write-scad dactyl-bottom-right))
+
+(spit "things/dactyl-top-left.scad"
+ (write-scad dactyl-top-left))
+
+(spit "things/dactyl-bottom-left.scad"
+ (write-scad dactyl-bottom-left))