Refactor for new modifiers

This commit is contained in:
alonso.torres 2022-10-19 13:27:44 +02:00
parent c3ed46d3ab
commit 11f347941e
15 changed files with 445 additions and 824 deletions

View file

@ -6,13 +6,13 @@
(ns app.common.geom.shapes.constraints (ns app.common.geom.shapes.constraints
(:require (:require
[app.common.data :as d]
[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]
[app.common.geom.shapes.intersect :as gsi] [app.common.geom.shapes.intersect :as gsi]
[app.common.geom.shapes.rect :as gre] [app.common.geom.shapes.rect :as gre]
[app.common.geom.shapes.transforms :as gst] [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.uuid :as uuid])) [app.common.uuid :as uuid]))
;; Auxiliary methods to work in an specifica axis ;; Auxiliary methods to work in an specifica axis
@ -152,8 +152,7 @@
end-angl (gpt/angle-with-other end-before end-after) end-angl (gpt/angle-with-other end-before end-after)
target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before))
disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end))] disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end))]
[{:type :move (ctm/move disp-vector-end)))
:vector disp-vector-end}]))
(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 transformed-parent]
@ -177,11 +176,7 @@
scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec))) scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec)))
] ]
[{:type :resize (ctm/resize (get-scale axis scale) c0 (:transform transformed-parent) (:transform-inverse transformed-parent))))
:vector (get-scale axis scale)
:origin c0
:transform (:transform transformed-parent)
:transform-inverse (:transform-inverse transformed-parent)}]))
(defmethod constraint-modifier :center (defmethod constraint-modifier :center
[_ axis child-points-before parent-points-before child-points-after parent-points-after] [_ axis child-points-before parent-points-before child-points-after parent-points-after]
@ -190,8 +185,7 @@
center-angl (gpt/angle-with-other center-before center-after) center-angl (gpt/angle-with-other center-before center-after)
target-center (if (mth/close? center-angl 180) (- (gpt/length center-before)) (gpt/length center-before)) target-center (if (mth/close? center-angl 180) (- (gpt/length center-before)) (gpt/length center-before))
disp-vector-center (gpt/subtract center-after (gpt/scale (gpt/unit center-after) target-center))] disp-vector-center (gpt/subtract center-after (gpt/scale (gpt/unit center-after) target-center))]
[{:type :move (ctm/move disp-vector-center)))
:vector disp-vector-center}]))
(defmethod constraint-modifier :default [_ _ _ _ _] (defmethod constraint-modifier :default [_ _ _ _ _]
[]) [])
@ -222,29 +216,6 @@
:top :top
:scale))) :scale)))
#_(defn clean-modifiers
"Remove redundant modifiers"
[{:keys [displacement resize-vector resize-vector-2] :as modifiers}]
(cond-> modifiers
;; Displacement with value 0. We don't move in any direction
(and (some? displacement)
(mth/almost-zero? (:e displacement))
(mth/almost-zero? (:f displacement)))
(dissoc :displacement)
;; Resize with value very close to 1 means no resize
(and (some? resize-vector)
(mth/almost-zero? (- 1.0 (:x resize-vector)))
(mth/almost-zero? (- 1.0 (:y resize-vector))))
(dissoc :resize-origin :resize-vector)
(and (some? resize-vector)
(mth/almost-zero? (- 1.0 (:x resize-vector-2)))
(mth/almost-zero? (- 1.0 (:y resize-vector-2))))
(dissoc :resize-origin-2 :resize-vector-2)))
(defn bounding-box-parent-transform (defn bounding-box-parent-transform
"Returns a bounding box for the child in the same coordinate system "Returns a bounding box for the child in the same coordinate system
as the parent. as the parent.
@ -259,36 +230,27 @@
(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 transformed-parent] [constraints-h constraints-v modifiers child parent transformed-child {:keys [transform transform-inverse] :as transformed-parent}]
(let [child-bb-before (gst/parent-coords-rect child parent) (let [child-bb-before (gst/parent-coords-rect child parent)
child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) child-bb-after (gst/parent-coords-rect transformed-child transformed-parent)
scale-x (/ (:width child-bb-before) (:width child-bb-after)) scale-x (/ (:width child-bb-before) (:width child-bb-after))
scale-y (/ (:height child-bb-before) (:height child-bb-after))] scale-y (/ (:height child-bb-before) (:height child-bb-after))
(-> modifiers ;; TODO LAYOUT: Is the first always the origin?
(update :v2 #(cond-> % resize-origin (-> transformed-parent :points first)]
(cond-> modifiers
(not= :scale constraints-h) (not= :scale constraints-h)
(conj (ctm/set-resize (gpt/point scale-x 1) resize-origin transform transform-inverse)
;; This resize will leave the shape in its original position relative to the parent
{:type :resize
:transform (:transform transformed-parent)
:transform-inverse (:transform-inverse transformed-parent)
:origin (-> transformed-parent :points (nth 0))
:vector (gpt/point scale-x 1)})
(not= :scale constraints-v) (not= :scale constraints-v)
(conj (ctm/set-resize (gpt/point 1 scale-y) resize-origin transform transform-inverse))))
{:type :resize
:transform (:transform transformed-parent)
:transform-inverse (:transform-inverse transformed-parent)
:origin (-> transformed-parent :points (nth 0))
:vector (gpt/point 1 scale-y)}))))))
(defn calc-child-modifiers (defn calc-child-modifiers
[parent child modifiers ignore-constraints transformed-parent] [parent child modifiers ignore-constraints transformed-parent]
(let [modifiers (select-keys modifiers [:v2]) (let [modifiers (ctm/select-child-modifiers modifiers)
constraints-h constraints-h
(if-not ignore-constraints (if-not ignore-constraints
@ -306,12 +268,12 @@
(let [transformed-child (gst/transform-shape child modifiers) (let [transformed-child (gst/transform-shape child modifiers)
modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent)
tranformed-child-2 (gst/transform-shape child modifiers) transformed-child (gst/transform-shape child modifiers)
parent-points-before (:points parent) parent-points-before (:points parent)
child-points-before (bounding-box-parent-transform child parent) child-points-before (bounding-box-parent-transform child parent)
parent-points-after (:points transformed-parent) parent-points-after (:points transformed-parent)
child-points-after (bounding-box-parent-transform tranformed-child-2 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-points-before
@ -323,6 +285,6 @@
child-points-after parent-points-after child-points-after parent-points-after
transformed-parent)] transformed-parent)]
(update modifiers :v2 d/concat-vec modifiers-h modifiers-v))))) (-> modifiers
(ctm/add-modifiers modifiers-h)
(ctm/add-modifiers modifiers-v))))))

View file

@ -10,9 +10,11 @@
[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]
[app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.rect :as gsr] [app.common.geom.shapes.rect :as gsr]
[app.common.geom.shapes.transforms :as gst] [app.common.geom.shapes.transforms :as gst]
[app.common.pages.helpers :as cph])) [app.common.pages.helpers :as cph]
[app.common.types.modifiers :as ctm]))
;; :layout ;; true if active, false if not ;; :layout ;; true if active, false if not
;; :layout-dir ;; :right, :left, :top, :bottom ;; :layout-dir ;; :right, :left, :top, :bottom
@ -56,107 +58,18 @@
[{:keys [layout-v-orientation]}] [{:keys [layout-v-orientation]}]
(= layout-v-orientation :bottom)) (= layout-v-orientation :bottom))
(defn add-padding [transformed-rect {:keys [layout-padding-type layout-padding]}]
(let [{:keys [p1 p2 p3 p4]} layout-padding
[p1 p2 p3 p4]
(if (= layout-padding-type :multiple)
[p1 p2 p3 p4]
[p1 p1 p1 p1])]
(-> transformed-rect
(update :y + p1)
(update :width - p2 p3)
(update :x + p3)
(update :height - p1 p4))))
;; FUNCTIONS TO WORK WITH POINTS SQUARES
(defn origin
[points]
(nth points 0))
(defn start-hv
"Horizontal vector from the origin with a magnitude `val`"
[[p0 p1 _ _] val]
(-> (gpt/to-vec p0 p1)
(gpt/unit)
(gpt/scale val)))
(defn end-hv
"Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`"
[[p0 p1 _ _] val]
(-> (gpt/to-vec p1 p0)
(gpt/unit)
(gpt/scale val)))
(defn start-vv
"Vertical vector from the oposite to the origin in the x axis with a magnitude `val`"
[[p0 _ _ p3] val]
(-> (gpt/to-vec p0 p3)
(gpt/unit)
(gpt/scale val)))
(defn end-vv
"Vertical vector from the oposite to the origin in the x axis with a magnitude `val`"
[[p0 _ _ p3] val]
(-> (gpt/to-vec p3 p0)
(gpt/unit)
(gpt/scale val)))
;;(defn start-hp
;; [[p0 _ _ _ :as points] val]
;; (gpt/add p0 (start-hv points val)))
;;
;;(defn end-hp
;; "Horizontal Vector from the oposite to the origin in the x axis with a magnitude `val`"
;; [[_ p1 _ _ :as points] val]
;; (gpt/add p1 (end-hv points val)))
;;
;;(defn start-vp
;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`"
;; [[p0 _ _ _ :as points] val]
;; (gpt/add p0 (start-vv points val)))
;;
;;(defn end-vp
;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`"
;; [[_ _ p3 _ :as points] val]
;; (gpt/add p3 (end-vv points val)))
(defn width-points
[[p0 p1 _ _]]
(gpt/length (gpt/to-vec p0 p1)))
(defn height-points
[[p0 _ _ p3]]
(gpt/length (gpt/to-vec p0 p3)))
(defn pad-points
[[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left]
(let [top-v (start-vv points pad-top)
right-v (end-hv points pad-right)
bottom-v (end-vv points pad-bottom)
left-v (start-hv points pad-left)]
[(-> p0 (gpt/add left-v) (gpt/add top-v))
(-> p1 (gpt/add right-v) (gpt/add top-v))
(-> p2 (gpt/add right-v) (gpt/add bottom-v))
(-> p3 (gpt/add left-v) (gpt/add bottom-v))]))
;;;;
(defn calc-layout-lines (defn calc-layout-lines
[{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds] [{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds]
(let [wrap? (= layout-wrap-type :wrap) (let [wrap? (= layout-wrap-type :wrap)
layout-width (width-points layout-bounds) layout-width (gpo/width-points layout-bounds)
layout-height (height-points layout-bounds) layout-height (gpo/height-points layout-bounds)
reduce-fn reduce-fn
(fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child]
(let [child-bounds (gst/parent-coords-points child parent) (let [child-bounds (gst/parent-coords-points child parent)
child-width (width-points child-bounds) child-width (gpo/width-points child-bounds)
child-height (height-points child-bounds) child-height (gpo/height-points child-bounds)
col? (col? parent) col? (col? parent)
row? (row? parent) row? (row? parent)
@ -212,8 +125,8 @@
(defn calc-layout-lines-position (defn calc-layout-lines-position
[{:keys [layout-gap] :as parent} layout-bounds layout-lines] [{:keys [layout-gap] :as parent} layout-bounds layout-lines]
(let [layout-width (width-points layout-bounds) (let [layout-width (gpo/width-points layout-bounds)
layout-height (height-points layout-bounds) layout-height (gpo/height-points layout-bounds)
row? (row? parent) row? (row? parent)
col? (col? parent) col? (col? parent)
space-between? (= :space-between (:layout-type parent)) space-between? (= :space-between (:layout-type parent))
@ -225,16 +138,16 @@
(letfn [;; short version to not repeat always with all arguments (letfn [;; short version to not repeat always with all arguments
(xv [val] (xv [val]
(start-hv layout-bounds val)) (gpo/start-hv layout-bounds val))
;; short version to not repeat always with all arguments ;; short version to not repeat always with all arguments
(yv [val] (yv [val]
(start-vv layout-bounds val)) (gpo/start-vv layout-bounds val))
(get-base-line (get-base-line
[total-width total-height] [total-width total-height]
(cond-> (origin layout-bounds) (cond-> (gpo/origin layout-bounds)
(and row? h-center?) (and row? h-center?)
(gpt/add (xv (/ (- layout-width total-width) 2))) (gpt/add (xv (/ (- layout-width total-width) 2)))
@ -348,8 +261,8 @@
layout-bounds layout-bounds
{:keys [num-children line-width line-height child-fill?] :as line-data}] {:keys [num-children line-width line-height child-fill?] :as line-data}]
(let [width (width-points layout-bounds) (let [width (gpo/width-points layout-bounds)
height (height-points layout-bounds) height (gpo/height-points layout-bounds)
layout-gap layout-gap
(cond (cond
@ -396,8 +309,8 @@
v-end? (v-end? parent) v-end? (v-end? parent)
points (:points parent) points (:points parent)
xv (partial start-hv points) xv (partial gpo/start-hv points)
yv (partial start-vv points) yv (partial gpo/start-vv points)
corner-p corner-p
(cond-> start-p (cond-> start-p
@ -447,26 +360,18 @@
(cond (cond
(and (col? parent) (= :fill layout-h-behavior) child-fill?) (and (col? parent) (= :fill layout-h-behavior) child-fill?)
(let [layout-width (width-points layout-bounds) (let [layout-width (gpo/width-points layout-bounds)
fill-space (- layout-width line-width (* layout-gap (dec num-children))) fill-space (- layout-width line-width (* layout-gap (dec num-children)))
fill-width (/ fill-space (:num-child-fill layout-data)) fill-width (/ fill-space (:num-child-fill layout-data))
fill-scale (/ fill-width child-width)] fill-scale (/ fill-width child-width)]
{:width fill-width {:width fill-width
:modifiers [{:type :resize :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})
:origin child-origin
:transform transform
:transform-inverse transform-inverse
:vector (gpt/point fill-scale 1)}]})
(and (row? parent) (= :fill layout-h-behavior) line-fill?) (and (row? parent) (= :fill layout-h-behavior) line-fill?)
(let [fill-scale (/ line-width child-width)] (let [fill-scale (/ line-width child-width)]
{:width line-width {:width line-width
:modifiers [{:type :resize :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})))
:origin child-origin
:transform transform
:transform-inverse transform-inverse
:vector (gpt/point fill-scale 1)}]})
))
(defn calc-fill-height-data (defn calc-fill-height-data
"Calculates the size and modifiers for the height of an auto-fill child" "Calculates the size and modifiers for the height of an auto-fill child"
@ -477,43 +382,33 @@
(cond (cond
(and (row? parent) (= :fill layout-v-behavior) child-fill?) (and (row? parent) (= :fill layout-v-behavior) child-fill?)
(let [layout-height (height-points layout-bounds) (let [layout-height (gpo/height-points layout-bounds)
fill-space (- layout-height line-height (* layout-gap (dec num-children))) fill-space (- layout-height line-height (* layout-gap (dec num-children)))
fill-height (/ fill-space (:num-child-fill layout-data)) fill-height (/ fill-space (:num-child-fill layout-data))
fill-scale (/ fill-height child-height)] fill-scale (/ fill-height child-height)]
{:height fill-height {:height fill-height
:modifiers [{:type :resize :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})
:origin child-origin
:transform transform
:transform-inverse transform-inverse
:vector (gpt/point 1 fill-scale)}]})
(and (col? parent) (= :fill layout-v-behavior) line-fill?) (and (col? parent) (= :fill layout-v-behavior) line-fill?)
(let [fill-scale (/ line-height child-height)] (let [fill-scale (/ line-height child-height)]
{:height line-height {:height line-height
:modifiers [{:type :resize :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})))
:origin child-origin
:transform transform
:transform-inverse transform-inverse
:vector (gpt/point 1 fill-scale)}]})
))
(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"
[parent child modifiers transformed-parent] [parent child modifiers {:keys [transform transform-inverse] :as transformed-parent}]
(let [transformed-child (gst/transform-shape child modifiers) (let [transformed-child (gst/transform-shape child modifiers)
child-bb-before (gst/parent-coords-rect child parent) child-bb-before (gst/parent-coords-rect child parent)
child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) child-bb-after (gst/parent-coords-rect transformed-child transformed-parent)
scale-x (/ (:width child-bb-before) (:width child-bb-after)) scale-x (/ (:width child-bb-before) (:width child-bb-after))
scale-y (/ (:height child-bb-before) (:height child-bb-after))] scale-y (/ (:height child-bb-before) (:height child-bb-after))
resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin?n
resize-vector (gpt/point scale-x scale-y)]
(-> modifiers (-> modifiers
(update :v2 #(conj % (ctm/select-child-modifiers)
{:type :resize (ctm/set-resize resize-vector resize-origin transform transform-inverse))))
:transform (:transform transformed-parent)
:transform-inverse (:transform-inverse transformed-parent)
:origin (-> transformed-parent :points (nth 0))
:vector (gpt/point scale-x scale-y)})))))
(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"
@ -529,7 +424,7 @@
;; Normalize the points to remove flips ;; Normalize the points to remove flips
points (gst/parent-coords-points parent parent) points (gst/parent-coords-points parent parent)
layout-bounds (pad-points points pad-top pad-right pad-bottom pad-left) layout-bounds (gpo/pad-points points pad-top pad-right pad-bottom pad-left)
;; Reverse ;; Reverse
reverse? (or (= :left layout-dir) (= :bottom layout-dir)) reverse? (or (= :left layout-dir) (= :bottom layout-dir))
@ -549,9 +444,9 @@
[parent child layout-line] [parent child layout-line]
(let [child-bounds (gst/parent-coords-points child parent) (let [child-bounds (gst/parent-coords-points child parent)
child-origin (origin child-bounds) child-origin (gpo/origin child-bounds)
child-width (width-points child-bounds) child-width (gpo/width-points child-bounds)
child-height (height-points child-bounds) child-height (gpo/height-points child-bounds)
fill-width (calc-fill-width-data parent child child-origin child-width layout-line) fill-width (calc-fill-width-data parent child child-origin child-width layout-line)
fill-height (calc-fill-height-data parent child child-origin child-height layout-line) fill-height (calc-fill-height-data parent child child-origin child-height layout-line)
@ -564,15 +459,15 @@
move-vec (gpt/to-vec child-origin corner-p) move-vec (gpt/to-vec child-origin corner-p)
modifiers modifiers
(-> [] (-> (ctm/empty-modifiers)
(cond-> fill-width (d/concat-vec (:modifiers fill-width))) (cond-> fill-width (ctm/add-modifiers (:modifiers fill-width)))
(cond-> fill-height (d/concat-vec (:modifiers fill-height))) (cond-> fill-height (ctm/add-modifiers (:modifiers fill-height)))
(conj {:type :move :vector move-vec}))] (ctm/set-move move-vec))]
[modifiers layout-line])) [modifiers layout-line]))
(defn drop-areas (defn layout-drop-areas
[{:keys [margin-x margin-y] :as frame} layout-data children] [{:keys [margin-x margin-y] :as frame} layout-data children]
(let [col? (col? frame) (let [col? (col? frame)
@ -730,6 +625,6 @@
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 (calc-layout-data frame children) layout-data (calc-layout-data frame children)
drop-areas (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

@ -7,118 +7,22 @@
(ns app.common.geom.shapes.modifiers (ns app.common.geom.shapes.modifiers
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[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.layout :as gcl] [app.common.geom.shapes.layout :as gcl]
[app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.pixel-precision :as gpp]
[app.common.geom.shapes.transforms :as gtr] [app.common.geom.shapes.transforms :as gtr]
[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]))
;; TODO LAYOUT: ADAPT TO NEW MODIFIERS
(defn set-pixel-precision
"Adjust modifiers so they adjust to the pixel grid"
[modifiers shape]
(if (and (some? (:resize-transform modifiers))
(not (gmt/unit? (:resize-transform modifiers))))
;; If we're working with a rotation we don't handle pixel precision because
;; the transformation won't have the precision anyway
modifiers
(let [center (gco/center-shape shape)
base-bounds (-> (:points shape) (gpr/points->rect))
raw-bounds
(-> (gtr/transform-bounds (:points shape) center modifiers)
(gpr/points->rect))
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
(neg? (get-in modifiers [:resize-vector-2 :y])))
path? (= :path (:type shape))
vertical-line? (and path? (<= (:width raw-bounds) 0.01))
horizontal-line? (and path? (<= (:height raw-bounds) 0.01))
target-width (if vertical-line?
(:width raw-bounds)
(max 1 (mth/round (:width raw-bounds))))
target-height (if horizontal-line?
(:height raw-bounds)
(max 1 (mth/round (:height raw-bounds))))
target-p (cond-> (gpt/round (gpt/point raw-bounds))
flip-x?
(update :x + target-width)
flip-y?
(update :y + target-height))
ratio-width (/ target-width (:width raw-bounds))
ratio-height (/ target-height (:height raw-bounds))
modifiers
(-> modifiers
(d/without-nils)
(d/update-in-when
[:resize-vector :x] #(* % ratio-width))
;; If the resize-vector-2 modifier arrives means the resize-vector
;; will only resize on the x axis
(cond-> (nil? (:resize-vector-2 modifiers))
(d/update-in-when
[:resize-vector :y] #(* % ratio-height)))
(d/update-in-when
[:resize-vector-2 :y] #(* % ratio-height)))
origin (get modifiers :resize-origin)
origin-2 (get modifiers :resize-origin-2)
resize-v (get modifiers :resize-vector)
resize-v-2 (get modifiers :resize-vector-2)
displacement (get modifiers :displacement)
target-p-inv
(-> target-p
(gpt/transform
(cond-> (gmt/matrix)
(some? displacement)
(gmt/multiply (gmt/inverse displacement))
(and (some? resize-v) (some? origin))
(gmt/scale (gpt/inverse resize-v) origin)
(and (some? resize-v-2) (some? origin-2))
(gmt/scale (gpt/inverse resize-v-2) origin-2))))
delta-v (gpt/subtract target-p-inv (gpt/point base-bounds))
modifiers
(-> modifiers
(d/update-when :displacement #(gmt/multiply (gmt/translate-matrix delta-v) %))
(cond-> (nil? (:displacement modifiers))
(assoc :displacement (gmt/translate-matrix delta-v))))]
modifiers)))
(defn set-children-modifiers (defn set-children-modifiers
[modif-tree objects parent ignore-constraints snap-pixel?] [modif-tree objects parent ignore-constraints snap-pixel?]
;; TODO LAYOUT: SNAP PIXEL!
(letfn [(set-child [transformed-parent _snap-pixel? modif-tree child] (letfn [(set-child [transformed-parent _snap-pixel? modif-tree child]
(let [modifiers (get-in modif-tree [(:id parent) :modifiers]) (let [modifiers (get-in modif-tree [(:id parent) :modifiers])
child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent)
;;child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child)) child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))]
]
(cond-> modif-tree (cond-> modif-tree
(not (ctm/empty-modifiers? child-modifiers)) (not (ctm/empty-modifiers? child-modifiers))
(update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers)))))] (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))]
(let [children (map (d/getf objects) (:shapes parent)) (let [children (map (d/getf objects) (:shapes parent))
modifiers (get-in modif-tree [(:id parent) :modifiers]) modifiers (get-in modif-tree [(:id parent) :modifiers])
transformed-parent (gtr/transform-shape parent modifiers)] transformed-parent (gtr/transform-shape parent modifiers)]
@ -144,7 +48,7 @@
child-modifiers (gcl/normalize-child-modifiers parent child modifiers transformed-parent)] child-modifiers (gcl/normalize-child-modifiers parent child modifiers transformed-parent)]
(cond-> modif-tree (cond-> modif-tree
(not (ctm/empty-modifiers? child-modifiers)) (not (ctm/empty-modifiers? child-modifiers))
(update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers))))) (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))
(apply-modifiers [modif-tree child] (apply-modifiers [modif-tree child]
(let [modifiers (get-in modif-tree [(:id child) :modifiers])] (let [modifiers (get-in modif-tree [(:id child) :modifiers])]
@ -162,7 +66,7 @@
modif-tree modif-tree
(cond-> modif-tree (cond-> modif-tree
(d/not-empty? modifiers) (d/not-empty? modifiers)
(update-in [(:id child) :modifiers :v2] d/concat-vec modifiers))] (update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))]
[layout-line modif-tree]))] [layout-line modif-tree]))]
@ -197,73 +101,6 @@
modif-tree))))) modif-tree)))))
#_(defn set-layout-modifiers'
;; TODO LAYOUT: SNAP PIXEL!
[modif-tree objects parent _snap-pixel?]
(letfn [(transform-child [child]
(let [modifiers (get modif-tree (:id child))
child
(cond-> child
(some? modifiers)
(-> (merge modifiers) gtr/transform-shape)
(and (nil? modifiers) (group? child))
(gtr/apply-group-modifiers objects modif-tree))
child
(-> child
(gtr/apply-transform (gmt/transform-in (gco/center-shape parent) (:transform-inverse parent))))]
child))
(set-layout-modifiers [parent transform [layout-data modif-tree] child]
(let [[modifiers layout-data]
(gcl/calc-layout-modifiers parent transform child layout-data)
modif-tree
(cond-> modif-tree
(d/not-empty? modifiers)
(update-in [(:id child) :modifiers :v2] d/concat-vec modifiers))]
[layout-data modif-tree]))]
(let [modifiers (get modif-tree (:id parent))
shape (-> parent (merge modifiers) gtr/transform-shape)
children (->> (:shapes shape)
(map (d/getf objects))
(map transform-child))
center (gco/center-shape shape)
{:keys [transform transform-inverse]} shape
shape
(-> shape
(gtr/apply-transform (gmt/transform-in center transform-inverse)))
transformed-rect (:selrect shape)
layout-data (gcl/calc-layout-data shape children transformed-rect)
children (into [] (cond-> children (:reverse? layout-data) reverse))
max-idx (dec (count children))
layout-lines (:layout-lines layout-data)]
(loop [modif-tree modif-tree
layout-line (first layout-lines)
pending (rest layout-lines)
from-idx 0]
(if (and (some? layout-line) (<= from-idx max-idx))
(let [to-idx (+ from-idx (:num-children layout-line))
children (subvec children from-idx to-idx)
[_ modif-tree]
(reduce (partial set-layout-modifiers shape transform) [layout-line modif-tree] children)]
(recur modif-tree (first pending) (rest pending) to-idx))
modif-tree)))))
(defn get-first-layout (defn get-first-layout
[id objects] [id objects]
@ -337,8 +174,11 @@
(let [set-modifiers (let [set-modifiers
(fn [modif-tree id] (fn [modif-tree id]
(let [shape (get objects id) (let [root? (= uuid/zero id)
modifiers (cond-> (get-modifier shape) snap-pixel? (set-pixel-precision shape))] shape (get objects id)
modifiers (cond-> (get-modifier shape)
(and (not root?) snap-pixel?)
(gpp/set-pixel-precision shape))]
(-> modif-tree (-> modif-tree
(assoc id {:modifiers modifiers})))) (assoc id {:modifiers modifiers}))))
@ -349,11 +189,12 @@
(->> shapes-tree (->> shapes-tree
(reduce (reduce
(fn [modif-tree shape] (fn [modif-tree shape]
(let [modifiers (get-in modif-tree [(:id shape) :modifiers]) (let [root? (= uuid/zero (:id shape))
modifiers (get-in modif-tree [(:id shape) :modifiers])
has-modifiers? (some? modifiers) has-modifiers? (some? modifiers)
is-layout? (layout? shape) is-layout? (layout? shape)
is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape)))) is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape))))
root? (= uuid/zero (:id shape))
;; If the current child is inside the layout we ignore the constraints ;; If the current child is inside the layout we ignore the constraints
is-inside-layout? (inside-layout? objects shape)] is-inside-layout? (inside-layout? objects shape)]

View file

@ -0,0 +1,53 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.common.geom.shapes.pixel-precision
(:require
[app.common.geom.point :as gpt]
[app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.rect :as gpr]
[app.common.geom.shapes.transforms :as gtr]
[app.common.math :as mth]
[app.common.pages.helpers :as cph]
[app.common.types.modifiers :as ctm]))
(defn size-pixel-precision
[modifiers shape]
(let [{:keys [points transform transform-inverse] :as shape} (gtr/transform-shape shape modifiers)
origin (gpo/origin points)
curr-width (gpo/width-points points)
curr-height (gpo/height-points points)
path? (cph/path-shape? shape)
vertical-line? (and path? (<= curr-width 0.01))
horizontal-line? (and path? (<= curr-height 0.01))
target-width (if vertical-line? curr-width (max 1 (mth/round curr-width)))
target-height (if horizontal-line? curr-height (max 1 (mth/round curr-height)))
ratio-width (/ target-width curr-width)
ratio-height (/ target-height curr-height)
scalev (gpt/point ratio-width ratio-height)]
(-> modifiers
(ctm/set-resize scalev origin transform transform-inverse))))
(defn position-pixel-precision
[modifiers shape]
(let [{:keys [points]} (gtr/transform-shape shape modifiers)
bounds (gpr/points->rect points)
corner (gpt/point bounds)
target-corner (gpt/round corner)
deltav (gpt/to-vec corner target-corner)]
(-> modifiers
(ctm/set-move deltav))))
(defn set-pixel-precision
"Adjust modifiers so they adjust to the pixel grid"
[modifiers shape]
(-> modifiers
(size-pixel-precision shape)
(position-pixel-precision shape)))

View file

@ -0,0 +1,61 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.common.geom.shapes.points
(:require
[app.common.geom.point :as gpt]))
(defn origin
[points]
(nth points 0))
(defn start-hv
"Horizontal vector from the origin with a magnitude `val`"
[[p0 p1 _ _] val]
(-> (gpt/to-vec p0 p1)
(gpt/unit)
(gpt/scale val)))
(defn end-hv
"Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`"
[[p0 p1 _ _] val]
(-> (gpt/to-vec p1 p0)
(gpt/unit)
(gpt/scale val)))
(defn start-vv
"Vertical vector from the oposite to the origin in the x axis with a magnitude `val`"
[[p0 _ _ p3] val]
(-> (gpt/to-vec p0 p3)
(gpt/unit)
(gpt/scale val)))
(defn end-vv
"Vertical vector from the oposite to the origin in the x axis with a magnitude `val`"
[[p0 _ _ p3] val]
(-> (gpt/to-vec p3 p0)
(gpt/unit)
(gpt/scale val)))
(defn width-points
[[p0 p1 _ _]]
(gpt/length (gpt/to-vec p0 p1)))
(defn height-points
[[p0 _ _ p3]]
(gpt/length (gpt/to-vec p0 p3)))
(defn pad-points
[[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left]
(let [top-v (start-vv points pad-top)
right-v (end-hv points pad-right)
bottom-v (end-vv points pad-bottom)
left-v (start-hv points pad-left)]
[(-> p0 (gpt/add left-v) (gpt/add top-v))
(-> p1 (gpt/add right-v) (gpt/add top-v))
(-> p2 (gpt/add right-v) (gpt/add bottom-v))
(-> p3 (gpt/add left-v) (gpt/add bottom-v))]))

View file

@ -14,8 +14,6 @@
[app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.path :as gpa]
[app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.rect :as gpr]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.helpers :as cph]
[app.common.text :as txt]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.uuid :as uuid])) [app.common.uuid :as uuid]))
@ -312,6 +310,8 @@
(dissoc :transform :transform-inverse)) (dissoc :transform :transform-inverse))
(cond-> (some? selrect) (cond-> (some? selrect)
(assoc :selrect selrect)) (assoc :selrect selrect))
;; TODO LAYOUT: Make sure the order of points is alright
(cond-> (d/not-empty? points) (cond-> (d/not-empty? points)
(assoc :points points)) (assoc :points points))
(assoc :rotation rotation)))) (assoc :rotation rotation))))
@ -376,113 +376,22 @@
(assoc :flip-x (-> mask :flip-x)) (assoc :flip-x (-> mask :flip-x))
(assoc :flip-y (-> mask :flip-y))))) (assoc :flip-y (-> mask :flip-y)))))
#_(defn- set-flip [shape modifiers]
(let [rv1x (or (get-in modifiers [:resize-vector :x]) 1)
rv1y (or (get-in modifiers [:resize-vector :y]) 1)
rv2x (or (get-in modifiers [:resize-vector-2 :x]) 1)
rv2y (or (get-in modifiers [:resize-vector-2 :y]) 1)]
(cond-> shape
(or (neg? rv1x) (neg? rv2x))
(-> (update :flip-x not)
(update :rotation -))
(or (neg? rv1y) (neg? rv2y))
(-> (update :flip-y not)
(update :rotation -)))))
#_(defn- set-flip-2 [shape transform]
(let [pt-a (gpt/point (:selrect shape))
pt-b (gpt/point (-> shape :selrect :x2) (-> shape :selrect :y2))
shape-transform (:transform shape (gmt/matrix))
pt-a' (gpt/transform pt-a (gmt/multiply shape-transform transform ))
pt-b' (gpt/transform pt-b (gmt/multiply shape-transform transform ))
{:keys [x y]} (gpt/to-vec pt-a' pt-b')]
(cond-> shape
(neg? x)
(-> (update :flip-x not)
(update :rotation -))
(neg? y)
(-> (update :flip-y not)
(update :rotation -)))))
#_(defn- apply-displacement [shape]
(let [modifiers (:modifiers shape)]
(if (contains? modifiers :displacement)
(let [mov-vec (-> (gpt/point 0 0)
(gpt/transform (:displacement modifiers)))
shape (move shape mov-vec)
modifiers (dissoc modifiers :displacement)]
(-> shape
(assoc :modifiers modifiers)
(cond-> (empty-modifiers? modifiers)
(dissoc :modifiers))))
shape)))
(defn- apply-text-resize
[shape modifiers]
(if (and (= (:type shape) :text)
(:resize-scale-text modifiers))
(let [merge-attrs (fn [attrs]
(let [font-size (-> (get attrs :font-size 14)
(d/parse-double)
(* (get-in modifiers [:resize-vector :x] 1))
(* (get-in modifiers [:resize-vector-2 :x] 1))
(str))]
(d/txt-merge attrs {:font-size font-size})))]
(update shape :content #(txt/transform-nodes
txt/is-text-node?
merge-attrs
%)))
shape))
(defn- apply-structure-modifiers
[shape modifiers]
(let [remove-children
(fn [shapes children-to-remove]
(let [remove? (set children-to-remove)]
(d/removev remove? shapes)))
apply-modifier
(fn [shape {:keys [type value index]}]
(cond-> shape
(and (= type :add-children) (some? index))
(update :shapes
(fn [shapes]
(if (vector? shapes)
(cph/insert-at-index shapes index value)
(d/concat-vec shapes value))))
(and (= type :add-children) (nil? index))
(update :shapes d/concat-vec value)
(= type :remove-children)
(update :shapes remove-children value)))]
(reduce apply-modifier shape (:v3 modifiers))))
(defn apply-modifiers (defn apply-modifiers
[shape modifiers] [shape modifiers]
(let [center (gco/center-shape shape) (let [transform (ctm/modifiers->transform modifiers)]
transform (ctm/modifiers->transform center modifiers)]
(cond-> shape (cond-> shape
#_(set-flip-2 transform)
(and (some? transform) (and (some? transform)
;; Never transform the root frame ;; Never transform the root frame
(not= uuid/zero (:id shape))) (not= uuid/zero (:id shape)))
(apply-transform transform) (apply-transform transform)
:always :always
(apply-structure-modifiers modifiers)))) (ctm/apply-structure-modifiers modifiers))))
(defn apply-objects-modifiers (defn apply-objects-modifiers
[objects modifiers] [objects modifiers]
(letfn [(process-shape [objects [id modifier]] (letfn [(process-shape [objects [id modifier]]
(update objects id apply-modifiers (:modifiers modifier)))] (d/update-when objects id apply-modifiers (:modifiers modifier)))]
(reduce process-shape objects modifiers))) (reduce process-shape objects modifiers)))
(defn transform-shape (defn transform-shape
@ -495,66 +404,12 @@
([shape modifiers] ([shape modifiers]
(cond-> shape (cond-> shape
(and (some? modifiers) (not (ctm/empty-modifiers? modifiers))) (and (some? modifiers) (not (ctm/empty-modifiers? modifiers)))
(-> (apply-modifiers modifiers) (apply-modifiers modifiers))))
(apply-text-resize modifiers)))))
(defn transform-bounds-v2
[points center modifiers]
(let [transform (ctm/modifiers->transform center {:v2 modifiers})
result (gco/transform-points points center transform)]
;;(.log js/console "??" (str transform) (clj->js result))
result)
#_(letfn [(apply-modifier [points {:keys [type vector origin]}]
(case type
:move
(let [displacement (gmt/translate-matrix vector)]
(gco/transform-points points displacement))
:resize
(gco/transform-points points origin (gmt/scale-matrix vector))
points))]
(->> modifiers
(reduce apply-modifier points))))
(defn transform-bounds (defn transform-bounds
[points center {:keys [v2 displacement displacement-after resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}] [points center modifiers]
(let [transform (ctm/modifiers->transform modifiers)]
;; FIXME: Improve Performance (gco/transform-points points center transform)))
(if (some? v2)
(transform-bounds-v2 points center v2)
(let [resize-transform-inverse (or resize-transform-inverse (gmt/matrix))
displacement
(when (some? displacement)
(gmt/multiply resize-transform-inverse displacement))
resize-origin
(when (some? resize-origin)
(gmt/transform-point-center resize-origin center resize-transform-inverse))
resize-origin-2
(when (some? resize-origin-2)
(gmt/transform-point-center resize-origin-2 center resize-transform-inverse))
]
(if (and (nil? displacement) (nil? resize-origin) (nil? resize-origin-2) (nil? displacement-after))
points
(cond-> points
(some? displacement)
(gco/transform-points displacement)
(some? resize-origin)
(gco/transform-points resize-origin (gmt/scale-matrix resize-vector))
(some? resize-origin-2)
(gco/transform-points resize-origin-2 (gmt/scale-matrix resize-vector-2))
(some? displacement-after)
(gco/transform-points displacement-after))))))
(defn transform-selrect (defn transform-selrect
[selrect modifiers] [selrect modifiers]

View file

@ -10,70 +10,168 @@
[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]
[app.common.spec :as us])) [app.common.pages.helpers :as cph]
[app.common.spec :as us]
[app.common.text :as txt]))
;; --- Modifiers ;; --- Modifiers
;; The `modifiers` structure contains a list of transformations to ;; Moodifiers types
;; do make to a shape, in this order: ;; - geometry: Geometry
;; * move
;; * resize
;; * rotation
;; - structure-parent: Structure non recursive
;; * add-children
;; * remove-children
;; - structure-child: Structre recursive
;; * scale-content
;; ;;
;; - resize-origin (gpt/point) + resize-vector (gpt/point)q
;; apply a scale vector to all points of the shapes, starting (def conjv (fnil conj []))
;; from the origin point.
;; ;; Public builder API
;; - resize-origin-2 + resize-vector-2
;; same as the previous one, for cases in that we need to make (defn empty-modifiers []
;; two vectors from different origin points. {})
;;
;; - displacement (gmt/matrix) (defn set-move
;; apply a translation matrix to the shape ([modifiers x y]
;; (set-move modifiers (gpt/point x y)))
;; - rotation (gmt/matrix)
;; apply a rotation matrix to the shape ([modifiers vector]
;; (-> modifiers
;; - resize-transform (gmt/matrix) + resize-transform-inverse (gmt/matrix) (update :geometry conjv {:type :move :vector vector}))))
;; a copy of the rotation matrix currently applied to the shape;
;; this is needed temporarily to apply the resize vectors. (defn set-resize
;; ([modifiers vector origin]
;; - resize-scale-text (bool) (-> modifiers
;; tells if the resize vectors must be applied to text shapes (update :geometry conjv {:type :resize
;; or not. :vector vector
:origin origin})))
([modifiers vector origin transform transform-inverse]
(-> modifiers
(update :geometry conjv {:type :resize
:vector vector
:origin origin
:transform transform
:transform-inverse transform-inverse}))))
(defn set-rotation
[modifiers center angle]
(-> modifiers
(update :geometry conjv {:type :rotation
:center center
:rotation angle})))
(defn set-remove-children
[modifiers shapes]
(-> modifiers
(update :structure-parent conjv {:type :remove-children
:value shapes}))
)
(defn set-add-children
[modifiers shapes index]
(-> modifiers
(update :structure-parent conjv {:type :add-children
:value shapes
:index index})))
(defn set-scale-content
[modifiers value]
(-> modifiers
(update :structure-child conjv {:type :scale-content :value value})))
(defn add-modifiers
[modifiers new-modifiers]
(cond-> modifiers
(some? (:geometry new-modifiers))
(update :geometry #(d/concat-vec [] % (:geometry new-modifiers)))
(some? (:structure-parent new-modifiers))
(update :structure-parent #(d/concat-vec [] % (:structure-parent new-modifiers)))
(some? (:structure-child new-modifiers))
(update :structure-child #(d/concat-vec [] % (:structure-child new-modifiers)))))
;; These are convenience methods to create single operation modifiers without the builder
(defn move (defn move
([x y] ([x y]
(move (gpt/point x y))) (set-move (empty-modifiers) (gpt/point x y)))
([vector] ([vector]
{:v2 [{:type :move :vector vector}]})) (set-move (empty-modifiers) vector)))
(defn resize (defn resize
[vector origin] ([vector origin]
{:v2 [{:type :resize :vector vector :origin origin}]}) (set-resize (empty-modifiers) vector origin))
([vector origin transform transform-inverse]
(set-resize (empty-modifiers) vector origin transform transform-inverse)))
(defn rotation
[shape center angle]
(let [shape-center (gco/center-shape shape)
rotation (-> (gmt/matrix)
(gmt/rotate angle center)
(gmt/rotate (- angle) shape-center))]
(-> (empty-modifiers)
(set-rotation shape-center angle)
(set-move (gpt/transform (gpt/point 1 1) rotation)))))
(defn remove-children
[shapes]
(-> (empty-modifiers)
(set-remove-children shapes)))
(defn add-children
[shapes index]
(-> (empty-modifiers)
(set-add-children shapes index)))
(defn scale-content
[value]
(-> (empty-modifiers)
(set-scale-content value)))
(defn select-child-modifiers
[modifiers]
(select-keys modifiers [:geometry :structure-child]))
(defn select-structure
[modifiers]
(select-keys modifiers [:structure-parent]))
(defn add-move (defn add-move
([object x y] ([object x y]
(add-move object (gpt/point x y))) (add-move object (gpt/point x y)))
([object vector] ([object vector]
(assoc-in (update object :modifiers (move vector))))
object
[:modifiers :displacement]
(gmt/translate-matrix (:x vector) (:y vector)))))
(defn add-resize (defn add-resize
[object vector origin] [object vector origin]
(-> object (update object :modifiers (resize vector origin)))
(assoc-in [:modifiers :resize-vector] vector)
(assoc-in [:modifiers :resize-origin] origin)))
(defn empty-modifiers? [modifiers] (defn empty-modifiers?
(empty? (dissoc modifiers :ignore-geometry?))) [modifiers]
(and (empty? (:geometry modifiers))
(empty? (:structure-parent modifiers))
(empty? (:structure-child modifiers))))
(defn resize-modifiers (defn change-dimensions
[shape attr value] [shape attr value]
(us/assert map? shape) (us/assert map? shape)
(us/assert #{:width :height} attr) (us/assert #{:width :height} attr)
(us/assert number? value) (us/assert number? value)
(let [{:keys [proportion proportion-lock]} shape (let [{:keys [proportion proportion-lock]} shape
size (select-keys (:selrect shape) [:width :height]) size (select-keys (:selrect shape) [:width :height])
new-size (if-not proportion-lock new-size (if-not proportion-lock
@ -99,10 +197,8 @@
scalev (gpt/divide (gpt/point width height) scalev (gpt/divide (gpt/point width height)
(gpt/point sr-width sr-height))] (gpt/point sr-width sr-height))]
{:resize-vector scalev
:resize-origin origin (resize scalev origin shape-transform shape-transform-inv)))
:resize-transform shape-transform
:resize-transform-inverse shape-transform-inv}))
(defn change-orientation-modifiers (defn change-orientation-modifiers
[shape orientation] [shape orientation]
@ -124,26 +220,8 @@
scalev (gpt/divide (gpt/point new-width new-height) scalev (gpt/divide (gpt/point new-width new-height)
(gpt/point sr-width sr-height))] (gpt/point sr-width sr-height))]
{:resize-vector scalev
:resize-origin origin
:resize-transform shape-transform
:resize-transform-inverse shape-transform-inv}))
(defn rotation-modifiers (resize scalev origin shape-transform shape-transform-inv)))
[shape center angle]
(let [shape-center (gco/center-shape shape)
rotation (-> (gmt/matrix)
(gmt/rotate angle center)
(gmt/rotate (- angle) shape-center))]
{:v2 [{:type :rotation
:center shape-center
:rotation angle}
{:type :move
:vector (gpt/transform (gpt/point 1 1) rotation)}]}
#_{:rotation angle
:displacement displacement}))
(defn merge-modifiers (defn merge-modifiers
[objects modifiers] [objects modifiers]
@ -155,7 +233,29 @@
(->> modifiers (->> modifiers
(reduce set-modifier objects)))) (reduce set-modifier objects))))
(defn modifiers-v2->transform (defn only-move?
[modifier]
(and (= 1 (-> modifier :geometry count))
(= :move (-> modifier :geometry first :type))))
(defn get-frame-add-children
[modif-tree]
(let [structure-changes
(into {}
(comp (filter (fn [[_ val]] (-> val :modifiers :structure-parent some?)))
(map (fn [[key val]]
[key (-> val :modifiers :structure-parent)])))
modif-tree)]
(into []
(mapcat (fn [[frame-id changes]]
(->> changes
(filter (fn [{:keys [type]}] (= type :add-children)))
(mapcat (fn [{:keys [value]}]
(->> value (map (fn [id] {:frame frame-id :shape id}))))))))
structure-changes)))
(defn modifiers->transform
[modifiers] [modifiers]
(letfn [(apply-modifier [matrix {:keys [type vector rotation center origin transform transform-inverse] :as modifier}] (letfn [(apply-modifier [matrix {:keys [type vector rotation center origin transform transform-inverse] :as modifier}]
(case type (case type
@ -182,77 +282,58 @@
(gmt/multiply (gmt/rotate-matrix rotation)) (gmt/multiply (gmt/rotate-matrix rotation))
(gmt/translate (gpt/negate center))) (gmt/translate (gpt/negate center)))
matrix)))] matrix)))]
(->> modifiers (->> modifiers :geometry
(reduce apply-modifier (gmt/matrix))))) (reduce apply-modifier (gmt/matrix)))))
(defn- normalize-scale (defn scale-text-content
"We normalize the scale so it's not too close to 0" [content value]
[scale]
(cond
(and (< scale 0) (> scale -0.01)) -0.01
(and (>= scale 0) (< scale 0.01)) 0.01
:else scale))
(defn modifiers->transform (->> content
([modifiers] (txt/transform-nodes
(modifiers->transform nil modifiers)) txt/is-text-node?
(fn [attrs]
(let [font-size (-> (get attrs :font-size 14)
(d/parse-double)
(* value)
(str)) ]
(d/txt-merge attrs {:font-size font-size}))))))
([center modifiers] (defn apply-scale-content
(if (some? (:v2 modifiers)) [shape value]
(modifiers-v2->transform (:v2 modifiers))
(let [displacement (:displacement modifiers)
displacement-after (:displacement-after modifiers)
resize-v1 (:resize-vector modifiers)
resize-v2 (:resize-vector-2 modifiers)
origin-1 (:resize-origin modifiers (gpt/point))
origin-2 (:resize-origin-2 modifiers (gpt/point))
;; Normalize x/y vector coordinates because scale by 0 is infinite (cond-> shape
resize-1 (when (some? resize-v1) (cph/text-shape? shape)
(gpt/point (normalize-scale (:x resize-v1)) (update :content scale-text-content value)))
(normalize-scale (:y resize-v1))))
resize-2 (when (some? resize-v2) (defn apply-structure-modifiers
(gpt/point (normalize-scale (:x resize-v2)) [shape modifiers]
(normalize-scale (:y resize-v2)))) (let [remove-children
(fn [shapes children-to-remove]
(let [remove? (set children-to-remove)]
(d/removev remove? shapes)))
resize-transform (:resize-transform modifiers)
resize-transform-inverse (:resize-transform-inverse modifiers)
rt-modif (:rotation modifiers)]
(cond-> (gmt/matrix) apply-modifier
(some? displacement-after) (fn [shape {:keys [type value index]}]
(gmt/multiply displacement-after) (cond-> shape
(and (= type :add-children) (some? index))
(update :shapes
(fn [shapes]
(if (vector? shapes)
(cph/insert-at-index shapes index value)
(d/concat-vec shapes value))))
(some? resize-1) (and (= type :add-children) (nil? index))
(-> (gmt/translate origin-1) (update :shapes d/concat-vec value)
(cond-> (some? resize-transform)
(gmt/multiply resize-transform))
(gmt/scale resize-1)
(cond-> (some? resize-transform-inverse)
(gmt/multiply resize-transform-inverse))
(gmt/translate (gpt/negate origin-1)))
(some? resize-2) (= type :remove-children)
(-> (gmt/translate origin-2) (update :shapes remove-children value)
(cond-> (some? resize-transform)
(gmt/multiply resize-transform))
(gmt/scale resize-2)
(cond-> (some? resize-transform-inverse)
(gmt/multiply resize-transform-inverse))
(gmt/translate (gpt/negate origin-2)))
(some? displacement) (= type :scale-content)
(gmt/multiply displacement) (apply-scale-content value)))]
(some? rt-modif)
(-> (gmt/translate center)
(gmt/multiply (gmt/rotate-matrix rt-modif))
(gmt/translate (gpt/negate center))))))
))
(defn only-move? (as-> shape $
[modifier] (reduce apply-modifier $ (:structure-parent modifiers))
(and (= 1 (-> modifier :v2 count)) (reduce apply-modifier $ (:structure-child modifiers)))))
(= :move (-> modifier :v2 first :type))))

View file

@ -47,8 +47,9 @@
(-> shape (-> shape
(assoc :click-draw? false) (assoc :click-draw? false)
(gsh/transform-shape (ctm/resize scalev (gpt/point x y))) (gsh/transform-shape (-> (ctm/empty-modifiers)
(gsh/transform-shape (ctm/move movev))))) (ctm/set-resize scalev (gpt/point x y))
(ctm/set-move movev))))))
(defn update-drawing [state initial point lock?] (defn update-drawing [state initial point lock?]
(update-in state [:workspace-drawing :object] resize-shape initial point lock?)) (update-in state [:workspace-drawing :object] resize-shape initial point lock?))

View file

@ -22,7 +22,6 @@
[app.main.data.workspace.edition :as dwe] [app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.main.features :as features] [app.main.features :as features]
[app.main.streams :as ms] [app.main.streams :as ms]

View file

@ -320,8 +320,8 @@
(letfn [(update-fn [shape] (letfn [(update-fn [shape]
(let [{:keys [selrect grow-type]} shape (let [{:keys [selrect grow-type]} shape
{shape-width :width shape-height :height} selrect {shape-width :width shape-height :height} selrect
modifier-width (ctm/resize-modifiers shape :width new-width) modifier-width (ctm/change-dimensions shape :width new-width)
modifier-height (ctm/resize-modifiers shape :height new-height)] modifier-height (ctm/change-dimensions shape :height new-height)]
;; TODO LAYOUT: MEZCLAR ESTOS EN UN UNICO MODIFIER ;; TODO LAYOUT: MEZCLAR ESTOS EN UN UNICO MODIFIER
(cond-> shape (cond-> shape
(and (not-changed? shape-width new-width) (= grow-type :auto-width)) (and (not-changed? shape-width new-width) (= grow-type :auto-width))
@ -346,8 +346,8 @@
(defn apply-text-modifier (defn apply-text-modifier
[shape {:keys [width height position-data]}] [shape {:keys [width height position-data]}]
(let [modifier-width (when width (ctm/resize-modifiers shape :width width)) (let [modifier-width (when width (ctm/change-dimensions shape :width width))
modifier-height (when height (ctm/resize-modifiers shape :height height)) modifier-height (when height (ctm/change-dimensions shape :height height))
;; TODO LAYOUT: MEZCLAR LOS DOS EN UN UNICO MODIFIER ;; TODO LAYOUT: MEZCLAR LOS DOS EN UN UNICO MODIFIER
new-shape new-shape

View file

@ -146,11 +146,14 @@
(concat (keys workspace-modifiers) ids) (concat (keys workspace-modifiers) ids)
objects objects
(fn [shape] (fn [shape]
(let [modifiers (if (contains? ids (:id shape)) modifiers {}) (let [
old-modifiers-v3 (get-in state [:workspace-modifiers (:id shape) :modifiers :v3])] modifiers (if (contains? ids (:id shape)) modifiers (ctm/empty-modifiers))
structure-modifiers (ctm/select-structure
(get-in state [:workspace-modifiers (:id shape) :modifiers]))]
(cond-> modifiers (cond-> modifiers
(some? old-modifiers-v3) (some? structure-modifiers)
(assoc :v3 old-modifiers-v3)))) (ctm/add-modifiers structure-modifiers))))
ignore-constraints snap-pixel?)] ignore-constraints snap-pixel?)]
(update state :workspace-modifiers merge modif-tree)))))) (update state :workspace-modifiers merge modif-tree))))))
@ -175,7 +178,7 @@
get-modifier get-modifier
(fn [shape] (fn [shape]
(ctm/rotation-modifiers shape center angle)) (ctm/rotation shape center angle))
modif-tree modif-tree
(gsh/set-objects-modifiers ids objects get-modifier false false)] (gsh/set-objects-modifiers ids objects get-modifier false false)]
@ -396,32 +399,18 @@
resize-origin resize-origin
(cond-> (gmt/transform-point-center handler-origin shape-center shape-transform) (cond-> (gmt/transform-point-center handler-origin shape-center shape-transform)
(some? displacement) (some? displacement)
(gpt/add displacement))] (gpt/add displacement))
(rx/of (set-modifiers ids modifiers
{:v2 (-> [] (-> (ctm/empty-modifiers)
(cond-> displacement (cond-> displacement
(conj {:type :move (ctm/set-move displacement))
:vector displacement})) (ctm/set-resize scalev resize-origin shape-transform shape-transform-inverse)
(conj {:type :resize
:vector scalev (cond-> scale-text
:origin resize-origin (ctm/set-scale-content (:x scalev))))]
:transform shape-transform
:transform-inverse shape-transform-inverse})) (rx/of (set-modifiers ids modifiers))))
;;:displacement displacement
;;:resize-vector scalev
;;:resize-origin resize-origin
;;:resize-transform shape-transform
;;:resize-scale-text scale-text
;;:resize-transform-inverse shape-transform-inverse
}))
#_(rx/of (set-modifiers ids
{:displacement displacement
:resize-vector scalev
:resize-origin resize-origin
:resize-transform shape-transform
:resize-scale-text scale-text
:resize-transform-inverse shape-transform-inverse}))))
;; Unifies the instantaneous proportion lock modifier ;; Unifies the instantaneous proportion lock modifier
;; activated by Shift key and the shapes own proportion ;; activated by Shift key and the shapes own proportion
@ -471,7 +460,7 @@
snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid) snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid)
(int? value)) (int? value))
get-modifier get-modifier
(fn [shape] (ctm/resize-modifiers shape attr value)) (fn [shape] (ctm/change-dimensions shape attr value))
modif-tree modif-tree
(gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)] (gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)]
@ -655,15 +644,13 @@
(d/removev #(= target-frame %)))] (d/removev #(= target-frame %)))]
(cond (cond
(not= original-frame target-frame) (not= original-frame target-frame)
[[original-frame {:modifiers {:v3 [{:type :remove-children :value shapes}]}}] [[original-frame {:modifiers (ctm/remove-children shapes)}]
[target-frame {:modifiers {:v3 [{:type :add-children [target-frame {:modifiers (ctm/add-children shapes drop-index)}]]
:value shapes
:index drop-index}]}}]]
layout? layout?
[[target-frame {:modifiers {:v3 [{:type :add-children [[target-frame {:modifiers (ctm/add-children shapes drop-index)}]]))))
:value shapes
:index drop-index}]}}]]))))
(keys origin-frame-ids))] (keys origin-frame-ids))]
(assoc state :workspace-modifiers modif-tree))))) (assoc state :workspace-modifiers modif-tree)))))
(defn- start-move (defn- start-move
@ -725,8 +712,7 @@
;; We try to use the previous snap so we don't have to wait for the result of the new ;; We try to use the previous snap so we don't have to wait for the result of the new
(rx/map snap/correct-snap-point) (rx/map snap/correct-snap-point)
(rx/map ctm/move)
(rx/map (fn [move-vec] {:v2 [{:type :move :vector move-vec}]}))
(rx/map (partial set-modifiers ids)) (rx/map (partial set-modifiers ids))
(rx/take-until stopper))) (rx/take-until stopper)))
@ -867,14 +853,9 @@
origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))] origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))]
(rx/of (set-modifiers selected (rx/of (set-modifiers selected
{:v2 [{:type :resize (-> (ctm/empty-modifiers)
:vector (gpt/point -1.0 1.0) (ctm/set-resize (gpt/point -1.0 1.0) origin)
:origin origin} (ctm/move (gpt/point (:width selrect) 0)))
{:type :move
:vector (gpt/point (:width selrect) 0)}]}
#_{:resize-vector (gpt/point -1.0 1.0)
:resize-origin origin
:displacement (gmt/translate-matrix (gpt/point (- (:width selrect)) 0))}
true) true)
(apply-modifiers)))))) (apply-modifiers))))))
@ -889,13 +870,8 @@
origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))] origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))]
(rx/of (set-modifiers selected (rx/of (set-modifiers selected
{:v2 [{:type :resize (-> (ctm/empty-modifiers)
:vector (gpt/point 1.0 -1.0) (ctm/set-resize (gpt/point 1.0 -1.0) origin)
:origin origin} (ctm/move (gpt/point 0 (:height selrect))))
{:type :move
:vector (gpt/point 0 (:height selrect))}]}
#_{:resize-vector (gpt/point 1.0 -1.0)
:resize-origin origin
:displacement (gmt/translate-matrix (gpt/point 0 (- (:height selrect))))}
true) true)
(apply-modifiers)))))) (apply-modifiers))))))

View file

@ -103,7 +103,7 @@
opts #js {:shape shape :thumbnail? thumbnail?}] opts #js {:shape shape :thumbnail? thumbnail?}]
(when (and (some? shape) (not (:hidden shape))) (when (and (some? shape) (not (:hidden shape)))
[:g.ws-shape-wrapper [:g.workspace-shape-wrapper
(case (:type shape) (case (:type shape)
:path [:> path/path-wrapper opts] :path [:> path/path-wrapper opts]
:text [:> text/text-wrapper opts] :text [:> text/text-wrapper opts]

View file

@ -19,67 +19,6 @@
[app.util.globals :as globals] [app.util.globals :as globals]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defn- transform-no-resize
"If we apply a scale directly to the texts it will show deformed so we need to create this
correction matrix to \"undo\" the resize but keep the other transformations."
[{:keys [x y width height points transform transform-inverse] :as shape} current-transform modifiers]
(let [corner-pt (first points)
corner-pt (cond-> corner-pt (some? transform-inverse) (gpt/transform transform-inverse))
resize-x? (some? (:resize-vector modifiers))
resize-y? (some? (:resize-vector-2 modifiers))
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
(neg? (get-in modifiers [:resize-vector-2 :y])))
result (cond-> (gmt/matrix)
(and (some? transform) (or resize-x? resize-y?))
(gmt/multiply transform)
resize-x?
(gmt/scale (gpt/inverse (:resize-vector modifiers)) corner-pt)
resize-y?
(gmt/scale (gpt/inverse (:resize-vector-2 modifiers)) corner-pt)
flip-x?
(gmt/scale (gpt/point -1 1) corner-pt)
flip-y?
(gmt/scale (gpt/point 1 -1) corner-pt)
(and (some? transform) (or resize-x? resize-y?))
(gmt/multiply transform-inverse))
[width height]
(if (or resize-x? resize-y?)
(let [pc (cond-> (gpt/point x y)
(some? transform)
(gpt/transform transform)
(some? current-transform)
(gpt/transform current-transform))
pw (cond-> (gpt/point (+ x width) y)
(some? transform)
(gpt/transform transform)
(some? current-transform)
(gpt/transform current-transform))
ph (cond-> (gpt/point x (+ y height))
(some? transform)
(gpt/transform transform)
(some? current-transform)
(gpt/transform current-transform))]
[(gpt/distance pc pw) (gpt/distance pc ph)])
[width height])]
[result width height]))
(defn get-shape-node (defn get-shape-node
([id] ([id]
(get-shape-node js/document id)) (get-shape-node js/document id))
@ -191,15 +130,8 @@
(let [transform (get transforms id) (let [transform (get transforms id)
modifiers (get-in modifiers [id :modifiers])] modifiers (get-in modifiers [id :modifiers])]
;; TODO LAYOUT: Adapt to new modifiers
(doseq [node nodes] (doseq [node nodes]
(cond (cond
;; Text shapes need special treatment because their resize only change
;; the text area, not the change size/position
(dom/class? node "frame-thumbnail")
(let [[transform] (transform-no-resize shape transform modifiers)]
(set-transform-att! node "transform" transform))
(dom/class? node "frame-children") (dom/class? node "frame-children")
(set-transform-att! node "transform" (gmt/inverse transform)) (set-transform-att! node "transform" (gmt/inverse transform))
@ -256,11 +188,7 @@
(/ (:height shape) (:height shape')))] (/ (:height shape) (:height shape')))]
;; Reverse the change in size so we can recalculate the layout ;; Reverse the change in size so we can recalculate the layout
(-> modifiers (-> modifiers
(update :v2 conj {:type :resize (ctm/set-resize scalev (-> shape' :points first) (:transform shape') (:transform-inverse shape')))))
:vector scalev
:transform (:transform shape')
:transform-inverse (:transform-inverse shape')
:origin (-> shape' :points first)}))))
(defn use-dynamic-modifiers (defn use-dynamic-modifiers
[objects node modifiers] [objects node modifiers]
@ -272,37 +200,13 @@
(when (some? modifiers) (when (some? modifiers)
(d/mapm (fn [id {modifiers :modifiers}] (d/mapm (fn [id {modifiers :modifiers}]
(let [shape (get objects id) (let [shape (get objects id)
center (gsh/center-shape shape)
text? (= :text (:type shape)) text? (= :text (:type shape))
modifiers (cond-> modifiers text? (adapt-text-modifiers shape))] modifiers (cond-> modifiers text? (adapt-text-modifiers shape))]
(ctm/modifiers->transform center modifiers))) (ctm/modifiers->transform modifiers)))
modifiers)))) modifiers))))
structure-changes add-children (mf/use-memo (mf/deps modifiers) #(ctm/get-frame-add-children modifiers))
(mf/use-memo add-children (hooks/use-equal-memo add-children)
(mf/deps modifiers)
(fn []
(into {}
(comp (filter (fn [[_ val]] (-> val :modifiers :v3 some?)))
(map (fn [[key val]]
[key (-> val :modifiers :v3)])))
modifiers)))
structure-changes (hooks/use-equal-memo structure-changes)
add-children
(mf/use-memo
(mf/deps structure-changes)
(fn []
(into []
(mapcat (fn [[frame-id changes]]
(->> changes
(filter (fn [{:keys [type]}] (= type :add-children)))
(mapcat (fn [{:keys [value]}]
(->> value (map (fn [id] {:frame frame-id :shape id}))))))))
structure-changes)))
add-children-prev (hooks/use-previous add-children) add-children-prev (hooks/use-previous add-children)
shapes shapes

View file

@ -35,13 +35,6 @@
(with-meta (meta (:position-data shape)))) (with-meta (meta (:position-data shape))))
(dissoc :position-data :transform :transform-inverse))) (dissoc :position-data :transform :transform-inverse)))
#_(defn strip-modifier
[modifier]
(if (or (some? (dm/get-in modifier [:modifiers :resize-vector]))
(some? (dm/get-in modifier [:modifiers :resize-vector-2])))
modifier
(d/update-when modifier :modifiers dissoc :displacement :rotation)))
(defn fix-position [shape modifier] (defn fix-position [shape modifier]
(let [shape' (-> shape (let [shape' (-> shape
(assoc :grow-type :fixed) (assoc :grow-type :fixed)

View file

@ -31,7 +31,7 @@
(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) layout-data (gsl/calc-layout-data shape children)
drop-areas (gsl/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)}
(for [[idx drop-area] (d/enumerate drop-areas)] (for [[idx drop-area] (d/enumerate drop-areas)]