<commit_before>#+SETUPFILE: setup.org

* Namespace: thi.ng.geom.core
Providing an easy-to-use & easy-to-learn API for both common and
advanced geometry operations is one of this project's main focal
points. We attempt to realise this by defining all operations in
the form of protocols which are then implemented by various core
types.

This namespace contains all basic vector operations and core
protocols related to common higher level geometric operations.

#+INCLUDE: "types.org" :minlevel 3

** Namespace declaration                                           :noexport:
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx :mkdirp yes :padline no
  (ns thi.ng.geom.core
    (:refer-clojure :exclude [+ - * / min max])
    (:require
     [thi.ng.common.data.core :as d]
     [thi.ng.common.error :as err]
     [thi.ng.common.math.core :as m :refer [*eps* PI TWO_PI]]
     [thi.ng.geom.types :as types]
     ,#+clj [thi.ng.macromath.core :as mm]
     ,#+clj [thi.ng.geom.macros.core :as gmc])
    ,#+cljs
    (:require-macros
     [thi.ng.macromath.core :as mm]
     [thi.ng.geom.macros.core :as gmc])
    ,#+clj
    (:import
     [thi.ng.geom.types Circle Rect AABB Sphere]))
#+END_SRC

** Protocols
*** Math operations
**** PMathOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMathOps
    (+ [_] [_ a] [_ a b] [_ a b c])
    (- [_] [_ a] [_ a b] [_ a b c])
    (* [_] [_ a] [_ a b] [_ a b c])
    (div [_] [_ a] [_ a b] [_ a b c])
    (madd [_ a b])
    (abs [_]))
#+END_SRC
**** PConjugate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PConjugate
    (conjugate [_]))
#+END_SRC
**** PCrossProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCrossProduct
    (cross [_ a]))
#+END_SRC
**** PDeterminant
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDeterminant
    (determinant [_]))
#+END_SRC
**** PDistance
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDistance
    (dist [_ a])
    (dist-squared [_ a]))
#+END_SRC
**** PDotProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDotProduct
    (dot [_ a]))
#+END_SRC
**** PHeading
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PHeading
    (heading [_])
    (heading-xy [_])
    (heading-xz [_])
    (heading-yz [_])
    (angle-between [_ a])
    (normal [_] [_ a])
    (slope-xy [_])
    (slope-xz [_])
    (slope-yz [_]))
#+END_SRC
**** PInterpolate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PInterpolate
    (mix [_ x] [_ x t]))
#+END_SRC
**** PInvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PInvert
    (invert [_]))
#+END_SRC
**** PSetOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSetOps
    (union [_ x])
    (intersection [_ y])
    (difference [_ x]))
#+END_SRC
**** PLimit
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PLimit
    (limit [_ x]))
#+END_SRC
**** PMagnitude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMagnitude
    (mag [_])
    (mag-squared [_]))
#+END_SRC
**** PMatrixConvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMatrixConvert
    (as-matrix [_]))
#+END_SRC
**** PMinMax
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMinMax
    (min [_ x] [_ a b])
    (max [_ y] [_ a b]))
#+END_SRC
**** PNormalize
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PNormalize
    (normalize [_] [_ len])
    (normalized? [_]))
#+END_SRC
**** PTranspose
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTranspose
    (transpose [_]))
#+END_SRC
*** Spatial transform operations

The position, size and orientation of spatial entities can
usually be manipulated via the three basic operations: rotate,
scale & translate. Other, more complex transformations can be
achieved through combination and repetition of these.

**** PPolar
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PPolar
    (as-polar [_])
    (as-cartesian [_]))
#+END_SRC
**** PReflect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PReflect
    (reflect [_ r]))
#+END_SRC
**** PRotate & PRotate3D
  Rotation is always relative to the world origin. For 2D
  implementations, the rotation angle \theta (theta) is always
  interpreted clockwise and only the =rotate= method is
  implemented.
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PRotate
    (rotate [_ t]))

  (defprotocol PRotate3D
    (rotate-x [_ t])
    (rotate-y [_ t])
    (rotate-z [_ t])
    (rotate-around-axis [_ a t]))
#+END_SRC
**** PScale
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PScale
    (scale [_ s] [_ a b] [_ a b c])
    (scale-size [_ s]))
#+END_SRC
**** PShear
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PShear
    (shear [_ s] [_ sx sy] [_ sx sy sz]))
#+END_SRC
**** PTransform
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTransform
    (transform [_ matrix]))
#+END_SRC
**** PTranslate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTranslate
    (translate [_ t] [_ x y] [_ x y z]))
#+END_SRC
**** PVectorTransform
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PVectorTransform
    (transform-vector [_ v]))
#+END_SRC
*** Graph operations

Most geometric shape constructs can be understood as an undirected
graph of vertices, connected by edges. This protocol provides read
access to entities in this context.

**** PGraph
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PGraph
    (connected-components [_])
    (cyclic? [_])
    (edges [_] [_ n])
    (vertices [_] [_ n])
    (vertex-valence [_ v])
    (vertex-neighbors [_ v])
    (remove-vertex [_ v])
    (replace-vertex [_ a b])
    (merge-vertices [_ a b]))
#+END_SRC
**** PDirectedGraph
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDirectedGraph
    (in-vertices [_ v])
    (out-vertices [_ v]))
#+END_SRC
**** PGraphConvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PGraphConvert
    (as-graph [_] [_ opts]))
#+END_SRC
*** Shape based & structural operations
**** PAlign
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PAlign
    (align-with [_ x opts]
      "Returns updated entity aligned with `x` in the specified manner"))
#+END_SRC
**** PArea
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PArea
    (area [_]
      "Returns an entity's total surface area"))
#+END_SRC
**** PBoundary
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBoundary
    (contains-entity? [_ s])
    (contains-point? [_ p]))
#+END_SRC
**** PBoundingCircle
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBoundingCircle
    (bounding-circle [_]))
#+END_SRC
**** PBoundingSphere
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBoundingSphere
    (bounding-sphere [_]))
#+END_SRC
**** PBounds
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBounds
    (bounds [_]
      "Returns bounding rect for 2d entities or box for 3d")
    (depth [_]
      "Returns entity's extent along Z (zero for 2d)")
    (height [_]
      "Returns entity's extent along Y axis")
    (width [_]
      "Returns entity's extent along X axis"))
#+END_SRC
**** PCenter
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCenter
    (center [_] [_ p]
      "Returns updated entity centered around world origin or given point")
    (centroid [_]
      "Returns centroid of entity"))
#+END_SRC
**** PCircumference
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCircumference
    (circumference [_]
      "Returns an entity's circumference"))
#+END_SRC
**** PClassify
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PClassify
    (classify-point [_ p]))
#+END_SRC
**** TODO PClip
***** TODO remove protocol, method is already part of PSetOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PClip
    (clip-with [_ s]))
#+END_SRC
**** TODO PConvexHull
***** TODO rename into PConvex, add convex? method
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PConvexHull
    (convex-hull [_]))
#+END_SRC
**** PExtrude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PExtrude
    (extrude [_ opts])
    (extrude-shell [_ opts]))
#+END_SRC
**** PFlip
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PFlip
    (flip [_]))
#+END_SRC
**** PIntersect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PIntersect
    (intersect-line [_ l] [_ p q])
    (intersect-ray [_ r] [_ p dir])
    (intersect-shape [_ s]))
#+END_SRC
**** PMeshConvert

Anything which can be turned into a 2D or 3D mesh will implement _
protocol consisting of just _ one function: =as-mesh=.

#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMeshConvert
    (as-mesh [_] [_ opts]
      "Transforms the current enitity into a Mesh instance"))
 #+END_SRC
**** PPolygonConvert
       Anything which can be turned into a polygon will implement _
       protocol consisting of just _ one function: =as-polygon=.
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PPolygonConvert
    (as-polygon [_] [_ res]
      "Transforms current entity into a Polygon instance"))
#+END_SRC
**** PProximity
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PProximity
    (closest-point [_ p]))
#+END_SRC
**** PSample
***** TODO move random-point-inside into PBoundary
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSample
    (point-at [_ t] [_ u v])
    (random-point [_])
    (random-point-inside [_])
    (sample-uniform [_ dist include-last?])
    (sample-with-resolution [_ res]))
#+END_SRC
**** PSlice
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSlice
    (slice-with [_ e] [_ e classifier] [_ e classifier parts]))
#+END_SRC
**** PSubdivide
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSubdivide
    (subdivide [_] [_ opts])
    (subdivide-edge [_ a b splits])
    (subdivide-face [_ f p displace splits]))
#+END_SRC
**** PTessellate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTessellate
    (tessellate [_] [_ opts]))
#+END_SRC
**** PVolume
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PVolume
    (volume [_] "Returns an entity's inner volume."))
#+END_SRC
*** Type specific operations
**** PCurve
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCurve
    (arc-length [_])
    (auto-spline [_]))
#+END_SRC
**** PMesh
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMesh
    (add-face [_ f])
    (compute-face-normals [_])
    (compute-vertex-normals [_])
    (faces [_])
    (into-mesh [_ m])
    (remove-face [_ f])
    (vertex-faces [_ v]))
#+END_SRC
** Vector implementations

For performance reasons we decided to define custom data types for
vectors & matrices. Since they implement the necessary protocols and
interfaces, these types can be used much like standard Clojure
vectors/seqs, but also provide implementations for the above geometry
protocols and custom key lookups to enable swizzling.

Furthermore, since we aim for full ClojureScript compatibility,
the following implementations are quite lengthy.

*** Declarations

Some functions used by the following vector types will be
defined further on, but need to be declared already.

#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (declare vec2 swizzle2 swizzle2-assoc)
  (declare vec3 swizzle3 swizzle3-assoc)
  (declare M32 M44)
  (declare vec2-op-1 vec2-op-2 vec2-op-2* vec2-op-3)
  (declare vec3-op-1 vec3-op-2 vec3-op-3)
#+END_SRC
*** Protocol helpers
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+clj
  (defn map-entry
    [k ^double v]
    (reify
      clojure.lang.IMapEntry
      java.util.Map$Entry
      (key [_] k)
      (getKey [_] k)
      (val [_] v)
      (getValue [_] v)
      (hashCode [_]
        (hash-combine
         (clojure.lang.Util/hash k)
         (clojure.lang.Util/hash v)))
      (equals [_ x]
        (and (instance? java.util.Map$Entry x)
             (clojure.lang.Util/equals
              k (.getKey ^java.util.Map$Entry x))
             (clojure.lang.Util/equals
              v (.getValue ^java.util.Map$Entry x))))))
#+END_SRC
*** 2D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (deftype Vec2
    ,#+clj [^double x ^double y _meta]
    ,#+cljs [x y _meta]
#+END_SRC
**** Clojure protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+clj clojure.lang.IObj
  ,#+clj (meta
         [_]_meta)
  ,#+clj (withMeta
         [_ m*] (Vec2. x y m*))
  
  ,#+clj clojure.lang.ILookup
  ,#+clj (valAt
         [_ k] (swizzle2 _ k nil))
  ,#+clj (valAt
         [_ k nf] (swizzle2 _ k nf))
  
  ,#+clj java.util.concurrent.Callable
  ,#+clj (call
         [_] (.invoke ^clojure.lang.IFn _))
  ,#+clj java.lang.Runnable
  ,#+clj (run
         [_] (.invoke ^clojure.lang.IFn _))
  
  ,#+clj clojure.lang.IFn
  ,#+clj (invoke
         [_ k] (swizzle2 _ k nil))
  ,#+clj (invoke
         [_ k nf] (swizzle2 _ k nf))
  ,#+clj (applyTo
         [_ args]
         (condp = (count args)
           1 (swizzle2 _ (first args) nil)
           2 (swizzle2 _ (first args) (second args))
           (err/arity-error! (count args))))
  
  ,#+clj clojure.lang.IMapEntry
  ,#+clj java.util.Map$Entry
  ,#+clj (key
         [_] x)
  ,#+clj (getKey
         [_] x)
  ,#+clj (val
         [_] y)
  ,#+clj (getValue
         [_] y)
  
  ,#+clj clojure.lang.Associative
  ,#+clj clojure.lang.IPersistentVector
  ,#+clj (count
         [_] 2)
  ,#+clj (length
         [_] 2)
  ,#+clj (containsKey
         [_ k] (not (nil? (#{0 1 :x :y} k))))
  ,#+clj (entryAt
         [_ k] (map-entry k (case (int k) 0 x, 1 y, (err/key-error! k))))
  ,#+clj (assoc
            [_ k v] (swizzle2-assoc _ k v))
  ,#+clj (assocN
         [_ k v] (case (int k) 0 (Vec2. v y _meta), 1 (Vec2. x v _meta), (err/key-error! k)))
  
  ,#+clj java.util.Collection
  ,#+clj (isEmpty
         [_] false)
  ,#+clj (iterator
         [_] (.iterator ^java.util.Collection (list x y)))
  ,#+clj (toArray
         [_] (double-array 2 [x y]))
  ,#+clj (size [_] 2)
  
  ,#+clj clojure.lang.IPersistentCollection
  ,#+clj clojure.lang.Indexed
  ,#+clj clojure.lang.Sequential
  ,#+clj clojure.lang.ISeq
  ,#+clj clojure.lang.Seqable
  ,#+clj (first
         [_] x)
  ,#+clj (next
         [_] (cons y nil))
  ,#+clj (more
         [_] (cons y nil))
  ,#+clj (cons
         [_ z] (with-meta (vec3 x y z) _meta))
  ,#+clj (peek
         [_] y)
  ,#+clj (pop
         [_] [x])
  ,#+clj (rseq
         [_] (Vec2. y x _meta))
  ,#+clj (seq
         [_] _)
  ,#+clj (nth
         [_ n] (case (int n) 0 x, 1 y, (err/key-error! n)))
  ,#+clj (nth
         [_ n nf] (case (int n) 0 x, 1 y, nf))
  ,#+clj (equiv
         [_ o]
         (if (instance? Vec2 o)
           (and (clojure.lang.Numbers/equiv x (.-x ^Vec2 o))
                (clojure.lang.Numbers/equiv y (.-y ^Vec2 o)))
           (and (instance? java.util.Collection o)
                (= 2 (count o))
                (clojure.lang.Util/equiv x (nth o 0))
                (clojure.lang.Util/equiv y (nth o 1)))))
  ,#+clj (equals
         [_ o]
         (if (instance? Vec2 o)
           (and (clojure.lang.Util/equals x (.-x ^Vec2 o))
                (clojure.lang.Util/equals y (.-y ^Vec2 o)))
           (and (instance? java.util.Collection o)
                (= 2 (count o))
                (clojure.lang.Util/equals x (nth o 0))
                (clojure.lang.Util/equals y (nth o 1)))))
  
  ;; http://docs.oracle.com/javase/7/docs/api/java/util/List.html#hashCode()
  ,#+clj (hashCode
         [_]
         (-> 31
             (unchecked-add-int (hash x))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash y))))
  
  ;; http://clojure.org/data_structures#hash
  ,#+clj clojure.lang.IHashEq
  ,#+clj (hasheq
         [_]
         (-> 31
             (unchecked-add-int (hash x))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash y))
             (mix-collection-hash 2)))
  
  Object
  (toString
   [_] (str "[" x " " y "]"))
#+END_SRC
**** ClojureScript protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+cljs IMeta
  ,#+cljs (-meta
          [_] _meta)
  ,#+cljs IWithMeta
  ,#+cljs (-with-meta
          [_ m*] (Vec2. x y m*))
  
  ,#+cljs ICloneable
  ,#+cljs (-clone
          [_] (Vec2. x y _meta))
  
  ,#+cljs ILookup
  ,#+cljs (-lookup
          [_ k] (swizzle2 _ k nil))
  ,#+cljs (-lookup
          [_ k nf] (swizzle2 _ k nf))
  
  ,#+cljs IFn
  ,#+cljs (-invoke
          [_ k] (swizzle2 _ k nil))
  ,#+cljs (-invoke
          [_ k nf] (swizzle2 _ k nf))
  
  ,#+cljs ICounted
  ,#+cljs (-count
          [_] 2)
  
  ,#+cljs IAssociative
  ,#+cljs (-contains-key?
          [_ k] (not (nil? (#{0 1 :x :y} k))))
  ,#+cljs (-assoc
          [_ k v] (swizzle2-assoc _ k v))
  
  ,#+cljs IVector
  ,#+cljs (-assoc-n
          [_ k v] (case k 0 (Vec2. v y _meta), 1 (Vec2. x v _meta), (err/key-error! k)))
  
  ,#+cljs ISequential
  ,#+cljs ISeq
  ,#+cljs (-first
          [_] x)
  ,#+cljs (-rest
          [_] (cons y nil))
  
  ,#+cljs INext
  ,#+cljs (-next
          [_] (cons y nil))
  
  ,#+cljs ISeqable
  ,#+cljs (-seq
          [_] _)
  
  ,#+cljs IReversible
  ,#+cljs (-rseq
          [_] (Vec2. y x _meta))
  
  ,#+cljs IIndexed
  ,#+cljs (-nth
          [_ n] (case n 0 x, 1 y, (err/key-error! n)))
  ,#+cljs (-nth
          [_ n nf] (case n 0 x, 1 y, nf))
  
  ,#+cljs ICollection
  ,#+cljs (-conj
          [_ z] (with-meta (vec3 x y z) _meta))
  
  ,#+cljs IStack
  ,#+cljs (-peek
          [_] y)
  ,#+cljs (-pop
          [_] [x])
  
  ,#+cljs IComparable
  ,#+cljs (-compare
          [_ o]
          (if (instance? Vec2 o)
            (let [c (compare x (.-x ^Vec2 o))]
              (if (== 0 c) (compare y (.-y ^Vec2 o)) c))
            (let [c (count o)]
              (if (= 2 c) (compare o _) (- 2 c)))))
  
  ,#+cljs IHash
  ,#+cljs (-hash
          [_] (hash-combine (hash x) (hash y)))
  
  ,#+cljs IEquiv
  ,#+cljs (-equiv
          [_ o]
          (if (instance? Vec2 o)
            (and (== x (.-x ^Vec2 o)) (== y (.-y ^Vec2 o)))
            (and (sequential? o) (= 2 (count o))
                 (= x (nth o 0)) (= y (nth o 1)))))
#+END_SRC
**** Transformations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PScale
  (scale
   [_ a] (vec2-op-1 clojure.core/* _ a 1.0 _meta))
  (scale
   [_ a b] (vec2-op-2 clojure.core/* _ a b 1.0 1.0 _meta))
  (scale
   [_ a b c] (vec2-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  PTranslate
  (translate
   [_ a] (vec2-op-1 clojure.core/+ _ a 0.0 _meta))
  (translate
   [_ a b] (vec2-op-2 clojure.core/+ _ a b 0.0 0.0 _meta))
  (translate
   [_ a b c] (vec2-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  PRotate
  (rotate
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec2. (mm/msub x c y s) (mm/madd x s y c) _meta)))
  PRotate3D
  (rotate-x
   [_ theta] (rotate-x (vec3 _) theta))
  (rotate-y
   [_ theta] (rotate-y (vec3 _) theta))
  (rotate-z
   [_ theta] (vec3 (rotate _ theta)))
  (rotate-around-axis
   [_ axis theta] (rotate-around-axis (vec3 _) axis theta))
  
  PTransform
  (transform
   [_ m] (transform-vector m _))
#+END_SRC
**** PMathOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMathOps
  (abs [_] (Vec2. (m/abs x) (m/abs y) _meta))
  (+ [_] _)
  (+ [_ a] (vec2-op-1 clojure.core/+ _ a 0.0 _meta))
  (+ [_ a b] (vec2-op-2 clojure.core/+ _ a b 0.0 0.0 _meta))
  (+ [_ a b c] (vec2-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  (- [_] (Vec2. (clojure.core/- x) (clojure.core/- y) _meta))
  (- [_ a] (vec2-op-1 clojure.core/- _ a 0.0 _meta))
  (- [_ a b] (vec2-op-2 clojure.core/- _ a b 0.0 0.0 _meta))
  (- [_ a b c] (vec2-op-3 clojure.core/- _ a b c 0.0 _meta))
  
  (* [_] _)
  (* [_ a] (vec2-op-1 clojure.core/* _ a 1.0 _meta))
  (* [_ a b] (vec2-op-2 clojure.core/* _ a b 1.0 1.0 _meta))
  (* [_ a b c] (vec2-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  (div [_] (Vec2. (clojure.core// x) (clojure.core// y) _meta))
  (div [_ a] (vec2-op-1 clojure.core// _ a 0.0 _meta))
  (div [_ a b] (vec2-op-2 clojure.core// _ a b 0.0 0.0 _meta))
  (div [_ a b c] (vec2-op-3 clojure.core// _ a b c 0.0 _meta))
  
  (madd [_ a b] (vec2-op-2* clojure.core/* clojure.core/+ _ a b 1.0 0.0 _meta))
#+END_SRC
**** PDotProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PDotProduct
  (dot
   [_ [ax ay]] (mm/madd x ax y ay))
#+END_SRC
**** PCrossProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PCrossProduct
  (cross
   [_ [ax ay]] (mm/msub x ay y ax))
#+END_SRC
**** PLimit
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PLimit
  (limit
   [_ len]
   (if (> (mag-squared _) (mm/mul len len))
     (normalize _ len) _))
#+END_SRC
**** PMinMax
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMinMax
  (min
   [_ [ax ay]]
   (Vec2.
    (clojure.core/min x ax)
    (clojure.core/min y ay) _meta))
  (min
   [_ [ax ay] [bx by]]
   (Vec2.
    (clojure.core/min (clojure.core/min x ax) bx)
    (clojure.core/min (clojure.core/min y ay) by) _meta))
  (max
   [_ [ax ay]]
   (Vec2.
    (clojure.core/max x ax)
    (clojure.core/max y ay) _meta))
  (max
   [_ [ax ay] [bx by]]
   (Vec2.
    (clojure.core/max (clojure.core/max x ax) bx)
    (clojure.core/max (clojure.core/max y ay) by) _meta))
#+END_SRC
**** PMagnitude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMagnitude
  (mag
   [_]
   (Math/sqrt (mm/madd x x y y)))
  (mag-squared
   [_] (mm/madd x x y y))
#+END_SRC
**** PNormalize
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PNormalize
  (normalize
   [_]
   (let [l (Math/sqrt (mm/madd x x y y))]
     (if (pos? l)
       (Vec2. (mm/div x l) (mm/div y l) _meta)
       _)))
  (normalize
   [_ len]
   (let [l (Math/sqrt (mm/madd x x y y))]
     (if (pos? l)
       (let [l (mm/div len l)]
         (Vec2. (mm/mul x l) (mm/mul y l) _meta))
       _)))
  (normalized?
   [_] (m/delta= 1.0 (mag-squared _)))
#+END_SRC
**** PDistance
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PDistance
  (dist
   [_ a]
   (let [[dx dy] (if (instance? Vec2 a)
                   [(mm/sub x (.-x ^Vec2 a)) (mm/sub y (.-y ^Vec2 a))]
                   [(mm/sub x (nth a 0)) (mm/sub y (nth a 1))])]
     (Math/sqrt (mm/madd dx dx dy dy))))
  (dist-squared
   [_ a]
   (let [[dx dy] (if (instance? Vec2 a)
                   [(mm/sub x (.-x ^Vec2 a)) (mm/sub y (.-y ^Vec2 a))]
                   [(mm/sub x (nth a 0)) (mm/sub y (nth a 1))])]
     (mm/madd dx dx dy dy)))
#+END_SRC
**** PReflect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PReflect
  (reflect
   [_ [rx ry :as r]]
    (let [d (mm/mul (dot _ r) 2.0)]
      (Vec2.
       (mm/msub rx d x)
       (mm/msub ry d y) _meta)))
#+END_SRC
**** PInvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInvert
  (invert
   [_] (Vec2. (clojure.core/- x) (clojure.core/- y) _meta))
#+END_SRC
**** PInterpolate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInterpolate
  (mix
   [_ [ax ay]]
   (Vec2. (mm/submadd ax x 0.5 x) (mm/submadd ay y 0.5 y) _meta))
  (mix
   [_ [ax ay] t]
   (Vec2. (mm/submadd ax x t x) (mm/submadd ay y t y) _meta))
#+END_SRC
**** PHeading
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PHeading
  (heading
   [_]
   (let [t (Math/atan2 y x)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (heading-xy [_] (heading _))
  (angle-between
   [_ a]
   (let [t (mm/sub (heading-xy a) (heading-xy _))]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (slope-xy [_] (mm/div y x))
  (normal [_] (Vec2. (clojure.core/- y) x _meta))
#+END_SRC
**** PPolar
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PPolar
  (as-polar
   [_] (Vec2. (mag _) (heading-xy _) _meta))
  (as-cartesian
   [_] (Vec2. (mm/mul x (Math/cos y)) (mm/mul x (Math/sin y)) _meta))
#+END_SRC
**** End of implementations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  )
#+END_SRC
**** Override print methods
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  #+clj (require 'clojure.pprint)
  #+clj (prefer-method clojure.pprint/simple-dispatch clojure.lang.IPersistentVector clojure.lang.ISeq)
  #+clj (defmethod print-method Vec2 [o ^java.io.Writer w] (.write w (.toString o)))
#+END_SRC
*** 3D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (deftype Vec3
    #+clj [^double x ^double y ^double z _meta]
    #+cljs [x y z _meta]
#+END_SRC
**** Clojure protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+clj clojure.lang.IObj
  ,#+clj (meta
         [_] _meta)
  ,#+clj (withMeta
         [_ m*] (Vec3. x y z m*))
  
  ,#+clj clojure.lang.ILookup
  ,#+clj (valAt
         [_ k] (swizzle3 _ k nil))
  ,#+clj (valAt
         [_ k nf] (swizzle3 _ k nf))
  
  ,#+clj java.util.concurrent.Callable
  ,#+clj (call
         [_] (.invoke ^clojure.lang.IFn _))
  ,#+clj java.lang.Runnable
  ,#+clj (run
         [_] (.invoke ^clojure.lang.IFn _))
  
  ,#+clj clojure.lang.IFn
  ,#+clj (invoke
         [_ k] (swizzle3 _ k nil))
  ,#+clj (invoke
         [_ k nf] (swizzle3 _ k nf))
  ,#+clj (applyTo
         [_ args]
         (condp = (count args)
           1 (swizzle3 _ (first args) nil)
           2 (swizzle3 _ (first args) (second args))
           (err/arity-error! (count args))))
  
  ,#+clj clojure.lang.Associative
  ,#+clj clojure.lang.IPersistentVector
  ,#+clj (count
         [_] 3)
  ,#+clj (length
         [_] 3)
  ,#+clj (containsKey
         [_ k] (not (nil? (#{0 1 2 :x :y :z} k))))
  ,#+clj (entryAt
         [_ k] (map-entry k (case (int k) 0 x, 1 y, 2 z, (err/key-error! k))))
  ,#+clj (assoc
            [_ k v] (swizzle3-assoc _ k v))
  ,#+clj (assocN
         [_ k v]
         (case (int k)
           0 (Vec3. v y z _meta)
           1 (Vec3. x v z _meta)
           2 (Vec3. x y v _meta)
           (err/key-error! k)))
  
  ,#+clj java.util.Collection
  ,#+clj (isEmpty
         [_] false)
  ,#+clj (iterator
         [_] (.iterator ^java.util.Collection (list x y z)))
  ,#+clj (toArray
         [_] (double-array 3 [x y z]))
  ,#+clj (size
         [_] 3)
  
  ,#+clj clojure.lang.IPersistentCollection
  ,#+clj clojure.lang.Indexed
  ,#+clj clojure.lang.Sequential
  ,#+clj clojure.lang.ISeq
  ,#+clj clojure.lang.Seqable
  ,#+clj (first
         [_] x)
  ,#+clj (next
         [_] (cons y (cons z nil)))
  ,#+clj (more
         [_] (cons y (cons z nil)))
  ,#+clj (cons
         [_ w] (with-meta [x y z w] _meta))
  ,#+clj (peek
         [_] z)
  ,#+clj (pop
         [_] (Vec2. x y _meta))
  ,#+clj (rseq
         [_] (Vec3. z y x _meta))
  ,#+clj (seq
         [_] _)
  ,#+clj (nth
         [_ n] (condp = n 0 x 1 y 2 z (err/key-error! n)))
  ,#+clj (nth
         [_ n nf] (condp = n 0 x 1 y 2 z nf))
  ,#+clj (equiv
         [_ o]
         (if (instance? Vec3 o)
           (and (clojure.lang.Numbers/equiv x (.-x ^Vec3 o))
                (clojure.lang.Numbers/equiv y (.-y ^Vec3 o))
                (clojure.lang.Numbers/equiv z (.-z ^Vec3 o)))
           (and (instance? java.util.Collection o)
                (= 3 (count o))
                (clojure.lang.Util/equiv x (nth o 0))
                (clojure.lang.Util/equiv y (nth o 1))
                (clojure.lang.Util/equiv z (nth o 2)))))
  ,#+clj (equals
         [_ o]
         (if (instance? Vec3 o)
           (and (clojure.lang.Util/equals x (.-x ^Vec3 o))
                (clojure.lang.Util/equals y (.-y ^Vec3 o))
                (clojure.lang.Util/equals z (.-z ^Vec3 o)))
           (and (instance? java.util.Collection o)
                (= 3 (count o))
                (clojure.lang.Util/equals x (nth o 0))
                (clojure.lang.Util/equals y (nth o 1))
                (clojure.lang.Util/equals z (nth o 2)))))
  
  ,#+clj Comparable
  ,#+clj (compareTo
         [_ o]
         (if (instance? Vec3 o)
           (let [c (compare x (.-x ^Vec3 o))]
             (if (== 0 c)
               (let [c (compare y (.-y ^Vec3 o))]
                 (if (== 0 c)
                   (compare z (.-z ^Vec3 o))
                   c))
               c))
           (let [c (count o)]
             (if (== 3 c) (compare o _) (- 3 c)))))
  ,#+clj (hashCode
         [_]
         (-> 31
             (unchecked-add-int (hash x))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash y))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash z))))
  
  ,#+clj clojure.lang.IHashEq
  ,#+clj (hasheq
           [_]
           (-> 31
               (unchecked-add-int (hash x))
               (unchecked-multiply-int 31)
               (unchecked-add-int (hash y))
               (unchecked-multiply-int 31)
               (unchecked-add-int (hash z))
               (mix-collection-hash 3)))
  
  Object
  (toString
    [_] (str "[" x " " y " " z "]"))
#+END_SRC
**** ClojureScript protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+cljs IMeta
  ,#+cljs (-meta
          [_] _meta)
  ,#+cljs IWithMeta
  ,#+cljs (-with-meta
          [_ m*] (Vec3. x y z m*))
  
  ,#+cljs ICloneable
  ,#+cljs (-clone
          [_] (Vec3. x y z _meta))
  
  ,#+cljs ILookup
  ,#+cljs (-lookup
          [_ k] (swizzle3 _ k nil))
  ,#+cljs (-lookup
          [_ k nf] (swizzle3 _ k nf))
  
  ,#+cljs IFn
  ,#+cljs (-invoke
          [_ k] (swizzle3 _ k nil))
  ,#+cljs (-invoke
          [_ k nf] (swizzle3 _ k nf))
  
  ,#+cljs ICounted
  ,#+cljs (-count
          [_] 3)
  
  ,#+cljs IAssociative
  ,#+cljs (-contains-key?
          [_ k] (not (nil? (#{0 1 2 :x :y :z} k))))
  ,#+cljs (-assoc
          [_ k v] (swizzle3-assoc _ k v))
  
  ,#+cljs IVector
  ,#+cljs (-assoc-n
          [_ k v]
          (case k
            0 (Vec3. v y z _meta)
            1 (Vec3. x v z _meta)
            2 (Vec3. x y v _meta)
            (err/key-error! k)))
  
  ,#+cljs ISequential
  ,#+cljs ISeq
  ,#+cljs (-first
          [_] x)
  ,#+cljs (-rest
          [_] (cons y (cons z nil)))
  
  ,#+cljs INext
  ,#+cljs (-next
          [_] (cons y (cons z nil)))
  
  ,#+cljs ISeqable
  ,#+cljs (-seq
          [_] _)
  
  ,#+cljs IReversible
  ,#+cljs (-rseq
          [_] (Vec3. z y x _meta))
  
  ,#+cljs IIndexed
  ,#+cljs (-nth
          [_ n] (case n 0 x, 1 y, 2 z, (err/key-error! n)))
  ,#+cljs (-nth
          [_ n nf] (case n 0 x, 1 y, 2 z, nf))
  
  ,#+cljs ICollection
  ,#+cljs (-conj
          [_ w] (with-meta [x y z w] _meta))
  
  ,#+cljs IStack
  ,#+cljs (-peek
          [_] z)
  ,#+cljs (-pop
          [_] (Vec2. x y _meta))
  
  ,#+cljs IComparable
  ,#+cljs (-compare
          [_ o]
          (if (instance? Vec3 o)
            (let [c (compare x (.-x ^Vec3 o))]
              (if (== 0 c)
                (let [c (compare y (.-y ^Vec3 o))]
                  (if (== 0 c)
                    (compare z (.-z ^Vec3 o))
                    c))
                c))
            (let [c (count o)]
              (if (= 3 c) (compare o _) (- 3 c)))))
  
  ,#+cljs IHash
  ,#+cljs (-hash
          [_] (-> (hash x)
                  (hash-combine (hash y))
                  (hash-combine (hash z))))
  
  ,#+cljs IEquiv
  ,#+cljs (-equiv
          [_ o]
          (if (instance? Vec3 o)
            (and (== x (.-x ^Vec3 o)) (== y (.-y ^Vec3 o)) (== z (.-z ^Vec3 o)))
            (and (sequential? o) (= 3 (count o))
                 (= x (nth o 0)) (= y (nth o 1)) (= z (nth o 2)))))
#+END_SRC
**** Transformations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PScale
  (scale
   [_ a] (vec3-op-1 clojure.core/* _ a 1.0 _meta))
  (scale
   [_ a b] (vec3-op-2 clojure.core/* clojure.core/* _ a b 1.0 1.0 _meta))
  (scale
   [_ a b c] (vec3-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  PTranslate
  (translate
   [_ a] (vec3-op-1 clojure.core/+ _ a 0.0 _meta))
  (translate
   [_ a b] (vec3-op-2 clojure.core/+ clojure.core/+ _ a b 0.0 0.0 _meta))
  (translate
   [_ a b c] (vec3-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  PRotate
  (rotate [_ theta] (rotate-z _ theta))
  
  PRotate3D
  (rotate-x
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec3. x (mm/msub y c z s) (mm/madd y s z c) _meta)))
  (rotate-y
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec3. (mm/madd x c z s) y (mm/msub z c x s) _meta)))
  (rotate-z
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec3. (mm/msub x c y s) (mm/madd x s y c) z _meta)))
  (rotate-around-axis
   [_ [ax ay az] theta]
   (let [ux (mm/mul ax x), uy (mm/mul ax y), uz (mm/mul ax z)
         vx (mm/mul ay x), vy (mm/mul ay y), vz (mm/mul ay z)
         wx (mm/mul az x), wy (mm/mul az y), wz (mm/mul az z)
         ax2 (mm/mul ax ax), ay2 (mm/mul ay ay), az2 (mm/mul az az)
         s (Math/sin theta), c (Math/cos theta)
         uvw (mm/add (mm/add ux vy) wz)]
     (Vec3.
      (mm/madd uvw ax
               (mm/msub (mm/add ay2 az2) x (mm/add vy wz) ax) c
               (mm/subm vz wy s))
  
      (mm/madd uvw ay
               (mm/msub (mm/add ax2 az2) y (mm/add ux wz) ay) c
               (mm/subm wx uz s))
  
      (mm/madd uvw az
               (mm/msub (mm/add ax2 ay2) z (mm/add ux vy) az) c
               (mm/subm uy vx s))
      _meta)))
  
  PTransform
  (transform
   [_ m] (transform-vector m _))
#+END_SRC
**** PMathOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMathOps
  (abs [_] (Vec3. (m/abs x) (m/abs y) (m/abs z) _meta))
  (+ [_] _)
  (+ [_ a] (vec3-op-1 clojure.core/+ _ a 0.0 _meta))
  (+ [_ a b] (vec3-op-2 clojure.core/+ clojure.core/+ _ a b 0.0 0.0 _meta))
  (+ [_ a b c] (vec3-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  (- [_] (Vec3. (clojure.core/- x) (clojure.core/- y) (clojure.core/- z) _meta))
  (- [_ a] (vec3-op-1 clojure.core/- _ a 0.0 _meta))
  (- [_ a b] (vec3-op-2 clojure.core/- clojure.core/- _ a b 0.0 0.0 _meta))
  (- [_ a b c] (vec3-op-3 clojure.core/- _ a b c 0.0 _meta))
  
  (* [_] _)
  (* [_ a] (vec3-op-1 clojure.core/* _ a 1.0 _meta))
  (* [_ a b] (vec3-op-2 clojure.core/* clojure.core/* _ a b 1.0 1.0 _meta))
  (* [_ a b c] (vec3-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  (div [_] (Vec3. (clojure.core// x) (clojure.core// y) (clojure.core// z) _meta))
  (div [_ a] (vec3-op-1 clojure.core// _ a 0.0 _meta))
  (div [_ a b] (vec3-op-2 clojure.core// clojure.core// _ a b 0.0 0.0 _meta))
  (div [_ a b c] (vec3-op-3 clojure.core// _ a b c 0.0 _meta))
  
  (madd
   [_ a b] (vec3-op-2 clojure.core/* clojure.core/+ _ a b 1.0 0.0 _meta))
  
  PDotProduct
  (dot
   [_ [ax ay az]]
   (mm/madd x ax y ay z az))
  
  PCrossProduct
  (cross
   [_ [ax ay az]]
   (Vec3.
    (mm/msub y az ay z)
    (mm/msub z ax az x)
    (mm/msub x ay ax y) _meta))
  
  PLimit
  (limit
   [_ len]
   (if (> (mag-squared _) (mm/mul len len))
     (normalize _ len)
     _))
  
  PMinMax
  (min
   [_ [ax ay az]]
   (Vec3.
    (clojure.core/min x ax)
    (clojure.core/min y ay)
    (clojure.core/min z az) _meta))
  (min
   [_ [ax ay az] [bx by bz]]
   (Vec3.
    (clojure.core/min (clojure.core/min x ax) bx)
    (clojure.core/min (clojure.core/min y ay) by)
    (clojure.core/min (clojure.core/min z az) bz) _meta))
  (max
   [_ [ax ay az]]
   (Vec3.
    (clojure.core/max x ax)
    (clojure.core/max y ay)
    (clojure.core/max z az) _meta))
  (max
   [_ [ax ay az] [bx by bz]]
   (Vec3.
    (clojure.core/max (clojure.core/max x ax) bx)
    (clojure.core/max (clojure.core/max y ay) by)
    (clojure.core/max (clojure.core/max z az) bz) _meta))
#+END_SRC
**** PMagnitude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMagnitude
  (mag
   [_]
   (Math/sqrt (mm/madd x x y y z z)))
  (mag-squared
   [_] (mm/madd x x y y z z))
#+END_SRC
**** PNormalize
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PNormalize
  (normalize
   [_]
   (let [l (Math/sqrt (mm/madd x x y y z z))]
     (if (pos? l)
       (Vec3. (mm/div x l) (mm/div y l) (mm/div z l) _meta)
       _)))
  (normalize
   [_ len]
   (let [l (Math/sqrt (mm/madd x x y y z z))]
     (if (pos? l)
       (let [l (mm/div len l)]
         (Vec3. (mm/mul x l) (mm/mul y l) (mm/mul z l) _meta)) _)))
  (normalized?
   [_] (m/delta= 1.0 (mag-squared _)))
#+END_SRC
**** PDistance
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PDistance
  (dist
   [_ a] (Math/sqrt (dist-squared _ a)))
  (dist-squared
   [_ a]
   (let [[dx dy dz] (if (instance? Vec3 a)
                      [(mm/sub x (.-x ^Vec3 a))
                       (mm/sub y (.-y ^Vec3 a))
                       (mm/sub z (.-z ^Vec3 a))]
                      [(mm/sub x (nth a 0))
                       (mm/sub y (nth a 1))
                       (mm/sub z (nth a 2 0.0))])]
     (mm/madd dx dx dy dy dz dz)))
#+END_SRC
**** PReflect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PReflect
  (reflect
   [_ [rx ry rz :as r]]
    (let [d (mm/mul (dot _ r) 2.0)]
      (Vec3.
       (mm/msub rx d x)
       (mm/msub ry d y)
       (mm/msub rz d z) _meta)))
#+END_SRC
**** PInvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInvert
  (invert
   [_] (Vec3. (clojure.core/- x) (clojure.core/- y) (clojure.core/- z) _meta))
#+END_SRC
**** PInterpolate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInterpolate
  (mix
   [_ [ax ay az]]
   (Vec3.
    (mm/submadd ax x 0.5 x)
    (mm/submadd ay y 0.5 y)
    (mm/submadd az z 0.5 z) _meta))
  (mix
   [_ [ax ay az] t]
   (Vec3.
    (mm/submadd ax x t x)
    (mm/submadd ay y t y)
    (mm/submadd az z t z) _meta))
#+END_SRC
**** PHeading
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PHeading
  (heading [_] (heading-xy _))
  (heading-xy
   [_]
   (let [t (Math/atan2 y x)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (heading-xz
   [_]
   (let [t (Math/atan2 z x)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (heading-yz
   [_]
   (let [t (Math/atan2 z y)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (angle-between
   [_ a]
   (let [t (mm/sub (heading-xy a) (heading-xy _))]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (slope-xy [_] (mm/div y x))
  (slope-xz [_] (mm/div x x))
  (slope-yz [_] (mm/div z y))
#+END_SRC
**** PPolar
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ;; http://mathworld.wolfram.com/SphericalCoordinates.html
  PPolar
  (as-polar
   [_]
    (let [r (mag _)
          theta (Math/atan2 y x)
          phi (Math/acos (mm/div z r))]
      (Vec3. r theta phi _meta)))
  (as-cartesian [_]
    (let [rsphi (mm/mul x (Math/sin z))]
      (Vec3.
       (mm/mul (Math/cos y) rsphi)
       (mm/mul (Math/sin y) rsphi)
       (mm/mul x (Math/cos z)) _meta)))
#+END_SRC
**** End of implementations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
    )
#+END_SRC
**** Override print methods
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  #+clj (defmethod print-method Vec3 [o ^java.io.Writer w] (.write w (.toString o)))
#+END_SRC
*** Vector operations
**** 2D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defn vec2-op-seq
    [op ^Vec2 acc xs]
    (loop [ax (.-x acc), ay (.-y acc), xs xs]
      (if xs
        (let [v ^Vec2 (first xs)]
          (recur (op ax (.-x v)) (op ay (.-y v)) (next xs)))
        (Vec2. ax ay (.-meta acc)))))
  
  (defn vec2-op-1
    [op ^Vec2 _ a d m]
    (if (instance? Vec2 a)
      (Vec2.
       (op (.-x _) (.-x ^Vec2 a))
       (op (.-y _) (.-y ^Vec2 a)) m)
      (if (number? a)
        (Vec2. (op (.-x _) a) (op (.-y _) a) m)
        (if (instance? Vec2 (first a))
          (vec2-op-seq op _ a)
          (Vec2.
           (op (.-x _) (nth a 0 d))
           (op (.-y _) (nth a 1 d)) m)))))
  
  (defn vec2-op-2
    [op ^Vec2 _ a b d1 d2 m]
    (if (instance? Vec2 a)
      (if (instance? Vec2 b)
        (Vec2. ;; v v
         (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b))
         (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) m)
        (if (number? b)
          (Vec2. ;; v n
           (op (op (.-x _) (.-x ^Vec2 a)) b)
           (op (op (.-y _) (.-y ^Vec2 a)) b) m)
          (Vec2. ;; v ?
           (op (op (.-x _) (.-x ^Vec2 a)) (nth b 0 d2))
           (op (op (.-y _) (.-y ^Vec2 a)) (nth b 1 d2)) m)))
      (let [an? (number? a) bn? (number? b)]
        (if (and an? bn?)
          (Vec2. ;; n n
           (op (.-x _) a)
           (op (.-y _) b) m)
          (let [[ax ay] (if an? [a a] a)
                [bx by] (if bn? [b b] b)]
            (Vec2. ;; ? ?
             (op (op (.-x _) (or ax d1)) (or bx d2))
             (op (op (.-y _) (or ay d1)) (or by d2)) m))))))
  
  (defn vec2-op-2*
    "Similar to vec2-op-2 but takes 2 fn args and handles case with
    a & b being both numbers differently."
    [op op2 ^Vec2 _ a b d1 d2 m]
    (if (instance? Vec2 a)
      (if (instance? Vec2 b)
        (Vec2. ;; v v
         (op2 (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b))
         (op2 (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) m)
        (if (number? b)
          (Vec2. ;; v n
           (op2 (op (.-x _) (.-x ^Vec2 a)) b)
           (op2 (op (.-y _) (.-y ^Vec2 a)) b) m)
          (Vec2. ;; v ?
           (op2 (op (.-x _) (.-x ^Vec2 a)) (nth b 0 d2))
           (op2 (op (.-y _) (.-y ^Vec2 a)) (nth b 1 d2)) m)))
      (let [an? (number? a) bn? (number? b)]
        (if (and an? bn?)
          (Vec2. ;; n n
           (op2 (op (.-x _) a) b)    ;; difference to vec2-op-2
           (op2 (op (.-y _) a) b) m)
          (let [[ax ay] (if an? [a a] a)
                [bx by] (if bn? [b b] b)]
            (Vec2. ;; ? ?
             (op2 (op (.-x _) (or ax d1)) (or bx d2))
             (op2 (op (.-y _) (or ay d1)) (or by d2)) m))))))
  
  (defn vec2-op-3
    [op ^Vec2 _ a b c d m]
    (if (instance? Vec2 a)
      (if (instance? Vec2 b)
        (if (instance? Vec2 c)
          (Vec2. ;; v v v
           (op (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b)) (.-x ^Vec2 c))
           (op (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) (.-y ^Vec2 c)) m)
          (if (number? c)
            (Vec2. ;; v v n
             (op (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b)) c)
             (op (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) c) m)
            (Vec2. ;; v v ?
             (op (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b)) (nth c 0 d))
             (op (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) (nth c 1 d)) m)))
        (let [[bx by] (if (number? b) [b b] b)
              [cx cy] (if (number? c) [c c] c)]
          (Vec2. ;; v ? ?
           (op (op (op (.-x _) (.-x ^Vec2 a)) (or bx d)) (or cx d))
           (op (op (op (.-y _) (.-y ^Vec2 a)) (or by d)) (or cy d)) m)))
      (let [[ax ay] (if (number? a) [a a] a)
            [bx by] (if (number? b) [b b] b)
            [cx cy] (if (number? c) [c c] c)]
        (Vec2. ;; ? ? ?
         (op (op (op (.-x _) (or ax d)) (or bx d)) (or cx d))
         (op (op (op (.-y _) (or ay d)) (or by d)) (or cy d)) m))))
#+END_SRC
**** 3D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defn vec3-op-seq
    [op ^Vec3 acc xs]
    (loop [ax (.-x acc), ay (.-y acc), az (.-z acc), xs xs]
      (if xs
        (let [v ^Vec3 (first xs)]
          (recur (op ax (.-x v)) (op ay (.-y v)) (op az (.-z v)) (next xs)))
        (Vec3. ax ay az (.-meta acc)))))<commit_msg>bug fix _meta field use in vec-op fns<commit_after>#+SETUPFILE: setup.org

* Namespace: thi.ng.geom.core
Providing an easy-to-use & easy-to-learn API for both common and
advanced geometry operations is one of this project's main focal
points. We attempt to realise this by defining all operations in
the form of protocols which are then implemented by various core
types.

This namespace contains all basic vector operations and core
protocols related to common higher level geometric operations.

#+INCLUDE: "types.org" :minlevel 3

** Namespace declaration                                           :noexport:
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx :mkdirp yes :padline no
  (ns thi.ng.geom.core
    (:refer-clojure :exclude [+ - * / min max])
    (:require
     [thi.ng.common.data.core :as d]
     [thi.ng.common.error :as err]
     [thi.ng.common.math.core :as m :refer [*eps* PI TWO_PI]]
     [thi.ng.geom.types :as types]
     ,#+clj [thi.ng.macromath.core :as mm]
     ,#+clj [thi.ng.geom.macros.core :as gmc])
    ,#+cljs
    (:require-macros
     [thi.ng.macromath.core :as mm]
     [thi.ng.geom.macros.core :as gmc])
    ,#+clj
    (:import
     [thi.ng.geom.types Circle Rect AABB Sphere]))
#+END_SRC

** Protocols
*** Math operations
**** PMathOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMathOps
    (+ [_] [_ a] [_ a b] [_ a b c])
    (- [_] [_ a] [_ a b] [_ a b c])
    (* [_] [_ a] [_ a b] [_ a b c])
    (div [_] [_ a] [_ a b] [_ a b c])
    (madd [_ a b])
    (abs [_]))
#+END_SRC
**** PConjugate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PConjugate
    (conjugate [_]))
#+END_SRC
**** PCrossProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCrossProduct
    (cross [_ a]))
#+END_SRC
**** PDeterminant
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDeterminant
    (determinant [_]))
#+END_SRC
**** PDistance
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDistance
    (dist [_ a])
    (dist-squared [_ a]))
#+END_SRC
**** PDotProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDotProduct
    (dot [_ a]))
#+END_SRC
**** PHeading
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PHeading
    (heading [_])
    (heading-xy [_])
    (heading-xz [_])
    (heading-yz [_])
    (angle-between [_ a])
    (normal [_] [_ a])
    (slope-xy [_])
    (slope-xz [_])
    (slope-yz [_]))
#+END_SRC
**** PInterpolate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PInterpolate
    (mix [_ x] [_ x t]))
#+END_SRC
**** PInvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PInvert
    (invert [_]))
#+END_SRC
**** PSetOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSetOps
    (union [_ x])
    (intersection [_ y])
    (difference [_ x]))
#+END_SRC
**** PLimit
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PLimit
    (limit [_ x]))
#+END_SRC
**** PMagnitude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMagnitude
    (mag [_])
    (mag-squared [_]))
#+END_SRC
**** PMatrixConvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMatrixConvert
    (as-matrix [_]))
#+END_SRC
**** PMinMax
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMinMax
    (min [_ x] [_ a b])
    (max [_ y] [_ a b]))
#+END_SRC
**** PNormalize
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PNormalize
    (normalize [_] [_ len])
    (normalized? [_]))
#+END_SRC
**** PTranspose
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTranspose
    (transpose [_]))
#+END_SRC
*** Spatial transform operations

The position, size and orientation of spatial entities can
usually be manipulated via the three basic operations: rotate,
scale & translate. Other, more complex transformations can be
achieved through combination and repetition of these.

**** PPolar
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PPolar
    (as-polar [_])
    (as-cartesian [_]))
#+END_SRC
**** PReflect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PReflect
    (reflect [_ r]))
#+END_SRC
**** PRotate & PRotate3D
  Rotation is always relative to the world origin. For 2D
  implementations, the rotation angle \theta (theta) is always
  interpreted clockwise and only the =rotate= method is
  implemented.
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PRotate
    (rotate [_ t]))

  (defprotocol PRotate3D
    (rotate-x [_ t])
    (rotate-y [_ t])
    (rotate-z [_ t])
    (rotate-around-axis [_ a t]))
#+END_SRC
**** PScale
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PScale
    (scale [_ s] [_ a b] [_ a b c])
    (scale-size [_ s]))
#+END_SRC
**** PShear
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PShear
    (shear [_ s] [_ sx sy] [_ sx sy sz]))
#+END_SRC
**** PTransform
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTransform
    (transform [_ matrix]))
#+END_SRC
**** PTranslate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTranslate
    (translate [_ t] [_ x y] [_ x y z]))
#+END_SRC
**** PVectorTransform
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PVectorTransform
    (transform-vector [_ v]))
#+END_SRC
*** Graph operations

Most geometric shape constructs can be understood as an undirected
graph of vertices, connected by edges. This protocol provides read
access to entities in this context.

**** PGraph
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PGraph
    (connected-components [_])
    (cyclic? [_])
    (edges [_] [_ n])
    (vertices [_] [_ n])
    (vertex-valence [_ v])
    (vertex-neighbors [_ v])
    (remove-vertex [_ v])
    (replace-vertex [_ a b])
    (merge-vertices [_ a b]))
#+END_SRC
**** PDirectedGraph
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PDirectedGraph
    (in-vertices [_ v])
    (out-vertices [_ v]))
#+END_SRC
**** PGraphConvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PGraphConvert
    (as-graph [_] [_ opts]))
#+END_SRC
*** Shape based & structural operations
**** PAlign
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PAlign
    (align-with [_ x opts]
      "Returns updated entity aligned with `x` in the specified manner"))
#+END_SRC
**** PArea
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PArea
    (area [_]
      "Returns an entity's total surface area"))
#+END_SRC
**** PBoundary
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBoundary
    (contains-entity? [_ s])
    (contains-point? [_ p]))
#+END_SRC
**** PBoundingCircle
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBoundingCircle
    (bounding-circle [_]))
#+END_SRC
**** PBoundingSphere
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBoundingSphere
    (bounding-sphere [_]))
#+END_SRC
**** PBounds
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PBounds
    (bounds [_]
      "Returns bounding rect for 2d entities or box for 3d")
    (depth [_]
      "Returns entity's extent along Z (zero for 2d)")
    (height [_]
      "Returns entity's extent along Y axis")
    (width [_]
      "Returns entity's extent along X axis"))
#+END_SRC
**** PCenter
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCenter
    (center [_] [_ p]
      "Returns updated entity centered around world origin or given point")
    (centroid [_]
      "Returns centroid of entity"))
#+END_SRC
**** PCircumference
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCircumference
    (circumference [_]
      "Returns an entity's circumference"))
#+END_SRC
**** PClassify
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PClassify
    (classify-point [_ p]))
#+END_SRC
**** TODO PClip
***** TODO remove protocol, method is already part of PSetOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PClip
    (clip-with [_ s]))
#+END_SRC
**** TODO PConvexHull
***** TODO rename into PConvex, add convex? method
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PConvexHull
    (convex-hull [_]))
#+END_SRC
**** PExtrude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PExtrude
    (extrude [_ opts])
    (extrude-shell [_ opts]))
#+END_SRC
**** PFlip
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PFlip
    (flip [_]))
#+END_SRC
**** PIntersect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PIntersect
    (intersect-line [_ l] [_ p q])
    (intersect-ray [_ r] [_ p dir])
    (intersect-shape [_ s]))
#+END_SRC
**** PMeshConvert

Anything which can be turned into a 2D or 3D mesh will implement _
protocol consisting of just _ one function: =as-mesh=.

#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMeshConvert
    (as-mesh [_] [_ opts]
      "Transforms the current enitity into a Mesh instance"))
 #+END_SRC
**** PPolygonConvert
       Anything which can be turned into a polygon will implement _
       protocol consisting of just _ one function: =as-polygon=.
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PPolygonConvert
    (as-polygon [_] [_ res]
      "Transforms current entity into a Polygon instance"))
#+END_SRC
**** PProximity
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PProximity
    (closest-point [_ p]))
#+END_SRC
**** PSample
***** TODO move random-point-inside into PBoundary
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSample
    (point-at [_ t] [_ u v])
    (random-point [_])
    (random-point-inside [_])
    (sample-uniform [_ dist include-last?])
    (sample-with-resolution [_ res]))
#+END_SRC
**** PSlice
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSlice
    (slice-with [_ e] [_ e classifier] [_ e classifier parts]))
#+END_SRC
**** PSubdivide
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PSubdivide
    (subdivide [_] [_ opts])
    (subdivide-edge [_ a b splits])
    (subdivide-face [_ f p displace splits]))
#+END_SRC
**** PTessellate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PTessellate
    (tessellate [_] [_ opts]))
#+END_SRC
**** PVolume
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PVolume
    (volume [_] "Returns an entity's inner volume."))
#+END_SRC
*** Type specific operations
**** PCurve
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PCurve
    (arc-length [_])
    (auto-spline [_]))
#+END_SRC
**** PMesh
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defprotocol PMesh
    (add-face [_ f])
    (compute-face-normals [_])
    (compute-vertex-normals [_])
    (faces [_])
    (into-mesh [_ m])
    (remove-face [_ f])
    (vertex-faces [_ v]))
#+END_SRC
** Vector implementations

For performance reasons we decided to define custom data types for
vectors & matrices. Since they implement the necessary protocols and
interfaces, these types can be used much like standard Clojure
vectors/seqs, but also provide implementations for the above geometry
protocols and custom key lookups to enable swizzling.

Furthermore, since we aim for full ClojureScript compatibility,
the following implementations are quite lengthy.

*** Declarations

Some functions used by the following vector types will be
defined further on, but need to be declared already.

#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (declare vec2 swizzle2 swizzle2-assoc)
  (declare vec3 swizzle3 swizzle3-assoc)
  (declare M32 M44)
  (declare vec2-op-1 vec2-op-2 vec2-op-2* vec2-op-3)
  (declare vec3-op-1 vec3-op-2 vec3-op-3)
#+END_SRC
*** Protocol helpers
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+clj
  (defn map-entry
    [k ^double v]
    (reify
      clojure.lang.IMapEntry
      java.util.Map$Entry
      (key [_] k)
      (getKey [_] k)
      (val [_] v)
      (getValue [_] v)
      (hashCode [_]
        (hash-combine
         (clojure.lang.Util/hash k)
         (clojure.lang.Util/hash v)))
      (equals [_ x]
        (and (instance? java.util.Map$Entry x)
             (clojure.lang.Util/equals
              k (.getKey ^java.util.Map$Entry x))
             (clojure.lang.Util/equals
              v (.getValue ^java.util.Map$Entry x))))))
#+END_SRC
*** 2D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (deftype Vec2
    ,#+clj [^double x ^double y _meta]
    ,#+cljs [x y _meta]
#+END_SRC
**** Clojure protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+clj clojure.lang.IObj
  ,#+clj (meta
         [_]_meta)
  ,#+clj (withMeta
         [_ m*] (Vec2. x y m*))
  
  ,#+clj clojure.lang.ILookup
  ,#+clj (valAt
         [_ k] (swizzle2 _ k nil))
  ,#+clj (valAt
         [_ k nf] (swizzle2 _ k nf))
  
  ,#+clj java.util.concurrent.Callable
  ,#+clj (call
         [_] (.invoke ^clojure.lang.IFn _))
  ,#+clj java.lang.Runnable
  ,#+clj (run
         [_] (.invoke ^clojure.lang.IFn _))
  
  ,#+clj clojure.lang.IFn
  ,#+clj (invoke
         [_ k] (swizzle2 _ k nil))
  ,#+clj (invoke
         [_ k nf] (swizzle2 _ k nf))
  ,#+clj (applyTo
         [_ args]
         (condp = (count args)
           1 (swizzle2 _ (first args) nil)
           2 (swizzle2 _ (first args) (second args))
           (err/arity-error! (count args))))
  
  ,#+clj clojure.lang.IMapEntry
  ,#+clj java.util.Map$Entry
  ,#+clj (key
         [_] x)
  ,#+clj (getKey
         [_] x)
  ,#+clj (val
         [_] y)
  ,#+clj (getValue
         [_] y)
  
  ,#+clj clojure.lang.Associative
  ,#+clj clojure.lang.IPersistentVector
  ,#+clj (count
         [_] 2)
  ,#+clj (length
         [_] 2)
  ,#+clj (containsKey
         [_ k] (not (nil? (#{0 1 :x :y} k))))
  ,#+clj (entryAt
         [_ k] (map-entry k (case (int k) 0 x, 1 y, (err/key-error! k))))
  ,#+clj (assoc
            [_ k v] (swizzle2-assoc _ k v))
  ,#+clj (assocN
         [_ k v] (case (int k) 0 (Vec2. v y _meta), 1 (Vec2. x v _meta), (err/key-error! k)))
  
  ,#+clj java.util.Collection
  ,#+clj (isEmpty
         [_] false)
  ,#+clj (iterator
         [_] (.iterator ^java.util.Collection (list x y)))
  ,#+clj (toArray
         [_] (double-array 2 [x y]))
  ,#+clj (size [_] 2)
  
  ,#+clj clojure.lang.IPersistentCollection
  ,#+clj clojure.lang.Indexed
  ,#+clj clojure.lang.Sequential
  ,#+clj clojure.lang.ISeq
  ,#+clj clojure.lang.Seqable
  ,#+clj (first
         [_] x)
  ,#+clj (next
         [_] (cons y nil))
  ,#+clj (more
         [_] (cons y nil))
  ,#+clj (cons
         [_ z] (with-meta (vec3 x y z) _meta))
  ,#+clj (peek
         [_] y)
  ,#+clj (pop
         [_] [x])
  ,#+clj (rseq
         [_] (Vec2. y x _meta))
  ,#+clj (seq
         [_] _)
  ,#+clj (nth
         [_ n] (case (int n) 0 x, 1 y, (err/key-error! n)))
  ,#+clj (nth
         [_ n nf] (case (int n) 0 x, 1 y, nf))
  ,#+clj (equiv
         [_ o]
         (if (instance? Vec2 o)
           (and (clojure.lang.Numbers/equiv x (.-x ^Vec2 o))
                (clojure.lang.Numbers/equiv y (.-y ^Vec2 o)))
           (and (instance? java.util.Collection o)
                (= 2 (count o))
                (clojure.lang.Util/equiv x (nth o 0))
                (clojure.lang.Util/equiv y (nth o 1)))))
  ,#+clj (equals
         [_ o]
         (if (instance? Vec2 o)
           (and (clojure.lang.Util/equals x (.-x ^Vec2 o))
                (clojure.lang.Util/equals y (.-y ^Vec2 o)))
           (and (instance? java.util.Collection o)
                (= 2 (count o))
                (clojure.lang.Util/equals x (nth o 0))
                (clojure.lang.Util/equals y (nth o 1)))))
  
  ;; http://docs.oracle.com/javase/7/docs/api/java/util/List.html#hashCode()
  ,#+clj (hashCode
         [_]
         (-> 31
             (unchecked-add-int (hash x))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash y))))
  
  ;; http://clojure.org/data_structures#hash
  ,#+clj clojure.lang.IHashEq
  ,#+clj (hasheq
         [_]
         (-> 31
             (unchecked-add-int (hash x))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash y))
             (mix-collection-hash 2)))
  
  Object
  (toString
   [_] (str "[" x " " y "]"))
#+END_SRC
**** ClojureScript protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+cljs IMeta
  ,#+cljs (-meta
          [_] _meta)
  ,#+cljs IWithMeta
  ,#+cljs (-with-meta
          [_ m*] (Vec2. x y m*))
  
  ,#+cljs ICloneable
  ,#+cljs (-clone
          [_] (Vec2. x y _meta))
  
  ,#+cljs ILookup
  ,#+cljs (-lookup
          [_ k] (swizzle2 _ k nil))
  ,#+cljs (-lookup
          [_ k nf] (swizzle2 _ k nf))
  
  ,#+cljs IFn
  ,#+cljs (-invoke
          [_ k] (swizzle2 _ k nil))
  ,#+cljs (-invoke
          [_ k nf] (swizzle2 _ k nf))
  
  ,#+cljs ICounted
  ,#+cljs (-count
          [_] 2)
  
  ,#+cljs IAssociative
  ,#+cljs (-contains-key?
          [_ k] (not (nil? (#{0 1 :x :y} k))))
  ,#+cljs (-assoc
          [_ k v] (swizzle2-assoc _ k v))
  
  ,#+cljs IVector
  ,#+cljs (-assoc-n
          [_ k v] (case k 0 (Vec2. v y _meta), 1 (Vec2. x v _meta), (err/key-error! k)))
  
  ,#+cljs ISequential
  ,#+cljs ISeq
  ,#+cljs (-first
          [_] x)
  ,#+cljs (-rest
          [_] (cons y nil))
  
  ,#+cljs INext
  ,#+cljs (-next
          [_] (cons y nil))
  
  ,#+cljs ISeqable
  ,#+cljs (-seq
          [_] _)
  
  ,#+cljs IReversible
  ,#+cljs (-rseq
          [_] (Vec2. y x _meta))
  
  ,#+cljs IIndexed
  ,#+cljs (-nth
          [_ n] (case n 0 x, 1 y, (err/key-error! n)))
  ,#+cljs (-nth
          [_ n nf] (case n 0 x, 1 y, nf))
  
  ,#+cljs ICollection
  ,#+cljs (-conj
          [_ z] (with-meta (vec3 x y z) _meta))
  
  ,#+cljs IStack
  ,#+cljs (-peek
          [_] y)
  ,#+cljs (-pop
          [_] [x])
  
  ,#+cljs IComparable
  ,#+cljs (-compare
          [_ o]
          (if (instance? Vec2 o)
            (let [c (compare x (.-x ^Vec2 o))]
              (if (== 0 c) (compare y (.-y ^Vec2 o)) c))
            (let [c (count o)]
              (if (= 2 c) (compare o _) (- 2 c)))))
  
  ,#+cljs IHash
  ,#+cljs (-hash
          [_] (hash-combine (hash x) (hash y)))
  
  ,#+cljs IEquiv
  ,#+cljs (-equiv
          [_ o]
          (if (instance? Vec2 o)
            (and (== x (.-x ^Vec2 o)) (== y (.-y ^Vec2 o)))
            (and (sequential? o) (= 2 (count o))
                 (= x (nth o 0)) (= y (nth o 1)))))
#+END_SRC
**** Transformations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PScale
  (scale
   [_ a] (vec2-op-1 clojure.core/* _ a 1.0 _meta))
  (scale
   [_ a b] (vec2-op-2 clojure.core/* _ a b 1.0 1.0 _meta))
  (scale
   [_ a b c] (vec2-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  PTranslate
  (translate
   [_ a] (vec2-op-1 clojure.core/+ _ a 0.0 _meta))
  (translate
   [_ a b] (vec2-op-2 clojure.core/+ _ a b 0.0 0.0 _meta))
  (translate
   [_ a b c] (vec2-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  PRotate
  (rotate
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec2. (mm/msub x c y s) (mm/madd x s y c) _meta)))
  PRotate3D
  (rotate-x
   [_ theta] (rotate-x (vec3 _) theta))
  (rotate-y
   [_ theta] (rotate-y (vec3 _) theta))
  (rotate-z
   [_ theta] (vec3 (rotate _ theta)))
  (rotate-around-axis
   [_ axis theta] (rotate-around-axis (vec3 _) axis theta))
  
  PTransform
  (transform
   [_ m] (transform-vector m _))
#+END_SRC
**** PMathOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMathOps
  (abs [_] (Vec2. (m/abs x) (m/abs y) _meta))
  (+ [_] _)
  (+ [_ a] (vec2-op-1 clojure.core/+ _ a 0.0 _meta))
  (+ [_ a b] (vec2-op-2 clojure.core/+ _ a b 0.0 0.0 _meta))
  (+ [_ a b c] (vec2-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  (- [_] (Vec2. (clojure.core/- x) (clojure.core/- y) _meta))
  (- [_ a] (vec2-op-1 clojure.core/- _ a 0.0 _meta))
  (- [_ a b] (vec2-op-2 clojure.core/- _ a b 0.0 0.0 _meta))
  (- [_ a b c] (vec2-op-3 clojure.core/- _ a b c 0.0 _meta))
  
  (* [_] _)
  (* [_ a] (vec2-op-1 clojure.core/* _ a 1.0 _meta))
  (* [_ a b] (vec2-op-2 clojure.core/* _ a b 1.0 1.0 _meta))
  (* [_ a b c] (vec2-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  (div [_] (Vec2. (clojure.core// x) (clojure.core// y) _meta))
  (div [_ a] (vec2-op-1 clojure.core// _ a 0.0 _meta))
  (div [_ a b] (vec2-op-2 clojure.core// _ a b 0.0 0.0 _meta))
  (div [_ a b c] (vec2-op-3 clojure.core// _ a b c 0.0 _meta))
  
  (madd [_ a b] (vec2-op-2* clojure.core/* clojure.core/+ _ a b 1.0 0.0 _meta))
#+END_SRC
**** PDotProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PDotProduct
  (dot
   [_ [ax ay]] (mm/madd x ax y ay))
#+END_SRC
**** PCrossProduct
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PCrossProduct
  (cross
   [_ [ax ay]] (mm/msub x ay y ax))
#+END_SRC
**** PLimit
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PLimit
  (limit
   [_ len]
   (if (> (mag-squared _) (mm/mul len len))
     (normalize _ len) _))
#+END_SRC
**** PMinMax
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMinMax
  (min
   [_ [ax ay]]
   (Vec2.
    (clojure.core/min x ax)
    (clojure.core/min y ay) _meta))
  (min
   [_ [ax ay] [bx by]]
   (Vec2.
    (clojure.core/min (clojure.core/min x ax) bx)
    (clojure.core/min (clojure.core/min y ay) by) _meta))
  (max
   [_ [ax ay]]
   (Vec2.
    (clojure.core/max x ax)
    (clojure.core/max y ay) _meta))
  (max
   [_ [ax ay] [bx by]]
   (Vec2.
    (clojure.core/max (clojure.core/max x ax) bx)
    (clojure.core/max (clojure.core/max y ay) by) _meta))
#+END_SRC
**** PMagnitude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMagnitude
  (mag
   [_]
   (Math/sqrt (mm/madd x x y y)))
  (mag-squared
   [_] (mm/madd x x y y))
#+END_SRC
**** PNormalize
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PNormalize
  (normalize
   [_]
   (let [l (Math/sqrt (mm/madd x x y y))]
     (if (pos? l)
       (Vec2. (mm/div x l) (mm/div y l) _meta)
       _)))
  (normalize
   [_ len]
   (let [l (Math/sqrt (mm/madd x x y y))]
     (if (pos? l)
       (let [l (mm/div len l)]
         (Vec2. (mm/mul x l) (mm/mul y l) _meta))
       _)))
  (normalized?
   [_] (m/delta= 1.0 (mag-squared _)))
#+END_SRC
**** PDistance
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PDistance
  (dist
   [_ a]
   (let [[dx dy] (if (instance? Vec2 a)
                   [(mm/sub x (.-x ^Vec2 a)) (mm/sub y (.-y ^Vec2 a))]
                   [(mm/sub x (nth a 0)) (mm/sub y (nth a 1))])]
     (Math/sqrt (mm/madd dx dx dy dy))))
  (dist-squared
   [_ a]
   (let [[dx dy] (if (instance? Vec2 a)
                   [(mm/sub x (.-x ^Vec2 a)) (mm/sub y (.-y ^Vec2 a))]
                   [(mm/sub x (nth a 0)) (mm/sub y (nth a 1))])]
     (mm/madd dx dx dy dy)))
#+END_SRC
**** PReflect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PReflect
  (reflect
   [_ [rx ry :as r]]
    (let [d (mm/mul (dot _ r) 2.0)]
      (Vec2.
       (mm/msub rx d x)
       (mm/msub ry d y) _meta)))
#+END_SRC
**** PInvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInvert
  (invert
   [_] (Vec2. (clojure.core/- x) (clojure.core/- y) _meta))
#+END_SRC
**** PInterpolate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInterpolate
  (mix
   [_ [ax ay]]
   (Vec2. (mm/submadd ax x 0.5 x) (mm/submadd ay y 0.5 y) _meta))
  (mix
   [_ [ax ay] t]
   (Vec2. (mm/submadd ax x t x) (mm/submadd ay y t y) _meta))
#+END_SRC
**** PHeading
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PHeading
  (heading
   [_]
   (let [t (Math/atan2 y x)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (heading-xy [_] (heading _))
  (angle-between
   [_ a]
   (let [t (mm/sub (heading-xy a) (heading-xy _))]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (slope-xy [_] (mm/div y x))
  (normal [_] (Vec2. (clojure.core/- y) x _meta))
#+END_SRC
**** PPolar
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PPolar
  (as-polar
   [_] (Vec2. (mag _) (heading-xy _) _meta))
  (as-cartesian
   [_] (Vec2. (mm/mul x (Math/cos y)) (mm/mul x (Math/sin y)) _meta))
#+END_SRC
**** End of implementations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  )
#+END_SRC
**** Override print methods
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  #+clj (require 'clojure.pprint)
  #+clj (prefer-method clojure.pprint/simple-dispatch clojure.lang.IPersistentVector clojure.lang.ISeq)
  #+clj (defmethod print-method Vec2 [o ^java.io.Writer w] (.write w (.toString o)))
#+END_SRC
*** 3D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (deftype Vec3
    #+clj [^double x ^double y ^double z _meta]
    #+cljs [x y z _meta]
#+END_SRC
**** Clojure protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+clj clojure.lang.IObj
  ,#+clj (meta
         [_] _meta)
  ,#+clj (withMeta
         [_ m*] (Vec3. x y z m*))
  
  ,#+clj clojure.lang.ILookup
  ,#+clj (valAt
         [_ k] (swizzle3 _ k nil))
  ,#+clj (valAt
         [_ k nf] (swizzle3 _ k nf))
  
  ,#+clj java.util.concurrent.Callable
  ,#+clj (call
         [_] (.invoke ^clojure.lang.IFn _))
  ,#+clj java.lang.Runnable
  ,#+clj (run
         [_] (.invoke ^clojure.lang.IFn _))
  
  ,#+clj clojure.lang.IFn
  ,#+clj (invoke
         [_ k] (swizzle3 _ k nil))
  ,#+clj (invoke
         [_ k nf] (swizzle3 _ k nf))
  ,#+clj (applyTo
         [_ args]
         (condp = (count args)
           1 (swizzle3 _ (first args) nil)
           2 (swizzle3 _ (first args) (second args))
           (err/arity-error! (count args))))
  
  ,#+clj clojure.lang.Associative
  ,#+clj clojure.lang.IPersistentVector
  ,#+clj (count
         [_] 3)
  ,#+clj (length
         [_] 3)
  ,#+clj (containsKey
         [_ k] (not (nil? (#{0 1 2 :x :y :z} k))))
  ,#+clj (entryAt
         [_ k] (map-entry k (case (int k) 0 x, 1 y, 2 z, (err/key-error! k))))
  ,#+clj (assoc
            [_ k v] (swizzle3-assoc _ k v))
  ,#+clj (assocN
         [_ k v]
         (case (int k)
           0 (Vec3. v y z _meta)
           1 (Vec3. x v z _meta)
           2 (Vec3. x y v _meta)
           (err/key-error! k)))
  
  ,#+clj java.util.Collection
  ,#+clj (isEmpty
         [_] false)
  ,#+clj (iterator
         [_] (.iterator ^java.util.Collection (list x y z)))
  ,#+clj (toArray
         [_] (double-array 3 [x y z]))
  ,#+clj (size
         [_] 3)
  
  ,#+clj clojure.lang.IPersistentCollection
  ,#+clj clojure.lang.Indexed
  ,#+clj clojure.lang.Sequential
  ,#+clj clojure.lang.ISeq
  ,#+clj clojure.lang.Seqable
  ,#+clj (first
         [_] x)
  ,#+clj (next
         [_] (cons y (cons z nil)))
  ,#+clj (more
         [_] (cons y (cons z nil)))
  ,#+clj (cons
         [_ w] (with-meta [x y z w] _meta))
  ,#+clj (peek
         [_] z)
  ,#+clj (pop
         [_] (Vec2. x y _meta))
  ,#+clj (rseq
         [_] (Vec3. z y x _meta))
  ,#+clj (seq
         [_] _)
  ,#+clj (nth
         [_ n] (condp = n 0 x 1 y 2 z (err/key-error! n)))
  ,#+clj (nth
         [_ n nf] (condp = n 0 x 1 y 2 z nf))
  ,#+clj (equiv
         [_ o]
         (if (instance? Vec3 o)
           (and (clojure.lang.Numbers/equiv x (.-x ^Vec3 o))
                (clojure.lang.Numbers/equiv y (.-y ^Vec3 o))
                (clojure.lang.Numbers/equiv z (.-z ^Vec3 o)))
           (and (instance? java.util.Collection o)
                (= 3 (count o))
                (clojure.lang.Util/equiv x (nth o 0))
                (clojure.lang.Util/equiv y (nth o 1))
                (clojure.lang.Util/equiv z (nth o 2)))))
  ,#+clj (equals
         [_ o]
         (if (instance? Vec3 o)
           (and (clojure.lang.Util/equals x (.-x ^Vec3 o))
                (clojure.lang.Util/equals y (.-y ^Vec3 o))
                (clojure.lang.Util/equals z (.-z ^Vec3 o)))
           (and (instance? java.util.Collection o)
                (= 3 (count o))
                (clojure.lang.Util/equals x (nth o 0))
                (clojure.lang.Util/equals y (nth o 1))
                (clojure.lang.Util/equals z (nth o 2)))))
  
  ,#+clj Comparable
  ,#+clj (compareTo
         [_ o]
         (if (instance? Vec3 o)
           (let [c (compare x (.-x ^Vec3 o))]
             (if (== 0 c)
               (let [c (compare y (.-y ^Vec3 o))]
                 (if (== 0 c)
                   (compare z (.-z ^Vec3 o))
                   c))
               c))
           (let [c (count o)]
             (if (== 3 c) (compare o _) (- 3 c)))))
  ,#+clj (hashCode
         [_]
         (-> 31
             (unchecked-add-int (hash x))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash y))
             (unchecked-multiply-int 31)
             (unchecked-add-int (hash z))))
  
  ,#+clj clojure.lang.IHashEq
  ,#+clj (hasheq
           [_]
           (-> 31
               (unchecked-add-int (hash x))
               (unchecked-multiply-int 31)
               (unchecked-add-int (hash y))
               (unchecked-multiply-int 31)
               (unchecked-add-int (hash z))
               (mix-collection-hash 3)))
  
  Object
  (toString
    [_] (str "[" x " " y " " z "]"))
#+END_SRC
**** ClojureScript protocols
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ,#+cljs IMeta
  ,#+cljs (-meta
          [_] _meta)
  ,#+cljs IWithMeta
  ,#+cljs (-with-meta
          [_ m*] (Vec3. x y z m*))
  
  ,#+cljs ICloneable
  ,#+cljs (-clone
          [_] (Vec3. x y z _meta))
  
  ,#+cljs ILookup
  ,#+cljs (-lookup
          [_ k] (swizzle3 _ k nil))
  ,#+cljs (-lookup
          [_ k nf] (swizzle3 _ k nf))
  
  ,#+cljs IFn
  ,#+cljs (-invoke
          [_ k] (swizzle3 _ k nil))
  ,#+cljs (-invoke
          [_ k nf] (swizzle3 _ k nf))
  
  ,#+cljs ICounted
  ,#+cljs (-count
          [_] 3)
  
  ,#+cljs IAssociative
  ,#+cljs (-contains-key?
          [_ k] (not (nil? (#{0 1 2 :x :y :z} k))))
  ,#+cljs (-assoc
          [_ k v] (swizzle3-assoc _ k v))
  
  ,#+cljs IVector
  ,#+cljs (-assoc-n
          [_ k v]
          (case k
            0 (Vec3. v y z _meta)
            1 (Vec3. x v z _meta)
            2 (Vec3. x y v _meta)
            (err/key-error! k)))
  
  ,#+cljs ISequential
  ,#+cljs ISeq
  ,#+cljs (-first
          [_] x)
  ,#+cljs (-rest
          [_] (cons y (cons z nil)))
  
  ,#+cljs INext
  ,#+cljs (-next
          [_] (cons y (cons z nil)))
  
  ,#+cljs ISeqable
  ,#+cljs (-seq
          [_] _)
  
  ,#+cljs IReversible
  ,#+cljs (-rseq
          [_] (Vec3. z y x _meta))
  
  ,#+cljs IIndexed
  ,#+cljs (-nth
          [_ n] (case n 0 x, 1 y, 2 z, (err/key-error! n)))
  ,#+cljs (-nth
          [_ n nf] (case n 0 x, 1 y, 2 z, nf))
  
  ,#+cljs ICollection
  ,#+cljs (-conj
          [_ w] (with-meta [x y z w] _meta))
  
  ,#+cljs IStack
  ,#+cljs (-peek
          [_] z)
  ,#+cljs (-pop
          [_] (Vec2. x y _meta))
  
  ,#+cljs IComparable
  ,#+cljs (-compare
          [_ o]
          (if (instance? Vec3 o)
            (let [c (compare x (.-x ^Vec3 o))]
              (if (== 0 c)
                (let [c (compare y (.-y ^Vec3 o))]
                  (if (== 0 c)
                    (compare z (.-z ^Vec3 o))
                    c))
                c))
            (let [c (count o)]
              (if (= 3 c) (compare o _) (- 3 c)))))
  
  ,#+cljs IHash
  ,#+cljs (-hash
          [_] (-> (hash x)
                  (hash-combine (hash y))
                  (hash-combine (hash z))))
  
  ,#+cljs IEquiv
  ,#+cljs (-equiv
          [_ o]
          (if (instance? Vec3 o)
            (and (== x (.-x ^Vec3 o)) (== y (.-y ^Vec3 o)) (== z (.-z ^Vec3 o)))
            (and (sequential? o) (= 3 (count o))
                 (= x (nth o 0)) (= y (nth o 1)) (= z (nth o 2)))))
#+END_SRC
**** Transformations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PScale
  (scale
   [_ a] (vec3-op-1 clojure.core/* _ a 1.0 _meta))
  (scale
   [_ a b] (vec3-op-2 clojure.core/* clojure.core/* _ a b 1.0 1.0 _meta))
  (scale
   [_ a b c] (vec3-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  PTranslate
  (translate
   [_ a] (vec3-op-1 clojure.core/+ _ a 0.0 _meta))
  (translate
   [_ a b] (vec3-op-2 clojure.core/+ clojure.core/+ _ a b 0.0 0.0 _meta))
  (translate
   [_ a b c] (vec3-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  PRotate
  (rotate [_ theta] (rotate-z _ theta))
  
  PRotate3D
  (rotate-x
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec3. x (mm/msub y c z s) (mm/madd y s z c) _meta)))
  (rotate-y
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec3. (mm/madd x c z s) y (mm/msub z c x s) _meta)))
  (rotate-z
   [_ theta]
   (let [s (Math/sin theta) c (Math/cos theta)]
     (Vec3. (mm/msub x c y s) (mm/madd x s y c) z _meta)))
  (rotate-around-axis
   [_ [ax ay az] theta]
   (let [ux (mm/mul ax x), uy (mm/mul ax y), uz (mm/mul ax z)
         vx (mm/mul ay x), vy (mm/mul ay y), vz (mm/mul ay z)
         wx (mm/mul az x), wy (mm/mul az y), wz (mm/mul az z)
         ax2 (mm/mul ax ax), ay2 (mm/mul ay ay), az2 (mm/mul az az)
         s (Math/sin theta), c (Math/cos theta)
         uvw (mm/add (mm/add ux vy) wz)]
     (Vec3.
      (mm/madd uvw ax
               (mm/msub (mm/add ay2 az2) x (mm/add vy wz) ax) c
               (mm/subm vz wy s))
  
      (mm/madd uvw ay
               (mm/msub (mm/add ax2 az2) y (mm/add ux wz) ay) c
               (mm/subm wx uz s))
  
      (mm/madd uvw az
               (mm/msub (mm/add ax2 ay2) z (mm/add ux vy) az) c
               (mm/subm uy vx s))
      _meta)))
  
  PTransform
  (transform
   [_ m] (transform-vector m _))
#+END_SRC
**** PMathOps
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMathOps
  (abs [_] (Vec3. (m/abs x) (m/abs y) (m/abs z) _meta))
  (+ [_] _)
  (+ [_ a] (vec3-op-1 clojure.core/+ _ a 0.0 _meta))
  (+ [_ a b] (vec3-op-2 clojure.core/+ clojure.core/+ _ a b 0.0 0.0 _meta))
  (+ [_ a b c] (vec3-op-3 clojure.core/+ _ a b c 0.0 _meta))
  
  (- [_] (Vec3. (clojure.core/- x) (clojure.core/- y) (clojure.core/- z) _meta))
  (- [_ a] (vec3-op-1 clojure.core/- _ a 0.0 _meta))
  (- [_ a b] (vec3-op-2 clojure.core/- clojure.core/- _ a b 0.0 0.0 _meta))
  (- [_ a b c] (vec3-op-3 clojure.core/- _ a b c 0.0 _meta))
  
  (* [_] _)
  (* [_ a] (vec3-op-1 clojure.core/* _ a 1.0 _meta))
  (* [_ a b] (vec3-op-2 clojure.core/* clojure.core/* _ a b 1.0 1.0 _meta))
  (* [_ a b c] (vec3-op-3 clojure.core/* _ a b c 1.0 _meta))
  
  (div [_] (Vec3. (clojure.core// x) (clojure.core// y) (clojure.core// z) _meta))
  (div [_ a] (vec3-op-1 clojure.core// _ a 0.0 _meta))
  (div [_ a b] (vec3-op-2 clojure.core// clojure.core// _ a b 0.0 0.0 _meta))
  (div [_ a b c] (vec3-op-3 clojure.core// _ a b c 0.0 _meta))
  
  (madd
   [_ a b] (vec3-op-2 clojure.core/* clojure.core/+ _ a b 1.0 0.0 _meta))
  
  PDotProduct
  (dot
   [_ [ax ay az]]
   (mm/madd x ax y ay z az))
  
  PCrossProduct
  (cross
   [_ [ax ay az]]
   (Vec3.
    (mm/msub y az ay z)
    (mm/msub z ax az x)
    (mm/msub x ay ax y) _meta))
  
  PLimit
  (limit
   [_ len]
   (if (> (mag-squared _) (mm/mul len len))
     (normalize _ len)
     _))
  
  PMinMax
  (min
   [_ [ax ay az]]
   (Vec3.
    (clojure.core/min x ax)
    (clojure.core/min y ay)
    (clojure.core/min z az) _meta))
  (min
   [_ [ax ay az] [bx by bz]]
   (Vec3.
    (clojure.core/min (clojure.core/min x ax) bx)
    (clojure.core/min (clojure.core/min y ay) by)
    (clojure.core/min (clojure.core/min z az) bz) _meta))
  (max
   [_ [ax ay az]]
   (Vec3.
    (clojure.core/max x ax)
    (clojure.core/max y ay)
    (clojure.core/max z az) _meta))
  (max
   [_ [ax ay az] [bx by bz]]
   (Vec3.
    (clojure.core/max (clojure.core/max x ax) bx)
    (clojure.core/max (clojure.core/max y ay) by)
    (clojure.core/max (clojure.core/max z az) bz) _meta))
#+END_SRC
**** PMagnitude
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PMagnitude
  (mag
   [_]
   (Math/sqrt (mm/madd x x y y z z)))
  (mag-squared
   [_] (mm/madd x x y y z z))
#+END_SRC
**** PNormalize
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PNormalize
  (normalize
   [_]
   (let [l (Math/sqrt (mm/madd x x y y z z))]
     (if (pos? l)
       (Vec3. (mm/div x l) (mm/div y l) (mm/div z l) _meta)
       _)))
  (normalize
   [_ len]
   (let [l (Math/sqrt (mm/madd x x y y z z))]
     (if (pos? l)
       (let [l (mm/div len l)]
         (Vec3. (mm/mul x l) (mm/mul y l) (mm/mul z l) _meta)) _)))
  (normalized?
   [_] (m/delta= 1.0 (mag-squared _)))
#+END_SRC
**** PDistance
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PDistance
  (dist
   [_ a] (Math/sqrt (dist-squared _ a)))
  (dist-squared
   [_ a]
   (let [[dx dy dz] (if (instance? Vec3 a)
                      [(mm/sub x (.-x ^Vec3 a))
                       (mm/sub y (.-y ^Vec3 a))
                       (mm/sub z (.-z ^Vec3 a))]
                      [(mm/sub x (nth a 0))
                       (mm/sub y (nth a 1))
                       (mm/sub z (nth a 2 0.0))])]
     (mm/madd dx dx dy dy dz dz)))
#+END_SRC
**** PReflect
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PReflect
  (reflect
   [_ [rx ry rz :as r]]
    (let [d (mm/mul (dot _ r) 2.0)]
      (Vec3.
       (mm/msub rx d x)
       (mm/msub ry d y)
       (mm/msub rz d z) _meta)))
#+END_SRC
**** PInvert
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInvert
  (invert
   [_] (Vec3. (clojure.core/- x) (clojure.core/- y) (clojure.core/- z) _meta))
#+END_SRC
**** PInterpolate
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PInterpolate
  (mix
   [_ [ax ay az]]
   (Vec3.
    (mm/submadd ax x 0.5 x)
    (mm/submadd ay y 0.5 y)
    (mm/submadd az z 0.5 z) _meta))
  (mix
   [_ [ax ay az] t]
   (Vec3.
    (mm/submadd ax x t x)
    (mm/submadd ay y t y)
    (mm/submadd az z t z) _meta))
#+END_SRC
**** PHeading
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  PHeading
  (heading [_] (heading-xy _))
  (heading-xy
   [_]
   (let [t (Math/atan2 y x)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (heading-xz
   [_]
   (let [t (Math/atan2 z x)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (heading-yz
   [_]
   (let [t (Math/atan2 z y)]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (angle-between
   [_ a]
   (let [t (mm/sub (heading-xy a) (heading-xy _))]
     (if (neg? t) (mm/add t TWO_PI) t)))
  (slope-xy [_] (mm/div y x))
  (slope-xz [_] (mm/div x x))
  (slope-yz [_] (mm/div z y))
#+END_SRC
**** PPolar
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  ;; http://mathworld.wolfram.com/SphericalCoordinates.html
  PPolar
  (as-polar
   [_]
    (let [r (mag _)
          theta (Math/atan2 y x)
          phi (Math/acos (mm/div z r))]
      (Vec3. r theta phi _meta)))
  (as-cartesian [_]
    (let [rsphi (mm/mul x (Math/sin z))]
      (Vec3.
       (mm/mul (Math/cos y) rsphi)
       (mm/mul (Math/sin y) rsphi)
       (mm/mul x (Math/cos z)) _meta)))
#+END_SRC
**** End of implementations
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
    )
#+END_SRC
**** Override print methods
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  #+clj (defmethod print-method Vec3 [o ^java.io.Writer w] (.write w (.toString o)))
#+END_SRC
*** Vector operations
**** 2D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defn vec2-op-seq
    [op ^Vec2 acc xs]
    (loop [ax (.-x acc), ay (.-y acc), xs xs]
      (if xs
        (let [v ^Vec2 (first xs)]
          (recur (op ax (.-x v)) (op ay (.-y v)) (next xs)))
        (Vec2. ax ay (.-_meta acc)))))
  
  (defn vec2-op-1
    [op ^Vec2 _ a d m]
    (if (instance? Vec2 a)
      (Vec2.
       (op (.-x _) (.-x ^Vec2 a))
       (op (.-y _) (.-y ^Vec2 a)) m)
      (if (number? a)
        (Vec2. (op (.-x _) a) (op (.-y _) a) m)
        (if (instance? Vec2 (first a))
          (vec2-op-seq op _ a)
          (Vec2.
           (op (.-x _) (nth a 0 d))
           (op (.-y _) (nth a 1 d)) m)))))
  
  (defn vec2-op-2
    [op ^Vec2 _ a b d1 d2 m]
    (if (instance? Vec2 a)
      (if (instance? Vec2 b)
        (Vec2. ;; v v
         (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b))
         (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) m)
        (if (number? b)
          (Vec2. ;; v n
           (op (op (.-x _) (.-x ^Vec2 a)) b)
           (op (op (.-y _) (.-y ^Vec2 a)) b) m)
          (Vec2. ;; v ?
           (op (op (.-x _) (.-x ^Vec2 a)) (nth b 0 d2))
           (op (op (.-y _) (.-y ^Vec2 a)) (nth b 1 d2)) m)))
      (let [an? (number? a) bn? (number? b)]
        (if (and an? bn?)
          (Vec2. ;; n n
           (op (.-x _) a)
           (op (.-y _) b) m)
          (let [[ax ay] (if an? [a a] a)
                [bx by] (if bn? [b b] b)]
            (Vec2. ;; ? ?
             (op (op (.-x _) (or ax d1)) (or bx d2))
             (op (op (.-y _) (or ay d1)) (or by d2)) m))))))
  
  (defn vec2-op-2*
    "Similar to vec2-op-2 but takes 2 fn args and handles case with
    a & b being both numbers differently."
    [op op2 ^Vec2 _ a b d1 d2 m]
    (if (instance? Vec2 a)
      (if (instance? Vec2 b)
        (Vec2. ;; v v
         (op2 (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b))
         (op2 (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) m)
        (if (number? b)
          (Vec2. ;; v n
           (op2 (op (.-x _) (.-x ^Vec2 a)) b)
           (op2 (op (.-y _) (.-y ^Vec2 a)) b) m)
          (Vec2. ;; v ?
           (op2 (op (.-x _) (.-x ^Vec2 a)) (nth b 0 d2))
           (op2 (op (.-y _) (.-y ^Vec2 a)) (nth b 1 d2)) m)))
      (let [an? (number? a) bn? (number? b)]
        (if (and an? bn?)
          (Vec2. ;; n n
           (op2 (op (.-x _) a) b)    ;; difference to vec2-op-2
           (op2 (op (.-y _) a) b) m)
          (let [[ax ay] (if an? [a a] a)
                [bx by] (if bn? [b b] b)]
            (Vec2. ;; ? ?
             (op2 (op (.-x _) (or ax d1)) (or bx d2))
             (op2 (op (.-y _) (or ay d1)) (or by d2)) m))))))
  
  (defn vec2-op-3
    [op ^Vec2 _ a b c d m]
    (if (instance? Vec2 a)
      (if (instance? Vec2 b)
        (if (instance? Vec2 c)
          (Vec2. ;; v v v
           (op (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b)) (.-x ^Vec2 c))
           (op (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) (.-y ^Vec2 c)) m)
          (if (number? c)
            (Vec2. ;; v v n
             (op (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b)) c)
             (op (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) c) m)
            (Vec2. ;; v v ?
             (op (op (op (.-x _) (.-x ^Vec2 a)) (.-x ^Vec2 b)) (nth c 0 d))
             (op (op (op (.-y _) (.-y ^Vec2 a)) (.-y ^Vec2 b)) (nth c 1 d)) m)))
        (let [[bx by] (if (number? b) [b b] b)
              [cx cy] (if (number? c) [c c] c)]
          (Vec2. ;; v ? ?
           (op (op (op (.-x _) (.-x ^Vec2 a)) (or bx d)) (or cx d))
           (op (op (op (.-y _) (.-y ^Vec2 a)) (or by d)) (or cy d)) m)))
      (let [[ax ay] (if (number? a) [a a] a)
            [bx by] (if (number? b) [b b] b)
            [cx cy] (if (number? c) [c c] c)]
        (Vec2. ;; ? ? ?
         (op (op (op (.-x _) (or ax d)) (or bx d)) (or cx d))
         (op (op (op (.-y _) (or ay d)) (or by d)) (or cy d)) m))))
#+END_SRC
**** 3D
#+BEGIN_SRC clojure :tangle ../babel/src/cljx/thi/ng/geom/core.cljx
  (defn vec3-op-seq
    [op ^Vec3 acc xs]
    (loop [ax (.-x acc), ay (.-y acc), az (.-z acc), xs xs]
      (if xs
        (let [v ^Vec3 (first xs)]
          (recur (op ax (.-x v)) (op ay (.-y v)) (op az (.-z v)) (next xs)))
        (Vec3. ax ay az (.-_meta acc)))))
{'fraction_non_alphanumeric': 0.18134639526542323, 'fraction_numerical': 0.014145444763271162, 'mean_word_length': 2.1257050765511685, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7504770', 'n_tokens_mistral': 40086, 'n_tokens_neox': 37151, 'n_words': 9716}