Merge pull request #2597 from penpot/alotor-performance-enhance

 Improve transforms performance
This commit is contained in:
Andrey Antukh 2022-11-24 11:06:34 +01:00 committed by GitHub
commit 0061b37c13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 402 additions and 247 deletions

View file

@ -6,7 +6,7 @@
(ns app.common.attrs (ns app.common.attrs
(:require (:require
[app.common.geom.shapes.transforms :as gst] [app.common.geom.shapes.transforms :as gtr]
[app.common.math :as mth])) [app.common.math :as mth]))
(defn- get-attr (defn- get-attr
@ -24,7 +24,7 @@
value value
(if-let [points (:points obj)] (if-let [points (:points obj)]
(if (not= points :multiple) (if (not= points :multiple)
(let [rect (gst/selection-rect [obj])] (let [rect (gtr/selection-rect [obj])]
(if (= attr :ox) (:x rect) (:y rect))) (if (= attr :ox) (:x rect) (:y rect)))
:multiple) :multiple)
(get obj attr ::unset))) (get obj attr ::unset)))

View file

@ -91,27 +91,34 @@
(defn multiply (defn multiply
([^Matrix m1 ^Matrix m2] ([^Matrix m1 ^Matrix m2]
(let [m1a (.-a m1) (cond
m1b (.-b m1) ;; nil matrixes are equivalent to unit-matrix
m1c (.-c m1) (and (nil? m1) (nil? m2)) (matrix)
m1d (.-d m1) (nil? m1) m2
m1e (.-e m1) (nil? m2) m1
m1f (.-f m1)
m2a (.-a m2) :else
m2b (.-b m2) (let [m1a (.-a m1)
m2c (.-c m2) m1b (.-b m1)
m2d (.-d m2) m1c (.-c m1)
m2e (.-e m2) m1d (.-d m1)
m2f (.-f m2)] m1e (.-e m1)
m1f (.-f m1)
(Matrix. m2a (.-a m2)
(+ (* m1a m2a) (* m1c m2b)) m2b (.-b m2)
(+ (* m1b m2a) (* m1d m2b)) m2c (.-c m2)
(+ (* m1a m2c) (* m1c m2d)) m2d (.-d m2)
(+ (* m1b m2c) (* m1d m2d)) m2e (.-e m2)
(+ (* m1a m2e) (* m1c m2f) m1e) m2f (.-f m2)]
(+ (* m1b m2e) (* m1d m2f) m1f))))
(Matrix.
(+ (* m1a m2a) (* m1c m2b))
(+ (* m1b m2a) (* m1d m2b))
(+ (* m1a m2c) (* m1c m2d))
(+ (* m1b m2c) (* m1d m2d))
(+ (* m1a m2e) (* m1c m2f) m1e)
(+ (* m1b m2e) (* m1d m2f) m1f)))))
([m1 m2 & others] ([m1 m2 & others]
(reduce multiply (multiply m1 m2) others))) (reduce multiply (multiply m1 m2) others)))

View file

@ -189,6 +189,10 @@
(defn angle-sign [v1 v2] (defn angle-sign [v1 v2]
(if (> (* (:y v1) (:x v2)) (* (:x v1) (:y v2))) -1 1)) (if (> (* (:y v1) (:x v2)) (* (:x v1) (:y v2))) -1 1))
(defn signed-angle-with-other
[v1 v2]
(* (angle-sign v1 v2) (angle-with-other v1 v2)))
(defn update-angle (defn update-angle
"Update the angle of the point." "Update the angle of the point."
[p angle] [p angle]

View file

@ -13,7 +13,7 @@
[app.common.geom.shapes.common :as gco] [app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.constraints :as gct]
[app.common.geom.shapes.corners :as gsc] [app.common.geom.shapes.corners :as gsc]
[app.common.geom.shapes.intersect :as gin] [app.common.geom.shapes.intersect :as gsi]
[app.common.geom.shapes.modifiers :as gsm] [app.common.geom.shapes.modifiers :as gsm]
[app.common.geom.shapes.path :as gsp] [app.common.geom.shapes.path :as gsp]
[app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.rect :as gpr]
@ -178,8 +178,6 @@
(dm/export gtr/transform-bounds) (dm/export gtr/transform-bounds)
(dm/export gtr/move-position-data) (dm/export gtr/move-position-data)
(dm/export gtr/apply-objects-modifiers) (dm/export gtr/apply-objects-modifiers)
(dm/export gtr/parent-coords-rect)
(dm/export gtr/parent-coords-points)
;; Constratins ;; Constratins
(dm/export gct/calc-child-modifiers) (dm/export gct/calc-child-modifiers)
@ -190,10 +188,10 @@
(dm/export gsp/open-path?) (dm/export gsp/open-path?)
;; Intersection ;; Intersection
(dm/export gin/overlaps?) (dm/export gsi/overlaps?)
(dm/export gin/has-point?) (dm/export gsi/has-point?)
(dm/export gin/has-point-rect?) (dm/export gsi/has-point-rect?)
(dm/export gin/rect-contains-shape?) (dm/export gsi/rect-contains-shape?)
;; Bool ;; Bool

View file

@ -6,12 +6,11 @@
(ns app.common.geom.shapes.constraints (ns app.common.geom.shapes.constraints
(:require (:require
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.intersect :as gsi] [app.common.geom.shapes.intersect :as gsi]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.rect :as gre] [app.common.geom.shapes.transforms :as gtr]
[app.common.geom.shapes.transforms :as gst]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.uuid :as uuid])) [app.common.uuid :as uuid]))
@ -184,7 +183,7 @@
(ctm/move-modifiers (displacement end-before end-after)))) (ctm/move-modifiers (displacement end-before end-after))))
(defmethod constraint-modifier :fixed (defmethod constraint-modifier :fixed
[_ axis child-points-before parent-points-before child-points-after parent-points-after transformed-parent] [_ axis child-points-before parent-points-before child-points-after parent-points-after {:keys [transform transform-inverse]} modifiers]
(let [;; Same as constraint end (let [;; Same as constraint end
end-before (end-vector axis child-points-before parent-points-before) end-before (end-vector axis child-points-before parent-points-before)
end-after (end-vector axis child-points-after parent-points-after) end-after (end-vector axis child-points-after parent-points-after)
@ -203,11 +202,16 @@
;; displacement (so its left+top position is constant) ;; displacement (so its left+top position is constant)
scale (/ (gpt/length after-vec) (gpt/length before-vec)) scale (/ (gpt/length after-vec) (gpt/length before-vec))
resize-origin (first child-points-after) resize-origin (gpo/origin child-points-after)
{:keys [transform transform-inverse]} transformed-parent]
modif-transform (ctm/modifiers->transform modifiers)
modif-transform-inverse (gmt/inverse modif-transform)
resize-transform (gmt/multiply modif-transform transform)
resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse)
resize-vector (get-scale axis scale)]
(-> (ctm/empty) (-> (ctm/empty)
(ctm/resize (get-scale axis scale) resize-origin transform transform-inverse) (ctm/resize resize-vector resize-origin resize-transform resize-transform-inverse)
(ctm/move disp-start)))) (ctm/move disp-start))))
(defmethod constraint-modifier :center (defmethod constraint-modifier :center
@ -245,37 +249,36 @@
:top :top
:scale))) :scale)))
(defn bounding-box-parent-transform
"Returns a bounding box for the child in the same coordinate system
as the parent.
Returns a points array"
[child parent]
(-> child
:points
(gco/transform-points (:transform-inverse parent))
(gre/points->rect)
(gre/rect->points) ;; Restore to points so we can transform them
(gco/transform-points (:transform parent))))
(defn normalize-modifiers (defn normalize-modifiers
"Before aplying constraints we need to remove the deformation caused by the resizing of the parent" "Before aplying constraints we need to remove the deformation caused by the resizing of the parent"
[constraints-h constraints-v modifiers child parent transformed-child {:keys [transform transform-inverse] :as transformed-parent}] [constraints-h constraints-v modifiers child {:keys [transform transform-inverse] :as parent} transformed-child-bounds transformed-parent-bounds]
(let [child-bb-before (gst/parent-coords-rect child parent) (let [child-bb-before (gpo/parent-coords-bounds (:points child) (:points parent))
child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
scale-x (/ (:width child-bb-before) (:width child-bb-after))
scale-y (/ (:height child-bb-before) (:height child-bb-after))
resize-origin (-> transformed-parent :points gpo/origin)]
(cond-> modifiers scale-x (if (= :scale constraints-h)
(not= :scale constraints-h) 1
(ctm/resize (gpt/point scale-x 1) resize-origin transform transform-inverse) (/ (gpo/width-points child-bb-before) (gpo/width-points child-bb-after)))
(not= :scale constraints-v) scale-y (if (= :scale constraints-v)
(ctm/resize (gpt/point 1 scale-y) resize-origin transform transform-inverse)))) 1
(/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after)))
resize-vector (gpt/point scale-x scale-y)
modif-transform (ctm/modifiers->transform modifiers)
modif-transform-inverse (gmt/inverse modif-transform)
resize-transform (gmt/multiply modif-transform transform)
resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse)
resize-origin (gpo/origin transformed-child-bounds)]
(-> modifiers
(ctm/resize
resize-vector
resize-origin
resize-transform
resize-transform-inverse))))
(defn calc-child-modifiers (defn calc-child-modifiers
[parent child modifiers ignore-constraints transformed-parent] [parent child modifiers ignore-constraints parent-bounds transformed-parent-bounds]
(let [modifiers (ctm/select-child-modifiers modifiers) (let [modifiers (ctm/select-child-modifiers modifiers)
@ -292,26 +295,24 @@
(if (and (= :scale constraints-h) (= :scale constraints-v)) (if (and (= :scale constraints-h) (= :scale constraints-v))
modifiers modifiers
(let [transformed-child (gst/transform-shape child (ctm/select-child-modifiers modifiers)) (let [child-bounds (:points child)
modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) modifiers (ctm/select-child-modifiers modifiers)
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child-bounds transformed-parent-bounds)
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
transformed-child (gst/transform-shape child modifiers) child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds)
child-points-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
parent-points-before (bounding-box-parent-transform parent parent)
child-points-before (bounding-box-parent-transform child parent)
parent-points-after (bounding-box-parent-transform transformed-parent transformed-parent)
child-points-after (bounding-box-parent-transform transformed-child transformed-parent)
modifiers-h (constraint-modifier (constraints-h const->type+axis) :x modifiers-h (constraint-modifier (constraints-h const->type+axis) :x
child-points-before parent-points-before child-points-before parent-bounds
child-points-after parent-points-after child-points-after transformed-parent-bounds
transformed-parent) parent modifiers)
modifiers-v (constraint-modifier (constraints-v const->type+axis) :y modifiers-v (constraint-modifier (constraints-v const->type+axis) :y
child-points-before parent-points-before child-points-before parent-bounds
child-points-after parent-points-after child-points-after transformed-parent-bounds
transformed-parent)] parent modifiers)]
(-> modifiers (-> modifiers
(ctm/add-modifiers modifiers-h) (ctm/add-modifiers modifiers-h)
(ctm/add-modifiers modifiers-v)))))) (ctm/add-modifiers modifiers-v))))))

View file

@ -10,25 +10,24 @@
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.shapes.common :as gco] [app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.flex-layout.lines :as fli] [app.common.geom.shapes.flex-layout.lines :as fli]
[app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.rect :as gsr] [app.common.geom.shapes.rect :as gsr]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.shape.layout :as ctl])) [app.common.types.shape.layout :as ctl]))
(defn drop-child-areas (defn drop-child-areas
[{:keys [transform-inverse] :as frame} parent-rect child index reverse? prev-x prev-y last?] [frame parent-rect child-bounds index reverse? prev-x prev-y last?]
(let [col? (ctl/col? frame) (let [col? (ctl/col? frame)
row? (ctl/row? frame) row? (ctl/row? frame)
[layout-gap-row layout-gap-col] (ctl/gaps frame) [layout-gap-row layout-gap-col] (ctl/gaps frame)
start-p (-> child :points first) start-p (gpo/origin child-bounds)
center (gco/center-shape frame)
start-p (gmt/transform-point-center start-p center transform-inverse)
box-x (:x start-p) box-x (:x start-p)
box-y (:y start-p) box-y (:y start-p)
box-width (-> child :selrect :width) box-width (gpo/width-points child-bounds)
box-height (-> child :selrect :height) box-height (gpo/height-points child-bounds)
x (if col? (:x parent-rect) prev-x) x (if col? (:x parent-rect) prev-x)
y (if row? (:y parent-rect) prev-y) y (if row? (:y parent-rect) prev-y)
@ -148,47 +147,45 @@
from-idx 0 from-idx 0
prev-line-x (:x frame) prev-line-x (:x frame)
prev-line-y (:y frame) prev-line-y (:y frame)
lines (seq lines)]
current-line (first lines) (if (empty? lines)
lines (rest lines)]
(if (nil? current-line)
areas areas
(let [line-area (drop-line-area frame current-line prev-line-x prev-line-y (nil? (first lines))) (let [current-line (first lines)
line-area (drop-line-area frame current-line prev-line-x prev-line-y (empty? (rest lines)))
children (subvec children from-idx (+ from-idx (:num-children current-line))) children (subvec children from-idx (+ from-idx (:num-children current-line)))
next-areas next-areas
(loop [areas areas (loop [areas areas
prev-child-x (:x line-area) prev-child-x (:x line-area)
prev-child-y (:y line-area) prev-child-y (:y line-area)
[index child] (first children) children (seq children)]
children (rest children)]
(if (nil? child) (if (empty? children)
areas areas
(let [[child-area child-area-start child-area-end] (let [[index [child-bounds _]] (first children)
(drop-child-areas frame line-area child index (not reverse?) prev-child-x prev-child-y (nil? (first children)))] [child-area child-area-start child-area-end]
(drop-child-areas frame line-area child-bounds index (not reverse?) prev-child-x prev-child-y (empty? (rest children)))]
(recur (conj areas child-area-start child-area-end) (recur (conj areas child-area-start child-area-end)
(+ (:x child-area) (:width child-area)) (+ (:x child-area) (:width child-area))
(+ (:y child-area) (:height child-area)) (+ (:y child-area) (:height child-area))
(first children)
(rest children)))))] (rest children)))))]
(recur next-areas (recur next-areas
(+ from-idx (:num-children current-line)) (+ from-idx (:num-children current-line))
(+ (:x line-area) (:width line-area)) (+ (:x line-area) (:width line-area))
(+ (:y line-area) (:height line-area)) (+ (:y line-area) (:height line-area))
(first lines)
(rest lines))))))) (rest lines)))))))
(defn get-drop-index (defn get-drop-index
[frame-id objects position] [frame-id objects position]
(let [frame (get objects frame-id) (let [frame (get objects frame-id)
position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame)) position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame))
children (cph/get-immediate-children objects frame-id) children (->> (cph/get-immediate-children objects frame-id)
layout-data (fli/calc-layout-data frame children) (map #(vector (gpo/parent-coords-bounds (:points %) (:points frame)) %)))
layout-data (fli/calc-layout-data frame children (:points frame))
drop-areas (layout-drop-areas frame layout-data children) drop-areas (layout-drop-areas frame layout-data children)
area (d/seek #(gsr/contains-point? % position) drop-areas)] area (d/seek #(gsr/contains-point? % position) drop-areas)]
(:index area))) (:index area)))

View file

@ -9,21 +9,20 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.shapes.flex-layout.positions :as flp] [app.common.geom.shapes.flex-layout.positions :as flp]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.transforms :as gst]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.shape.layout :as ctl])) [app.common.types.shape.layout :as ctl]))
(def conjv (fnil conj [])) (def conjv (fnil conj []))
(defn layout-bounds (defn layout-bounds
[{:keys [layout-padding layout-padding-type] :as shape}] [{:keys [layout-padding layout-padding-type] :as shape} shape-bounds]
(let [;; Add padding to the bounds (let [;; Add padding to the bounds
{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding
[pad-top pad-right pad-bottom pad-left] [pad-top pad-right pad-bottom pad-left]
(if (= layout-padding-type :multiple) (if (= layout-padding-type :multiple)
[pad-top pad-right pad-bottom pad-left] [pad-top pad-right pad-bottom pad-left]
[pad-top pad-top pad-top pad-top])] [pad-top pad-top pad-top pad-top])]
(gpo/pad-points (:points shape) pad-top pad-right pad-bottom pad-left))) (gpo/pad-points shape-bounds pad-top pad-right pad-bottom pad-left)))
(defn init-layout-lines (defn init-layout-lines
"Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation"
@ -43,18 +42,17 @@
(loop [line-data nil (loop [line-data nil
result [] result []
child (first children) children (seq children)]
children (rest children)]
(if (nil? child) (if (empty? children)
(cond-> result (some? line-data) (conj line-data)) (cond-> result (some? line-data) (conj line-data))
(let [{:keys [line-min-width line-min-height (let [[child-bounds child] (first children)
{:keys [line-min-width line-min-height
line-max-width line-max-height line-max-width line-max-height
num-children num-children
children-data]} line-data children-data]} line-data
child-bounds (gst/parent-coords-points child shape)
child-width (gpo/width-points child-bounds) child-width (gpo/width-points child-bounds)
child-height (gpo/height-points child-bounds) child-height (gpo/height-points child-bounds)
child-min-width (ctl/child-min-width child) child-min-width (ctl/child-min-width child)
@ -98,7 +96,6 @@
:num-children (inc num-children) :num-children (inc num-children)
:children-data (conjv children-data child-data)} :children-data (conjv children-data child-data)}
result result
(first children)
(rest children)) (rest children))
(recur {:line-min-width next-min-width (recur {:line-min-width next-min-width
@ -108,7 +105,6 @@
:num-children 1 :num-children 1
:children-data [child-data]} :children-data [child-data]}
(cond-> result (some? line-data) (conj line-data)) (cond-> result (some? line-data) (conj line-data))
(first children)
(rest children)))))))) (rest children))))))))
(defn add-space-to-items (defn add-space-to-items
@ -300,9 +296,9 @@
(defn calc-layout-data (defn calc-layout-data
"Digest the layout data to pass it to the constrains" "Digest the layout data to pass it to the constrains"
[shape children] [shape children shape-bounds]
(let [layout-bounds (layout-bounds shape) (let [layout-bounds (layout-bounds shape shape-bounds)
reverse? (ctl/reverse? shape) reverse? (ctl/reverse? shape)
children (cond->> children (not reverse?) reverse) children (cond->> children (not reverse?) reverse)
@ -310,10 +306,10 @@
layout-lines layout-lines
(->> (init-layout-lines shape children layout-bounds) (->> (init-layout-lines shape children layout-bounds)
(add-lines-positions shape layout-bounds) (add-lines-positions shape layout-bounds)
(into [] (into [] (comp (map (partial add-line-spacing shape layout-bounds))
(comp (map (partial add-line-spacing shape layout-bounds)) (map (partial add-children-resizes shape)))))]
(map (partial add-children-resizes shape)))))]
{:layout-lines layout-lines {:layout-lines layout-lines
:layout-bounds layout-bounds :layout-bounds layout-bounds
:reverse? reverse?})) :reverse? reverse?}))

View file

@ -6,27 +6,43 @@
(ns app.common.geom.shapes.flex-layout.modifiers (ns app.common.geom.shapes.flex-layout.modifiers
(:require (:require
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.flex-layout.positions :as fpo] [app.common.geom.shapes.flex-layout.positions :as fpo]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.transforms :as gst] [app.common.geom.shapes.transforms :as gtr]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape.layout :as ctl])) [app.common.types.shape.layout :as ctl]))
(defn normalize-child-modifiers (defn normalize-child-modifiers
"Apply the modifiers and then normalized them against the parent coordinates" "Apply the modifiers and then normalized them against the parent coordinates"
[modifiers parent child {:keys [transform transform-inverse] :as transformed-parent}] [modifiers {:keys [transform transform-inverse] :as parent} child transformed-parent-bounds]
(let [child-bounds (:points child)
parent-bounds (:points parent)
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
child-bb-before (gpo/parent-coords-bounds child-bounds parent-bounds)
child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
scale-x (/ (gpo/width-points child-bb-before) (gpo/width-points child-bb-after))
scale-y (/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after))
resize-vector (gpt/point scale-x scale-y)
modif-transform (ctm/modifiers->transform modifiers)
modif-transform-inverse (gmt/inverse modif-transform)
resize-transform (gmt/multiply modif-transform transform)
resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse)
resize-origin (gpo/origin transformed-child-bounds)]
(let [transformed-child (gst/transform-shape child modifiers)
child-bb-before (gst/parent-coords-rect child parent)
child-bb-after (gst/parent-coords-rect transformed-child transformed-parent)
scale-x (/ (:width child-bb-before) (:width child-bb-after))
scale-y (/ (:height child-bb-before) (:height child-bb-after))
resize-origin (-> transformed-parent :points gpo/origin)
resize-vector (gpt/point scale-x scale-y)]
(-> modifiers (-> modifiers
(ctm/select-child-modifiers) (ctm/select-child-modifiers)
(ctm/resize resize-vector resize-origin transform transform-inverse)))) (ctm/resize
resize-vector
resize-origin
resize-transform
resize-transform-inverse))))
(defn calc-fill-width-data (defn calc-fill-width-data
"Calculates the size and modifiers for the width of an auto-fill child" "Calculates the size and modifiers for the width of an auto-fill child"
@ -74,10 +90,8 @@
(defn layout-child-modifiers (defn layout-child-modifiers
"Calculates the modifiers for the layout" "Calculates the modifiers for the layout"
[parent child layout-line] [parent child child-bounds layout-line]
(let [child-bounds (gst/parent-coords-points child parent) (let [child-origin (gpo/origin child-bounds)
child-origin (gpo/origin child-bounds)
child-width (gpo/width-points child-bounds) child-width (gpo/width-points child-bounds)
child-height (gpo/height-points child-bounds) child-height (gpo/height-points child-bounds)

View file

@ -167,7 +167,7 @@
"Calculates the position for the current shape given the layout-data context" "Calculates the position for the current shape given the layout-data context"
[parent child [parent child
child-width child-height child-width child-height
{:keys [start-p layout-gap-row layout-gap-col margin-x margin-y line-height line-width] :as layout-data}] {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y line-height line-width layout-bounds] :as layout-data}]
(let [row? (ctl/row? parent) (let [row? (ctl/row? parent)
col? (ctl/col? parent) col? (ctl/col? parent)
@ -193,9 +193,8 @@
[margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)
points (:points parent) hv (partial gpo/start-hv layout-bounds)
hv (partial gpo/start-hv points) vv (partial gpo/start-vv layout-bounds)
vv (partial gpo/start-vv points)
corner-p corner-p
(cond-> start-p (cond-> start-p
@ -247,13 +246,13 @@
(gpt/add (vv margin-y))) (gpt/add (vv margin-y)))
;; Fix position when layout is flipped ;; Fix position when layout is flipped
corner-p ;;corner-p
(cond-> corner-p ;;(cond-> corner-p
(:flip-x parent) ;; (:flip-x parent)
(gpt/add (hv child-width)) ;; (gpt/add (hv child-width))
;;
(:flip-y parent) ;; (:flip-y parent)
(gpt/add (vv child-height))) ;; (gpt/add (vv child-height)))
next-p next-p
(cond-> start-p (cond-> start-p

View file

@ -12,6 +12,7 @@
[app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.constraints :as gct]
[app.common.geom.shapes.flex-layout :as gcl] [app.common.geom.shapes.flex-layout :as gcl]
[app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.pixel-precision :as gpp]
[app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.transforms :as gtr] [app.common.geom.shapes.transforms :as gtr]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us] [app.common.spec :as us]
@ -91,12 +92,12 @@
(defn- set-children-modifiers (defn- set-children-modifiers
"Propagates the modifiers from a parent too its children applying constraints if necesary" "Propagates the modifiers from a parent too its children applying constraints if necesary"
[modif-tree objects parent transformed-parent ignore-constraints] [modif-tree objects parent transformed-parent-bounds ignore-constraints]
(let [children (:shapes parent) (let [children (:shapes parent)
modifiers (dm/get-in modif-tree [(:id parent) :modifiers])] modifiers (dm/get-in modif-tree [(:id parent) :modifiers])]
;; Move modifiers don't need to calculate constraints
(if (ctm/only-move? modifiers) (if (ctm/only-move? modifiers)
;; Move modifiers don't need to calculate constraints
(loop [modif-tree modif-tree (loop [modif-tree modif-tree
children (seq children)] children (seq children)]
(if-let [current (first children)] (if-let [current (first children)]
@ -105,49 +106,65 @@
modif-tree)) modif-tree))
;; Check the constraints, then resize ;; Check the constraints, then resize
(let [parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers))] (let [parent-bounds (gtr/transform-bounds (:points parent) (ctm/select-parent-modifiers modifiers))]
(loop [modif-tree modif-tree (loop [modif-tree modif-tree
children (seq children)] children (seq children)]
(if-let [current (first children)] (if (empty? children)
(let [child-modifiers (gct/calc-child-modifiers parent (get objects current) modifiers ignore-constraints transformed-parent)] modif-tree
(let [child-id (first children)
child (get objects child-id)
child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints parent-bounds @transformed-parent-bounds)]
(recur (cond-> modif-tree (recur (cond-> modif-tree
(not (ctm/empty? child-modifiers)) (not (ctm/empty? child-modifiers))
(update-in [current :modifiers] ctm/add-modifiers child-modifiers)) (update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))
(rest children))) (rest children)))))))))
modif-tree))))))
(defn- process-layout-children (defn- process-layout-children
[modif-tree objects parent transformed-parent] [modif-tree objects parent transformed-parent-bounds]
(letfn [(process-child [modif-tree child] (letfn [(process-child [modif-tree child]
(let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) (let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers])
child-modifiers (-> modifiers child-modifiers (-> modifiers
(ctm/select-child-geometry-modifiers) (ctm/select-child-geometry-modifiers)
(gcl/normalize-child-modifiers parent child transformed-parent))] (gcl/normalize-child-modifiers parent child @transformed-parent-bounds))]
(cond-> modif-tree (cond-> modif-tree
(not (ctm/empty? child-modifiers)) (not (ctm/empty? child-modifiers))
(update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))]
(let [children (map (d/getf objects) (:shapes transformed-parent))] (let [children (map (d/getf objects) (:shapes parent))]
(reduce process-child modif-tree children)))) (reduce process-child modif-tree children))))
(defn get-bounds
[objects modif-tree shape]
(let [modifiers (-> (dm/get-in modif-tree [(:id shape) :modifiers])
(ctm/select-geometry))
children (cph/get-immediate-children objects (:id shape))
bounds (cond
(cph/group-shape? shape)
(let [children-bounds (->> children (mapv (partial get-bounds objects modif-tree)))]
(gtr/group-bounds shape children-bounds))
(cph/mask-shape? shape)
(get-bounds objects modif-tree (-> children first))
:else
(:points shape))]
(gtr/transform-bounds bounds modifiers)))
(defn- set-layout-modifiers (defn- set-layout-modifiers
[modif-tree objects parent] [modif-tree objects parent transformed-parent-bounds]
(letfn [(apply-modifiers [modif-tree child] (letfn [(apply-modifiers [child]
(let [modifiers (-> (dm/get-in modif-tree [(:id child) :modifiers]) [(-> (get-bounds objects modif-tree child)
(ctm/select-geometry))] (gpo/parent-coords-bounds @transformed-parent-bounds))
(cond child])
(cph/group-like-shape? child)
(gtr/apply-group-modifiers child objects modif-tree)
(some? modifiers) (set-child-modifiers [[layout-line modif-tree] [child-bounds child]]
(gtr/transform-shape child modifiers)
:else
child)))
(set-child-modifiers [parent [layout-line modif-tree] child]
(let [[modifiers layout-line] (let [[modifiers layout-line]
(gcl/layout-child-modifiers parent child layout-line) (gcl/layout-child-modifiers parent child child-bounds layout-line)
modif-tree modif-tree
(cond-> modif-tree (cond-> modif-tree
@ -156,13 +173,12 @@
[layout-line modif-tree]))] [layout-line modif-tree]))]
(let [children (map (d/getf objects) (:shapes parent)) (let [children (->> (:shapes parent)
children (->> children (map (partial apply-modifiers modif-tree))) (map (comp apply-modifiers (d/getf objects))))
layout-data (gcl/calc-layout-data parent children) layout-data (gcl/calc-layout-data parent children @transformed-parent-bounds)
children (into [] (cond-> children (not (:reverse? layout-data)) reverse)) children (into [] (cond-> children (not (:reverse? layout-data)) reverse))
max-idx (dec (count children)) max-idx (dec (count children))
layout-lines (:layout-lines layout-data)] layout-lines (:layout-lines layout-data)]
(loop [modif-tree modif-tree (loop [modif-tree modif-tree
layout-line (first layout-lines) layout-line (first layout-lines)
pending (rest layout-lines) pending (rest layout-lines)
@ -172,7 +188,7 @@
children (subvec children from-idx to-idx) children (subvec children from-idx to-idx)
[_ modif-tree] [_ modif-tree]
(reduce (partial set-child-modifiers parent) [layout-line modif-tree] children)] (reduce set-child-modifiers [layout-line modif-tree] children)]
(recur modif-tree (first pending) (rest pending) to-idx)) (recur modif-tree (first pending) (rest pending) to-idx))
modif-tree))))) modif-tree)))))
@ -195,11 +211,9 @@
(ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))] (ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))]
(let [children (->> parent :shapes (map (d/getf objects))) (let [children (->> parent :shapes (map (d/getf objects)))
{auto-width :width auto-height :height} {auto-width :width auto-height :height}
(when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent))) (when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
(gcl/layout-content-bounds parent children))] (gcl/layout-content-bounds parent children))]
(cond-> (ctm/empty) (cond-> (ctm/empty)
(and (some? auto-width) (ctl/auto-width? parent)) (and (some? auto-width) (ctl/auto-width? parent))
(set-parent-auto-width auto-width) (set-parent-auto-width auto-width)
@ -214,11 +228,12 @@
root? (= uuid/zero parent-id) root? (= uuid/zero parent-id)
modifiers (-> (dm/get-in modif-tree [parent-id :modifiers]) modifiers (-> (dm/get-in modif-tree [parent-id :modifiers])
(ctm/select-geometry)) (ctm/select-geometry))
transformed-parent (gtr/transform-shape parent modifiers)
transformed-parent-bounds (delay (gtr/transform-bounds (:points parent) modifiers))
has-modifiers? (ctm/child-modifiers? modifiers) has-modifiers? (ctm/child-modifiers? modifiers)
layout? (ctl/layout? parent) layout? (ctl/layout? parent)
auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
;; If the current child is inside the layout we ignore the constraints ;; If the current child is inside the layout we ignore the constraints
@ -226,11 +241,11 @@
[(cond-> modif-tree [(cond-> modif-tree
(and (not layout?) has-modifiers? parent? (not root?)) (and (not layout?) has-modifiers? parent? (not root?))
(set-children-modifiers objects parent transformed-parent (or ignore-constraints inside-layout?)) (set-children-modifiers objects parent transformed-parent-bounds (or ignore-constraints inside-layout?))
layout? layout?
(-> (process-layout-children objects parent transformed-parent) (-> (process-layout-children objects parent transformed-parent-bounds)
(set-layout-modifiers objects transformed-parent))) (set-layout-modifiers objects parent transformed-parent-bounds)))
;; Auto-width/height can change the positions in the parent so we need to recalculate ;; Auto-width/height can change the positions in the parent so we need to recalculate
(cond-> autolayouts auto? (conj (:id parent)))])) (cond-> autolayouts auto? (conj (:id parent)))]))
@ -247,21 +262,21 @@
[objects tree-seq modif-tree] [objects tree-seq modif-tree]
(letfn [(apply-shape [objects {:keys [id] :as shape}] (letfn [(apply-shape [objects {:keys [id] :as shape}]
(if (cph/group-shape? shape) (let [modifiers (get-in modif-tree [id :modifiers])
(let [children (cph/get-children objects id)] object
(assoc objects id (cond
(cond (cph/mask-shape? shape)
(cph/mask-shape? shape) (gtr/update-mask-selrect shape (cph/get-children objects id))
(gtr/update-mask-selrect shape children)
:else (cph/group-shape? shape)
(gtr/update-group-selrect shape children)))) (gtr/update-group-selrect shape (cph/get-children objects id))
(let [modifiers (get-in modif-tree [id :modifiers]) (some? modifiers)
object (cond-> shape (gtr/transform-shape shape modifiers)
(some? modifiers)
(gtr/transform-shape modifiers))] :else
(assoc objects id object))))] shape)]
(assoc objects id object)))]
(reduce apply-shape objects (reverse tree-seq)))) (reduce apply-shape objects (reverse tree-seq))))

View file

@ -9,15 +9,15 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.rect :as gpr]
[app.common.geom.shapes.transforms :as gtr]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.modifiers :as ctm])) [app.common.types.modifiers :as ctm]))
(defn size-pixel-precision (defn size-pixel-precision
[modifiers {:keys [points transform transform-inverse] :as shape}] [modifiers {:keys [transform transform-inverse] :as shape} points]
(let [origin (gpo/origin points) (let [origin (gpo/origin points)
curr-width (gpo/width-points points) curr-width (gpo/width-points points)
curr-height (gpo/height-points points) curr-height (gpo/height-points points)
@ -36,7 +36,7 @@
(ctm/resize scalev origin transform transform-inverse)))) (ctm/resize scalev origin transform transform-inverse))))
(defn position-pixel-precision (defn position-pixel-precision
[modifiers {:keys [points]}] [modifiers _ points]
(let [bounds (gpr/points->rect points) (let [bounds (gpr/points->rect points)
corner (gpt/point bounds) corner (gpt/point bounds)
target-corner (gpt/round corner) target-corner (gpt/round corner)
@ -47,24 +47,28 @@
(defn set-pixel-precision (defn set-pixel-precision
"Adjust modifiers so they adjust to the pixel grid" "Adjust modifiers so they adjust to the pixel grid"
[modifiers shape] [modifiers shape]
(let [move? (ctm/only-move? modifiers)] (let [points (-> shape :points (gco/transform-points (ctm/modifiers->transform modifiers)))
(cond-> modifiers has-resize? (not (ctm/only-move? modifiers))
(not move?)
(size-pixel-precision shape)
:always [modifiers points]
(position-pixel-precision shape)))) (let [modifiers
(cond-> modifiers
has-resize? (size-pixel-precision shape points))
points
(cond-> (:points shape)
has-resize? (gco/transform-points (ctm/modifiers->transform modifiers)))]
[modifiers points])]
(position-pixel-precision modifiers shape points)))
(defn adjust-pixel-precision (defn adjust-pixel-precision
[modif-tree objects] [modif-tree objects]
(let [update-modifiers (let [update-modifiers
(fn [modif-tree shape] (fn [modif-tree shape]
(let [modifiers (dm/get-in modif-tree [(:id shape) :modifiers])] (let [modifiers (dm/get-in modif-tree [(:id shape) :modifiers])]
(if-not (ctm/has-geometry? modifiers) (cond-> modif-tree
modif-tree (ctm/has-geometry? modifiers)
(let [shape (gtr/transform-shape shape modifiers)] (update-in [(:id shape) :modifiers] set-pixel-precision shape))))]
(-> modif-tree
(update-in [(:id shape) :modifiers] set-pixel-precision shape))))))]
(->> (keys modif-tree) (->> (keys modif-tree)
(map (d/getf objects)) (map (d/getf objects))

View file

@ -6,12 +6,21 @@
(ns app.common.geom.shapes.points (ns app.common.geom.shapes.points
(:require (:require
[app.common.geom.point :as gpt])) [app.common.geom.point :as gpt]
[app.common.geom.shapes.intersect :as gsi]))
(defn origin (defn origin
[points] [points]
(nth points 0)) (nth points 0))
(defn hv
[[p0 p1 _ _]]
(gpt/to-vec p0 p1))
(defn vv
[[p0 _ _ p3]]
(gpt/to-vec p0 p3))
(defn start-hv (defn start-hv
"Horizontal vector from the origin with a magnitude `val`" "Horizontal vector from the origin with a magnitude `val`"
[[p0 p1 _ _] val] [[p0 p1 _ _] val]
@ -60,3 +69,46 @@
(-> p1 (gpt/add right-v) (gpt/add top-v)) (-> p1 (gpt/add right-v) (gpt/add top-v))
(-> p2 (gpt/add right-v) (gpt/add bottom-v)) (-> p2 (gpt/add right-v) (gpt/add bottom-v))
(-> p3 (gpt/add left-v) (gpt/add bottom-v))]))) (-> p3 (gpt/add left-v) (gpt/add bottom-v))])))
#_(defn parent-coords-rect
[child-bounds parent-bounds]
#_(-> child-bounds
(gco/transform-points (:transform-inverse parent))
(gpr/points->rect)))
(defn closest-first
"Reorders the points so the closest to the line start-end is the first"
[[a b c d] start end]
(let [da (gpt/point-line-distance a start end)
db (gpt/point-line-distance b start end)
dc (gpt/point-line-distance c start end)
dd (gpt/point-line-distance d start end)]
(cond
(and (<= da db) (<= da dc) (<= da dd))
[a b c d]
(and (<= db da) (<= db dc) (<= db dd))
[b c d a]
(and (<= dc da) (<= dc db) (<= dc dd))
[c d a b]
:else
[d a b c])))
(defn parent-coords-bounds
[bounds [p1 p2 _ p4]]
(let [[b1 b2 b3 b4] (closest-first bounds p1 p2)
hv (gpt/to-vec p1 p2)
vv (gpt/to-vec p1 p4)
i1 (gsi/line-line-intersect b1 (gpt/add hv b1) b4 (gpt/add b4 vv))
i2 (gsi/line-line-intersect b1 (gpt/add hv b1) b2 (gpt/add b2 vv))
i3 (gsi/line-line-intersect b3 (gpt/add hv b3) b2 (gpt/add b2 vv))
i4 (gsi/line-line-intersect b3 (gpt/add hv b3) b4 (gpt/add b4 vv))]
[i1 i2 i3 i4]))

View file

@ -369,6 +369,16 @@
(update :width + (:width deltas)) (update :width + (:width deltas))
(update :height + (:height deltas))))))) (update :height + (:height deltas)))))))
(defn group-bounds
[group children-bounds]
(let [shape-center (gco/center-shape group)
points (flatten children-bounds)
points (if (empty? points) (:points group) points)]
(-> points
(gco/transform-points shape-center (:transform-inverse group (gmt/matrix)))
(gpr/squared-points)
(gco/transform-points shape-center (:transform group (gmt/matrix))))))
(defn update-group-selrect (defn update-group-selrect
[group children] [group children]
(let [shape-center (gco/center-shape group) (let [shape-center (gco/center-shape group)
@ -541,19 +551,3 @@
:else :else
group)))) group))))
(defn parent-coords-rect
[child parent]
(-> child
:points
(gco/transform-points (:transform-inverse parent))
(gpr/points->rect)))
(defn parent-coords-points
[child parent]
(-> child
:points
(gco/transform-points (:transform-inverse parent))
(gpr/points->rect)
(gpr/rect->points)
(gco/transform-points (:transform parent))))

View file

@ -8,6 +8,7 @@
(:refer-clojure :exclude [empty empty?]) (:refer-clojure :exclude [empty empty?])
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.common :as gco] [app.common.geom.shapes.common :as gco]
@ -50,7 +51,6 @@
(or (not (mth/almost-zero? (- (:x vector) 1))) (or (not (mth/almost-zero? (- (:x vector) 1)))
(not (mth/almost-zero? (- (:y vector) 1))))) (not (mth/almost-zero? (- (:y vector) 1)))))
(defn- mergeable-move? (defn- mergeable-move?
[op1 op2] [op1 op2]
(and (= :move (:type op1)) (and (= :move (:type op1))
@ -106,6 +106,13 @@
(conj item))) (conj item)))
(conj operations op))))) (conj operations op)))))
(defn valid-vector?
[{:keys [x y]}]
(and (some? x)
(some? y)
(not (mth/nan? x))
(not (mth/nan? y))))
;; Public builder API ;; Public builder API
(defn empty [] (defn empty []
@ -116,12 +123,14 @@
(move-parent modifiers (gpt/point x y))) (move-parent modifiers (gpt/point x y)))
([modifiers vector] ([modifiers vector]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
(cond-> modifiers (cond-> modifiers
(move-vec? vector) (move-vec? vector)
(update :geometry-parent conjv {:type :move :vector vector})))) (update :geometry-parent maybe-add-move {:type :move :vector vector}))))
(defn resize-parent (defn resize-parent
([modifiers vector origin] ([modifiers vector origin]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
(cond-> modifiers (cond-> modifiers
(resize-vec? vector) (resize-vec? vector)
(update :geometry-parent maybe-add-resize {:type :resize (update :geometry-parent maybe-add-resize {:type :resize
@ -129,6 +138,7 @@
:origin origin}))) :origin origin})))
([modifiers vector origin transform transform-inverse] ([modifiers vector origin transform transform-inverse]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
(cond-> modifiers (cond-> modifiers
(resize-vec? vector) (resize-vec? vector)
(update :geometry-parent maybe-add-resize {:type :resize (update :geometry-parent maybe-add-resize {:type :resize
@ -141,12 +151,14 @@
(move modifiers (gpt/point x y))) (move modifiers (gpt/point x y)))
([modifiers vector] ([modifiers vector]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
(cond-> modifiers (cond-> modifiers
(move-vec? vector) (move-vec? vector)
(update :geometry-child maybe-add-move {:type :move :vector vector})))) (update :geometry-child maybe-add-move {:type :move :vector vector}))))
(defn resize (defn resize
([modifiers vector origin] ([modifiers vector origin]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
(cond-> modifiers (cond-> modifiers
(resize-vec? vector) (resize-vec? vector)
(update :geometry-child maybe-add-resize {:type :resize (update :geometry-child maybe-add-resize {:type :resize
@ -154,6 +166,7 @@
:origin origin}))) :origin origin})))
([modifiers vector origin transform transform-inverse] ([modifiers vector origin transform transform-inverse]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
(cond-> modifiers (cond-> modifiers
(resize-vec? vector) (resize-vec? vector)
(update :geometry-child maybe-add-resize {:type :resize (update :geometry-child maybe-add-resize {:type :resize
@ -355,8 +368,9 @@
(defn only-move? (defn only-move?
"Returns true if there are only move operations" "Returns true if there are only move operations"
[{:keys [geometry-child geometry-parent]}] [{:keys [geometry-child geometry-parent]}]
(and (every? #(= :move (:type %)) geometry-child) (let [move-op? #(= :move (:type %))]
(every? #(= :move (:type %)) geometry-parent))) (and (every? move-op? geometry-child)
(every? move-op? geometry-parent))))
(defn has-geometry? (defn has-geometry?
[{:keys [geometry-parent geometry-child]}] [{:keys [geometry-parent geometry-child]}]
@ -418,16 +432,19 @@
(gmt/multiply (gmt/translate-matrix vector) matrix) (gmt/multiply (gmt/translate-matrix vector) matrix)
:resize :resize
(gmt/multiply (let [origin (cond-> origin
(-> (gmt/matrix) (or (some? transform-inverse)(some? transform))
(gmt/translate origin) (gpt/transform transform-inverse))]
(cond-> (some? transform) (gmt/multiply
(gmt/multiply transform)) (-> (gmt/matrix)
(gmt/scale vector) (cond-> (some? transform)
(cond-> (some? transform-inverse) (gmt/multiply transform))
(gmt/multiply transform-inverse)) (gmt/translate origin)
(gmt/translate (gpt/negate origin))) (gmt/scale vector)
matrix) (gmt/translate (gpt/negate origin))
(cond-> (some? transform-inverse)
(gmt/multiply transform-inverse)))
matrix))
:rotation :rotation
(gmt/multiply (gmt/multiply

View file

@ -12,9 +12,8 @@
[app.common.files.features :as ffeat] [app.common.files.features :as ffeat]
[app.common.geom.align :as gal] [app.common.geom.align :as gal]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.proportions :as gpr] [app.common.geom.proportions :as gpp]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.geom.shapes.rect :as gpsr]
[app.common.logging :as log] [app.common.logging :as log]
[app.common.pages.changes-builder :as pcb] [app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
@ -937,7 +936,7 @@
(if-not lock (if-not lock
(assoc shape :proportion-lock false) (assoc shape :proportion-lock false)
(-> (assoc shape :proportion-lock true) (-> (assoc shape :proportion-lock true)
(gpr/assign-proportions))))] (gpp/assign-proportions))))]
(rx/of (dch/update-shapes [id] assign-proportions)))))) (rx/of (dch/update-shapes [id] assign-proportions))))))
(defn toggle-proportion-lock (defn toggle-proportion-lock
@ -1776,10 +1775,10 @@
media (vals (:media file-data')) media (vals (:media file-data'))
media-points media-points
(map #(assoc % :points (gpsr/rect->points {:x 0 (map #(assoc % :points (gsh/rect->points {:x 0
:y 0 :y 0
:width (:width %) :width (:width %)
:height (:height %)})) :height (:height %)}))
media) media)
shape-grid shape-grid

View file

@ -8,7 +8,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.proportions :as gpr] [app.common.geom.proportions :as gpp]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages.changes-builder :as pcb] [app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
@ -69,7 +69,7 @@
(get-shape-layer-position objects selected-non-frames attrs)] (get-shape-layer-position objects selected-non-frames attrs)]
(-> (merge default-attrs attrs) (-> (merge default-attrs attrs)
(gpr/setup-proportions) (gpp/setup-proportions)
(assoc :frame-id frame-id (assoc :frame-id frame-id
:parent-id parent-id :parent-id parent-id
:index index)))) :index index))))

View file

@ -146,8 +146,8 @@
(fn [id] (fn [id]
(let [new-shape (get text-shapes id) (let [new-shape (get text-shapes id)
old-shape (get prev-text-shapes id) old-shape (get prev-text-shapes id)
old-modifiers (get prev-modifiers id) old-modifiers (ctm/select-geometry (get prev-modifiers id))
new-modifiers (get modifiers id) new-modifiers (ctm/select-geometry (get modifiers id))
remote? (some? (-> new-shape meta :session-id)) ] remote? (some? (-> new-shape meta :session-id)) ]
@ -155,10 +155,9 @@
(not (identical? old-shape new-shape)) (not (identical? old-shape new-shape))
(not= (dissoc old-shape :migrate) (not= (dissoc old-shape :migrate)
(dissoc new-shape :migrate))) (dissoc new-shape :migrate)))
(and (not= new-modifiers old-modifiers) (and (not= new-modifiers old-modifiers)
(or (nil? new-modifiers) (or (not (ctm/only-move? new-modifiers))
(nil? old-modifiers)
(not (ctm/only-move? new-modifiers))
(not (ctm/only-move? old-modifiers)))) (not (ctm/only-move? old-modifiers))))
;; When the position data is nil we force to recalculate ;; When the position data is nil we force to recalculate

View file

@ -429,6 +429,12 @@
:hover-top-frame-id @hover-top-frame-id :hover-top-frame-id @hover-top-frame-id
:zoom zoom}]) :zoom zoom}])
(when (debug? :parent-bounds)
[:& wvd/debug-parent-bounds {:selected-shapes selected-shapes
:objects objects-modified
:hover-top-frame-id @hover-top-frame-id
:zoom zoom}])
(when show-selection-handlers? (when show-selection-handlers?
[:g.selection-handlers {:clipPath "url(#clip-handlers)"} [:g.selection-handlers {:clipPath "url(#clip-handlers)"}
[:defs [:defs

View file

@ -14,6 +14,7 @@
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -76,7 +77,7 @@
col? (ctl/col? shape) col? (ctl/col? shape)
children (cph/get-immediate-children objects (:id shape)) children (cph/get-immediate-children objects (:id shape))
layout-data (gsl/calc-layout-data shape children) layout-data (gsl/calc-layout-data shape children (:points shape))
layout-bounds (:layout-bounds layout-data) layout-bounds (:layout-bounds layout-data)
xv #(gpo/start-hv layout-bounds %) xv #(gpo/start-hv layout-bounds %)
@ -112,8 +113,9 @@
shape (or selected-frame (get objects hover-top-frame-id))] shape (or selected-frame (get objects hover-top-frame-id))]
(when (and shape (:layout shape)) (when (and shape (:layout shape))
(let [children (cph/get-immediate-children objects (:id shape)) (let [children (->> (cph/get-immediate-children objects (:id shape))
layout-data (gsl/calc-layout-data shape children) (map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %)))
layout-data (gsl/calc-layout-data shape children (:points shape))
drop-areas (gsl/layout-drop-areas shape layout-data children)] drop-areas (gsl/layout-drop-areas shape layout-data children)]
[:g.debug-layout {:pointer-events "none" [:g.debug-layout {:pointer-events "none"
:transform (gsh/transform-str shape)} :transform (gsh/transform-str shape)}
@ -135,3 +137,51 @@
:alignment-baseline "hanging" :alignment-baseline "hanging"
:fill "black"} :fill "black"}
(:index drop-area)]])])))) (:index drop-area)]])]))))
(mf/defc shape-parent-bound
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "parent"]))]
::mf/wrap-props false}
[props]
(let [shape (unchecked-get props "shape")
parent (unchecked-get props "parent")
zoom (unchecked-get props "zoom")
[i1 i2 i3 i4] (gpo/parent-coords-bounds (:points shape) (:points parent))]
[:*
[:polygon {:points (->> [i1 i2 i3 i4] (map #(dm/fmt "%,%" (:x %) (:y %))) (str/join ","))
:style {:fill "none" :stroke "red" :stroke-width (/ 1 zoom)}}]
[:line {:x1 (:x i1)
:y1 (:y i1)
:x2 (:x i2)
:y2 (:y i2)
:style {:stroke "green" :stroke-width (/ 1 zoom)}}]
[:line {:x1 (:x i1)
:y1 (:y i1)
:x2 (:x i4)
:y2 (:y i4)
:style {:stroke "blue" :stroke-width (/ 1 zoom)}}]]))
(mf/defc debug-parent-bounds
{::mf/wrap-props false}
[props]
(let [objects (unchecked-get props "objects")
zoom (unchecked-get props "objects")
selected-shapes (unchecked-get props "selected-shapes")
hover-top-frame-id (unchecked-get props "hover-top-frame-id")
selected-frame
(when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type)))
(first selected-shapes))
parent (or selected-frame (get objects hover-top-frame-id))]
(when (and (some? parent) (not= uuid/zero (:id parent)))
(let [children (cph/get-immediate-children objects (:id parent))]
[:g.debug-parent-bounds {:pointer-events "none"}
(for [[idx child] (d/enumerate children)]
[:> shape-parent-bound {:key (dm/str "bound-" idx)
:zoom zoom
:shape child
:parent parent}])]))))

View file

@ -76,6 +76,9 @@
;; Makes the pixel grid red so its more visibile ;; Makes the pixel grid red so its more visibile
:pixel-grid :pixel-grid
;; Show the bounds relative to the parent
:parent-bounds
}) })
;; These events are excluded when we activate the :events flag ;; These events are excluded when we activate the :events flag