0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-20 19:51:23 -05:00

Snapping 180 angle with opposites handlers

This commit is contained in:
alonso.torres 2021-04-21 17:39:47 +02:00
parent 961a7a2e03
commit 6331dff484
8 changed files with 108 additions and 56 deletions
common/app/common/geom
frontend/src/app
main
data/workspace/path
ui/workspace/shapes/path
util/path

View file

@ -162,6 +162,8 @@
(mth/precision 6))]
(if (mth/nan? d) 0 d)))))
(defn angle-sign [v1 v2]
(if (> (* (:y v1) (:x v2)) (* (:x v1) (:y v2))) -1 1))
(defn update-angle
"Update the angle of the point."

View file

@ -161,7 +161,7 @@
v2 (gpt/to-vec center p2)
rot-angle (gpt/angle-with-other v1 v2)
rot-sign (if (> (* (:y v1) (:x v2)) (* (:x v1) (:y v2))) -1 1)]
rot-sign (gpt/angle-sign v1 v2)]
(* rot-sign rot-angle)))
(defn- calculate-dimensions

View file

@ -73,7 +73,7 @@
prefix (or prefix :c1)
position (or position (upc/command->point (nth content (dec index))))
old-handler (helpers/handler->point content index prefix)
old-handler (upc/handler->point content index prefix)
handler-position (cond-> (gpt/point x y)
shift? (helpers/position-fixed-angle position))

View file

@ -163,11 +163,14 @@
point (-> content (get (if (= prefix :c1) (dec index) index)) (upc/command->point))
handler (-> content (get index) (upc/get-handler prefix))
[op-idx op-prefix] (upc/opposite-index content index prefix)
opposite (upc/handler->point content op-idx op-prefix)
snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled])]
(streams/drag-stream
(rx/concat
(->> (streams/move-handler-stream snap-toggled start-point handler points)
(->> (streams/move-handler-stream snap-toggled start-point point handler opposite points)
(rx/take-until (->> stream (rx/filter ms/mouse-up?)))
(rx/map
(fn [{:keys [x y alt? shift?]}]

View file

@ -107,29 +107,6 @@
(update :content (fnil conj []) command)
(update-selrect))))
(defn prefix->coords [prefix]
(case prefix
:c1 [:c1x :c1y]
:c2 [:c2x :c2y]
nil))
(defn handler->point [content index prefix]
(when (and (some? index)
(some? prefix)
(contains? content index))
(let [[cx cy :as coords] (prefix->coords prefix)]
(if (= :curve-to (get-in content [index :command]))
(gpt/point (get-in content [index :params cx])
(get-in content [index :params cy]))
(gpt/point (get-in content [index :params :x])
(get-in content [index :params :y]))))))
(defn handler->node [content index prefix]
(if (= prefix :c1)
(upc/command->point (get content (dec index)))
(upc/command->point (get content index))))
(defn angle-points [common p1 p2]
(mth/abs
(gpt/angle-with-other
@ -153,7 +130,7 @@
v2 (gpt/to-vec node new-handler)
delta-angle (gpt/angle-with-other v1 v2)
delta-sign (if (> (* (:y v1) (:x v2)) (* (:x v1) (:y v2))) -1 1)
delta-sign (gpt/angle-sign v1 v2)
distance-scale (/ (gpt/distance node handler)
(gpt/distance node new-handler))
@ -170,14 +147,14 @@
(defn move-handler-modifiers
[content index prefix match-distance? match-angle? dx dy]
(let [[cx cy] (prefix->coords prefix)
(let [[cx cy] (upc/prefix->coords prefix)
[op-idx op-prefix] (upc/opposite-index content index prefix)
node (handler->node content index prefix)
handler (handler->point content index prefix)
opposite (handler->point content op-idx op-prefix)
node (upc/handler->node content index prefix)
handler (upc/handler->point content index prefix)
opposite (upc/handler->point content op-idx op-prefix)
[ocx ocy] (prefix->coords op-prefix)
[ocx ocy] (upc/prefix->coords op-prefix)
[odx ody] (calculate-opposite-delta node handler opposite match-angle? match-distance? dx dy)
hnv (if (some? handler)

View file

@ -73,24 +73,45 @@
(rx/map check-path-snap))))
(defn move-handler-stream
[snap-toggled start-point handler points]
[snap-toggled start-point node handler opposite points]
(let [zoom (get-in @st/state [:workspace-local :zoom] 1)
ranges (snap/create-ranges points)
d-pos (/ snap/snap-path-accuracy zoom)
initial-angle (gpt/angle-with-other (gpt/to-vec node handler)
(gpt/to-vec node opposite))
check-path-snap
(fn [position]
(if snap-toggled
(let [delta (gpt/subtract position start-point)
handler-position (gpt/add handler delta)
snap (snap/get-snap-delta [handler-position] ranges d-pos)]
(gpt/add position snap))
handler (gpt/add handler delta)
v1 (gpt/to-vec node opposite)
v2 (gpt/to-vec node handler)
rot-angle (gpt/angle-with-other v1 v2)
rot-sign (gpt/angle-sign v1 v2)
snap-opposite-angle?
(and (or (:alt? position) (> (- 180 initial-angle) 0.1))
(<= (- 180 rot-angle) 5))]
(cond
snap-opposite-angle?
(let [rot-handler (gpt/rotate handler node (- 180 (* rot-sign rot-angle)))
snap (gpt/to-vec handler rot-handler)]
(merge position (gpt/add position snap)))
:else
(let [snap (snap/get-snap-delta [handler] ranges d-pos)]
(merge position (gpt/add position snap)))))
position))]
(->> ms/mouse-position
(rx/map check-path-snap)
(rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %))))
(rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %)))))))
(rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %))))
(rx/map check-path-snap))))
(defn position-stream
[snap-toggled points]
@ -115,6 +136,5 @@
(let [snap (snap/get-snap-delta [position] ranges d-pos)]
(gpt/add position snap))
position)))
(rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %))))
(rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %)))))))

View file

@ -80,7 +80,7 @@
(= edit-mode :move) cur/pointer-node)
:fill "transparent"}}]]))
(mf/defc path-handler [{:keys [index prefix point handler zoom selected? hover? edit-mode]}]
(mf/defc path-handler [{:keys [index prefix point handler zoom selected? hover? edit-mode snap-angle?]}]
(when (and point handler)
(let [{:keys [x y]} handler
on-enter
@ -108,6 +108,16 @@
:y2 y
:style {:stroke (if hover? pc/black-color pc/gray-color)
:stroke-width (/ 1 zoom)}}]
(when snap-angle?
[:line
{:x1 (:x point)
:y1 (:y point)
:x2 x
:y2 y
:style {:stroke pc/secondary-color
:stroke-width (/ 1 zoom)}}])
[:rect
{:x (- x (/ 3 zoom))
:y (- y (/ 3 zoom))
@ -157,6 +167,18 @@
:style {:stroke pc/secondary-color
:stroke-width (/ 1 zoom)}}])]))
(defn matching-handler? [content node handlers]
(when (= 2 (count handlers))
(let [[[i1 p1] [i2 p2]] handlers
p1 (upc/handler->point content i1 p1)
p2 (upc/handler->point content i2 p2)
v1 (gpt/to-vec node p1)
v2 (gpt/to-vec node p2)
angle (gpt/angle-with-other v1 v2)]
(<= (- 180 angle) 0.1))))
(mf/defc path-editor
[{:keys [shape zoom]}]
@ -258,20 +280,24 @@
[:g.path-node
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
(for [[index prefix] (get handlers position)]
(let [command (get content index)
x (get-in command [:params (d/prefix-keyword prefix :x)])
y (get-in command [:params (d/prefix-keyword prefix :y)])
handler-position (gpt/point x y)
handler-hover? (contains? hover-handlers [index prefix])]
(when (not= position handler-position)
[:& path-handler {:point position
:handler handler-position
:index index
:prefix prefix
:zoom zoom
:hover? handler-hover?
:edit-mode edit-mode}])))]
(let [pos-handlers (get handlers position)]
(for [[index prefix] pos-handlers]
(let [command (get content index)
x (get-in command [:params (d/prefix-keyword prefix :x)])
y (get-in command [:params (d/prefix-keyword prefix :y)])
handler-position (gpt/point x y)
handler-hover? (contains? hover-handlers [index prefix])
moving-handler? (= handler-position moving-handler)
matching-handler? (matching-handler? content position pos-handlers)]
(when (not= position handler-position)
[:& path-handler {:point position
:handler handler-position
:index index
:prefix prefix
:zoom zoom
:hover? handler-hover?
:snap-angle? (and moving-handler? matching-handler?)
:edit-mode edit-mode}]))))]
[:& path-point {:position position
:zoom zoom
:edit-mode edit-mode
@ -289,6 +315,6 @@
(when show-snap?
[:g.path-snap {:pointer-events "none"}
[:& path-snap {:selected snap-selected
:points snap-points
:zoom zoom}]])]))
:points snap-points
:zoom zoom}]])]))

View file

@ -180,3 +180,27 @@
[content point]
(->> (d/enumerate content)
(filterv (fn [[idx cmd]] (= (command->point cmd) point)))))
(defn prefix->coords [prefix]
(case prefix
:c1 [:c1x :c1y]
:c2 [:c2x :c2y]
nil))
(defn handler->point [content index prefix]
(when (and (some? index)
(some? prefix)
(contains? content index))
(let [[cx cy :as coords] (prefix->coords prefix)]
(if (= :curve-to (get-in content [index :command]))
(gpt/point (get-in content [index :params cx])
(get-in content [index :params cy]))
(gpt/point (get-in content [index :params :x])
(get-in content [index :params :y]))))))
(defn handler->node [content index prefix]
(if (= prefix :c1)
(command->point (get content (dec index)))
(command->point (get content index))))