      :height height
      :x x
      :y y}))
-
-(defn- generic-outer-rect
-  [state {:keys [x1 y1] :as shape}]
-  (-> (assoc shape :x x1 :y y1)
-      (merge (size shape))
-      (apply-rotation-transformation)))
-
-(defn- line-outer-rect
-  [state {:keys [x1 y1 x2 y2 group] :as shape}]
-  (let [group (get-in state [:shapes-by-id 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- circle-outer-rect
-  [state {:keys [cx cy rx ry group] :as shape}]
-  (let [group (get-in state [:shapes-by-id 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- group-outer-rect
-  [state {:keys [id group rotation dx dy] :as shape}]
-  (let [shapes (->> (:items shape)
-                    (map #(get-in @st/state [:shapes-by-id %]))
-                    (map (partial 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)
-        x (+ x dx)
-        y (+ y dy)]
-    (-> (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})))
 
 ;; --- Transformation Matrix
 

  [state {:keys [dx dy rotation items] :or {rotation 0} :as shape}]
  (let [shapes-by-id (get state :shapes-by-id)
        shapes (map #(get shapes-by-id %) items)
        {:keys [x y width height]} (outer-rect shapes)
        center-x (+ x (/ width 2))
        center-y (+ y (/ height 2))]
    (-> (gmt/matrix)

         :rx (mth/abs (- x2 x1))
         :ry (mth/abs (- y2 y1))))

;; --- Inner Rect

(declare apply-rotation-transformation)
(declare generic-inner-rect)
(declare circle-inner-rect)
(declare group-inner-rect)

(defn inner-rect
  ([shape] (inner-rect @st/state shape))
  ([state shape]
   (case (:type shape)
     :icon (generic-inner-rect state shape)
     :rect (generic-inner-rect state shape)
     :text (generic-inner-rect shape shape)
     :line (generic-inner-rect state shape)
     :circle (circle-inner-rect state shape)
     :group (group-inner-rect state shape))))

(defn- generic-inner-rect
  [state {:keys [x1 y1] :as shape}]
  (-> (assoc shape :x x1 :y y1)
      (merge (size shape))
      (apply-rotation-transformation)))

(defn- circle-inner-rect
  [state {:keys [cx cy rx ry group] :as shape}]
  (let [props {:x (- cx rx)
               :y (- cy ry)
               :width (* rx 2)
               :height (* ry 2)}]
    (-> (merge shape props)
        (apply-rotation-transformation))))

(defn- group-inner-rect
  [state {:keys [id group rotation dx dy] :as shape}]
  (let [shapes (->> (:items shape)
                    (map #(get-in state [:shapes-by-id %]))
                    (map #(inner-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)
        x (+ x dx)
        y (+ y dy)]
    (-> (merge shape {:width width :height height :x x :y y})
        (apply-rotation-transformation))))

;; --- Outer Rect

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

(defn outer-rect
  ([shape]
   (outer-rect @st/state shape))
  ([state shape]
   (let [shape (case (:type shape)
                 :rect (generic-outer-rect state shape)
                 :text (generic-outer-rect state shape)
                 :icon (generic-outer-rect state shape)
                 :line (generic-outer-rect state shape)
                 :circle (circle-outer-rect state shape)
                 :group (group-outer-rect state shape))]
     (if (:group shape)
       (let [group (get-in state [:shapes-by-id (: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-by-id id])]
    (let [props {:x (+ x (:dx group 0))
                 :y (+ y (:dy group 0))}]
      (apply-parent-deltas state (merge shape props) (:group group)))
    shape))

(defn- generic-outer-rect
  [state {:keys [x1 y1 x2 y2 group] :as shape}]
  (let [group (get-in state [:shapes-by-id 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- circle-outer-rect
  [state {:keys [cx cy rx ry group] :as shape}]
  (let [group (get-in state [:shapes-by-id 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- group-outer-rect
  [state {:keys [id group rotation dx dy] :as shape}]
  (let [shapes (->> (:items shape)
                    (map #(get-in state [:shapes-by-id %]))
                    (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]
