mirror of
https://github.com/penpot/penpot.git
synced 2025-03-16 01:31:22 -05:00
Merge pull request #2856 from penpot/alotor-fix-transform-precision
🐛 Fix problem with transform when a coordinate was very close to …
This commit is contained in:
commit
073ec9ea2b
2 changed files with 72 additions and 52 deletions
|
@ -17,6 +17,7 @@
|
||||||
[app.common.geom.shapes.common :as gco]
|
[app.common.geom.shapes.common :as gco]
|
||||||
[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.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.common.uuid :as uuid]))
|
[app.common.uuid :as uuid]))
|
||||||
|
@ -159,67 +160,79 @@
|
||||||
"Calculate the transform matrix to convert from the selrect to the points bounds
|
"Calculate the transform matrix to convert from the selrect to the points bounds
|
||||||
TargetM = SourceM * Transform ==> Transform = TargetM * inv(SourceM)"
|
TargetM = SourceM * Transform ==> Transform = TargetM * inv(SourceM)"
|
||||||
[{:keys [x1 y1 x2 y2]} [d1 d2 _ d4]]
|
[{:keys [x1 y1 x2 y2]} [d1 d2 _ d4]]
|
||||||
#?(:clj
|
;; If the coordinates are very close to zero (but not zero) the rounding can mess with the
|
||||||
;; NOTE: the source matrix may not be invertible we can't
|
;; transforms. So we round to zero the values
|
||||||
;; calculate the transform, so on exception we return `nil`
|
(let [x1 (mth/round-to-zero x1)
|
||||||
(ex/ignoring
|
y1 (mth/round-to-zero y1)
|
||||||
(let [target-points-matrix
|
x2 (mth/round-to-zero x2)
|
||||||
(->> (list (:x d1) (:x d2) (:x d4)
|
y2 (mth/round-to-zero y2)
|
||||||
(:y d1) (:y d2) (:y d4)
|
d1x (mth/round-to-zero (:x d1))
|
||||||
1 1 1 )
|
d1y (mth/round-to-zero (:y d1))
|
||||||
(into-array Double/TYPE)
|
d2x (mth/round-to-zero (:x d2))
|
||||||
(Matrix/from1DArray 3 3))
|
d2y (mth/round-to-zero (:y d2))
|
||||||
|
d4x (mth/round-to-zero (:x d4))
|
||||||
|
d4y (mth/round-to-zero (:y d4))]
|
||||||
|
#?(:clj
|
||||||
|
;; NOTE: the source matrix may not be invertible we can't
|
||||||
|
;; calculate the transform, so on exception we return `nil`
|
||||||
|
(ex/ignoring
|
||||||
|
(let [target-points-matrix
|
||||||
|
(->> (list d1x d2x d4x
|
||||||
|
d1y d2y d4y
|
||||||
|
1 1 1)
|
||||||
|
(into-array Double/TYPE)
|
||||||
|
(Matrix/from1DArray 3 3))
|
||||||
|
|
||||||
source-points-matrix
|
source-points-matrix
|
||||||
(->> (list x1 x2 x1
|
(->> (list x1 x2 x1
|
||||||
y1 y1 y2
|
y1 y1 y2
|
||||||
1 1 1)
|
1 1 1)
|
||||||
(into-array Double/TYPE)
|
(into-array Double/TYPE)
|
||||||
(Matrix/from1DArray 3 3))
|
(Matrix/from1DArray 3 3))
|
||||||
|
|
||||||
;; May throw an exception if the matrix is not invertible
|
;; May throw an exception if the matrix is not invertible
|
||||||
source-points-matrix-inv
|
source-points-matrix-inv
|
||||||
(.. source-points-matrix
|
(.. source-points-matrix
|
||||||
(withInverter LinearAlgebra/GAUSS_JORDAN)
|
(withInverter LinearAlgebra/GAUSS_JORDAN)
|
||||||
(inverse))
|
(inverse))
|
||||||
|
|
||||||
transform-jvm
|
transform-jvm
|
||||||
(.. target-points-matrix
|
(.. target-points-matrix
|
||||||
(multiply source-points-matrix-inv))]
|
(multiply source-points-matrix-inv))]
|
||||||
|
|
||||||
(gmt/matrix (.get transform-jvm 0 0)
|
(gmt/matrix (.get transform-jvm 0 0)
|
||||||
(.get transform-jvm 1 0)
|
(.get transform-jvm 1 0)
|
||||||
(.get transform-jvm 0 1)
|
(.get transform-jvm 0 1)
|
||||||
(.get transform-jvm 1 1)
|
(.get transform-jvm 1 1)
|
||||||
(.get transform-jvm 0 2)
|
(.get transform-jvm 0 2)
|
||||||
(.get transform-jvm 1 2))))
|
(.get transform-jvm 1 2))))
|
||||||
|
|
||||||
:cljs
|
:cljs
|
||||||
(let [target-points-matrix
|
(let [target-points-matrix
|
||||||
(Matrix. #js [#js [(:x d1) (:x d2) (:x d4)]
|
(Matrix. #js [#js [d1x d2x d4x]
|
||||||
#js [(:y d1) (:y d2) (:y d4)]
|
#js [d1y d2y d4y]
|
||||||
#js [ 1 1 1]])
|
#js [ 1 1 1]])
|
||||||
|
|
||||||
source-points-matrix
|
source-points-matrix
|
||||||
(Matrix. #js [#js [x1 x2 x1]
|
(Matrix. #js [#js [x1 x2 x1]
|
||||||
#js [y1 y1 y2]
|
#js [y1 y1 y2]
|
||||||
#js [ 1 1 1]])
|
#js [ 1 1 1]])
|
||||||
|
|
||||||
;; returns nil if not invertible
|
;; returns nil if not invertible
|
||||||
source-points-matrix-inv (.getInverse source-points-matrix)
|
source-points-matrix-inv (.getInverse source-points-matrix)
|
||||||
|
|
||||||
;; TargetM = SourceM * Transform ==> Transform = TargetM * inv(SourceM)
|
;; TargetM = SourceM * Transform ==> Transform = TargetM * inv(SourceM)
|
||||||
transform-js
|
transform-js
|
||||||
(when source-points-matrix-inv
|
(when source-points-matrix-inv
|
||||||
(.multiply target-points-matrix source-points-matrix-inv))]
|
(.multiply target-points-matrix source-points-matrix-inv))]
|
||||||
|
|
||||||
(when transform-js
|
(when transform-js
|
||||||
(gmt/matrix (.getValueAt transform-js 0 0)
|
(gmt/matrix (.getValueAt transform-js 0 0)
|
||||||
(.getValueAt transform-js 1 0)
|
(.getValueAt transform-js 1 0)
|
||||||
(.getValueAt transform-js 0 1)
|
(.getValueAt transform-js 0 1)
|
||||||
(.getValueAt transform-js 1 1)
|
(.getValueAt transform-js 1 1)
|
||||||
(.getValueAt transform-js 0 2)
|
(.getValueAt transform-js 0 2)
|
||||||
(.getValueAt transform-js 1 2))))))
|
(.getValueAt transform-js 1 2)))))))
|
||||||
|
|
||||||
(defn calculate-geometry
|
(defn calculate-geometry
|
||||||
[points]
|
[points]
|
||||||
|
|
|
@ -174,6 +174,13 @@
|
||||||
(defn almost-zero? [num]
|
(defn almost-zero? [num]
|
||||||
(< (abs (double num)) 1e-4))
|
(< (abs (double num)) 1e-4))
|
||||||
|
|
||||||
|
(defn round-to-zero
|
||||||
|
"Given a number if it's close enough to zero round to the zero to avoid precision problems"
|
||||||
|
[num]
|
||||||
|
(if (almost-zero? num)
|
||||||
|
0
|
||||||
|
num))
|
||||||
|
|
||||||
(defonce float-equal-precision 0.001)
|
(defonce float-equal-precision 0.001)
|
||||||
|
|
||||||
(defn close?
|
(defn close?
|
||||||
|
|
Loading…
Add table
Reference in a new issue