mirror of
https://github.com/penpot/penpot.git
synced 2025-07-21 10:57:13 +02:00
✨ Add minor improvements to curve drawing internal impl
This commit is contained in:
parent
6f2ccabaa2
commit
1abaff9c52
4 changed files with 85 additions and 64 deletions
|
@ -130,7 +130,7 @@
|
||||||
[data _]
|
[data _]
|
||||||
(letfn [(migrate-path [shape]
|
(letfn [(migrate-path [shape]
|
||||||
(if-not (contains? shape :content)
|
(if-not (contains? shape :content)
|
||||||
(let [content (path.segment/segments->content (:segments shape) (:close? shape))
|
(let [content (path.segment/points->content (:segments shape) :close (:close? shape))
|
||||||
selrect (path.segment/content->selrect content)
|
selrect (path.segment/content->selrect content)
|
||||||
points (grc/rect->points selrect)]
|
points (grc/rect->points selrect)]
|
||||||
(-> shape
|
(-> shape
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"A collection of helpers for work with plain segment type"
|
"A collection of helpers for work with plain segment type"
|
||||||
(: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.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
|
@ -96,11 +97,12 @@
|
||||||
|
|
||||||
:else nil)))
|
:else nil)))
|
||||||
|
|
||||||
|
;; FIXME: rename to get-point
|
||||||
(defn get-handler-point
|
(defn get-handler-point
|
||||||
"Given a segment index and prefix, get a handler point"
|
"Given a segment index and prefix, get a handler point"
|
||||||
[content index prefix]
|
[content index prefix]
|
||||||
(when (and (some? index)
|
(when (and (some? index)
|
||||||
(some? prefix))
|
(some? content))
|
||||||
(impl/-lookup content index
|
(impl/-lookup content index
|
||||||
(fn [command c1x c1y c2x c2y x y]
|
(fn [command c1x c1y c2x c2y x y]
|
||||||
(let [prefix (if (= :curve-to command)
|
(let [prefix (if (= :curve-to command)
|
||||||
|
@ -141,25 +143,6 @@
|
||||||
(gpt/point x y)))
|
(gpt/point x y)))
|
||||||
[])))
|
[])))
|
||||||
|
|
||||||
(defn segments->content
|
|
||||||
([segments]
|
|
||||||
(segments->content segments false))
|
|
||||||
|
|
||||||
([segments closed?]
|
|
||||||
(let [initial (first segments)
|
|
||||||
lines (rest segments)]
|
|
||||||
|
|
||||||
(d/concat-vec
|
|
||||||
[{:command :move-to
|
|
||||||
:params (select-keys initial [:x :y])}]
|
|
||||||
|
|
||||||
(->> lines
|
|
||||||
(map #(hash-map :command :line-to
|
|
||||||
:params (select-keys % [:x :y]))))
|
|
||||||
|
|
||||||
(when closed?
|
|
||||||
[{:command :close-path}])))))
|
|
||||||
|
|
||||||
;; FIXME: incorrect API, don't need full shape
|
;; FIXME: incorrect API, don't need full shape
|
||||||
(defn path->lines
|
(defn path->lines
|
||||||
"Given a path returns a list of lines that approximate the path"
|
"Given a path returns a list of lines that approximate the path"
|
||||||
|
@ -880,3 +863,27 @@
|
||||||
:else
|
:else
|
||||||
content)]
|
content)]
|
||||||
(conj content (impl/check-segment segment))))
|
(conj content (impl/check-segment segment))))
|
||||||
|
|
||||||
|
(defn points->content
|
||||||
|
"Given a vector of points generate a path content.
|
||||||
|
|
||||||
|
Mainly used for generate a path content from user drawing points
|
||||||
|
using curve drawing tool."
|
||||||
|
[points & {:keys [close]}]
|
||||||
|
(let [initial (first points)
|
||||||
|
point->params
|
||||||
|
(fn [point]
|
||||||
|
{:x (dm/get-prop point :x)
|
||||||
|
:y (dm/get-prop point :y)})]
|
||||||
|
(loop [points (rest points)
|
||||||
|
result [{:command :move-to
|
||||||
|
:params (point->params initial)}]]
|
||||||
|
(if-let [point (first points)]
|
||||||
|
(recur (rest points)
|
||||||
|
(conj result {:command :line-to
|
||||||
|
:params (point->params point)}))
|
||||||
|
|
||||||
|
(let [result (if close
|
||||||
|
(conj result {:command :close-path})
|
||||||
|
result)]
|
||||||
|
(impl/from-plain result))))))
|
||||||
|
|
|
@ -286,6 +286,17 @@
|
||||||
{:command :line-to, :params {:x 0, :y 0}}
|
{:command :line-to, :params {:x 0, :y 0}}
|
||||||
{:command :close-path :params {}}])
|
{:command :close-path :params {}}])
|
||||||
|
|
||||||
|
(t/deftest points-to-content
|
||||||
|
(let [initial [(gpt/point 0.0 0.0)
|
||||||
|
(gpt/point 10.0 10.0)
|
||||||
|
(gpt/point 10.0 5.0)]
|
||||||
|
content (path.segment/points->content initial)
|
||||||
|
segments (vec content)]
|
||||||
|
(t/is (= 3 (count segments)))
|
||||||
|
(t/is (= {:command :move-to, :params {:x 0.0, :y 0.0}} (nth segments 0)))
|
||||||
|
(t/is (= {:command :line-to, :params {:x 10.0, :y 10.0}} (nth segments 1)))
|
||||||
|
(t/is (= {:command :line-to, :params {:x 10.0, :y 5.0}} (nth segments 2)))))
|
||||||
|
|
||||||
(t/deftest get-segments
|
(t/deftest get-segments
|
||||||
(let [content (path/content sample-content-square)
|
(let [content (path/content sample-content-square)
|
||||||
points #{(gpt/point 10.0 0.0)
|
points #{(gpt/point 10.0 0.0)
|
||||||
|
|
|
@ -7,12 +7,11 @@
|
||||||
(ns app.main.data.workspace.drawing.curve
|
(ns app.main.data.workspace.drawing.curve
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.point :as gpt]
|
|
||||||
[app.common.geom.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
[app.common.geom.shapes.flex-layout :as gslf]
|
[app.common.geom.shapes.flex-layout :as gslf]
|
||||||
[app.common.geom.shapes.grid-layout :as gslg]
|
[app.common.geom.shapes.grid-layout :as gslg]
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.path.segment :as path.segm]
|
[app.common.types.path.segment :as path.segment]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
@ -25,7 +24,37 @@
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(def simplify-tolerance 0.3)
|
(def ^:const simplify-tolerance 0.3)
|
||||||
|
|
||||||
|
(defn- setup-frame
|
||||||
|
[]
|
||||||
|
(ptk/reify ::setup-frame
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [objects (dsh/lookup-page-objects state)
|
||||||
|
content (dm/get-in state [:workspace-drawing :object :content])
|
||||||
|
position (path.segment/get-handler-point content 0 nil)
|
||||||
|
|
||||||
|
frame-id (->> (ctst/top-nested-frame objects position)
|
||||||
|
(ctn/get-first-not-copy-parent objects) ;; We don't want to change the structure of component copies
|
||||||
|
:id)
|
||||||
|
|
||||||
|
flex-layout? (ctl/flex-layout? objects frame-id)
|
||||||
|
grid-layout? (ctl/grid-layout? objects frame-id)
|
||||||
|
|
||||||
|
drop-index (when flex-layout? (gslf/get-drop-index frame-id objects position))
|
||||||
|
drop-cell (when grid-layout? (gslg/get-drop-cell frame-id objects position))]
|
||||||
|
|
||||||
|
(update-in state [:workspace-drawing :object]
|
||||||
|
(fn [object]
|
||||||
|
(-> object
|
||||||
|
(assoc :frame-id frame-id)
|
||||||
|
(assoc :parent-id frame-id)
|
||||||
|
;; FIXME: with-meta twice only one wins
|
||||||
|
(cond-> (some? drop-index)
|
||||||
|
(with-meta {:index drop-index}))
|
||||||
|
(cond-> (some? drop-cell)
|
||||||
|
(with-meta {:cell drop-cell})))))))))
|
||||||
|
|
||||||
(defn- insert-point
|
(defn- insert-point
|
||||||
[point]
|
[point]
|
||||||
|
@ -34,43 +63,16 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-drawing :object]
|
(update-in state [:workspace-drawing :object]
|
||||||
(fn [object]
|
(fn [object]
|
||||||
(let [segments (-> (:segments object)
|
(let [points (-> (::points object)
|
||||||
(conj point))
|
(conj point))
|
||||||
content (path.segm/segments->content segments)
|
content (path.segment/points->content points)
|
||||||
selrect (path.segm/content->selrect content)
|
selrect (path.segment/content->selrect content)
|
||||||
points (grc/rect->points selrect)]
|
points' (grc/rect->points selrect)]
|
||||||
(-> object
|
(-> object
|
||||||
(assoc :segments segments)
|
(assoc ::points points)
|
||||||
(assoc :content content)
|
(assoc :content content)
|
||||||
(assoc :selrect selrect)
|
(assoc :selrect selrect)
|
||||||
(assoc :points points))))))))
|
(assoc :points points'))))))))
|
||||||
|
|
||||||
(defn- setup-frame
|
|
||||||
[]
|
|
||||||
(ptk/reify ::setup-frame
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(let [objects (dsh/lookup-page-objects state)
|
|
||||||
content (dm/get-in state [:workspace-drawing :object :content] [])
|
|
||||||
start (dm/get-in content [0 :params] nil)
|
|
||||||
position (when start (gpt/point start))
|
|
||||||
frame-id (->> (ctst/top-nested-frame objects position)
|
|
||||||
(ctn/get-first-not-copy-parent objects) ;; We don't want to change the structure of component copies
|
|
||||||
:id)
|
|
||||||
flex-layout? (ctl/flex-layout? objects frame-id)
|
|
||||||
|
|
||||||
grid-layout? (ctl/grid-layout? objects frame-id)
|
|
||||||
drop-index (when flex-layout? (gslf/get-drop-index frame-id objects position))
|
|
||||||
drop-cell (when grid-layout? (gslg/get-drop-cell frame-id objects position))]
|
|
||||||
(update-in state [:workspace-drawing :object]
|
|
||||||
(fn [object]
|
|
||||||
(-> object
|
|
||||||
(assoc :frame-id frame-id)
|
|
||||||
(assoc :parent-id frame-id)
|
|
||||||
(cond-> (some? drop-index)
|
|
||||||
(with-meta {:index drop-index}))
|
|
||||||
(cond-> (some? drop-cell)
|
|
||||||
(with-meta {:cell drop-cell})))))))))
|
|
||||||
|
|
||||||
(defn finish-drawing
|
(defn finish-drawing
|
||||||
[]
|
[]
|
||||||
|
@ -78,13 +80,14 @@
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-drawing :object]
|
(update-in state [:workspace-drawing :object]
|
||||||
(fn [{:keys [segments] :as shape}]
|
(fn [{:keys [::points] :as shape}]
|
||||||
(let [segments (ups/simplify segments simplify-tolerance)
|
(let [points (ups/simplify points simplify-tolerance)
|
||||||
content (path.segm/segments->content segments)
|
content (path.segment/points->content points)
|
||||||
selrect (path.segm/content->selrect content)
|
selrect (path.segment/content->selrect content)
|
||||||
points (grc/rect->points selrect)]
|
points (grc/rect->points selrect)]
|
||||||
|
|
||||||
(-> shape
|
(-> shape
|
||||||
(dissoc :segments)
|
(dissoc ::points)
|
||||||
(assoc :content content)
|
(assoc :content content)
|
||||||
(assoc :selrect selrect)
|
(assoc :selrect selrect)
|
||||||
(assoc :points points)
|
(assoc :points points)
|
||||||
|
@ -104,7 +107,7 @@
|
||||||
:initialized? true
|
:initialized? true
|
||||||
:frame-id uuid/zero
|
:frame-id uuid/zero
|
||||||
:parent-id uuid/zero
|
:parent-id uuid/zero
|
||||||
:segments []})]
|
::points []})]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of #(update % :workspace-drawing assoc :object shape))
|
(rx/of #(update % :workspace-drawing assoc :object shape))
|
||||||
(->> mouse
|
(->> mouse
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue