   [{:keys [rx ry] :as shape}]
   (merge shape {:width (* rx 2)
                 :height (* ry 2)}))
-
-;; --- Vertex Access
-
-(declare get-rect-vertext-point)
-(declare get-circle-vertext-point)
-
-(defn get-vertex-point
-  [shape id]
-  (case (:type shape)
-    :icon (get-rect-vertext-point shape id)
-    :image (get-rect-vertext-point shape id)
-    :rect (get-rect-vertext-point shape id)
-    :circle (get-circle-vertext-point shape id)
-    :text (get-rect-vertext-point shape id)))
-
-(defn- get-rect-vertext-point
-  [{:keys [x1 y1 x2 y2]} id]
-  (case id
-    :top-left (gpt/point x1 y1)
-    :top-right (gpt/point x2 y1)
-    :bottom-left (gpt/point x1 y2)
-    :bottom-right (gpt/point x2 y2)
-    :top (gpt/point (/ (+ x1 x2) 2) y1)
-    :right (gpt/point x2 (/ (+ y1 y2) 2))
-    :left (gpt/point x1 (/ (+ y1 y2) 2))
-    :bottom (gpt/point (/ (+ x1 x2) 2)
-                       (/ (+ y1 y2) 2))))
-
-(defn- get-circle-vertext-point
-  [{:keys [rx ry]} id]
-  (gpt/point rx ry))
-
-;; --- Vertex Movement (Relative)
-
-(declare move-rect-vertex)
-(declare move-circle-vertex)
-
-(defn move-vertex
-  "Resize the shape moving one of its vertex using
-  relative delta."
-  [shape vid dpoint]
-  (case (:type shape)
-    :rect (move-rect-vertex shape vid dpoint)
-    :text (move-rect-vertex shape vid dpoint)
-    :icon (move-rect-vertex shape vid dpoint)
-    :image (move-rect-vertex shape vid dpoint)
-    :path (move-rect-vertex shape vid dpoint)
-    :circle (move-circle-vertex shape vid dpoint)))
-
-(defn- move-rect-vertex
-  "A specialized function for vertex movement
-  for rect-like shapes."
-  [shape vid {dx :x dy :y lock? :lock}]
-  (letfn [(handle-positioning [{:keys [x1 x2 y1 y2] :as shape}]
-            (case vid
-              :top-left (assoc shape
-                               :x1 (min x2 (+ x1 dx))
-                               :y1 (min y2 (+ y1 dy)))
-              :top-right (assoc shape
-                                :x2 (max x1 (+ x2 dx))
-                                :y1 (min y2 (+ y1 dy)))
-              :bottom-left (assoc shape
-                                  :x1 (min x2 (+ x1 dx))
-                                  :y2 (max y1 (+ y2 dy)))
-              :bottom-right (assoc shape
-                                   :x2 (max x1 (+ x2 dx))
-                                   :y2 (max y1 (+ y2 dy)))
-              :top (assoc shape :y1 (min y2 (+ y1 dy)))
-              :right (assoc shape :x2 (max x1 (+ x2 dx)))
-              :bottom (assoc shape :y2 (max y1 (+ y2 dy)))
-              :left (assoc shape :x1 (min x2 (+ x1 dx)))))
-
-          (handle-proportion [{:keys [y1 proportion proportion-lock] :as shape}]
-            (let [{:keys [width height]} (size shape)]
-              (if (or lock? proportion-lock)
-                (assoc shape :y2 (+ y1 (/ width proportion)))
-                shape)))]
-    (-> shape
-        (handle-positioning)
-        (handle-proportion))))
-
-(defn- move-circle-vertex
-  "A specialized function for vertex movement
-  for circle shapes."
-  [shape vid {dx :x dy :y lock? :lock}]
-  (letfn [(handle-positioning [shape]
-            (case vid
-              :top-left (assoc shape
-                               :rx (max 0 (- (:rx shape) dx))
-                               :ry (max 0 (- (:ry shape) dy)))
-              :top-right (assoc shape
-                                :rx (max 0 (+ (:rx shape) dx))
-                                :ry (max 0 (- (:ry shape) dy)))
-              :bottom-left (assoc shape
-                                  :rx (max 0 (- (:rx shape) dx))
-                                  :ry (max 0 (+ (:ry shape) dy)))
-              :bottom-right (assoc shape
-                                   :rx (max 0 (+ (:rx shape) dx))
-                                   :ry (max 0 (+ (:ry shape) dy)))
-              :top (assoc shape :ry (max 0 (- (:ry shape) dy)))
-              :right (assoc shape :rx (max 0 (+ (:rx shape) dx)))
-              :bottom (assoc shape :ry (max 0 (+ (:ry shape) dy)))
-              :left (assoc shape :rx (max 0 (+ (:rx shape) dx)))))
-          (handle-proportion [{:keys [rx proportion proportion-lock] :as shape}]
-            (let [{:keys [width height]} (size shape)]
-              (if (or lock? proportion-lock)
-                (assoc shape :ry (/ rx proportion))
-                shape)))]
-    (-> shape
-        (handle-positioning)
-        (handle-proportion))))
 
 ;; --- Paths
 


;; --- Outer Rect

(declare outer-rect-generic)
(declare outer-rect-circle)
(declare outer-rect-path)
(declare outer-rect-group)
(declare apply-rotation-transformation)
(declare apply-parent-deltas)

(defn outer-rect
  ([shape]
   (outer-rect @st/state shape))
  ([state shape]
   (let [shape (case (:type shape)
                 :path (outer-rect-path state shape)
                 :circle (outer-rect-circle state shape)
                 :group (outer-rect-group state shape)
                 (outer-rect-generic state shape))]
     (if (:group shape)
       (let [group (get-in state [:shapes (:group shape)])]
         (apply-parent-deltas state shape (:group group)))
       shape))))

(defn- apply-parent-deltas
  [state {:keys [x y] :as shape} id]
  (if-let [group (get-in state [:shapes id])]
    (let [props {:x (+ x (:dx group 0))
                 :y (+ y (:dy group 0))}]
      (apply-parent-deltas state (merge shape props) (:group group)))
    shape))

(defn- outer-rect-generic
  [state {:keys [x1 y1 x2 y2 group] :as shape}]
  (let [group (get-in state [:shapes group])
        props {:x (+ x1 (:dx group 0))
               :y (+ y1 (:dy group 0))
               :width (- x2 x1)
               :height (- y2 y1)}]
    (-> (merge shape props)
        (apply-rotation-transformation))))

(defn- outer-rect-circle
  [state {:keys [cx cy rx ry group] :as shape}]
  (let [group (get-in state [:shapes group])
        props {:x (+ (- cx rx) (:dx group 0))
               :y (+ (- cy ry) (:dy group 0))
               :width (* rx 2)
               :height (* ry 2)}]
    (-> (merge shape props)
        (apply-rotation-transformation))))

(defn- outer-rect-path
  [state {:keys [points group] :as shape}]
  (let [group (get-in state [:shapes group])
        minx (apply min (map :x points))
        miny (apply min (map :y points))
        maxx (apply max (map :x points))
        maxy (apply max (map :y points))

        props {:x (+ minx (:dx group 0))
               :y (+ miny (:dy group 0))
               :width (- maxx minx)
               :height (- maxy miny)}]
    (-> (merge shape props)
        (apply-rotation-transformation))))


(defn- outer-rect-group
  [state {:keys [id group rotation dx dy] :as shape}]
  (let [shapes (->> (:items shape)
                    (map #(get-in state [:shapes %]))
                    (map #(outer-rect state %)))
        x (apply min (map :x shapes))
        y (apply min (map :y shapes))
        x' (apply max (map (fn [{:keys [x width]}] (+ x width)) shapes))
        y' (apply max (map (fn [{:keys [y height]}] (+ y height)) shapes))
        width (- x' x)
        height (- y' y)]
    (-> (merge shape {:width width :height height :x x :y y})
        (apply-rotation-transformation))))

(declare apply-rotation)

(defn- apply-rotation-transformation
  [{:keys [x y width height rotation] :as shape}]
  (let [center-x (+ x (/ width 2))
        center-y (+ y (/ height 2))

        angle (mth/radians (or rotation 0))
        x1 (- x center-x)
        y1 (- y center-y)

        x2 (- (+ x width) center-x)
        y2 (- y center-y)

        [rx1 ry1] (apply-rotation [x1 y1] rotation)
        [rx2 ry2] (apply-rotation [x2 y2] rotation)

        [d1 d2] (cond
                  (and (>= rotation 0)
                       (< rotation 90))
                  [(mth/abs ry1)
                   (mth/abs rx2)]

                  (and (>= rotation 90)
                       (< rotation 180))
                  [(mth/abs ry2)
                   (mth/abs rx1)]

                  (and (>= rotation 180)
                       (< rotation 270))
                  [(mth/abs ry1)
                   (mth/abs rx2)]

                  (and (>= rotation 270)
                       (<= rotation 360))
                  [(mth/abs ry2)
                   (mth/abs rx1)])
        final-x (- center-x d2)
        final-y (- center-y d1)
        final-width (* d2 2)
        final-height (* d1 2)]
    (merge shape
           {:x final-x
            :y final-y
            :width final-width
            :height final-height})))

;; --- Outer Rect Coll

(defn outer-rect-coll
  [shapes]
  {:pre [(seq shapes)]}
  (let [shapes (map outer-rect shapes)
        x (apply min (map :x shapes))
        y (apply min (map :y shapes))
        x' (apply max (map (fn [{:keys [x width]}] (+ x width)) shapes))
        y' (apply max (map (fn [{:keys [y height]}] (+ y height)) shapes))
        width (- x' x)
        height (- y' y)]
    {:width width
     :height height
     :x x
     :y y}))

;; --- Helpers

(defn apply-rotation
  [[x y :as v] rotation]
  (let [angle (mth/radians rotation)
        rx (- (* x (mth/cos angle))
              (* y (mth/sin angle)))
        ry (+ (* x (mth/sin angle))
              (* y (mth/cos angle)))]
    (let [r [(mth/precision rx 6)
             (mth/precision ry 6)]]
      r)))

(defn resolve-parent
  "Recursively resolve the real shape parent."

;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>

(ns uxbox.main.geom
  (:require [cljs.pprint :refer [pprint]]
            [uxbox.util.geom.matrix :as gmt]
            [uxbox.util.geom.point :as gpt]
            [uxbox.util.math :as mth]
            [uxbox.store :as st]))

;; --- Relative Movement

(declare move-rect)
(declare move-path)
(declare move-circle)
