mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 23:28:12 +08:00
Initial working versions of decimate and vectorize
This commit is contained in:
Generated
+292
-31
@@ -33,12 +33,24 @@ dependencies = [
|
|||||||
"gimli",
|
"gimli",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler32"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.12"
|
version = "0.8.12"
|
||||||
@@ -124,6 +136,15 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.20"
|
version = "0.6.20"
|
||||||
@@ -405,6 +426,17 @@ version = "1.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.1.19",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -421,7 +453,7 @@ dependencies = [
|
|||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
"nom",
|
"nom",
|
||||||
"num-rational",
|
"num-rational 0.4.2",
|
||||||
"v_frame",
|
"v_frame",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -443,7 +475,7 @@ dependencies = [
|
|||||||
"addr2line",
|
"addr2line",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide 0.8.9",
|
||||||
"object",
|
"object",
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
@@ -470,9 +502,15 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bit-vec 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bit-vec"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -652,7 +690,7 @@ source = "git+https://github.com/rust-gpu/cargo-gpu?rev=f969528e87baa17a7d48eecf
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"clap",
|
"clap 4.5.46",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"directories",
|
"directories",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
@@ -814,6 +852,21 @@ dependencies = [
|
|||||||
"half",
|
"half",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.34.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"atty",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"strsim 0.8.0",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width 0.1.14",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.46"
|
version = "4.5.46"
|
||||||
@@ -833,7 +886,7 @@ dependencies = [
|
|||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"strsim",
|
"strsim 0.11.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -871,7 +924,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"unicode-width",
|
"unicode-width 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -930,7 +983,7 @@ dependencies = [
|
|||||||
"encode_unicode",
|
"encode_unicode",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"unicode-width",
|
"unicode-width 0.2.1",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1044,7 +1097,7 @@ dependencies = [
|
|||||||
"anes",
|
"anes",
|
||||||
"cast",
|
"cast",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
"clap",
|
"clap 4.5.46",
|
||||||
"criterion-plot",
|
"criterion-plot",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1161,6 +1214,16 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
|
checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deflate"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||||
|
dependencies = [
|
||||||
|
"adler32",
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1302,7 +1365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8de5f62da6c2850fd20cdefef7dd5389121869a88de8af3fda5a20bc849eafdd"
|
checksum = "8de5f62da6c2850fd20cdefef7dd5389121869a88de8af3fda5a20bc849eafdd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bzip2",
|
"bzip2",
|
||||||
"clap",
|
"clap 4.5.46",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"regex",
|
"regex",
|
||||||
"semver",
|
"semver",
|
||||||
@@ -1497,7 +1560,7 @@ dependencies = [
|
|||||||
"bit_field",
|
"bit_field",
|
||||||
"half",
|
"half",
|
||||||
"lebe",
|
"lebe",
|
||||||
"miniz_oxide",
|
"miniz_oxide 0.8.9",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"zune-inflate",
|
"zune-inflate",
|
||||||
@@ -1517,6 +1580,9 @@ name = "fastrand"
|
|||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
@@ -1562,7 +1628,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide",
|
"miniz_oxide 0.8.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flo_curves"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c227ffb4f98baa9073c033e23243089d0ed3dd1f5cd620894452074db48a29b"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.8.2",
|
||||||
|
"roots 0.0.6",
|
||||||
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1882,6 +1959,16 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gif"
|
||||||
|
version = "0.11.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
|
||||||
|
dependencies = [
|
||||||
|
"color_quant",
|
||||||
|
"weezl",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.13.3"
|
version = "0.13.3"
|
||||||
@@ -2060,7 +2147,7 @@ name = "graphene-cli"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap 4.5.46",
|
||||||
"fern",
|
"fern",
|
||||||
"futures",
|
"futures",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
@@ -2085,7 +2172,7 @@ dependencies = [
|
|||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-core-shaders",
|
"graphene-core-shaders",
|
||||||
"image",
|
"image 0.25.6",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
"log",
|
"log",
|
||||||
"lyon_geom",
|
"lyon_geom",
|
||||||
@@ -2103,6 +2190,8 @@ dependencies = [
|
|||||||
"specta",
|
"specta",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"visioncortex",
|
||||||
|
"vtracer",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2163,7 +2252,7 @@ dependencies = [
|
|||||||
"graphene-core",
|
"graphene-core",
|
||||||
"graphene-core-shaders",
|
"graphene-core-shaders",
|
||||||
"graphene-raster-nodes-shaders",
|
"graphene-raster-nodes-shaders",
|
||||||
"image",
|
"image 0.25.6",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
"node-macro",
|
"node-macro",
|
||||||
@@ -2209,7 +2298,7 @@ dependencies = [
|
|||||||
"graphene-path-bool",
|
"graphene-path-bool",
|
||||||
"graphene-raster-nodes",
|
"graphene-raster-nodes",
|
||||||
"graphene-svg-renderer",
|
"graphene-svg-renderer",
|
||||||
"image",
|
"image 0.25.6",
|
||||||
"log",
|
"log",
|
||||||
"node-macro",
|
"node-macro",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@@ -2287,7 +2376,7 @@ dependencies = [
|
|||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"graphite-editor",
|
"graphite-editor",
|
||||||
"image",
|
"image 0.25.6",
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.16",
|
"thiserror 2.0.16",
|
||||||
@@ -2311,7 +2400,7 @@ dependencies = [
|
|||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"graphite-proc-macros",
|
"graphite-proc-macros",
|
||||||
"image",
|
"image 0.25.6",
|
||||||
"interpreted-executor",
|
"interpreted-executor",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
@@ -2422,6 +2511,15 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -2740,6 +2838,25 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.23.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder",
|
||||||
|
"color_quant",
|
||||||
|
"gif 0.11.4",
|
||||||
|
"jpeg-decoder 0.1.22",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational 0.3.2",
|
||||||
|
"num-traits",
|
||||||
|
"png 0.16.8",
|
||||||
|
"scoped_threadpool",
|
||||||
|
"tiff 0.6.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.6"
|
version = "0.25.6"
|
||||||
@@ -2750,15 +2867,15 @@ dependencies = [
|
|||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"exr",
|
"exr",
|
||||||
"gif",
|
"gif 0.13.3",
|
||||||
"image-webp 0.2.4",
|
"image-webp 0.2.4",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png 0.17.16",
|
||||||
"qoi",
|
"qoi",
|
||||||
"ravif",
|
"ravif",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rgb",
|
"rgb",
|
||||||
"tiff",
|
"tiff 0.9.1",
|
||||||
"zune-core",
|
"zune-core",
|
||||||
"zune-jpeg",
|
"zune-jpeg",
|
||||||
]
|
]
|
||||||
@@ -2832,7 +2949,7 @@ checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"unicode-width",
|
"unicode-width 0.2.1",
|
||||||
"unit-prefix",
|
"unit-prefix",
|
||||||
"web-time",
|
"web-time",
|
||||||
]
|
]
|
||||||
@@ -2946,6 +3063,15 @@ version = "1.70.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -3026,6 +3152,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jpeg-decoder"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
|
||||||
|
dependencies = [
|
||||||
|
"rayon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "jpeg-decoder"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@@ -3329,6 +3464,25 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||||
|
dependencies = [
|
||||||
|
"adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
@@ -3577,6 +3731,28 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-rational"
|
name = "num-rational"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -3941,11 +4117,11 @@ dependencies = [
|
|||||||
"criterion",
|
"criterion",
|
||||||
"glam",
|
"glam",
|
||||||
"glob",
|
"glob",
|
||||||
"image",
|
"image 0.25.6",
|
||||||
"lyon_geom",
|
"lyon_geom",
|
||||||
"regex",
|
"regex",
|
||||||
"resvg",
|
"resvg",
|
||||||
"roots",
|
"roots 0.0.8",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -4124,6 +4300,18 @@ dependencies = [
|
|||||||
"plotters-backend",
|
"plotters-backend",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "png"
|
||||||
|
version = "0.16.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"crc32fast",
|
||||||
|
"deflate",
|
||||||
|
"miniz_oxide 0.3.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.16"
|
version = "0.17.16"
|
||||||
@@ -4134,7 +4322,7 @@ dependencies = [
|
|||||||
"crc32fast",
|
"crc32fast",
|
||||||
"fdeflate",
|
"fdeflate",
|
||||||
"flate2",
|
"flate2",
|
||||||
"miniz_oxide",
|
"miniz_oxide 0.8.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4145,7 +4333,7 @@ checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"hermit-abi",
|
"hermit-abi 0.5.2",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
@@ -4673,7 +4861,7 @@ version = "0.44.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a325d5e8d1cebddd070b13f44cec8071594ab67d1012797c121f27a669b7958"
|
checksum = "4a325d5e8d1cebddd070b13f44cec8071594ab67d1012797c121f27a669b7958"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gif",
|
"gif 0.13.3",
|
||||||
"image-webp 0.1.3",
|
"image-webp 0.1.3",
|
||||||
"log",
|
"log",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
@@ -4744,6 +4932,12 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roots"
|
||||||
|
version = "0.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84348444bd7ad45729d0c49a4240d7cdc11c9d512c06c5ad1835c1ad4acda6db"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roots"
|
name = "roots"
|
||||||
version = "0.0.8"
|
version = "0.0.8"
|
||||||
@@ -4941,6 +5135,12 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scoped_threadpool"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -5330,7 +5530,7 @@ version = "0.9.0"
|
|||||||
source = "git+https://github.com/rust-gpu/rust-gpu?rev=c12f216121820580731440ee79ebc7403d6ea04f#c12f216121820580731440ee79ebc7403d6ea04f"
|
source = "git+https://github.com/rust-gpu/rust-gpu?rev=c12f216121820580731440ee79ebc7403d6ea04f#c12f216121820580731440ee79ebc7403d6ea04f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"clap",
|
"clap 4.5.46",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"notify",
|
"notify",
|
||||||
@@ -5394,6 +5594,12 @@ dependencies = [
|
|||||||
"float-cmp",
|
"float-cmp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -5597,6 +5803,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width 0.1.14",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@@ -5646,6 +5861,17 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tiff"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437"
|
||||||
|
dependencies = [
|
||||||
|
"jpeg-decoder 0.1.22",
|
||||||
|
"miniz_oxide 0.4.4",
|
||||||
|
"weezl",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@@ -5653,7 +5879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder 0.3.2",
|
||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5699,7 +5925,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"log",
|
"log",
|
||||||
"png",
|
"png 0.17.16",
|
||||||
"tiny-skia-path",
|
"tiny-skia-path",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6090,6 +6316,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
|
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -6261,6 +6493,12 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vello"
|
name = "vello"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -6270,7 +6508,7 @@ dependencies = [
|
|||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"log",
|
"log",
|
||||||
"peniko",
|
"peniko",
|
||||||
"png",
|
"png 0.17.16",
|
||||||
"skrifa 0.31.3",
|
"skrifa 0.31.3",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"thiserror 2.0.16",
|
"thiserror 2.0.16",
|
||||||
@@ -6315,6 +6553,29 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "visioncortex"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dbe154fc281d74b2322adc18de7f9bbb9c4318d58ef6c201007f3fd99df9fff"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec 0.6.3",
|
||||||
|
"flo_curves",
|
||||||
|
"log",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vtracer"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "git+https://github.com/otdavies/vtracer?rev=31a8b270f6ff825955cf3af888eae6fbfd36e146#31a8b270f6ff825955cf3af888eae6fbfd36e146"
|
||||||
|
dependencies = [
|
||||||
|
"clap 2.34.0",
|
||||||
|
"fastrand",
|
||||||
|
"image 0.23.14",
|
||||||
|
"visioncortex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -6626,7 +6887,7 @@ checksum = "f7b882196f8368511d613c6aeec80655160db6646aebddf8328879a88d54e500"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"bit-vec",
|
"bit-vec 0.8.0",
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
|
|||||||
+13
-5
@@ -56,14 +56,17 @@ default-members = [
|
|||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
vtracer = { git = "https://github.com/otdavies/vtracer", rev = "31a8b270f6ff825955cf3af888eae6fbfd36e146" }
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
dyn-any = { path = "libraries/dyn-any", features = [
|
dyn-any = { path = "libraries/dyn-any", features = [
|
||||||
"derive",
|
"derive",
|
||||||
"glam",
|
"glam",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"log-bad-types",
|
"log-bad-types",
|
||||||
"rc",
|
"rc",
|
||||||
] }
|
] }
|
||||||
preprocessor = { path = "node-graph/preprocessor" }
|
preprocessor = { path = "node-graph/preprocessor" }
|
||||||
math-parser = { path = "libraries/math-parser" }
|
math-parser = { path = "libraries/math-parser" }
|
||||||
@@ -195,9 +198,14 @@ open = "5.3"
|
|||||||
poly-cool = "0.3"
|
poly-cool = "0.3"
|
||||||
spin = "0.10"
|
spin = "0.10"
|
||||||
clap = "4.5"
|
clap = "4.5"
|
||||||
|
# Set compile type to rlib for wasm compatibility
|
||||||
|
visioncortex = { version = "0.8.8" }
|
||||||
|
vtracer = { version = "0.6.4" }
|
||||||
spirv-std = { git = "https://github.com/rust-gpu/rust-gpu", rev = "c12f216121820580731440ee79ebc7403d6ea04f", features = ["bytemuck"] }
|
spirv-std = { git = "https://github.com/rust-gpu/rust-gpu", rev = "c12f216121820580731440ee79ebc7403d6ea04f", features = ["bytemuck"] }
|
||||||
cargo-gpu = { git = "https://github.com/rust-gpu/cargo-gpu", rev = "f969528e87baa17a7d48eecf4a6fcfdcaaf30566" }
|
cargo-gpu = { git = "https://github.com/rust-gpu/cargo-gpu", rev = "f969528e87baa17a7d48eecf4a6fcfdcaaf30566" }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[workspace.lints.rust]
|
[workspace.lints.rust]
|
||||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] }
|
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] }
|
||||||
|
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ pub(crate) fn property_from_type(
|
|||||||
Some(x) if x == TypeId::of::<StrokeAlign>() => enum_choice::<StrokeAlign>().for_socket(default_info).property_row(),
|
Some(x) if x == TypeId::of::<StrokeAlign>() => enum_choice::<StrokeAlign>().for_socket(default_info).property_row(),
|
||||||
Some(x) if x == TypeId::of::<PaintOrder>() => enum_choice::<PaintOrder>().for_socket(default_info).property_row(),
|
Some(x) if x == TypeId::of::<PaintOrder>() => enum_choice::<PaintOrder>().for_socket(default_info).property_row(),
|
||||||
Some(x) if x == TypeId::of::<ArcType>() => enum_choice::<ArcType>().for_socket(default_info).property_row(),
|
Some(x) if x == TypeId::of::<ArcType>() => enum_choice::<ArcType>().for_socket(default_info).property_row(),
|
||||||
|
// Add here
|
||||||
Some(x) if x == TypeId::of::<TextAlign>() => enum_choice::<TextAlign>().for_socket(default_info).property_row(),
|
Some(x) if x == TypeId::of::<TextAlign>() => enum_choice::<TextAlign>().for_socket(default_info).property_row(),
|
||||||
Some(x) if x == TypeId::of::<MergeByDistanceAlgorithm>() => enum_choice::<MergeByDistanceAlgorithm>().for_socket(default_info).property_row(),
|
Some(x) if x == TypeId::of::<MergeByDistanceAlgorithm>() => enum_choice::<MergeByDistanceAlgorithm>().for_socket(default_info).property_row(),
|
||||||
Some(x) if x == TypeId::of::<PointSpacingType>() => enum_choice::<PointSpacingType>().for_socket(default_info).property_row(),
|
Some(x) if x == TypeId::of::<PointSpacingType>() => enum_choice::<PointSpacingType>().for_socket(default_info).property_row(),
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ lyon_geom = { workspace = true }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
base64 = { workspace = true }
|
base64 = { workspace = true }
|
||||||
poly-cool = { workspace = true }
|
poly-cool = { workspace = true }
|
||||||
|
vtracer = { workspace = true }
|
||||||
|
visioncortex = { workspace = true }
|
||||||
|
|
||||||
# Optional workspace dependencies
|
# Optional workspace dependencies
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use glam::DVec2;
|
||||||
|
|
||||||
|
/// Implements the Ramer-Douglas-Peucker algorithm to find indices of points to keep.
|
||||||
|
pub fn ramer_douglas_peucker(points: &[DVec2], epsilon: f64) -> Vec<usize> {
|
||||||
|
if points.len() <= 2 {
|
||||||
|
return (0..points.len()).collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut kept_indices = Vec::new();
|
||||||
|
rdp_recursive(points, 0, points.len() - 1, epsilon, &mut kept_indices);
|
||||||
|
kept_indices.sort_unstable();
|
||||||
|
kept_indices.dedup();
|
||||||
|
kept_indices
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rdp_recursive(points: &[DVec2], start_idx: usize, end_idx: usize, epsilon: f64, kept_indices: &mut Vec<usize>) {
|
||||||
|
if start_idx >= end_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dmax = 0.0;
|
||||||
|
let mut index = start_idx;
|
||||||
|
|
||||||
|
// Find the point with maximum perpendicular distance from the line segment
|
||||||
|
for i in (start_idx + 1)..end_idx {
|
||||||
|
let d = perpendicular_distance(points[i], points[start_idx], points[end_idx]);
|
||||||
|
if d > dmax {
|
||||||
|
index = i;
|
||||||
|
dmax = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If max distance is greater than epsilon, recursively simplify
|
||||||
|
if dmax > epsilon {
|
||||||
|
rdp_recursive(points, start_idx, index, epsilon, kept_indices);
|
||||||
|
rdp_recursive(points, index, end_idx, epsilon, kept_indices);
|
||||||
|
} else {
|
||||||
|
// Keep only the endpoints
|
||||||
|
kept_indices.push(start_idx);
|
||||||
|
kept_indices.push(end_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the perpendicular distance from a point to a line defined by two endpoints.
|
||||||
|
pub fn perpendicular_distance(point: DVec2, line_start: DVec2, line_end: DVec2) -> f64 {
|
||||||
|
let dx = line_end.x - line_start.x;
|
||||||
|
let dy = line_end.y - line_start.y;
|
||||||
|
|
||||||
|
let line_length_squared = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
// If the line segment is actually a point, return the distance to that point
|
||||||
|
if line_length_squared == 0.0 {
|
||||||
|
return point.distance(line_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate perpendicular distance using the cross product formula:
|
||||||
|
// distance = |dy·px - dx·py + x2·y1 - y2·x1| / √(dx² + dy²)
|
||||||
|
let numerator = (dy * point.x - dx * point.y + line_end.x * line_start.y - line_end.y * line_start.x).abs();
|
||||||
|
let denominator = line_length_squared.sqrt();
|
||||||
|
|
||||||
|
numerator / denominator
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
pub mod bezpath_algorithms;
|
pub mod bezpath_algorithms;
|
||||||
mod contants;
|
mod contants;
|
||||||
|
pub mod decimation;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
pub mod intersection;
|
pub mod intersection;
|
||||||
pub mod merge_by_distance;
|
pub mod merge_by_distance;
|
||||||
@@ -7,3 +8,4 @@ pub mod offset_subpath;
|
|||||||
pub mod poisson_disk;
|
pub mod poisson_disk;
|
||||||
pub mod spline;
|
pub mod spline;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
pub mod vectorize;
|
||||||
|
|||||||
@@ -0,0 +1,357 @@
|
|||||||
|
use crate::{
|
||||||
|
Graphic,
|
||||||
|
raster_types::{CPU, Raster},
|
||||||
|
table::{Table, TableRow, TableRowRef},
|
||||||
|
vector::Vector,
|
||||||
|
vector::VectorExt,
|
||||||
|
vector::style::Fill,
|
||||||
|
};
|
||||||
|
use glam::{DAffine2, DVec2};
|
||||||
|
use graphene_core_shaders::color::Color;
|
||||||
|
use kurbo::{BezPath, PathEl};
|
||||||
|
use visioncortex::PathSimplifyMode;
|
||||||
|
use vtracer::{ColorMode, Config, Hierarchical};
|
||||||
|
|
||||||
|
/// Parses SVG path data and appends it to a Vector
|
||||||
|
pub fn parse_svg_paths_to_vector(svg_content: &str) -> Vec<TableRow<Vector>> {
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
|
||||||
|
for element in extract_path_elements(svg_content) {
|
||||||
|
let attributes = parse_path_attributes(&element);
|
||||||
|
let Some(path_data) = attribute_value(&attributes, "d") else { continue };
|
||||||
|
let Ok(bezpath) = BezPath::from_svg(path_data) else { continue };
|
||||||
|
|
||||||
|
let fill = parse_fill_attribute(attribute_value(&attributes, "fill"));
|
||||||
|
let transform = parse_transform_attribute(attribute_value(&attributes, "transform"));
|
||||||
|
|
||||||
|
for subpath in split_bezpath_subpaths(&bezpath) {
|
||||||
|
if subpath.elements().is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut vector = Vector::default();
|
||||||
|
vector.append_bezpath(subpath);
|
||||||
|
vector.style.set_fill(fill.clone());
|
||||||
|
|
||||||
|
let mut table_row = TableRow::new_from_element(vector);
|
||||||
|
table_row.transform = transform;
|
||||||
|
rows.push(table_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split_bezpath_subpaths(bezpath: &BezPath) -> Vec<BezPath> {
|
||||||
|
let mut subpaths = Vec::new();
|
||||||
|
let mut current = BezPath::new();
|
||||||
|
|
||||||
|
for element in bezpath.elements() {
|
||||||
|
match element {
|
||||||
|
PathEl::MoveTo(_) => {
|
||||||
|
if !current.is_empty() {
|
||||||
|
subpaths.push(std::mem::take(&mut current));
|
||||||
|
}
|
||||||
|
current.push(*element);
|
||||||
|
}
|
||||||
|
PathEl::ClosePath => {
|
||||||
|
current.close_path();
|
||||||
|
subpaths.push(std::mem::take(&mut current));
|
||||||
|
}
|
||||||
|
_ => current.push(*element),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !current.is_empty() {
|
||||||
|
subpaths.push(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
subpaths
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_path_elements(svg_content: &str) -> Vec<String> {
|
||||||
|
let mut elements = Vec::new();
|
||||||
|
let mut search_start = 0;
|
||||||
|
|
||||||
|
while let Some(relative_start) = svg_content[search_start..].find("<path") {
|
||||||
|
let start = search_start + relative_start;
|
||||||
|
let mut index = start + "<path".len();
|
||||||
|
let mut in_quotes = false;
|
||||||
|
let mut quote_char = '\0';
|
||||||
|
|
||||||
|
while index < svg_content.len() {
|
||||||
|
let ch = svg_content.as_bytes()[index] as char;
|
||||||
|
|
||||||
|
match ch {
|
||||||
|
'"' | '\'' if !in_quotes => {
|
||||||
|
in_quotes = true;
|
||||||
|
quote_char = ch;
|
||||||
|
}
|
||||||
|
c if c == quote_char && in_quotes => {
|
||||||
|
in_quotes = false;
|
||||||
|
}
|
||||||
|
'>' if !in_quotes => {
|
||||||
|
elements.push(svg_content[start..=index].to_string());
|
||||||
|
search_start = index + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if index >= svg_content.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_attribute_name_char(ch: char) -> bool {
|
||||||
|
ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | ':' | '.')
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_path_attributes(element: &str) -> Vec<(String, String)> {
|
||||||
|
let mut attributes = Vec::new();
|
||||||
|
let mut body = element.trim();
|
||||||
|
|
||||||
|
if let Some(start) = body.find("<path") {
|
||||||
|
body = &body[start + "<path".len()..];
|
||||||
|
} else {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(end) = body.rfind('>') {
|
||||||
|
body = &body[..end];
|
||||||
|
}
|
||||||
|
|
||||||
|
body = body.trim();
|
||||||
|
if let Some(stripped) = body.strip_suffix('/') {
|
||||||
|
body = stripped.trim_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = body.as_bytes();
|
||||||
|
let mut index = 0;
|
||||||
|
|
||||||
|
while index < bytes.len() {
|
||||||
|
while index < bytes.len() && bytes[index].is_ascii_whitespace() {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if index >= bytes.len() || bytes[index] == b'/' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name_start = index;
|
||||||
|
while index < bytes.len() && is_attribute_name_char(body.as_bytes()[index] as char) {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if name_start == index {
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = body[name_start..index].trim();
|
||||||
|
|
||||||
|
while index < bytes.len() && bytes[index].is_ascii_whitespace() {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if index >= bytes.len() || bytes[index] != b'=' {
|
||||||
|
while index < bytes.len() && !bytes[index].is_ascii_whitespace() && bytes[index] != b'/' {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
while index < bytes.len() && bytes[index].is_ascii_whitespace() {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if index >= bytes.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut value = String::new();
|
||||||
|
|
||||||
|
if bytes[index] == b'"' || bytes[index] == b'\'' {
|
||||||
|
let quote = bytes[index];
|
||||||
|
index += 1;
|
||||||
|
let value_start = index;
|
||||||
|
|
||||||
|
while index < bytes.len() && bytes[index] != quote {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
value.push_str(body[value_start..index.min(bytes.len())].trim());
|
||||||
|
if index < bytes.len() {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let value_start = index;
|
||||||
|
while index < bytes.len() && !bytes[index].is_ascii_whitespace() && bytes[index] != b'/' {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
value.push_str(body[value_start..index].trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes.push((name.to_string(), value));
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attribute_value<'a>(attributes: &'a [(String, String)], name: &str) -> Option<&'a str> {
|
||||||
|
attributes.iter().find_map(|(key, value)| (key == name).then_some(value.as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_fill_attribute(value: Option<&str>) -> Fill {
|
||||||
|
let Some(value) = value.map(str::trim) else {
|
||||||
|
return Fill::None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if value.eq_ignore_ascii_case("none") {
|
||||||
|
return Fill::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(hex) = value.strip_prefix('#') {
|
||||||
|
if let Some(color) = Color::from_rgb_str(hex) {
|
||||||
|
return Fill::Solid(color);
|
||||||
|
}
|
||||||
|
} else if let Some(color) = Color::from_rgb_str(value) {
|
||||||
|
return Fill::Solid(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fill::None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_from_function(name: &str, arguments: &[f64]) -> DAffine2 {
|
||||||
|
match name {
|
||||||
|
"translate" => match arguments.len() {
|
||||||
|
0 => DAffine2::IDENTITY,
|
||||||
|
1 => DAffine2::from_translation(DVec2::new(arguments[0], 0.)),
|
||||||
|
_ => DAffine2::from_translation(DVec2::new(arguments[0], arguments[1])),
|
||||||
|
},
|
||||||
|
"scale" => match arguments.len() {
|
||||||
|
0 => DAffine2::IDENTITY,
|
||||||
|
1 => DAffine2::from_scale(DVec2::splat(arguments[0])),
|
||||||
|
_ => DAffine2::from_scale(DVec2::new(arguments[0], arguments[1])),
|
||||||
|
},
|
||||||
|
"rotate" => {
|
||||||
|
if arguments.is_empty() {
|
||||||
|
return DAffine2::IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
let angle = arguments[0].to_radians();
|
||||||
|
if arguments.len() >= 3 {
|
||||||
|
let center = DVec2::new(arguments[1], arguments[2]);
|
||||||
|
DAffine2::from_translation(center) * DAffine2::from_angle(angle) * DAffine2::from_translation(-center)
|
||||||
|
} else {
|
||||||
|
DAffine2::from_angle(angle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"matrix" if arguments.len() == 6 => DAffine2::from_cols_array(&[arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]]),
|
||||||
|
_ => DAffine2::IDENTITY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_transform_attribute(value: Option<&str>) -> DAffine2 {
|
||||||
|
let Some(value) = value.map(str::trim) else {
|
||||||
|
return DAffine2::IDENTITY;
|
||||||
|
};
|
||||||
|
let mut transform = DAffine2::IDENTITY;
|
||||||
|
let mut remaining = value;
|
||||||
|
|
||||||
|
while let Some(open_paren) = remaining.find('(') {
|
||||||
|
let (name_part, after_name) = remaining.split_at(open_paren);
|
||||||
|
let name = name_part.trim();
|
||||||
|
let after_name = &after_name[1..];
|
||||||
|
|
||||||
|
if let Some(close_paren) = after_name.find(')') {
|
||||||
|
let arguments = after_name[..close_paren]
|
||||||
|
.split(|c| matches!(c, ',' | ' ' | '\t'))
|
||||||
|
.filter_map(|token| {
|
||||||
|
let trimmed = token.trim();
|
||||||
|
if trimmed.is_empty() { None } else { trimmed.parse::<f64>().ok() }
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
transform = transform * transform_from_function(name, &arguments);
|
||||||
|
remaining = &after_name[close_paren + 1..];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transform
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color_mode_from_u32(value: u32) -> ColorMode {
|
||||||
|
match value {
|
||||||
|
0 => ColorMode::Color,
|
||||||
|
1 => ColorMode::Binary,
|
||||||
|
_ => ColorMode::Color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hierarchical_from_u32(value: u32) -> Hierarchical {
|
||||||
|
match value {
|
||||||
|
0 => Hierarchical::Stacked,
|
||||||
|
1 => Hierarchical::Cutout,
|
||||||
|
_ => Hierarchical::Stacked,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn simplify_mode_from_u32(value: u32) -> PathSimplifyMode {
|
||||||
|
match value {
|
||||||
|
0 => PathSimplifyMode::None,
|
||||||
|
1 => PathSimplifyMode::Polygon,
|
||||||
|
2 => PathSimplifyMode::Spline,
|
||||||
|
_ => PathSimplifyMode::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_vectorize_config(
|
||||||
|
color_mode: u32,
|
||||||
|
hierarchical: u32,
|
||||||
|
path_simplify_mode: u32,
|
||||||
|
filter_speckle: u32,
|
||||||
|
color_precision: u32,
|
||||||
|
layer_difference: u32,
|
||||||
|
corner_threshold: f32,
|
||||||
|
length_threshold: f64,
|
||||||
|
max_iterations: u32,
|
||||||
|
splice_threshold: f32,
|
||||||
|
path_precision: u32,
|
||||||
|
) -> Config {
|
||||||
|
Config {
|
||||||
|
color_mode: color_mode_from_u32(color_mode),
|
||||||
|
hierarchical: hierarchical_from_u32(hierarchical),
|
||||||
|
mode: simplify_mode_from_u32(path_simplify_mode),
|
||||||
|
filter_speckle: filter_speckle as usize,
|
||||||
|
color_precision: color_precision as i32,
|
||||||
|
layer_difference: layer_difference as i32,
|
||||||
|
corner_threshold: corner_threshold as i32,
|
||||||
|
length_threshold,
|
||||||
|
max_iterations: max_iterations as usize,
|
||||||
|
splice_threshold: splice_threshold as i32,
|
||||||
|
path_precision: Some(path_precision),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vector_row_to_graphic_row(mut vector_row: TableRow<Vector>, source_row: &TableRowRef<'_, Raster<CPU>>) -> TableRow<Graphic> {
|
||||||
|
vector_row.transform = *source_row.transform * vector_row.transform;
|
||||||
|
vector_row.alpha_blending = source_row.alpha_blending.clone();
|
||||||
|
vector_row.source_node_id = source_row.source_node_id.clone();
|
||||||
|
|
||||||
|
TableRow {
|
||||||
|
element: Graphic::Vector(Table::new_from_row(vector_row)),
|
||||||
|
transform: DAffine2::IDENTITY,
|
||||||
|
alpha_blending: Default::default(),
|
||||||
|
source_node_id: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,6 +74,8 @@ pub enum ArcType {
|
|||||||
PieSlice,
|
PieSlice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add enum here (widget Dropdown vs Radio)
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
|
||||||
#[widget(Radio)]
|
#[widget(Radio)]
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ use crate::table::{Table, TableRow, TableRowMut};
|
|||||||
use crate::transform::{Footprint, ReferencePoint, Transform};
|
use crate::transform::{Footprint, ReferencePoint, Transform};
|
||||||
use crate::vector::PointDomain;
|
use crate::vector::PointDomain;
|
||||||
use crate::vector::algorithms::bezpath_algorithms::eval_pathseg_euclidean;
|
use crate::vector::algorithms::bezpath_algorithms::eval_pathseg_euclidean;
|
||||||
|
use crate::vector::algorithms::decimation::ramer_douglas_peucker;
|
||||||
use crate::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
use crate::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
||||||
|
use crate::vector::algorithms::vectorize::{build_vectorize_config, parse_svg_paths_to_vector, vector_row_to_graphic_row};
|
||||||
use crate::vector::misc::{MergeByDistanceAlgorithm, PointSpacingType, is_linear};
|
use crate::vector::misc::{MergeByDistanceAlgorithm, PointSpacingType, is_linear};
|
||||||
use crate::vector::misc::{handles_to_segment, segment_to_handles};
|
use crate::vector::misc::{handles_to_segment, segment_to_handles};
|
||||||
use crate::vector::style::{PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
use crate::vector::style::{PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
@@ -202,6 +204,177 @@ where
|
|||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[node_macro::node(category("Raster: Filter"), path(graphene_core::vector))]
|
||||||
|
async fn vectorize(
|
||||||
|
_: impl Ctx,
|
||||||
|
image: Table<Raster<CPU>>,
|
||||||
|
color_mode: u32,
|
||||||
|
hierarchical: u32,
|
||||||
|
path_simplify_mode: u32,
|
||||||
|
#[default(4)]
|
||||||
|
#[hard_min(1.)]
|
||||||
|
filter_speckle: u32,
|
||||||
|
#[default(6)]
|
||||||
|
#[hard_min(1.)]
|
||||||
|
#[hard_max(8.)]
|
||||||
|
color_precision: u32,
|
||||||
|
#[default(16)]
|
||||||
|
#[hard_min(0.)]
|
||||||
|
#[hard_max(255.)]
|
||||||
|
layer_difference: u32,
|
||||||
|
#[default(60)]
|
||||||
|
#[hard_min(0.)]
|
||||||
|
#[hard_max(180.)]
|
||||||
|
corner_threshold: f32,
|
||||||
|
#[default(4.)]
|
||||||
|
#[hard_min(3.5)]
|
||||||
|
length_threshold: f64,
|
||||||
|
#[default(10)]
|
||||||
|
#[hard_min(1.)]
|
||||||
|
max_iterations: u32,
|
||||||
|
#[default(45)]
|
||||||
|
#[hard_min(0.)]
|
||||||
|
#[hard_max(180.)]
|
||||||
|
splice_threshold: f32,
|
||||||
|
#[default(8)]
|
||||||
|
#[hard_min(0.)]
|
||||||
|
path_precision: u32,
|
||||||
|
) -> Table<Graphic> {
|
||||||
|
let mut result_table = Table::new();
|
||||||
|
|
||||||
|
for row in image.iter() {
|
||||||
|
let raster = &row.element;
|
||||||
|
|
||||||
|
if raster.width == 0 || raster.height == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (pixel_data, width, height) = raster.to_flat_u8();
|
||||||
|
let color_image = vtracer::ColorImage {
|
||||||
|
pixels: pixel_data,
|
||||||
|
width: width as usize,
|
||||||
|
height: height as usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = build_vectorize_config(
|
||||||
|
color_mode,
|
||||||
|
hierarchical,
|
||||||
|
path_simplify_mode,
|
||||||
|
filter_speckle,
|
||||||
|
color_precision,
|
||||||
|
layer_difference,
|
||||||
|
corner_threshold,
|
||||||
|
length_threshold,
|
||||||
|
max_iterations,
|
||||||
|
splice_threshold,
|
||||||
|
path_precision,
|
||||||
|
);
|
||||||
|
|
||||||
|
match vtracer::convert(color_image, config) {
|
||||||
|
Ok(svg_file) => {
|
||||||
|
let svg_content = svg_file.to_string();
|
||||||
|
log::trace!("Generated SVG content:\n{}", svg_content);
|
||||||
|
|
||||||
|
let vector_rows = parse_svg_paths_to_vector(&svg_content);
|
||||||
|
|
||||||
|
let mut graphic_table = Table::new();
|
||||||
|
for vector_row in vector_rows {
|
||||||
|
graphic_table.push(vector_row_to_graphic_row(vector_row, &row));
|
||||||
|
}
|
||||||
|
|
||||||
|
let graphic_group = Graphic::Graphic(graphic_table);
|
||||||
|
let mut graphic_row = TableRow::new_from_element(graphic_group);
|
||||||
|
graphic_row.transform = *row.transform;
|
||||||
|
graphic_row.alpha_blending = *row.alpha_blending;
|
||||||
|
graphic_row.source_node_id = *row.source_node_id;
|
||||||
|
result_table.push(graphic_row);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Vectorization failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result_table
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simplifies vector paths using the Ramer-Douglas-Peucker algorithm for line decimation.
|
||||||
|
/// Reduces the number of points in a path while preserving its overall shape within a specified tolerance.
|
||||||
|
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))]
|
||||||
|
fn decimate(
|
||||||
|
_: impl Ctx,
|
||||||
|
source: Table<Vector>,
|
||||||
|
#[default(0.1)]
|
||||||
|
#[hard_min(0.001)]
|
||||||
|
tolerance: f64,
|
||||||
|
) -> Table<Vector> {
|
||||||
|
use crate::vector::misc::{dvec2_to_point, point_to_dvec2};
|
||||||
|
use kurbo::Affine;
|
||||||
|
|
||||||
|
source
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| {
|
||||||
|
let transform = Affine::new(row.transform.to_cols_array());
|
||||||
|
let vector = row.element;
|
||||||
|
|
||||||
|
let mut new_vector = Vector {
|
||||||
|
style: vector.style.clone(),
|
||||||
|
upstream_nested_layers: vector.upstream_nested_layers.clone(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process each bezpath in the vector
|
||||||
|
for mut bezpath in vector.stroke_bezpath_iter() {
|
||||||
|
// Apply transform to work in world space for accurate distance calculations
|
||||||
|
bezpath.apply_affine(transform);
|
||||||
|
|
||||||
|
// Extract anchor points from the bezpath
|
||||||
|
let anchors: Vec<DVec2> = bezpath.segments().map(|seg| point_to_dvec2(seg.start())).collect();
|
||||||
|
|
||||||
|
// Handle the last point if the path isn't closed
|
||||||
|
let is_closed = bezpath.elements().last() == Some(&kurbo::PathEl::ClosePath);
|
||||||
|
let mut all_anchors = anchors;
|
||||||
|
if !is_closed {
|
||||||
|
if let Some(last_seg) = bezpath.segments().last() {
|
||||||
|
all_anchors.push(point_to_dvec2(last_seg.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if all_anchors.len() <= 2 {
|
||||||
|
// Can't simplify paths with 2 or fewer points
|
||||||
|
bezpath.apply_affine(transform.inverse());
|
||||||
|
new_vector.append_bezpath(bezpath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply RDP algorithm
|
||||||
|
let simplified_indices = ramer_douglas_peucker(&all_anchors, tolerance);
|
||||||
|
|
||||||
|
// Build new bezpath from simplified points
|
||||||
|
let mut simplified_bezpath = kurbo::BezPath::new();
|
||||||
|
if let Some(&first_idx) = simplified_indices.first() {
|
||||||
|
simplified_bezpath.move_to(dvec2_to_point(all_anchors[first_idx]));
|
||||||
|
|
||||||
|
for &idx in simplified_indices.iter().skip(1) {
|
||||||
|
simplified_bezpath.line_to(dvec2_to_point(all_anchors[idx]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the path if the original was closed and we have enough points
|
||||||
|
if is_closed && simplified_indices.len() > 2 {
|
||||||
|
simplified_bezpath.close_path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform back to local space
|
||||||
|
simplified_bezpath.apply_affine(transform.inverse());
|
||||||
|
new_vector.append_bezpath(simplified_bezpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableRow { element: new_vector, ..row }
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[node_macro::node(category("Instancing"), path(graphene_core::vector))]
|
#[node_macro::node(category("Instancing"), path(graphene_core::vector))]
|
||||||
async fn repeat<I: 'n + Send + Clone>(
|
async fn repeat<I: 'n + Send + Clone>(
|
||||||
_: impl Ctx,
|
_: impl Ctx,
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ tagged_value! {
|
|||||||
SelectiveColorChoice(graphene_raster_nodes::adjustments::SelectiveColorChoice),
|
SelectiveColorChoice(graphene_raster_nodes::adjustments::SelectiveColorChoice),
|
||||||
GridType(graphene_core::vector::misc::GridType),
|
GridType(graphene_core::vector::misc::GridType),
|
||||||
ArcType(graphene_core::vector::misc::ArcType),
|
ArcType(graphene_core::vector::misc::ArcType),
|
||||||
|
// Add here
|
||||||
MergeByDistanceAlgorithm(graphene_core::vector::misc::MergeByDistanceAlgorithm),
|
MergeByDistanceAlgorithm(graphene_core::vector::misc::MergeByDistanceAlgorithm),
|
||||||
PointSpacingType(graphene_core::vector::misc::PointSpacingType),
|
PointSpacingType(graphene_core::vector::misc::PointSpacingType),
|
||||||
SpiralType(graphene_core::vector::misc::SpiralType),
|
SpiralType(graphene_core::vector::misc::SpiralType),
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::SelectiveColorChoice]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::SelectiveColorChoice]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::GridType]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::GridType]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::ArcType]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::ArcType]),
|
||||||
|
// Add here
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::MergeByDistanceAlgorithm]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::MergeByDistanceAlgorithm]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::PointSpacingType]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::PointSpacingType]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::FillType]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::FillType]),
|
||||||
@@ -217,6 +218,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::SelectiveColorChoice]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::SelectiveColorChoice]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::GridType]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::GridType]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::ArcType]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::ArcType]),
|
||||||
|
// add here
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::MergeByDistanceAlgorithm]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::MergeByDistanceAlgorithm]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::PointSpacingType]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::PointSpacingType]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
||||||
|
|||||||
Reference in New Issue
Block a user