0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-19 05:15:44 -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 "A specialized function for vertex movement
for rect-like shapes." for rect-like shapes."
[shape vid {dx :x dy :y lock? :lock}] [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 (case vid
:top-left (assoc shape :top-left (assoc shape
:x1 (min x2 (+ x1 dx)) :x1 (min x2 (+ x1 dx))
@ -482,66 +482,124 @@
:proportion (/ width height) :proportion (/ width height)
:proportion-lock true))) :proportion-lock true)))
;; --- Inner Rect ;; --- Coerce to Rect-like shape.
(declare apply-rotation-transformation) (declare circle->rect-shape)
(declare inner-rect-circle) (declare path->rect-shape)
(declare inner-rect-group) (declare group->rect-shape)
(declare inner-rect-path)
(declare inner-rect-generic)
(defn inner-rect (defn shape->rect-shape
([shape] (inner-rect @st/state shape)) "Coerce shape to rect like shape."
([state shape] ([shape] (shape->rect-shape @st/state shape))
(case (:type shape) ([state {:keys [type] :as shape}]
:circle (inner-rect-circle state shape) (case type
:group (inner-rect-group state shape) :circle (circle->rect-shape state shape)
:path (inner-rect-path state shape) :path (path->rect-shape state shape)
(inner-rect-generic state shape)))) :group (group->rect-shape state shape)
shape)))
(defn- inner-rect-generic (defn shapes->rect-shape
[state {:keys [x1 y1] :as shape}] ([shapes] (shapes->rect-shape @st/state shapes))
(-> (assoc shape :x x1 :y y1) ([state shapes]
(merge (size shape)) {:pre [(seq shapes)]}
(apply-rotation-transformation))) (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}] [state {:keys [points] :as shape}]
(let [minx (apply min (map :x points)) (let [minx (apply min (map :x points))
miny (apply min (map :y points)) miny (apply min (map :y points))
maxx (apply max (map :x points)) maxx (apply max (map :x points))
maxy (apply max (map :y points)) maxy (apply max (map :y points))]
props {:x minx (assoc shape
:y miny :x1 minx
:width (- maxx minx) :y1 miny
:height (- maxy miny)}] :x2 maxx
(-> (merge shape props) :y2 maxy)))
(apply-rotation-transformation))))
(defn- inner-rect-circle (defn- circle->rect-shape
[state {:keys [cx cy rx ry group] :as shape}] [state {:keys [cx cy rx ry] :as shape}]
(let [props {:x (- cx rx) (let [width (* rx 2)
:y (- cy ry) height (* ry 2)
:width (* rx 2) x1 (- cx rx)
:height (* ry 2)}] y1 (- cy ry)]
(-> (merge shape props) (assoc shape
(apply-rotation-transformation)))) :x1 x1
:y1 y1
:x2 (+ x1 width)
:y2 (+ y1 height))))
(defn- inner-rect-group ;; --- Transform Shape
[state {:keys [id group rotation dx dy] :as shape}]
(let [shapes (->> (:items shape) (declare transform-rect)
(map #(get-in state [:shapes %])) (declare transform-circle)
(map #(inner-rect state %))) (declare transform-path)
x (apply min (map :x shapes))
y (apply min (map :y shapes)) (defn transform
x' (apply max (map (fn [{:keys [x width]}] (+ x width)) shapes)) "Apply the matrix transformation to shape."
y' (apply max (map (fn [{:keys [y height]}] (+ y height)) shapes)) ([shape xfmt] (transform @st/state shape xfmt))
width (- x' x) ([state {:keys [type] :as shape} xfmt]
height (- y' y) (case type
x (+ x dx) :rect (transform-rect shape xfmt)
y (+ y dy)] :icon (transform-rect shape xfmt)
(-> (merge shape {:width width :height height :x x :y y}) :image (transform-rect shape xfmt)
(apply-rotation-transformation)))) :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 ;; --- Outer Rect