0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-13 10:38:13 -05:00

Add geom helpers for apply a transformation matrix to shape.

This commit is contained in:
Andrey Antukh 2016-12-20 16:57:35 +01:00
parent 8ca15771d5
commit 747c07af00
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95

View file

@ -213,7 +213,7 @@
"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 proportion] :as shape}]
(letfn [(handle-positioning [{:keys [x1 x2 y1 y2] :as shape}]
(case vid
:top-left (assoc shape
:x1 (min x2 (+ x1 dx))
@ -482,66 +482,124 @@
:proportion (/ width height)
:proportion-lock true)))
;; --- Inner Rect
;; --- Coerce to Rect-like shape.
(declare apply-rotation-transformation)
(declare inner-rect-circle)
(declare inner-rect-group)
(declare inner-rect-path)
(declare inner-rect-generic)
(declare circle->rect-shape)
(declare path->rect-shape)
(declare group->rect-shape)
(defn inner-rect
([shape] (inner-rect @st/state shape))
([state shape]
(case (:type shape)
:circle (inner-rect-circle state shape)
:group (inner-rect-group state shape)
:path (inner-rect-path state shape)
(inner-rect-generic state shape))))
(defn shape->rect-shape
"Coerce shape to rect like shape."
([shape] (shape->rect-shape @st/state shape))
([state {:keys [type] :as shape}]
(case type
:circle (circle->rect-shape state shape)
:path (path->rect-shape state shape)
:group (group->rect-shape state shape)
shape)))
(defn- inner-rect-generic
[state {:keys [x1 y1] :as shape}]
(-> (assoc shape :x x1 :y y1)
(merge (size shape))
(apply-rotation-transformation)))
(defn shapes->rect-shape
([shapes] (shapes->rect-shape @st/state shapes))
([state shapes]
{:pre [(seq shapes)]}
(let [shapes (map shape->rect-shape shapes)
minx (apply min (map :x1 shapes))
miny (apply min (map :y1 shapes))
maxx (apply max (map :x2 shapes))
maxy (apply max (map :y2 shapes))]
{:x1 minx
:y1 miny
:x2 maxx
:y2 maxy
::shapes shapes})))
(defn- inner-rect-path
(defn- group->rect-shape
[state {:keys [items] :as group}]
(let [shapes (map #(get-in state [:shapes %]) items)]
(shapes->rect-shape state shapes)))
(defn- path->rect-shape
[state {:keys [points] :as shape}]
(let [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
:y miny
:width (- maxx minx)
:height (- maxy miny)}]
(-> (merge shape props)
(apply-rotation-transformation))))
maxy (apply max (map :y points))]
(assoc shape
:x1 minx
:y1 miny
:x2 maxx
:y2 maxy)))
(defn- inner-rect-circle
[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- circle->rect-shape
[state {:keys [cx cy rx ry] :as shape}]
(let [width (* rx 2)
height (* ry 2)
x1 (- cx rx)
y1 (- cy ry)]
(assoc shape
:x1 x1
:y1 y1
:x2 (+ x1 width)
:y2 (+ y1 height))))
(defn- inner-rect-group
[state {:keys [id group rotation dx dy] :as shape}]
(let [shapes (->> (:items shape)
(map #(get-in state [:shapes %]))
(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))))
;; --- Transform Shape
(declare transform-rect)
(declare transform-circle)
(declare transform-path)
(defn transform
"Apply the matrix transformation to shape."
([shape xfmt] (transform @st/state shape xfmt))
([state {:keys [type] :as shape} xfmt]
(case type
:rect (transform-rect shape xfmt)
:icon (transform-rect shape xfmt)
:image (transform-rect shape xfmt)
:path (transform-path shape xfmt)
:circle (transform-circle shape xfmt))))
(defn- transform-rect
[{:keys [x1 y1] :as shape} mx]
(let [{:keys [width height]} (size shape)
tl (gpt/transform [x1 y1] mx)
tr (gpt/transform [(+ x1 width) y1] mx)
bl (gpt/transform [x1 (+ y1 height)] mx)
br (gpt/transform [(+ x1 width) (+ y1 height)] mx)
minx (apply min (map :x [tl tr bl br]))
maxx (apply max (map :x [tl tr bl br]))
miny (apply min (map :y [tl tr bl br]))
maxy (apply max (map :y [tl tr bl br]))]
(assoc shape
:x1 minx
:y1 miny
:x2 (+ minx (- maxx minx))
:y2 (+ miny (- maxy miny)))))
(defn- transform-circle
[{:keys [cx cy rx ry] :as shape} xfmt]
(let [{:keys [x1 y1 x2 y2]} (shape->rect-shape shape)
tl (gpt/transform [x1 y1] xfmt)
tr (gpt/transform [x2 y1] xfmt)
bl (gpt/transform [x1 y2] xfmt)
br (gpt/transform [x2 y2] xfmt)
x (apply min (map :x [tl tr bl br]))
y (apply min (map :y [tl tr bl br]))
maxx (apply max (map :x [tl tr bl br]))
maxy (apply max (map :y [tl tr bl br]))
width (- maxx x)
height (- maxy y)
cx (+ x (/ width 2))
cy (+ y (/ height 2))
rx (/ width 2)
ry (/ height 2)]
(assoc shape :cx cx :cy cy :rx rx :ry ry)))
(defn- transform-path
[{:keys [points] :as shape} xfmt]
(let [points (map #(gpt/transform % xfmt) points)]
(assoc shape :points points)))
;; --- Outer Rect