mirror of
https://github.com/penpot/penpot.git
synced 2025-01-08 16:00:19 -05:00
✨ Add several improvements to svg path parser tests
And properly reorganize legacy implementations
This commit is contained in:
parent
62b1dc2a4b
commit
74447442b8
4 changed files with 519 additions and 37 deletions
|
@ -2,7 +2,8 @@
|
|||
* Arc to Bezier curves transformer
|
||||
*
|
||||
* Is a modified and google closure compatible version of the a2c
|
||||
* functions by https://github.com/fontello/svgpath
|
||||
* functions by https://github.com/fontello/svgpath used as reference
|
||||
* implementation for tests
|
||||
*
|
||||
* @author KALEIDOS INC
|
||||
* @license MIT License <https://opensource.org/licenses/MIT>
|
||||
|
@ -10,11 +11,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
goog.provide("common_tests.arc_to_bezier");
|
||||
goog.provide("app.common.svg.path.arc_to_bezier");
|
||||
|
||||
// https://raw.githubusercontent.com/fontello/svgpath/master/lib/a2c.js
|
||||
goog.scope(function() {
|
||||
const self = common_tests.arc_to_bezier;
|
||||
const self = app.common.svg.path.arc_to_bezier;
|
||||
|
||||
var TAU = Math.PI * 2;
|
||||
|
||||
|
@ -123,7 +124,7 @@ goog.scope(function() {
|
|||
return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
|
||||
}
|
||||
|
||||
function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
|
||||
function calculate_beziers(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
|
||||
var sin_phi = Math.sin(phi * TAU / 360);
|
||||
var cos_phi = Math.cos(phi * TAU / 360);
|
||||
|
||||
|
@ -132,6 +133,8 @@ goog.scope(function() {
|
|||
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
|
||||
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
|
||||
|
||||
// console.log("L", x1p, y1p)
|
||||
|
||||
if (x1p === 0 && y1p === 0) {
|
||||
// we're asked to draw line to itself
|
||||
return [];
|
||||
|
@ -204,5 +207,5 @@ goog.scope(function() {
|
|||
});
|
||||
}
|
||||
|
||||
self.a2c = a2c;
|
||||
self.calculateBeziers = calculate_beziers;
|
||||
});
|
325
common/src/app/common/svg/path/legacy_parser1.cljs
Normal file
325
common/src/app/common/svg/path/legacy_parser1.cljs
Normal file
|
@ -0,0 +1,325 @@
|
|||
;; 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.svg.path.legacy-parser1
|
||||
"The first SVG Path parser implementation.
|
||||
|
||||
Written in a mix of CLJS and JS code and used in production until
|
||||
1.19, used mainly for tests."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.path :as upg]
|
||||
[app.common.svg :as csvg]
|
||||
[app.common.svg.path.arc-to-bezier :as a2b]
|
||||
[app.common.svg.path.command :as upc]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(def commands-regex #"(?i)[mzlhvcsqta][^mzlhvcsqta]*")
|
||||
|
||||
;; Matches numbers for path values allows values like... -.01, 10, +12.22
|
||||
;; 0 and 1 are special because can refer to flags
|
||||
(def num-regex #"[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?")
|
||||
|
||||
(def flag-regex #"[01]")
|
||||
|
||||
(defn extract-params [cmd-str extract-commands]
|
||||
(loop [result []
|
||||
extract-idx 0
|
||||
current {}
|
||||
remain (-> cmd-str (subs 1) (str/trim))]
|
||||
|
||||
(let [[param type] (nth extract-commands extract-idx)
|
||||
regex (case type
|
||||
:flag flag-regex
|
||||
#_:number num-regex)
|
||||
match (re-find regex remain)]
|
||||
|
||||
(if match
|
||||
(let [value (-> match first csvg/fix-dot-number d/read-string)
|
||||
remain (str/replace-first remain regex "")
|
||||
current (assoc current param value)
|
||||
extract-idx (inc extract-idx)
|
||||
[result current extract-idx]
|
||||
(if (>= extract-idx (count extract-commands))
|
||||
[(conj result current) {} 0]
|
||||
[result current extract-idx])]
|
||||
(recur result
|
||||
extract-idx
|
||||
current
|
||||
remain))
|
||||
(cond-> result
|
||||
(seq current) (conj current))))))
|
||||
|
||||
;; Path specification
|
||||
;; https://www.w3.org/TR/SVG11/paths.html
|
||||
(defmulti parse-command (comp str/upper first))
|
||||
|
||||
(defmethod parse-command "M" [cmd]
|
||||
(let [relative (str/starts-with? cmd "m")
|
||||
param-list (extract-params cmd [[:x :number]
|
||||
[:y :number]])]
|
||||
|
||||
(into [{:command :move-to
|
||||
:relative relative
|
||||
:params (first param-list)}]
|
||||
|
||||
(for [params (rest param-list)]
|
||||
{:command :line-to
|
||||
:relative relative
|
||||
:params params}))))
|
||||
|
||||
(defmethod parse-command "Z" [_]
|
||||
[{:command :close-path}])
|
||||
|
||||
(defmethod parse-command "L" [cmd]
|
||||
(let [relative (str/starts-with? cmd "l")
|
||||
param-list (extract-params cmd [[:x :number]
|
||||
[:y :number]])]
|
||||
(for [params param-list]
|
||||
{:command :line-to
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "H" [cmd]
|
||||
(let [relative (str/starts-with? cmd "h")
|
||||
param-list (extract-params cmd [[:value :number]])]
|
||||
(for [params param-list]
|
||||
{:command :line-to-horizontal
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "V" [cmd]
|
||||
(let [relative (str/starts-with? cmd "v")
|
||||
param-list (extract-params cmd [[:value :number]])]
|
||||
(for [params param-list]
|
||||
{:command :line-to-vertical
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "C" [cmd]
|
||||
(let [relative (str/starts-with? cmd "c")
|
||||
param-list (extract-params cmd [[:c1x :number]
|
||||
[:c1y :number]
|
||||
[:c2x :number]
|
||||
[:c2y :number]
|
||||
[:x :number]
|
||||
[:y :number]])
|
||||
]
|
||||
(for [params param-list]
|
||||
{:command :curve-to
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "S" [cmd]
|
||||
(let [relative (str/starts-with? cmd "s")
|
||||
param-list (extract-params cmd [[:cx :number]
|
||||
[:cy :number]
|
||||
[:x :number]
|
||||
[:y :number]])]
|
||||
(for [params param-list]
|
||||
{:command :smooth-curve-to
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "Q" [cmd]
|
||||
(let [relative (str/starts-with? cmd "q")
|
||||
param-list (extract-params cmd [[:cx :number]
|
||||
[:cy :number]
|
||||
[:x :number]
|
||||
[:y :number]])]
|
||||
(for [params param-list]
|
||||
{:command :quadratic-bezier-curve-to
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "T" [cmd]
|
||||
(let [relative (str/starts-with? cmd "t")
|
||||
param-list (extract-params cmd [[:x :number]
|
||||
[:y :number]])]
|
||||
(for [params param-list]
|
||||
{:command :smooth-quadratic-bezier-curve-to
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defmethod parse-command "A" [cmd]
|
||||
(let [relative (str/starts-with? cmd "a")
|
||||
param-list (extract-params cmd [[:rx :number]
|
||||
[:ry :number]
|
||||
[:x-axis-rotation :number]
|
||||
[:large-arc-flag :flag]
|
||||
[:sweep-flag :flag]
|
||||
[:x :number]
|
||||
[:y :number]])]
|
||||
(for [params param-list]
|
||||
{:command :elliptical-arc
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(defn smooth->curve
|
||||
[{:keys [params]} pos handler]
|
||||
(let [{c1x :x c1y :y} (upg/calculate-opposite-handler pos handler)]
|
||||
{:c1x c1x
|
||||
:c1y c1y
|
||||
:c2x (:cx params)
|
||||
:c2y (:cy params)}))
|
||||
|
||||
(defn quadratic->curve
|
||||
[sp ep cp]
|
||||
(let [cp1 (-> (gpt/to-vec sp cp)
|
||||
(gpt/scale (/ 2 3))
|
||||
(gpt/add sp))
|
||||
|
||||
cp2 (-> (gpt/to-vec ep cp)
|
||||
(gpt/scale (/ 2 3))
|
||||
(gpt/add ep))]
|
||||
|
||||
{:c1x (:x cp1)
|
||||
:c1y (:y cp1)
|
||||
:c2x (:x cp2)
|
||||
:c2y (:y cp2)}))
|
||||
|
||||
(defn arc->beziers*
|
||||
[from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation]
|
||||
(a2b/calculateBeziers from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation))
|
||||
|
||||
(defn arc->beziers [from-p command]
|
||||
(let [to-command
|
||||
(fn [[_ _ c1x c1y c2x c2y x y]]
|
||||
{:command :curve-to
|
||||
:relative (:relative command)
|
||||
:params {:c1x c1x :c1y c1y
|
||||
:c2x c2x :c2y c2y
|
||||
:x x :y y}})
|
||||
|
||||
{from-x :x from-y :y} from-p
|
||||
{:keys [rx ry x-axis-rotation large-arc-flag sweep-flag x y]} (:params command)
|
||||
result (arc->beziers* from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation)]
|
||||
(mapv to-command result)))
|
||||
|
||||
(defn simplify-commands
|
||||
"Removes some commands and convert relative to absolute coordinates"
|
||||
[commands]
|
||||
(let [simplify-command
|
||||
;; prev-pos : previous position for the current path. Necessary for relative commands
|
||||
;; prev-start : previous move-to necessary for Z commands
|
||||
;; prev-cc : previous command control point for cubic beziers
|
||||
;; prev-qc : previous command control point for quadratic curves
|
||||
(fn [[result prev-pos prev-start prev-cc prev-qc] [command _prev]]
|
||||
(let [command (assoc command :prev-pos prev-pos)
|
||||
|
||||
command
|
||||
(cond-> command
|
||||
(:relative command)
|
||||
(-> (assoc :relative false)
|
||||
(d/update-in-when [:params :c1x] + (:x prev-pos))
|
||||
(d/update-in-when [:params :c1y] + (:y prev-pos))
|
||||
|
||||
(d/update-in-when [:params :c2x] + (:x prev-pos))
|
||||
(d/update-in-when [:params :c2y] + (:y prev-pos))
|
||||
|
||||
(d/update-in-when [:params :cx] + (:x prev-pos))
|
||||
(d/update-in-when [:params :cy] + (:y prev-pos))
|
||||
|
||||
(d/update-in-when [:params :x] + (:x prev-pos))
|
||||
(d/update-in-when [:params :y] + (:y prev-pos))
|
||||
|
||||
(cond->
|
||||
(= :line-to-horizontal (:command command))
|
||||
(d/update-in-when [:params :value] + (:x prev-pos))
|
||||
|
||||
(= :line-to-vertical (:command command))
|
||||
(d/update-in-when [:params :value] + (:y prev-pos)))))
|
||||
|
||||
params (:params command)
|
||||
orig-command command
|
||||
|
||||
command
|
||||
(cond-> command
|
||||
(= :line-to-horizontal (:command command))
|
||||
(-> (assoc :command :line-to)
|
||||
(update :params dissoc :value)
|
||||
(assoc-in [:params :x] (:value params))
|
||||
(assoc-in [:params :y] (:y prev-pos)))
|
||||
|
||||
(= :line-to-vertical (:command command))
|
||||
(-> (assoc :command :line-to)
|
||||
(update :params dissoc :value)
|
||||
(assoc-in [:params :y] (:value params))
|
||||
(assoc-in [:params :x] (:x prev-pos)))
|
||||
|
||||
(= :smooth-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params dissoc :cx :cy)
|
||||
(update :params merge (smooth->curve command prev-pos prev-cc)))
|
||||
|
||||
(= :quadratic-bezier-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params dissoc :cx :cy)
|
||||
(update :params merge (quadratic->curve prev-pos (gpt/point params) (gpt/point (:cx params) (:cy params)))))
|
||||
|
||||
(= :smooth-quadratic-bezier-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params merge (quadratic->curve prev-pos (gpt/point params) (upg/calculate-opposite-handler prev-pos prev-qc)))))
|
||||
|
||||
result (if (= :elliptical-arc (:command command))
|
||||
(into result (arc->beziers prev-pos command))
|
||||
(conj result command))
|
||||
|
||||
next-cc (case (:command orig-command)
|
||||
:smooth-curve-to
|
||||
(gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
|
||||
|
||||
:curve-to
|
||||
(gpt/point (get-in orig-command [:params :c2x]) (get-in orig-command [:params :c2y]))
|
||||
|
||||
(:line-to-horizontal :line-to-vertical)
|
||||
(gpt/point (get-in command [:params :x]) (get-in command [:params :y]))
|
||||
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))
|
||||
|
||||
next-qc (case (:command orig-command)
|
||||
:quadratic-bezier-curve-to
|
||||
(gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
|
||||
|
||||
:smooth-quadratic-bezier-curve-to
|
||||
(upg/calculate-opposite-handler prev-pos prev-qc)
|
||||
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))
|
||||
|
||||
next-pos (if (= :close-path (:command command))
|
||||
prev-start
|
||||
(upc/command->point prev-pos command))
|
||||
|
||||
next-start (if (= :move-to (:command command)) next-pos prev-start)]
|
||||
|
||||
[result next-pos next-start next-cc next-qc]))
|
||||
|
||||
start (first commands)
|
||||
start (cond-> start
|
||||
(:relative start)
|
||||
(assoc :relative false))
|
||||
|
||||
start-pos (gpt/point (:params start))]
|
||||
|
||||
(->> (map vector (rest commands) commands)
|
||||
(reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
|
||||
(first))))
|
||||
|
||||
(defn parse [path-str]
|
||||
(if (empty? path-str)
|
||||
path-str
|
||||
(let [clean-path-str
|
||||
(-> path-str
|
||||
(str/trim)
|
||||
;; Change "commas" for spaces
|
||||
(str/replace #"," " ")
|
||||
;; Remove all consecutive spaces
|
||||
(str/replace #"\s+" " "))
|
||||
commands (re-seq commands-regex clean-path-str)]
|
||||
(-> (mapcat parse-command commands)
|
||||
(simplify-commands)))))
|
||||
|
|
@ -4,9 +4,11 @@
|
|||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.common.svg.path.legacy
|
||||
"The first svg path parser implementation in pure clojure, used as reference impl
|
||||
and for tests."
|
||||
(ns app.common.svg.path.legacy-parser2
|
||||
"The second SVG Path parser implementation.
|
||||
|
||||
Written in crossplatform CLJC code. Used meanwhile a hight
|
||||
performance parser is developed in the 1.20 version."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.point :as gpt]
|
||||
|
@ -16,7 +18,6 @@
|
|||
[app.common.svg.path.command :as upc]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
|
||||
(def commands-regex #"(?i)[mzlhvcsqta][^mzlhvcsqta]*")
|
||||
(def regex #"[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?")
|
||||
|
||||
|
@ -296,10 +297,10 @@
|
|||
y1p (+ (/ (* (- sin-phi) (- x1 x2)) 2)
|
||||
(/ (* cos-phi (- y1 y2)) 2))]
|
||||
|
||||
(if (or (zero? x1p)
|
||||
(zero? y1p)
|
||||
(zero? rx)
|
||||
(zero? ry))
|
||||
(if (or (and (zero? x1p)
|
||||
(zero? y1p))
|
||||
(and (zero? rx)
|
||||
(zero? ry)))
|
||||
[]
|
||||
(let [
|
||||
rx (mth/abs rx)
|
||||
|
@ -462,19 +463,10 @@
|
|||
(reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
|
||||
(first))))
|
||||
|
||||
|
||||
(defn parse
|
||||
[path-str]
|
||||
(if (empty? path-str)
|
||||
path-str
|
||||
(let [commands (re-seq commands-regex path-str)]
|
||||
(->> (mapcat parse-command commands)
|
||||
(simplify-commands)
|
||||
(map (fn [segment]
|
||||
;; (prn "LEGACY:" segment)
|
||||
segment))))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(simplify-commands)))))
|
|
@ -10,9 +10,9 @@
|
|||
[app.common.pprint :as pp]
|
||||
[app.common.math :as mth]
|
||||
[app.common.svg.path :as svg.path]
|
||||
[app.common.svg.path.legacy :as svg.path.legacy]
|
||||
[app.common.svg.path.legacy-parser2 :as svg.path.legacy2]
|
||||
[clojure.test :as t]
|
||||
#?(:cljs [common-tests.arc-to-bezier :as impl])))
|
||||
#?(:cljs [app.common.svg.path.legacy-parser2 :as svg.path.legacy1])))
|
||||
|
||||
(t/deftest parse-test-1
|
||||
(let [data (str "m -994.563 4564.1423 149.3086 -52.8821 30.1828 "
|
||||
|
@ -23,14 +23,25 @@
|
|||
result1 (->> (svg.path/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
result2 (->> (svg.path.legacy/parse data)
|
||||
result2 (->> (svg.path.legacy2/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
|
||||
result3 #?(:cljs (->> (svg.path.legacy1/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
:clj nil)]
|
||||
|
||||
(t/is (= 15
|
||||
(count result1)
|
||||
(count result2)))
|
||||
|
||||
|
||||
#?(:cljs
|
||||
(t/is (= 15
|
||||
(count result1)
|
||||
(count result3))))
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(let [item1 (nth result1 i)
|
||||
item2 (nth result2 i)]
|
||||
|
@ -40,6 +51,14 @@
|
|||
(t/is (= (:params item1)
|
||||
(:params item2)))
|
||||
|
||||
#?(:cljs
|
||||
(let [item3 (nth result3 i)]
|
||||
(t/is (= (:command item1)
|
||||
(:command item3)))
|
||||
(t/is (= (:params item1)
|
||||
(:params item3)))))
|
||||
|
||||
|
||||
#_(println "------------------------")
|
||||
#_(pp/pprint (dissoc item1 :relative))
|
||||
#_(pp/pprint (dissoc item2 :prev-pos :relative))))))
|
||||
|
@ -92,7 +111,7 @@
|
|||
result1 (->> (svg.path/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
result2 (->> (svg.path.legacy/parse data)
|
||||
result2 (->> (svg.path.legacy2/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))]
|
||||
|
||||
|
@ -108,7 +127,6 @@
|
|||
(t/is (= (:command item1)
|
||||
(:command item2)))
|
||||
|
||||
|
||||
;; (println "================" (:command item1))
|
||||
;; (pp/pprint (:params item1))
|
||||
;; (println "---------")
|
||||
|
@ -124,7 +142,7 @@
|
|||
result1 (->> (svg.path/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
result2 (->> (svg.path.legacy/parse data)
|
||||
result2 (->> (svg.path.legacy2/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))]
|
||||
|
||||
|
@ -203,7 +221,7 @@
|
|||
result1 (->> (svg.path/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
result2 (->> (svg.path.legacy/parse data)
|
||||
result2 (->> (svg.path.legacy2/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))]
|
||||
|
||||
|
@ -256,7 +274,7 @@
|
|||
result1 (->> (svg.path/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
result2 (->> (svg.path.legacy/parse data)
|
||||
result2 (->> (svg.path.legacy2/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))]
|
||||
|
||||
|
@ -279,6 +297,61 @@
|
|||
(t/is (mth/close? v (get-in item2 [:params k]) 0.000000001))
|
||||
)))))
|
||||
|
||||
(t/deftest parse-test-6
|
||||
(let [data (str "M3.078 3.548v16.9a.5.5 0 0 0 1 0v-16.9a.5.5 0 0 0-1 0ZM18.422 11.5"
|
||||
"H7.582a2.5 2.5 0 0 1-2.5-2.5V6.565a2.5 2.5 0 0 1 2.5-2.5"
|
||||
"h10.84a2.5 2.5 0 0 1 2.5 2.5V9a2.5 2.5 0 0 1-2.5 2.5Z"
|
||||
"M7.582 5.065a1.5 1.5 0 0 0-1.5 1.5V9a1.5 1.5 0 0 0 1.5 1.5"
|
||||
"h10.84a1.5 1.5 0 0 0 1.5-1.5V6.565a1.5 1.5 0 0 0-1.5-1.5Z"
|
||||
"M13.451 19.938H7.582a2.5 2.5 0 0 1-2.5-2.5V15"
|
||||
"a2.5 2.5 0 0 1 2.5-2.5h5.869a2.5 2.5 0 0 1 2.5 2.5v2.436"
|
||||
"a2.5 2.5 0 0 1-2.5 2.502ZM7.582 13.5a1.5 1.5 0 0 0-1.5 1.5v2.436"
|
||||
"a1.5 1.5 0 0 0 1.5 1.5h5.869a1.5 1.5 0 0 0 1.5-1.5V15"
|
||||
"a1.5 1.5 0 0 0-1.5-1.5Z")
|
||||
|
||||
result1 (->> (svg.path/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))
|
||||
result2 (->> (svg.path.legacy2/parse data)
|
||||
(mapv (fn [entry]
|
||||
(update entry :params #(into (sorted-map) %)))))]
|
||||
|
||||
(t/is (= 47
|
||||
(count result1)
|
||||
(count result2)))
|
||||
|
||||
;; (pp/pprint result1 {:length 100})
|
||||
;; (pp/pprint result2 {:length 50})
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(let [item1 (nth result1 i)
|
||||
item2 (nth result2 i)
|
||||
]
|
||||
|
||||
(t/is (= (:command item1)
|
||||
(:command item2)))
|
||||
|
||||
(doseq [[k v] (:params item1)]
|
||||
(t/is (mth/close? v (get-in item2 [:params k]) 0.000000001))
|
||||
)))
|
||||
|
||||
#?(:cljs
|
||||
(let [result3 (svg.path.legacy1/parse data)]
|
||||
(t/is (= 47
|
||||
(count result1)
|
||||
(count result3)))
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(let [item1 (nth result1 i)
|
||||
item3 (nth result2 i)]
|
||||
|
||||
(t/is (= (:command item1)
|
||||
(:command item3)))
|
||||
|
||||
(t/is (= (:params item1)
|
||||
(:params item3)))))))))
|
||||
|
||||
|
||||
(t/deftest arc-to-bezier-1
|
||||
(let [expected1 [-1.6697754290362354e-13
|
||||
-5.258016244624741e-13
|
||||
|
@ -316,7 +389,7 @@
|
|||
(nth expected2 (+ i 2))
|
||||
0.0000000001))))
|
||||
|
||||
(let [[result1 result2 :as total] (svg.path.legacy/arc->beziers* 0 0 30 50 0 0 1 162.55 162.45)]
|
||||
(let [[result1 result2 :as total] (svg.path.legacy2/arc->beziers* 0 0 30 50 0 0 1 162.55 162.45)]
|
||||
(t/is (= (count total) 2))
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
|
@ -327,7 +400,96 @@
|
|||
(dotimes [i (count result2)]
|
||||
(t/is (mth/close? (nth result2 i)
|
||||
(nth expected2 i)
|
||||
0.000000000001))))))
|
||||
0.000000000001))))
|
||||
|
||||
#?(:cljs
|
||||
(let [[result1 result2 :as total] (svg.path.legacy1/arc->beziers* 0 0 30 50 0 0 1 162.55 162.45)]
|
||||
(t/is (= (count total) 2))
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(t/is (mth/close? (nth result1 i)
|
||||
(nth expected1 i)
|
||||
0.000000000001)))
|
||||
|
||||
(dotimes [i (count result2)]
|
||||
(t/is (mth/close? (nth result2 i)
|
||||
(nth expected2 i)
|
||||
0.000000000001)))))
|
||||
|
||||
))
|
||||
|
||||
(t/deftest arc-to-bezier-2
|
||||
(let [expected1 [3.0779999999999994,
|
||||
20.448,
|
||||
3.0780000082296834,
|
||||
20.724142369096132,
|
||||
3.3018576309038683,
|
||||
20.94799998509884,
|
||||
3.5779999999999994,
|
||||
20.94799998509884]
|
||||
|
||||
expected2 [3.5779999999999994,
|
||||
20.94799998509884,
|
||||
3.854142369096131,
|
||||
20.94799998509884,
|
||||
4.077999991770315,
|
||||
20.724142369096132,
|
||||
4.077999999999999,
|
||||
20.448]]
|
||||
|
||||
(let [[result1 result2 :as total] (->> (svg.path/arc->beziers 3.078 20.448 4.077999999999999 20.448 0 0 0.5 0.5 0)
|
||||
(mapv (fn [segment]
|
||||
(vec (.-params segment)))))]
|
||||
(t/is (= (count total) 2))
|
||||
;; (println "================" 11111111)
|
||||
;; (pp/pprint expected1 {:width 50})
|
||||
;; (println "------------")
|
||||
;; (pp/pprint result1 {:width 50})
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(t/is (mth/close? (nth result1 i)
|
||||
(nth expected1 (+ i 2))
|
||||
0.0000000001)))
|
||||
|
||||
(dotimes [i (count result2)]
|
||||
(t/is (mth/close? (nth result2 i)
|
||||
(nth expected2 (+ i 2))
|
||||
0.0000000001))))
|
||||
|
||||
(let [[result1 result2 :as total] (svg.path.legacy2/arc->beziers* 3.078 20.448 4.077999999999999 20.448 0 0 0.5 0.5 0)]
|
||||
(t/is (= (count total) 2))
|
||||
|
||||
;; (println "================" 11111111)
|
||||
;; (pp/pprint expected1 {:width 50})
|
||||
;; (println "------------")
|
||||
;; (pp/pprint (vec result1) {:width 50})
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(t/is (mth/close? (nth result1 i)
|
||||
(nth expected1 i)
|
||||
0.000000000001)))
|
||||
|
||||
(dotimes [i (count result2)]
|
||||
(t/is (mth/close? (nth result2 i)
|
||||
(nth expected2 i)
|
||||
0.000000000001))))
|
||||
|
||||
#?(:cljs
|
||||
(let [[result1 result2 :as total] (svg.path.legacy1/arc->beziers* 3.078 20.448 4.077999999999999 20.448 0 0 0.5 0.5 0)]
|
||||
(t/is (= (count total) 2))
|
||||
|
||||
(dotimes [i (count result1)]
|
||||
(t/is (mth/close? (nth result1 i)
|
||||
(nth expected1 i)
|
||||
0.000000000001)))
|
||||
|
||||
(dotimes [i (count result2)]
|
||||
(t/is (mth/close? (nth result2 i)
|
||||
(nth expected2 i)
|
||||
0.000000000001)))))
|
||||
|
||||
))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -357,14 +519,14 @@
|
|||
"59.9137 -301.293 -1.0595 -51.375 25.7186 -261.0492 -7.706 ")
|
||||
pattern [[:x :number] [:y :number]]]
|
||||
|
||||
(t/is (= expected (svg.path.legacy/extract-params cmdstr pattern)))))
|
||||
(t/is (= expected (svg.path.legacy2/extract-params cmdstr pattern)))))
|
||||
|
||||
(t/deftest extract-params-legacy-2
|
||||
(let [expected [{:x -994.563, :y 4564.1423 :r 0}]
|
||||
cmdstr (str "m -994.563 4564.1423 0")
|
||||
pattern [[:x :number] [:y :number] [:r :flag]]]
|
||||
|
||||
(t/is (= expected (svg.path.legacy/extract-params cmdstr pattern)))))
|
||||
(t/is (= expected (svg.path.legacy2/extract-params cmdstr pattern)))))
|
||||
|
||||
(t/deftest extract-params-legacy-3
|
||||
(let [cmdstr (str "a1.42 1.42 0 00-1.415-1.416 1.42 1.42 0 00-1.416 1.416 "
|
||||
|
@ -382,7 +544,7 @@
|
|||
[:sweep-flag :flag]
|
||||
[:x :number]
|
||||
[:y :number]]
|
||||
result (svg.path.legacy/extract-params cmdstr pattern)]
|
||||
result (svg.path.legacy2/extract-params cmdstr pattern)]
|
||||
|
||||
(t/is (= (nth result 0)
|
||||
(nth expected 0)))
|
||||
|
|
Loading…
Reference in a new issue