From 01dda6dd6b61316348dfe9f7daef9290e4774ed7 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 9 Jun 2025 12:36:03 +0200 Subject: [PATCH] :bug: Add better fix for path transformation --- common/src/app/common/types/path.cljc | 27 +--------- common/src/app/common/types/path/impl.cljc | 48 ++++++++--------- .../common_tests/types/path_data_test.cljc | 54 +++++++++++++++---- 3 files changed, 70 insertions(+), 59 deletions(-) diff --git a/common/src/app/common/types/path.cljc b/common/src/app/common/types/path.cljc index b06c72afbe..65336fe2d5 100644 --- a/common/src/app/common/types/path.cljc +++ b/common/src/app/common/types/path.cljc @@ -104,36 +104,11 @@ (impl/path-data (reduce apply-to-index (vec content) modifiers)))) -(defn- transform-content-legacy - [content transform] - (if (some? transform) - (let [set-tr - (fn [params px py] - (let [tr-point (-> (gpt/point (get params px) (get params py)) - (gpt/transform transform))] - (assoc params - px (:x tr-point) - py (:y tr-point)))) - - transform-params - (fn [{:keys [x c1x c2x] :as params}] - (cond-> params - (some? x) (set-tr :x :y) - (some? c1x) (set-tr :c1x :c1y) - (some? c2x) (set-tr :c2x :c2y)))] - - (into [] - (map #(update % :params transform-params)) - content)) - content)) - (defn transform-content "Applies a transformation matrix over content and returns a new content as PathData instance." [content transform] - #_(segment/transform-content content transform) - (some-> (transform-content-legacy (vec content) transform) - (impl/from-plain))) + (segment/transform-content content transform)) (defn move-content [content move-vec] diff --git a/common/src/app/common/types/path/impl.cljc b/common/src/app/common/types/path/impl.cljc index cb973ca70e..bc948d9f5c 100644 --- a/common/src/app/common/types/path/impl.cljc +++ b/common/src/app/common/types/path/impl.cljc @@ -65,34 +65,34 @@ (let [t (buf/read-short buffer offset)] (case t (1 2) - (let [x (buf/read-float buffer (+ offset 20)) - y (buf/read-float buffer (+ offset 24)) - x (+ (* x a) (* y c) e) - y (+ (* x b) (* y d) f)] - (buf/write-float buffer (+ offset 20) x) - (buf/write-float buffer (+ offset 24) y)) + (let [x (buf/read-float buffer (+ offset 20)) + y (buf/read-float buffer (+ offset 24)) + x' (+ (* x a) (* y c) e) + y' (+ (* x b) (* y d) f)] + (buf/write-float buffer (+ offset 20) x') + (buf/write-float buffer (+ offset 24) y')) 3 - (let [c1x (buf/read-float buffer (+ offset 4)) - c1y (buf/read-float buffer (+ offset 8)) - c2x (buf/read-float buffer (+ offset 12)) - c2y (buf/read-float buffer (+ offset 16)) - x (buf/read-float buffer (+ offset 20)) - y (buf/read-float buffer (+ offset 24)) + (let [c1x (buf/read-float buffer (+ offset 4)) + c1y (buf/read-float buffer (+ offset 8)) + c2x (buf/read-float buffer (+ offset 12)) + c2y (buf/read-float buffer (+ offset 16)) + x (buf/read-float buffer (+ offset 20)) + y (buf/read-float buffer (+ offset 24)) - c1x (+ (* c1x a) (* c1y c) e) - c1y (+ (* c1x b) (* c1y d) f) - c2x (+ (* c2x a) (* c2y c) e) - c2y (+ (* c2x b) (* c2y d) f) - x (+ (* x a) (* y c) e) - y (+ (* x b) (* y d) f)] + c1x' (+ (* c1x a) (* c1y c) e) + c1y' (+ (* c1x b) (* c1y d) f) + c2x' (+ (* c2x a) (* c2y c) e) + c2y' (+ (* c2x b) (* c2y d) f) + x' (+ (* x a) (* y c) e) + y' (+ (* x b) (* y d) f)] - (buf/write-float buffer (+ offset 4) c1x) - (buf/write-float buffer (+ offset 8) c1y) - (buf/write-float buffer (+ offset 12) c2x) - (buf/write-float buffer (+ offset 16) c2y) - (buf/write-float buffer (+ offset 20) x) - (buf/write-float buffer (+ offset 24) y)) + (buf/write-float buffer (+ offset 4) c1x') + (buf/write-float buffer (+ offset 8) c1y') + (buf/write-float buffer (+ offset 12) c2x') + (buf/write-float buffer (+ offset 16) c2y') + (buf/write-float buffer (+ offset 20) x') + (buf/write-float buffer (+ offset 24) y')) nil))) diff --git a/common/test/common_tests/types/path_data_test.cljc b/common/test/common_tests/types/path_data_test.cljc index b96d0e8458..aef996608a 100644 --- a/common/test/common_tests/types/path_data_test.cljc +++ b/common/test/common_tests/types/path_data_test.cljc @@ -25,6 +25,15 @@ {:command :curve-to :params {:c1x 368.0 :c1y 737.0 :c2x 310.0 :c2y 681.0 :x 264.0 :y 634.0}} {:command :close-path :params {}}]) +(def sample-content-square + [{:command :move-to, :params {:x 0, :y 0}} + {:command :line-to, :params {:x 10, :y 0}} + {:command :line-to, :params {:x 10, :y 10}} + {:command :line-to, :params {:x 10, :y 0}} + {:command :line-to, :params {:x 0, :y 10}} + {:command :line-to, :params {:x 0, :y 0}} + {:command :close-path :params {}}]) + (def sample-content-large [{:command :move-to :params {:x 480.0 :y 839.0}} {:command :line-to :params {:x 439.0 :y 802.0}} @@ -179,6 +188,42 @@ (t/is (= (vec result1) result2)) (t/is (= result2 result3)))) +(t/deftest path-transform-3 + (let [matrix (gmt/rotate-matrix 42 (gpt/point 0 0)) + content (path/content sample-content-square) + + result1 (path/transform-content content matrix) + result2 (transform-plain-content sample-content-square matrix) + result3 (transform-plain-content content matrix)] + + (t/is (= (count result1) (count result2))) + (doseq [[seg-a seg-b] (map vector result1 result2)] + (t/is (= (:command seg-a) + (:command seg-b))) + + (let [params-a (get seg-a :params) + params-b (get seg-b :params)] + + (t/is (mth/close? (get params-a :x 0) + (get params-b :x 0))) + (t/is (mth/close? (get params-a :y 0) + (get params-b :y 0))))) + + + (doseq [[seg-a seg-b] (map vector result1 result3)] + (t/is (= (:command seg-a) + (:command seg-b))) + + (let [params-a (get seg-a :params) + params-b (get seg-b :params)] + + (t/is (mth/close? (get params-a :x 0) + (get params-b :x 0))) + (t/is (mth/close? (get params-a :y 0) + (get params-b :y 0))))))) + + + (defn- content->points "Given a content return all points. @@ -278,15 +323,6 @@ (t/is (= result2 expect)) (t/is (= result3 expect)))) -(def sample-content-square - [{:command :move-to, :params {:x 0, :y 0}} - {:command :line-to, :params {:x 10, :y 0}} - {:command :line-to, :params {:x 10, :y 10}} - {:command :line-to, :params {:x 10, :y 0}} - {:command :line-to, :params {:x 0, :y 10}} - {:command :line-to, :params {:x 0, :y 0}} - {:command :close-path :params {}}]) - (t/deftest points-to-content (let [initial [(gpt/point 0.0 0.0) (gpt/point 10.0 10.0)