alpha
Login
or
Join now
gwen.works
/
shapemaker
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
This repository has no description
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
♻️ Construct our own SVG trees (#61)
author
Gwenn Le Bihan
committer
GitHub
date
8 months ago
(Oct 24, 2025, 1:12 AM +0200)
commit
edbe6fbd
edbe6fbddfccf9cc428ecb7e8a2e86b7c2e5bf78
parent
06bf9780
06bf978074a0452b09baaf7f2783397b9ccf972e
+783
-616
15 changed files
Expand all
Collapse all
Unified
Split
Cargo.lock
Cargo.toml
examples
dna-analysis-machine
src
snapshots
dna_analysis_machine__artwork.snap
specimen
src
snapshots
specimen__colors_shed.snap
specimen__grid.snap
specimen__shapes_shed.snap
src
graphics
fill.rs
objects.rs
rendering
canvas.rs
filter.rs
layer.rs
mod.rs
objects.rs
renderable.rs
svg.rs
+1
-7
Cargo.lock
Reviewed
···
4573
4573
"ndarray",
4574
4574
"nih_plug",
4575
4575
"once_cell",
4576
4576
+
"quick-xml",
4576
4577
"rand 0.9.2",
4577
4578
"rayon",
4578
4579
"resvg",
···
4584
4585
"slug",
4585
4586
"strum",
4586
4587
"strum_macros",
4587
4587
-
"svg",
4588
4588
"tiny-skia",
4589
4589
"tokio",
4590
4590
"toml 0.9.8",
···
4812
4812
version = "3.0.0"
4813
4813
source = "registry+https://github.com/rust-lang/crates.io-index"
4814
4814
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
4815
4815
-
4816
4816
-
[[package]]
4817
4817
-
name = "svg"
4818
4818
-
version = "0.18.0"
4819
4819
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4820
4820
-
checksum = "94afda9cd163c04f6bee8b4bf2501c91548deae308373c436f36aeff3cf3c4a3"
4821
4815
4822
4816
[[package]]
4823
4817
name = "svgtypes"
+1
-1
Cargo.toml
Reviewed
···
68
68
] }
69
69
serde_cbor = "0.11.2"
70
70
serde_json = "1.0.145"
71
71
-
svg = "0.18.0"
72
71
wasm-bindgen = { version = "0.2.104", optional = true }
73
72
getrandom = { version = "0.2", features = ["js"] }
74
73
web-sys = { version = "0.3.81", optional = true, features = [
···
107
106
url = "2.5.7"
108
107
tungstenite = { version = "0.28.0", optional = true }
109
108
axum = { version = "0.8.6", optional = true, features = ["json"] }
109
109
+
quick-xml = "0.38.3"
110
110
111
111
112
112
[dev-dependencies]
+193
-320
examples/dna-analysis-machine/src/snapshots/dna_analysis_machine__artwork.snap
Reviewed
···
5
5
<svg height="470" viewBox="-10 -10 820 470" width="820" xmlns="http://www.w3.org/2000/svg">
6
6
<rect fill="#000000" height="470" width="820" x="-10" y="-10"/>
7
7
<g class="layer" data-layer="hatches">
8
8
-
<rect data-object="hatches--anon-0" height="50" style="fill: url(#pattern-hatched-45deg-white-0.5-0.25);" width="50" x="50" y="50"/>
9
9
-
<rect data-object="hatches--anon-1" height="50" style="fill: url(#pattern-hatched-45deg-white-0.6-0.25);" width="50" x="100" y="50"/>
8
8
+
<rect data-object="hatches--anon-0" height="50" width="50" x="50" y="50" style="fill: url(#pattern-hatched-45deg-white-0.5-0.25);"/>
9
9
+
<rect data-object="hatches--anon-1" height="50" width="50" x="100" y="50" style="fill: url(#pattern-hatched-45deg-white-0.6-0.25);"/>
10
10
<circle cx="575" cy="75" data-object="hatches--anon-10" r="25" style="fill: url(#pattern-hatched-45deg-white-1.5-0.25);"/>
11
11
<circle cx="625" cy="75" data-object="hatches--anon-11" r="25" style="fill: url(#pattern-hatched-45deg-white-1.6-0.25);"/>
12
12
-
<rect data-object="hatches--anon-12" height="50" style="fill: url(#pattern-hatched-45deg-white-1.7-0.25);" width="50" x="650" y="50"/>
13
13
-
<rect data-object="hatches--anon-13" height="50" style="fill: url(#pattern-hatched-45deg-white-1.8-0.25);" width="50" x="700" y="50"/>
14
14
-
<rect data-object="hatches--anon-14" height="50" style="fill: url(#pattern-hatched-45deg-white-1.9-0.25);" width="50" x="50" y="100"/>
15
15
-
<rect data-object="hatches--anon-15" height="50" style="fill: url(#pattern-hatched-45deg-white-2-0.25);" width="50" x="100" y="100"/>
16
16
-
<rect data-object="hatches--anon-16" height="50" style="fill: url(#pattern-hatched-45deg-white-2.1-0.25);" width="50" x="150" y="100"/>
17
17
-
<rect data-object="hatches--anon-17" height="50" style="fill: url(#pattern-hatched-45deg-white-2.2-0.25);" width="50" x="200" y="100"/>
18
18
-
<rect data-object="hatches--anon-18" height="50" style="fill: url(#pattern-hatched-45deg-white-2.3-0.25);" width="50" x="250" y="100"/>
12
12
+
<rect data-object="hatches--anon-12" height="50" width="50" x="650" y="50" style="fill: url(#pattern-hatched-45deg-white-1.7-0.25);"/>
13
13
+
<rect data-object="hatches--anon-13" height="50" width="50" x="700" y="50" style="fill: url(#pattern-hatched-45deg-white-1.8-0.25);"/>
14
14
+
<rect data-object="hatches--anon-14" height="50" width="50" x="50" y="100" style="fill: url(#pattern-hatched-45deg-white-1.9-0.25);"/>
15
15
+
<rect data-object="hatches--anon-15" height="50" width="50" x="100" y="100" style="fill: url(#pattern-hatched-45deg-white-2-0.25);"/>
16
16
+
<rect data-object="hatches--anon-16" height="50" width="50" x="150" y="100" style="fill: url(#pattern-hatched-45deg-white-2.1-0.25);"/>
17
17
+
<rect data-object="hatches--anon-17" height="50" width="50" x="200" y="100" style="fill: url(#pattern-hatched-45deg-white-2.2-0.25);"/>
18
18
+
<rect data-object="hatches--anon-18" height="50" width="50" x="250" y="100" style="fill: url(#pattern-hatched-45deg-white-2.3-0.25);"/>
19
19
<circle cx="325" cy="125" data-object="hatches--anon-19" r="25" style="fill: url(#pattern-hatched-45deg-white-2.4-0.25);"/>
20
20
<circle cx="175" cy="75" data-object="hatches--anon-2" r="25" style="fill: url(#pattern-hatched-45deg-white-0.7-0.25);"/>
21
21
-
<rect data-object="hatches--anon-20" height="50" style="fill: url(#pattern-hatched-45deg-white-2.5-0.25);" width="50" x="350" y="100"/>
21
21
+
<rect data-object="hatches--anon-20" height="50" width="50" x="350" y="100" style="fill: url(#pattern-hatched-45deg-white-2.5-0.25);"/>
22
22
<circle cx="425" cy="125" data-object="hatches--anon-21" r="25" style="fill: url(#pattern-hatched-45deg-white-2.6-0.25);"/>
23
23
-
<rect data-object="hatches--anon-22" height="50" style="fill: url(#pattern-hatched-45deg-white-2.7-0.25);" width="50" x="450" y="100"/>
24
24
-
<rect data-object="hatches--anon-23" height="50" style="fill: url(#pattern-hatched-45deg-white-2.8-0.25);" width="50" x="500" y="100"/>
23
23
+
<rect data-object="hatches--anon-22" height="50" width="50" x="450" y="100" style="fill: url(#pattern-hatched-45deg-white-2.7-0.25);"/>
24
24
+
<rect data-object="hatches--anon-23" height="50" width="50" x="500" y="100" style="fill: url(#pattern-hatched-45deg-white-2.8-0.25);"/>
25
25
<circle cx="575" cy="125" data-object="hatches--anon-24" r="25" style="fill: url(#pattern-hatched-45deg-white-2.9-0.25);"/>
26
26
-
<rect data-object="hatches--anon-25" height="50" style="fill: url(#pattern-hatched-45deg-white-3-0.25);" width="50" x="600" y="100"/>
27
27
-
<rect data-object="hatches--anon-26" height="50" style="fill: url(#pattern-hatched-45deg-white-3.1-0.25);" width="50" x="650" y="100"/>
28
28
-
<rect data-object="hatches--anon-27" height="50" style="fill: url(#pattern-hatched-45deg-white-3.2-0.25);" width="50" x="700" y="100"/>
26
26
+
<rect data-object="hatches--anon-25" height="50" width="50" x="600" y="100" style="fill: url(#pattern-hatched-45deg-white-3-0.25);"/>
27
27
+
<rect data-object="hatches--anon-26" height="50" width="50" x="650" y="100" style="fill: url(#pattern-hatched-45deg-white-3.1-0.25);"/>
28
28
+
<rect data-object="hatches--anon-27" height="50" width="50" x="700" y="100" style="fill: url(#pattern-hatched-45deg-white-3.2-0.25);"/>
29
29
<circle cx="75" cy="175" data-object="hatches--anon-28" r="25" style="fill: url(#pattern-hatched-45deg-white-3.3-0.25);"/>
30
30
<circle cx="125" cy="175" data-object="hatches--anon-29" r="25" style="fill: url(#pattern-hatched-45deg-white-3.4-0.25);"/>
31
31
<circle cx="225" cy="75" data-object="hatches--anon-3" r="25" style="fill: url(#pattern-hatched-45deg-white-0.8-0.25);"/>
32
32
-
<rect data-object="hatches--anon-30" height="50" style="fill: url(#pattern-hatched-45deg-white-3.5-0.25);" width="50" x="150" y="150"/>
33
33
-
<rect data-object="hatches--anon-31" height="50" style="fill: url(#pattern-hatched-45deg-white-3.6-0.25);" width="50" x="200" y="150"/>
32
32
+
<rect data-object="hatches--anon-30" height="50" width="50" x="150" y="150" style="fill: url(#pattern-hatched-45deg-white-3.5-0.25);"/>
33
33
+
<rect data-object="hatches--anon-31" height="50" width="50" x="200" y="150" style="fill: url(#pattern-hatched-45deg-white-3.6-0.25);"/>
34
34
<circle cx="275" cy="175" data-object="hatches--anon-32" r="25" style="fill: url(#pattern-hatched-45deg-white-3.7-0.25);"/>
35
35
-
<rect data-object="hatches--anon-33" height="50" style="fill: url(#pattern-hatched-45deg-white-3.8-0.25);" width="50" x="300" y="150"/>
36
36
-
<rect data-object="hatches--anon-34" height="50" style="fill: url(#pattern-hatched-45deg-white-3.9-0.25);" width="50" x="350" y="150"/>
37
37
-
<rect data-object="hatches--anon-35" height="50" style="fill: url(#pattern-hatched-45deg-white-4-0.25);" width="50" x="400" y="150"/>
35
35
+
<rect data-object="hatches--anon-33" height="50" width="50" x="300" y="150" style="fill: url(#pattern-hatched-45deg-white-3.8-0.25);"/>
36
36
+
<rect data-object="hatches--anon-34" height="50" width="50" x="350" y="150" style="fill: url(#pattern-hatched-45deg-white-3.9-0.25);"/>
37
37
+
<rect data-object="hatches--anon-35" height="50" width="50" x="400" y="150" style="fill: url(#pattern-hatched-45deg-white-4-0.25);"/>
38
38
<circle cx="475" cy="175" data-object="hatches--anon-36" r="25" style="fill: url(#pattern-hatched-45deg-white-4.1-0.25);"/>
39
39
<circle cx="525" cy="175" data-object="hatches--anon-37" r="25" style="fill: url(#pattern-hatched-45deg-white-4.2-0.25);"/>
40
40
<circle cx="575" cy="175" data-object="hatches--anon-38" r="25" style="fill: url(#pattern-hatched-45deg-white-4.3-0.25);"/>
41
41
-
<rect data-object="hatches--anon-39" height="50" style="fill: url(#pattern-hatched-45deg-white-4.4-0.25);" width="50" x="600" y="150"/>
41
41
+
<rect data-object="hatches--anon-39" height="50" width="50" x="600" y="150" style="fill: url(#pattern-hatched-45deg-white-4.4-0.25);"/>
42
42
<circle cx="275" cy="75" data-object="hatches--anon-4" r="25" style="fill: url(#pattern-hatched-45deg-white-0.9-0.25);"/>
43
43
<circle cx="675" cy="175" data-object="hatches--anon-40" r="25" style="fill: url(#pattern-hatched-45deg-white-4.5-0.25);"/>
44
44
-
<rect data-object="hatches--anon-41" height="50" style="fill: url(#pattern-hatched-45deg-white-4.6-0.25);" width="50" x="700" y="150"/>
44
44
+
<rect data-object="hatches--anon-41" height="50" width="50" x="700" y="150" style="fill: url(#pattern-hatched-45deg-white-4.6-0.25);"/>
45
45
<circle cx="75" cy="225" data-object="hatches--anon-42" r="25" style="fill: url(#pattern-hatched-45deg-white-4.7-0.25);"/>
46
46
<circle cx="125" cy="225" data-object="hatches--anon-43" r="25" style="fill: url(#pattern-hatched-45deg-white-4.8-0.25);"/>
47
47
<circle cx="325" cy="225" data-object="hatches--anon-44" r="25" style="fill: url(#pattern-hatched-45deg-white-4.9-0.25);"/>
48
48
-
<rect data-object="hatches--anon-45" height="50" style="fill: url(#pattern-hatched-45deg-white-5-0.25);" width="50" x="350" y="200"/>
49
49
-
<rect data-object="hatches--anon-46" height="50" style="fill: url(#pattern-hatched-45deg-white-5.1-0.25);" width="50" x="400" y="200"/>
50
50
-
<rect data-object="hatches--anon-47" height="50" style="fill: url(#pattern-hatched-45deg-white-5.2-0.25);" width="50" x="450" y="200"/>
51
51
-
<rect data-object="hatches--anon-48" height="50" style="fill: url(#pattern-hatched-45deg-white-5.3-0.25);" width="50" x="500" y="200"/>
52
52
-
<rect data-object="hatches--anon-49" height="50" style="fill: url(#pattern-hatched-45deg-white-5.5-0.25);" width="50" x="600" y="200"/>
48
48
+
<rect data-object="hatches--anon-45" height="50" width="50" x="350" y="200" style="fill: url(#pattern-hatched-45deg-white-5-0.25);"/>
49
49
+
<rect data-object="hatches--anon-46" height="50" width="50" x="400" y="200" style="fill: url(#pattern-hatched-45deg-white-5.1-0.25);"/>
50
50
+
<rect data-object="hatches--anon-47" height="50" width="50" x="450" y="200" style="fill: url(#pattern-hatched-45deg-white-5.2-0.25);"/>
51
51
+
<rect data-object="hatches--anon-48" height="50" width="50" x="500" y="200" style="fill: url(#pattern-hatched-45deg-white-5.3-0.25);"/>
52
52
+
<rect data-object="hatches--anon-49" height="50" width="50" x="600" y="200" style="fill: url(#pattern-hatched-45deg-white-5.5-0.25);"/>
53
53
<circle cx="325" cy="75" data-object="hatches--anon-5" r="25" style="fill: url(#pattern-hatched-45deg-white-1-0.25);"/>
54
54
-
<rect data-object="hatches--anon-50" height="50" style="fill: url(#pattern-hatched-45deg-white-5.6-0.25);" width="50" x="650" y="200"/>
54
54
+
<rect data-object="hatches--anon-50" height="50" width="50" x="650" y="200" style="fill: url(#pattern-hatched-45deg-white-5.6-0.25);"/>
55
55
<circle cx="725" cy="225" data-object="hatches--anon-51" r="25" style="fill: url(#pattern-hatched-45deg-white-5.7-0.25);"/>
56
56
<circle cx="75" cy="275" data-object="hatches--anon-52" r="25" style="fill: url(#pattern-hatched-45deg-white-5.8-0.25);"/>
57
57
-
<rect data-object="hatches--anon-53" height="50" style="fill: url(#pattern-hatched-45deg-white-5.9-0.25);" width="50" x="100" y="250"/>
58
58
-
<rect data-object="hatches--anon-54" height="50" style="fill: url(#pattern-hatched-45deg-white-6-0.25);" width="50" x="300" y="250"/>
59
59
-
<rect data-object="hatches--anon-55" height="50" style="fill: url(#pattern-hatched-45deg-white-6.1-0.25);" width="50" x="350" y="250"/>
60
60
-
<rect data-object="hatches--anon-56" height="50" style="fill: url(#pattern-hatched-45deg-white-6.2-0.25);" width="50" x="400" y="250"/>
57
57
+
<rect data-object="hatches--anon-53" height="50" width="50" x="100" y="250" style="fill: url(#pattern-hatched-45deg-white-5.9-0.25);"/>
58
58
+
<rect data-object="hatches--anon-54" height="50" width="50" x="300" y="250" style="fill: url(#pattern-hatched-45deg-white-6-0.25);"/>
59
59
+
<rect data-object="hatches--anon-55" height="50" width="50" x="350" y="250" style="fill: url(#pattern-hatched-45deg-white-6.1-0.25);"/>
60
60
+
<rect data-object="hatches--anon-56" height="50" width="50" x="400" y="250" style="fill: url(#pattern-hatched-45deg-white-6.2-0.25);"/>
61
61
<circle cx="475" cy="275" data-object="hatches--anon-57" r="25" style="fill: url(#pattern-hatched-45deg-white-6.3-0.25);"/>
62
62
<circle cx="525" cy="275" data-object="hatches--anon-58" r="25" style="fill: url(#pattern-hatched-45deg-white-6.4-0.25);"/>
63
63
<circle cx="575" cy="275" data-object="hatches--anon-59" r="25" style="fill: url(#pattern-hatched-45deg-white-6.5-0.25);"/>
64
64
<circle cx="375" cy="75" data-object="hatches--anon-6" r="25" style="fill: url(#pattern-hatched-45deg-white-1.1-0.25);"/>
65
65
-
<rect data-object="hatches--anon-60" height="50" style="fill: url(#pattern-hatched-45deg-white-6.6-0.25);" width="50" x="600" y="250"/>
66
66
-
<rect data-object="hatches--anon-61" height="50" style="fill: url(#pattern-hatched-45deg-white-6.7-0.25);" width="50" x="650" y="250"/>
67
67
-
<rect data-object="hatches--anon-62" height="50" style="fill: url(#pattern-hatched-45deg-white-6.8-0.25);" width="50" x="700" y="250"/>
65
65
+
<rect data-object="hatches--anon-60" height="50" width="50" x="600" y="250" style="fill: url(#pattern-hatched-45deg-white-6.6-0.25);"/>
66
66
+
<rect data-object="hatches--anon-61" height="50" width="50" x="650" y="250" style="fill: url(#pattern-hatched-45deg-white-6.7-0.25);"/>
67
67
+
<rect data-object="hatches--anon-62" height="50" width="50" x="700" y="250" style="fill: url(#pattern-hatched-45deg-white-6.8-0.25);"/>
68
68
<circle cx="75" cy="325" data-object="hatches--anon-63" r="25" style="fill: url(#pattern-hatched-45deg-white-6.9-0.25);"/>
69
69
-
<rect data-object="hatches--anon-64" height="50" style="fill: url(#pattern-hatched-45deg-white-7-0.25);" width="50" x="100" y="300"/>
70
70
-
<rect data-object="hatches--anon-65" height="50" style="fill: url(#pattern-hatched-45deg-white-7.1-0.25);" width="50" x="300" y="300"/>
71
71
-
<rect data-object="hatches--anon-66" height="50" style="fill: url(#pattern-hatched-45deg-white-7.2-0.25);" width="50" x="350" y="300"/>
72
72
-
<rect data-object="hatches--anon-67" height="50" style="fill: url(#pattern-hatched-45deg-white-7.3-0.25);" width="50" x="400" y="300"/>
69
69
+
<rect data-object="hatches--anon-64" height="50" width="50" x="100" y="300" style="fill: url(#pattern-hatched-45deg-white-7-0.25);"/>
70
70
+
<rect data-object="hatches--anon-65" height="50" width="50" x="300" y="300" style="fill: url(#pattern-hatched-45deg-white-7.1-0.25);"/>
71
71
+
<rect data-object="hatches--anon-66" height="50" width="50" x="350" y="300" style="fill: url(#pattern-hatched-45deg-white-7.2-0.25);"/>
72
72
+
<rect data-object="hatches--anon-67" height="50" width="50" x="400" y="300" style="fill: url(#pattern-hatched-45deg-white-7.3-0.25);"/>
73
73
<circle cx="475" cy="325" data-object="hatches--anon-68" r="25" style="fill: url(#pattern-hatched-45deg-white-7.4-0.25);"/>
74
74
<circle cx="525" cy="325" data-object="hatches--anon-69" r="25" style="fill: url(#pattern-hatched-45deg-white-7.5-0.25);"/>
75
75
-
<rect data-object="hatches--anon-7" height="50" style="fill: url(#pattern-hatched-45deg-white-1.2-0.25);" width="50" x="400" y="50"/>
76
76
-
<rect data-object="hatches--anon-70" height="50" style="fill: url(#pattern-hatched-45deg-white-7.6-0.25);" width="50" x="550" y="300"/>
77
77
-
<rect data-object="hatches--anon-71" height="50" style="fill: url(#pattern-hatched-45deg-white-7.7-0.25);" width="50" x="600" y="300"/>
75
75
+
<rect data-object="hatches--anon-7" height="50" width="50" x="400" y="50" style="fill: url(#pattern-hatched-45deg-white-1.2-0.25);"/>
76
76
+
<rect data-object="hatches--anon-70" height="50" width="50" x="550" y="300" style="fill: url(#pattern-hatched-45deg-white-7.6-0.25);"/>
77
77
+
<rect data-object="hatches--anon-71" height="50" width="50" x="600" y="300" style="fill: url(#pattern-hatched-45deg-white-7.7-0.25);"/>
78
78
<circle cx="675" cy="325" data-object="hatches--anon-72" r="25" style="fill: url(#pattern-hatched-45deg-white-7.8-0.25);"/>
79
79
<circle cx="725" cy="325" data-object="hatches--anon-73" r="25" style="fill: url(#pattern-hatched-45deg-white-7.9-0.25);"/>
80
80
-
<rect data-object="hatches--anon-74" height="50" style="fill: url(#pattern-hatched-45deg-white-8-0.25);" width="50" x="50" y="350"/>
81
81
-
<rect data-object="hatches--anon-75" height="50" style="fill: url(#pattern-hatched-45deg-white-8.1-0.25);" width="50" x="100" y="350"/>
80
80
+
<rect data-object="hatches--anon-74" height="50" width="50" x="50" y="350" style="fill: url(#pattern-hatched-45deg-white-8-0.25);"/>
81
81
+
<rect data-object="hatches--anon-75" height="50" width="50" x="100" y="350" style="fill: url(#pattern-hatched-45deg-white-8.1-0.25);"/>
82
82
<circle cx="175" cy="375" data-object="hatches--anon-76" r="25" style="fill: url(#pattern-hatched-45deg-white-8.2-0.25);"/>
83
83
<circle cx="225" cy="375" data-object="hatches--anon-77" r="25" style="fill: url(#pattern-hatched-45deg-white-8.3-0.25);"/>
84
84
<circle cx="275" cy="375" data-object="hatches--anon-78" r="25" style="fill: url(#pattern-hatched-45deg-white-8.4-0.25);"/>
85
85
-
<rect data-object="hatches--anon-79" height="50" style="fill: url(#pattern-hatched-45deg-white-8.5-0.25);" width="50" x="300" y="350"/>
85
85
+
<rect data-object="hatches--anon-79" height="50" width="50" x="300" y="350" style="fill: url(#pattern-hatched-45deg-white-8.5-0.25);"/>
86
86
<circle cx="475" cy="75" data-object="hatches--anon-8" r="25" style="fill: url(#pattern-hatched-45deg-white-1.3-0.25);"/>
87
87
<circle cx="375" cy="375" data-object="hatches--anon-80" r="25" style="fill: url(#pattern-hatched-45deg-white-8.6-0.25);"/>
88
88
-
<rect data-object="hatches--anon-81" height="50" style="fill: url(#pattern-hatched-45deg-white-8.7-0.25);" width="50" x="400" y="350"/>
89
89
-
<rect data-object="hatches--anon-82" height="50" style="fill: url(#pattern-hatched-45deg-white-8.8-0.25);" width="50" x="450" y="350"/>
88
88
+
<rect data-object="hatches--anon-81" height="50" width="50" x="400" y="350" style="fill: url(#pattern-hatched-45deg-white-8.7-0.25);"/>
89
89
+
<rect data-object="hatches--anon-82" height="50" width="50" x="450" y="350" style="fill: url(#pattern-hatched-45deg-white-8.8-0.25);"/>
90
90
<circle cx="525" cy="375" data-object="hatches--anon-83" r="25" style="fill: url(#pattern-hatched-45deg-white-8.9-0.25);"/>
91
91
<circle cx="575" cy="375" data-object="hatches--anon-84" r="25" style="fill: url(#pattern-hatched-45deg-white-9-0.25);"/>
92
92
<circle cx="625" cy="375" data-object="hatches--anon-85" r="25" style="fill: url(#pattern-hatched-45deg-white-9.1-0.25);"/>
93
93
-
<rect data-object="hatches--anon-86" height="50" style="fill: url(#pattern-hatched-45deg-white-9.2-0.25);" width="50" x="650" y="350"/>
94
94
-
<rect data-object="hatches--anon-87" height="50" style="fill: url(#pattern-hatched-45deg-white-9.3-0.25);" width="50" x="700" y="350"/>
93
93
+
<rect data-object="hatches--anon-86" height="50" width="50" x="650" y="350" style="fill: url(#pattern-hatched-45deg-white-9.2-0.25);"/>
94
94
+
<rect data-object="hatches--anon-87" height="50" width="50" x="700" y="350" style="fill: url(#pattern-hatched-45deg-white-9.3-0.25);"/>
95
95
<circle cx="525" cy="75" data-object="hatches--anon-9" r="25" style="fill: url(#pattern-hatched-45deg-white-1.4-0.25);"/>
96
96
-
</g>
97
97
-
<g class="layer" data-layer="red dot">
98
98
-
<g data-object="red dot--anon-0" style="fill: #cf0a2b;transform-box: fill-box;filter: url(#filter-glow-5); overflow: visible;" transform-origin="575 225">
96
96
+
</g><g class="layer" data-layer="red dot">
97
97
+
<g style="fill: #cf0a2b;transform-box: fill-box;filter: url(#filter-glow-5); overflow: visible;">
99
98
<circle cx="575" cy="225" data-object="red dot--anon-0" r="25"/>
100
100
-
</g>
101
101
-
</g>
102
102
-
<g class="layer" data-layer="strands">
103
103
-
<g data-object="strands--strands#0" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300">
104
104
-
<path d="M150,250 Q200,250,200,300" data-object="strands--strands#0" stroke-width="2"/>
105
105
-
</g>
106
106
-
<g data-object="strands--strands#1" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 275">
99
99
+
</g></g><g class="layer" data-layer="strands">
100
100
+
<g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
101
101
+
<path d="M 150 250 Q 200 250 200 300" data-object="strands--strands#0" stroke-width="2"/>
102
102
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
107
103
<line data-object="strands--strands#1" stroke-width="2" x1="150" x2="200" y1="250" y2="250"/>
108
108
-
</g>
109
109
-
<g data-object="strands--strands#10" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250">
110
110
-
<path d="M200,250 Q150,250,150,200" data-object="strands--strands#10" stroke-width="2"/>
111
111
-
</g>
112
112
-
<g data-object="strands--strands#11" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="300 350">
113
113
-
<path d="M250,300 Q250,350,300,350" data-object="strands--strands#11" stroke-width="2"/>
114
114
-
</g>
115
115
-
<g data-object="strands--strands#12" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 250">
116
116
-
<path d="M250,200 Q200,200,200,250" data-object="strands--strands#12" stroke-width="2"/>
117
117
-
</g>
118
118
-
<g data-object="strands--strands#13" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="275 300">
104
104
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
105
105
+
<path d="M 200 250 Q 150 250 150 200" data-object="strands--strands#10" stroke-width="2"/>
106
106
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
107
107
+
<path d="M 250 300 Q 250 350 300 350" data-object="strands--strands#11" stroke-width="2"/>
108
108
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
109
109
+
<path d="M 250 200 Q 200 200 200 250" data-object="strands--strands#12" stroke-width="2"/>
110
110
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
119
111
<line data-object="strands--strands#13" stroke-width="2" x1="250" x2="250" y1="250" y2="300"/>
120
120
-
</g>
121
121
-
<g data-object="strands--strands#14" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 325">
112
112
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
122
113
<line data-object="strands--strands#14" stroke-width="2" x1="150" x2="200" y1="300" y2="300"/>
123
123
-
</g>
124
124
-
<g data-object="strands--strands#15" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 300">
125
125
-
<path d="M150,300 Q150,200,250,200" data-object="strands--strands#15" stroke-width="2"/>
126
126
-
</g>
127
127
-
<g data-object="strands--strands#16" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300">
114
114
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
115
115
+
<path d="M 150 300 Q 150 200 250 200" data-object="strands--strands#15" stroke-width="2"/>
116
116
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
128
117
<line data-object="strands--strands#16" stroke-width="2" x1="150" x2="200" y1="300" y2="200"/>
129
129
-
</g>
130
130
-
<g data-object="strands--strands#17" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 325">
131
131
-
<path d="M150,250 Q250,250,250,350" data-object="strands--strands#17" stroke-width="2"/>
132
132
-
</g>
133
133
-
<g data-object="strands--strands#18" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300">
134
134
-
<path d="M250,300 Q250,200,150,200" data-object="strands--strands#18" stroke-width="2"/>
135
135
-
</g>
136
136
-
<g data-object="strands--strands#19" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="175 275">
118
118
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
119
119
+
<path d="M 150 250 Q 250 250 250 350" data-object="strands--strands#17" stroke-width="2"/>
120
120
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
121
121
+
<path d="M 250 300 Q 250 200 150 200" data-object="strands--strands#18" stroke-width="2"/>
122
122
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
137
123
<line data-object="strands--strands#19" stroke-width="2" x1="150" x2="150" y1="250" y2="250"/>
138
138
-
</g>
139
139
-
<g data-object="strands--strands#2" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250">
140
140
-
<path d="M200,200 Q200,250,150,250" data-object="strands--strands#2" stroke-width="2"/>
141
141
-
</g>
142
142
-
<g data-object="strands--strands#20" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300">
143
143
-
<path d="M250,300 Q250,250,200,250" data-object="strands--strands#20" stroke-width="2"/>
144
144
-
</g>
145
145
-
<g data-object="strands--strands#21" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300">
146
146
-
<path d="M250,250 Q200,250,200,300" data-object="strands--strands#21" stroke-width="2"/>
147
147
-
</g>
148
148
-
<g data-object="strands--strands#22" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 275">
124
124
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
125
125
+
<path d="M 200 200 Q 200 250 150 250" data-object="strands--strands#2" stroke-width="2"/>
126
126
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
127
127
+
<path d="M 250 300 Q 250 250 200 250" data-object="strands--strands#20" stroke-width="2"/>
128
128
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
129
129
+
<path d="M 250 250 Q 200 250 200 300" data-object="strands--strands#21" stroke-width="2"/>
130
130
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
149
131
<line data-object="strands--strands#22" stroke-width="2" x1="250" x2="200" y1="250" y2="250"/>
150
150
-
</g>
151
151
-
<g data-object="strands--strands#23" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 225">
132
132
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
152
133
<line data-object="strands--strands#23" stroke-width="2" x1="250" x2="150" y1="200" y2="200"/>
153
153
-
</g>
154
154
-
<g data-object="strands--strands#24" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 250">
134
134
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
155
135
<line data-object="strands--strands#24" stroke-width="2" x1="250" x2="150" y1="200" y2="250"/>
156
156
-
</g>
157
157
-
<g data-object="strands--strands#25" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="175 325">
136
136
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
158
137
<line data-object="strands--strands#25" stroke-width="2" x1="150" x2="150" y1="300" y2="300"/>
159
159
-
</g>
160
160
-
<g data-object="strands--strands#26" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 225">
138
138
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
161
139
<line data-object="strands--strands#26" stroke-width="2" x1="200" x2="200" y1="200" y2="200"/>
162
162
-
</g>
163
163
-
<g data-object="strands--strands#27" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 250">
140
140
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
164
141
<line data-object="strands--strands#27" stroke-width="2" x1="200" x2="200" y1="200" y2="250"/>
165
165
-
</g>
166
166
-
<g data-object="strands--strands#28" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 275">
167
167
-
<path d="M150,200 Q150,300,250,300" data-object="strands--strands#28" stroke-width="2"/>
168
168
-
</g>
169
169
-
<g data-object="strands--strands#29" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300">
170
170
-
<path d="M250,300 Q150,300,150,200" data-object="strands--strands#29" stroke-width="2"/>
171
171
-
</g>
172
172
-
<g data-object="strands--strands#3" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 325">
142
142
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
143
143
+
<path d="M 150 200 Q 150 300 250 300" data-object="strands--strands#28" stroke-width="2"/>
144
144
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
145
145
+
<path d="M 250 300 Q 150 300 150 200" data-object="strands--strands#29" stroke-width="2"/>
146
146
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
173
147
<line data-object="strands--strands#3" stroke-width="2" x1="200" x2="150" y1="300" y2="300"/>
174
174
-
</g>
175
175
-
<g data-object="strands--strands#4" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250">
176
176
-
<path d="M150,250 Q150,200,200,200" data-object="strands--strands#4" stroke-width="2"/>
177
177
-
</g>
178
178
-
<g data-object="strands--strands#5" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="275 325">
179
179
-
<path d="M200,250 Q300,250,300,350" data-object="strands--strands#5" stroke-width="2"/>
180
180
-
</g>
181
181
-
<g data-object="strands--strands#6" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250">
182
182
-
<path d="M200,250 Q200,200,150,200" data-object="strands--strands#6" stroke-width="2"/>
183
183
-
</g>
184
184
-
<g data-object="strands--strands#7" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300">
185
185
-
<path d="M150,300 Q200,300,200,250" data-object="strands--strands#7" stroke-width="2"/>
186
186
-
</g>
187
187
-
<g data-object="strands--strands#8" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300">
188
188
-
<path d="M200,300 Q150,300,150,250" data-object="strands--strands#8" stroke-width="2"/>
189
189
-
</g>
190
190
-
<g data-object="strands--strands#9" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 250">
148
148
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
149
149
+
<path d="M 150 250 Q 150 200 200 200" data-object="strands--strands#4" stroke-width="2"/>
150
150
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
151
151
+
<path d="M 200 250 Q 300 250 300 350" data-object="strands--strands#5" stroke-width="2"/>
152
152
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
153
153
+
<path d="M 200 250 Q 200 200 150 200" data-object="strands--strands#6" stroke-width="2"/>
154
154
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
155
155
+
<path d="M 150 300 Q 200 300 200 250" data-object="strands--strands#7" stroke-width="2"/>
156
156
+
</g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
157
157
+
<path d="M 200 300 Q 150 300 150 250" data-object="strands--strands#8" stroke-width="2"/>
158
158
+
</g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;">
191
159
<line data-object="strands--strands#9" stroke-width="2" x1="200" x2="250" y1="250" y2="200"/>
192
192
-
</g>
193
193
-
</g>
194
194
-
<g class="layer" data-layer="root"/>
195
195
-
<defs>
160
160
+
</g></g><g class="layer" data-layer="root"/>
161
161
+
<defs >
196
162
<filter filterUnit="userSpaceOnUse" id="filter-glow-4">
197
163
<feGaussianBlur result="coloredBlur" stdDeviation="4"/>
198
198
-
<feMerge>
164
164
+
<feMerge >
199
165
<feMergeNode in="coloredBlur"/>
200
166
<feMergeNode in="SourceGraphic"/>
201
201
-
</feMerge>
202
202
-
</filter>
203
203
-
<filter filterUnit="userSpaceOnUse" id="filter-glow-5">
167
167
+
</feMerge></filter><filter filterUnit="userSpaceOnUse" id="filter-glow-5">
204
168
<feGaussianBlur result="coloredBlur" stdDeviation="5"/>
205
205
-
<feMerge>
169
169
+
<feMerge >
206
170
<feMergeNode in="coloredBlur"/>
207
171
<feMergeNode in="SourceGraphic"/>
208
208
-
</feMerge>
209
209
-
</filter>
210
210
-
<pattern height="1" id="pattern-hatched-45deg-white-0.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.5,0.5" width="1">
172
172
+
</feMerge></filter><pattern height="1" id="pattern-hatched-45deg-white-0.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.5,0.5" width="1">
211
173
<polygon fill="#ffffff" points="0,0 0.125,0 0,0.125"/>
212
174
<polygon fill="#ffffff" points="0,0.5 0.5,0 0.5,0.125 0.125,0.5"/>
213
213
-
</pattern>
214
214
-
<pattern height="1.2" id="pattern-hatched-45deg-white-0.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.6,0.6" width="1.2">
175
175
+
</pattern><pattern height="1.2" id="pattern-hatched-45deg-white-0.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.6,0.6" width="1.2">
215
176
<polygon fill="#ffffff" points="0,0 0.15,0 0,0.15"/>
216
177
<polygon fill="#ffffff" points="0,0.6 0.6,0 0.6,0.15 0.15,0.6"/>
217
217
-
</pattern>
218
218
-
<pattern height="1.4" id="pattern-hatched-45deg-white-0.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.7,0.7" width="1.4">
178
178
+
</pattern><pattern height="1.4" id="pattern-hatched-45deg-white-0.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.7,0.7" width="1.4">
219
179
<polygon fill="#ffffff" points="0,0 0.175,0 0,0.175"/>
220
180
<polygon fill="#ffffff" points="0,0.7 0.7,0 0.7,0.175 0.175,0.7"/>
221
221
-
</pattern>
222
222
-
<pattern height="1.6" id="pattern-hatched-45deg-white-0.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.8,0.8" width="1.6">
181
181
+
</pattern><pattern height="1.6" id="pattern-hatched-45deg-white-0.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.8,0.8" width="1.6">
223
182
<polygon fill="#ffffff" points="0,0 0.2,0 0,0.2"/>
224
183
<polygon fill="#ffffff" points="0,0.8 0.8,0 0.8,0.2 0.2,0.8"/>
225
225
-
</pattern>
226
226
-
<pattern height="1.8" id="pattern-hatched-45deg-white-0.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.9,0.9" width="1.8">
184
184
+
</pattern><pattern height="1.8" id="pattern-hatched-45deg-white-0.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.9,0.9" width="1.8">
227
185
<polygon fill="#ffffff" points="0,0 0.225,0 0,0.225"/>
228
186
<polygon fill="#ffffff" points="0,0.9 0.9,0 0.9,0.225 0.225,0.9"/>
229
229
-
</pattern>
230
230
-
<pattern height="2" id="pattern-hatched-45deg-white-1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1,1" width="2">
187
187
+
</pattern><pattern height="2" id="pattern-hatched-45deg-white-1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1,1" width="2">
231
188
<polygon fill="#ffffff" points="0,0 0.25,0 0,0.25"/>
232
189
<polygon fill="#ffffff" points="0,1 1,0 1,0.25 0.25,1"/>
233
233
-
</pattern>
234
234
-
<pattern height="2.2" id="pattern-hatched-45deg-white-1.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.1,1.1" width="2.2">
190
190
+
</pattern><pattern height="2.2" id="pattern-hatched-45deg-white-1.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.1,1.1" width="2.2">
235
191
<polygon fill="#ffffff" points="0,0 0.275,0 0,0.275"/>
236
192
<polygon fill="#ffffff" points="0,1.1 1.1,0 1.1,0.275 0.275,1.1"/>
237
237
-
</pattern>
238
238
-
<pattern height="2.4" id="pattern-hatched-45deg-white-1.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.2,1.2" width="2.4">
193
193
+
</pattern><pattern height="2.4" id="pattern-hatched-45deg-white-1.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.2,1.2" width="2.4">
239
194
<polygon fill="#ffffff" points="0,0 0.3,0 0,0.3"/>
240
195
<polygon fill="#ffffff" points="0,1.2 1.2,0 1.2,0.3 0.3,1.2"/>
241
241
-
</pattern>
242
242
-
<pattern height="2.6" id="pattern-hatched-45deg-white-1.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.3,1.3" width="2.6">
196
196
+
</pattern><pattern height="2.6" id="pattern-hatched-45deg-white-1.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.3,1.3" width="2.6">
243
197
<polygon fill="#ffffff" points="0,0 0.325,0 0,0.325"/>
244
198
<polygon fill="#ffffff" points="0,1.3 1.3,0 1.3,0.325 0.325,1.3"/>
245
245
-
</pattern>
246
246
-
<pattern height="2.8" id="pattern-hatched-45deg-white-1.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.4,1.4" width="2.8">
199
199
+
</pattern><pattern height="2.8" id="pattern-hatched-45deg-white-1.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.4,1.4" width="2.8">
247
200
<polygon fill="#ffffff" points="0,0 0.35,0 0,0.35"/>
248
201
<polygon fill="#ffffff" points="0,1.4 1.4,0 1.4,0.35 0.35,1.4"/>
249
249
-
</pattern>
250
250
-
<pattern height="3" id="pattern-hatched-45deg-white-1.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.5,1.5" width="3">
202
202
+
</pattern><pattern height="3" id="pattern-hatched-45deg-white-1.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.5,1.5" width="3">
251
203
<polygon fill="#ffffff" points="0,0 0.375,0 0,0.375"/>
252
204
<polygon fill="#ffffff" points="0,1.5 1.5,0 1.5,0.375 0.375,1.5"/>
253
253
-
</pattern>
254
254
-
<pattern height="3.2" id="pattern-hatched-45deg-white-1.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.6,1.6" width="3.2">
205
205
+
</pattern><pattern height="3.2" id="pattern-hatched-45deg-white-1.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.6,1.6" width="3.2">
255
206
<polygon fill="#ffffff" points="0,0 0.4,0 0,0.4"/>
256
207
<polygon fill="#ffffff" points="0,1.6 1.6,0 1.6,0.4 0.4,1.6"/>
257
257
-
</pattern>
258
258
-
<pattern height="3.4" id="pattern-hatched-45deg-white-1.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.7,1.7" width="3.4">
208
208
+
</pattern><pattern height="3.4" id="pattern-hatched-45deg-white-1.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.7,1.7" width="3.4">
259
209
<polygon fill="#ffffff" points="0,0 0.425,0 0,0.425"/>
260
210
<polygon fill="#ffffff" points="0,1.7 1.7,0 1.7,0.425 0.425,1.7"/>
261
261
-
</pattern>
262
262
-
<pattern height="3.6" id="pattern-hatched-45deg-white-1.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.8,1.8" width="3.6">
211
211
+
</pattern><pattern height="3.6" id="pattern-hatched-45deg-white-1.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.8,1.8" width="3.6">
263
212
<polygon fill="#ffffff" points="0,0 0.45,0 0,0.45"/>
264
213
<polygon fill="#ffffff" points="0,1.8 1.8,0 1.8,0.45 0.45,1.8"/>
265
265
-
</pattern>
266
266
-
<pattern height="3.8" id="pattern-hatched-45deg-white-1.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.9,1.9" width="3.8">
214
214
+
</pattern><pattern height="3.8" id="pattern-hatched-45deg-white-1.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.9,1.9" width="3.8">
267
215
<polygon fill="#ffffff" points="0,0 0.475,0 0,0.475"/>
268
216
<polygon fill="#ffffff" points="0,1.9 1.9,0 1.9,0.475 0.475,1.9"/>
269
269
-
</pattern>
270
270
-
<pattern height="4" id="pattern-hatched-45deg-white-2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2,2" width="4">
217
217
+
</pattern><pattern height="4" id="pattern-hatched-45deg-white-2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2,2" width="4">
271
218
<polygon fill="#ffffff" points="0,0 0.5,0 0,0.5"/>
272
219
<polygon fill="#ffffff" points="0,2 2,0 2,0.5 0.5,2"/>
273
273
-
</pattern>
274
274
-
<pattern height="4.2" id="pattern-hatched-45deg-white-2.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.1,2.1" width="4.2">
220
220
+
</pattern><pattern height="4.2" id="pattern-hatched-45deg-white-2.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.1,2.1" width="4.2">
275
221
<polygon fill="#ffffff" points="0,0 0.525,0 0,0.525"/>
276
222
<polygon fill="#ffffff" points="0,2.1 2.1,0 2.1,0.525 0.525,2.1"/>
277
277
-
</pattern>
278
278
-
<pattern height="4.4" id="pattern-hatched-45deg-white-2.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.2,2.2" width="4.4">
223
223
+
</pattern><pattern height="4.4" id="pattern-hatched-45deg-white-2.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.2,2.2" width="4.4">
279
224
<polygon fill="#ffffff" points="0,0 0.55,0 0,0.55"/>
280
225
<polygon fill="#ffffff" points="0,2.2 2.2,0 2.2,0.55 0.55,2.2"/>
281
281
-
</pattern>
282
282
-
<pattern height="4.6" id="pattern-hatched-45deg-white-2.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.3,2.3" width="4.6">
226
226
+
</pattern><pattern height="4.6" id="pattern-hatched-45deg-white-2.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.3,2.3" width="4.6">
283
227
<polygon fill="#ffffff" points="0,0 0.575,0 0,0.575"/>
284
228
<polygon fill="#ffffff" points="0,2.3 2.3,0 2.3,0.575 0.575,2.3"/>
285
285
-
</pattern>
286
286
-
<pattern height="4.8" id="pattern-hatched-45deg-white-2.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.4,2.4" width="4.8">
229
229
+
</pattern><pattern height="4.8" id="pattern-hatched-45deg-white-2.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.4,2.4" width="4.8">
287
230
<polygon fill="#ffffff" points="0,0 0.6,0 0,0.6"/>
288
231
<polygon fill="#ffffff" points="0,2.4 2.4,0 2.4,0.6 0.6,2.4"/>
289
289
-
</pattern>
290
290
-
<pattern height="5" id="pattern-hatched-45deg-white-2.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.5,2.5" width="5">
232
232
+
</pattern><pattern height="5" id="pattern-hatched-45deg-white-2.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.5,2.5" width="5">
291
233
<polygon fill="#ffffff" points="0,0 0.625,0 0,0.625"/>
292
234
<polygon fill="#ffffff" points="0,2.5 2.5,0 2.5,0.625 0.625,2.5"/>
293
293
-
</pattern>
294
294
-
<pattern height="5.2" id="pattern-hatched-45deg-white-2.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.6,2.6" width="5.2">
235
235
+
</pattern><pattern height="5.2" id="pattern-hatched-45deg-white-2.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.6,2.6" width="5.2">
295
236
<polygon fill="#ffffff" points="0,0 0.65,0 0,0.65"/>
296
237
<polygon fill="#ffffff" points="0,2.6 2.6,0 2.6,0.65 0.65,2.6"/>
297
297
-
</pattern>
298
298
-
<pattern height="5.4" id="pattern-hatched-45deg-white-2.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.7,2.7" width="5.4">
238
238
+
</pattern><pattern height="5.4" id="pattern-hatched-45deg-white-2.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.7,2.7" width="5.4">
299
239
<polygon fill="#ffffff" points="0,0 0.675,0 0,0.675"/>
300
240
<polygon fill="#ffffff" points="0,2.7 2.7,0 2.7,0.675 0.675,2.7"/>
301
301
-
</pattern>
302
302
-
<pattern height="5.6" id="pattern-hatched-45deg-white-2.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.8,2.8" width="5.6">
241
241
+
</pattern><pattern height="5.6" id="pattern-hatched-45deg-white-2.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.8,2.8" width="5.6">
303
242
<polygon fill="#ffffff" points="0,0 0.7,0 0,0.7"/>
304
243
<polygon fill="#ffffff" points="0,2.8 2.8,0 2.8,0.7 0.7,2.8"/>
305
305
-
</pattern>
306
306
-
<pattern height="5.8" id="pattern-hatched-45deg-white-2.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.9,2.9" width="5.8">
244
244
+
</pattern><pattern height="5.8" id="pattern-hatched-45deg-white-2.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.9,2.9" width="5.8">
307
245
<polygon fill="#ffffff" points="0,0 0.725,0 0,0.725"/>
308
246
<polygon fill="#ffffff" points="0,2.9 2.9,0 2.9,0.725 0.725,2.9"/>
309
309
-
</pattern>
310
310
-
<pattern height="6" id="pattern-hatched-45deg-white-3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3,3" width="6">
247
247
+
</pattern><pattern height="6" id="pattern-hatched-45deg-white-3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3,3" width="6">
311
248
<polygon fill="#ffffff" points="0,0 0.75,0 0,0.75"/>
312
249
<polygon fill="#ffffff" points="0,3 3,0 3,0.75 0.75,3"/>
313
313
-
</pattern>
314
314
-
<pattern height="6.2" id="pattern-hatched-45deg-white-3.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.1,3.1" width="6.2">
250
250
+
</pattern><pattern height="6.2" id="pattern-hatched-45deg-white-3.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.1,3.1" width="6.2">
315
251
<polygon fill="#ffffff" points="0,0 0.775,0 0,0.775"/>
316
252
<polygon fill="#ffffff" points="0,3.1 3.1,0 3.1,0.775 0.775,3.1"/>
317
317
-
</pattern>
318
318
-
<pattern height="6.4" id="pattern-hatched-45deg-white-3.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.2,3.2" width="6.4">
253
253
+
</pattern><pattern height="6.4" id="pattern-hatched-45deg-white-3.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.2,3.2" width="6.4">
319
254
<polygon fill="#ffffff" points="0,0 0.8,0 0,0.8"/>
320
255
<polygon fill="#ffffff" points="0,3.2 3.2,0 3.2,0.8 0.8,3.2"/>
321
321
-
</pattern>
322
322
-
<pattern height="6.6" id="pattern-hatched-45deg-white-3.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.3,3.3" width="6.6">
256
256
+
</pattern><pattern height="6.6" id="pattern-hatched-45deg-white-3.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.3,3.3" width="6.6">
323
257
<polygon fill="#ffffff" points="0,0 0.825,0 0,0.825"/>
324
258
<polygon fill="#ffffff" points="0,3.3 3.3,0 3.3,0.825 0.825,3.3"/>
325
325
-
</pattern>
326
326
-
<pattern height="6.8" id="pattern-hatched-45deg-white-3.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.4,3.4" width="6.8">
259
259
+
</pattern><pattern height="6.8" id="pattern-hatched-45deg-white-3.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.4,3.4" width="6.8">
327
260
<polygon fill="#ffffff" points="0,0 0.85,0 0,0.85"/>
328
261
<polygon fill="#ffffff" points="0,3.4 3.4,0 3.4,0.85 0.85,3.4"/>
329
329
-
</pattern>
330
330
-
<pattern height="7" id="pattern-hatched-45deg-white-3.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.5,3.5" width="7">
262
262
+
</pattern><pattern height="7" id="pattern-hatched-45deg-white-3.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.5,3.5" width="7">
331
263
<polygon fill="#ffffff" points="0,0 0.875,0 0,0.875"/>
332
264
<polygon fill="#ffffff" points="0,3.5 3.5,0 3.5,0.875 0.875,3.5"/>
333
333
-
</pattern>
334
334
-
<pattern height="7.2" id="pattern-hatched-45deg-white-3.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.6,3.6" width="7.2">
265
265
+
</pattern><pattern height="7.2" id="pattern-hatched-45deg-white-3.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.6,3.6" width="7.2">
335
266
<polygon fill="#ffffff" points="0,0 0.9,0 0,0.9"/>
336
267
<polygon fill="#ffffff" points="0,3.6 3.6,0 3.6,0.9 0.9,3.6"/>
337
337
-
</pattern>
338
338
-
<pattern height="7.4" id="pattern-hatched-45deg-white-3.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.7,3.7" width="7.4">
268
268
+
</pattern><pattern height="7.4" id="pattern-hatched-45deg-white-3.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.7,3.7" width="7.4">
339
269
<polygon fill="#ffffff" points="0,0 0.925,0 0,0.925"/>
340
270
<polygon fill="#ffffff" points="0,3.7 3.7,0 3.7,0.925 0.925,3.7"/>
341
341
-
</pattern>
342
342
-
<pattern height="7.6" id="pattern-hatched-45deg-white-3.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.8,3.8" width="7.6">
271
271
+
</pattern><pattern height="7.6" id="pattern-hatched-45deg-white-3.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.8,3.8" width="7.6">
343
272
<polygon fill="#ffffff" points="0,0 0.95,0 0,0.95"/>
344
273
<polygon fill="#ffffff" points="0,3.8 3.8,0 3.8,0.95 0.95,3.8"/>
345
345
-
</pattern>
346
346
-
<pattern height="7.8" id="pattern-hatched-45deg-white-3.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.9,3.9" width="7.8">
274
274
+
</pattern><pattern height="7.8" id="pattern-hatched-45deg-white-3.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.9,3.9" width="7.8">
347
275
<polygon fill="#ffffff" points="0,0 0.975,0 0,0.975"/>
348
276
<polygon fill="#ffffff" points="0,3.9 3.9,0 3.9,0.975 0.975,3.9"/>
349
349
-
</pattern>
350
350
-
<pattern height="8" id="pattern-hatched-45deg-white-4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4,4" width="8">
277
277
+
</pattern><pattern height="8" id="pattern-hatched-45deg-white-4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4,4" width="8">
351
278
<polygon fill="#ffffff" points="0,0 1,0 0,1"/>
352
279
<polygon fill="#ffffff" points="0,4 4,0 4,1 1,4"/>
353
353
-
</pattern>
354
354
-
<pattern height="8.2" id="pattern-hatched-45deg-white-4.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.1,4.1" width="8.2">
280
280
+
</pattern><pattern height="8.2" id="pattern-hatched-45deg-white-4.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.1,4.1" width="8.2">
355
281
<polygon fill="#ffffff" points="0,0 1.025,0 0,1.025"/>
356
282
<polygon fill="#ffffff" points="0,4.1 4.1,0 4.1,1.025 1.025,4.1"/>
357
357
-
</pattern>
358
358
-
<pattern height="8.4" id="pattern-hatched-45deg-white-4.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.2,4.2" width="8.4">
283
283
+
</pattern><pattern height="8.4" id="pattern-hatched-45deg-white-4.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.2,4.2" width="8.4">
359
284
<polygon fill="#ffffff" points="0,0 1.05,0 0,1.05"/>
360
285
<polygon fill="#ffffff" points="0,4.2 4.2,0 4.2,1.05 1.05,4.2"/>
361
361
-
</pattern>
362
362
-
<pattern height="8.6" id="pattern-hatched-45deg-white-4.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.3,4.3" width="8.6">
286
286
+
</pattern><pattern height="8.6" id="pattern-hatched-45deg-white-4.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.3,4.3" width="8.6">
363
287
<polygon fill="#ffffff" points="0,0 1.075,0 0,1.075"/>
364
288
<polygon fill="#ffffff" points="0,4.3 4.3,0 4.3,1.075 1.075,4.3"/>
365
365
-
</pattern>
366
366
-
<pattern height="8.8" id="pattern-hatched-45deg-white-4.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.4,4.4" width="8.8">
289
289
+
</pattern><pattern height="8.8" id="pattern-hatched-45deg-white-4.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.4,4.4" width="8.8">
367
290
<polygon fill="#ffffff" points="0,0 1.1,0 0,1.1"/>
368
291
<polygon fill="#ffffff" points="0,4.4 4.4,0 4.4,1.1 1.1,4.4"/>
369
369
-
</pattern>
370
370
-
<pattern height="9" id="pattern-hatched-45deg-white-4.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.5,4.5" width="9">
292
292
+
</pattern><pattern height="9" id="pattern-hatched-45deg-white-4.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.5,4.5" width="9">
371
293
<polygon fill="#ffffff" points="0,0 1.125,0 0,1.125"/>
372
294
<polygon fill="#ffffff" points="0,4.5 4.5,0 4.5,1.125 1.125,4.5"/>
373
373
-
</pattern>
374
374
-
<pattern height="9.2" id="pattern-hatched-45deg-white-4.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.6,4.6" width="9.2">
295
295
+
</pattern><pattern height="9.2" id="pattern-hatched-45deg-white-4.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.6,4.6" width="9.2">
375
296
<polygon fill="#ffffff" points="0,0 1.15,0 0,1.15"/>
376
297
<polygon fill="#ffffff" points="0,4.6 4.6,0 4.6,1.15 1.15,4.6"/>
377
377
-
</pattern>
378
378
-
<pattern height="9.4" id="pattern-hatched-45deg-white-4.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.7,4.7" width="9.4">
298
298
+
</pattern><pattern height="9.4" id="pattern-hatched-45deg-white-4.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.7,4.7" width="9.4">
379
299
<polygon fill="#ffffff" points="0,0 1.175,0 0,1.175"/>
380
300
<polygon fill="#ffffff" points="0,4.7 4.7,0 4.7,1.175 1.175,4.7"/>
381
381
-
</pattern>
382
382
-
<pattern height="9.6" id="pattern-hatched-45deg-white-4.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.8,4.8" width="9.6">
301
301
+
</pattern><pattern height="9.6" id="pattern-hatched-45deg-white-4.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.8,4.8" width="9.6">
383
302
<polygon fill="#ffffff" points="0,0 1.2,0 0,1.2"/>
384
303
<polygon fill="#ffffff" points="0,4.8 4.8,0 4.8,1.2 1.2,4.8"/>
385
385
-
</pattern>
386
386
-
<pattern height="9.8" id="pattern-hatched-45deg-white-4.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.9,4.9" width="9.8">
304
304
+
</pattern><pattern height="9.8" id="pattern-hatched-45deg-white-4.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.9,4.9" width="9.8">
387
305
<polygon fill="#ffffff" points="0,0 1.225,0 0,1.225"/>
388
306
<polygon fill="#ffffff" points="0,4.9 4.9,0 4.9,1.225 1.225,4.9"/>
389
389
-
</pattern>
390
390
-
<pattern height="10" id="pattern-hatched-45deg-white-5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5,5" width="10">
307
307
+
</pattern><pattern height="10" id="pattern-hatched-45deg-white-5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5,5" width="10">
391
308
<polygon fill="#ffffff" points="0,0 1.25,0 0,1.25"/>
392
309
<polygon fill="#ffffff" points="0,5 5,0 5,1.25 1.25,5"/>
393
393
-
</pattern>
394
394
-
<pattern height="10.2" id="pattern-hatched-45deg-white-5.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.1,5.1" width="10.2">
310
310
+
</pattern><pattern height="10.2" id="pattern-hatched-45deg-white-5.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.1,5.1" width="10.2">
395
311
<polygon fill="#ffffff" points="0,0 1.275,0 0,1.275"/>
396
312
<polygon fill="#ffffff" points="0,5.1 5.1,0 5.1,1.275 1.275,5.1"/>
397
397
-
</pattern>
398
398
-
<pattern height="10.4" id="pattern-hatched-45deg-white-5.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.2,5.2" width="10.4">
313
313
+
</pattern><pattern height="10.4" id="pattern-hatched-45deg-white-5.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.2,5.2" width="10.4">
399
314
<polygon fill="#ffffff" points="0,0 1.3,0 0,1.3"/>
400
315
<polygon fill="#ffffff" points="0,5.2 5.2,0 5.2,1.3 1.3,5.2"/>
401
401
-
</pattern>
402
402
-
<pattern height="10.6" id="pattern-hatched-45deg-white-5.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.3,5.3" width="10.6">
316
316
+
</pattern><pattern height="10.6" id="pattern-hatched-45deg-white-5.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.3,5.3" width="10.6">
403
317
<polygon fill="#ffffff" points="0,0 1.325,0 0,1.325"/>
404
318
<polygon fill="#ffffff" points="0,5.3 5.3,0 5.3,1.325 1.325,5.3"/>
405
405
-
</pattern>
406
406
-
<pattern height="11" id="pattern-hatched-45deg-white-5.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.5,5.5" width="11">
319
319
+
</pattern><pattern height="11" id="pattern-hatched-45deg-white-5.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.5,5.5" width="11">
407
320
<polygon fill="#ffffff" points="0,0 1.375,0 0,1.375"/>
408
321
<polygon fill="#ffffff" points="0,5.5 5.5,0 5.5,1.375 1.375,5.5"/>
409
409
-
</pattern>
410
410
-
<pattern height="11.2" id="pattern-hatched-45deg-white-5.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.6,5.6" width="11.2">
322
322
+
</pattern><pattern height="11.2" id="pattern-hatched-45deg-white-5.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.6,5.6" width="11.2">
411
323
<polygon fill="#ffffff" points="0,0 1.4,0 0,1.4"/>
412
324
<polygon fill="#ffffff" points="0,5.6 5.6,0 5.6,1.4 1.4,5.6"/>
413
413
-
</pattern>
414
414
-
<pattern height="11.4" id="pattern-hatched-45deg-white-5.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.7,5.7" width="11.4">
325
325
+
</pattern><pattern height="11.4" id="pattern-hatched-45deg-white-5.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.7,5.7" width="11.4">
415
326
<polygon fill="#ffffff" points="0,0 1.425,0 0,1.425"/>
416
327
<polygon fill="#ffffff" points="0,5.7 5.7,0 5.7,1.425 1.425,5.7"/>
417
417
-
</pattern>
418
418
-
<pattern height="11.6" id="pattern-hatched-45deg-white-5.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.8,5.8" width="11.6">
328
328
+
</pattern><pattern height="11.6" id="pattern-hatched-45deg-white-5.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.8,5.8" width="11.6">
419
329
<polygon fill="#ffffff" points="0,0 1.45,0 0,1.45"/>
420
330
<polygon fill="#ffffff" points="0,5.8 5.8,0 5.8,1.45 1.45,5.8"/>
421
421
-
</pattern>
422
422
-
<pattern height="11.8" id="pattern-hatched-45deg-white-5.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.9,5.9" width="11.8">
331
331
+
</pattern><pattern height="11.8" id="pattern-hatched-45deg-white-5.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.9,5.9" width="11.8">
423
332
<polygon fill="#ffffff" points="0,0 1.475,0 0,1.475"/>
424
333
<polygon fill="#ffffff" points="0,5.9 5.9,0 5.9,1.475 1.475,5.9"/>
425
425
-
</pattern>
426
426
-
<pattern height="12" id="pattern-hatched-45deg-white-6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6,6" width="12">
334
334
+
</pattern><pattern height="12" id="pattern-hatched-45deg-white-6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6,6" width="12">
427
335
<polygon fill="#ffffff" points="0,0 1.5,0 0,1.5"/>
428
336
<polygon fill="#ffffff" points="0,6 6,0 6,1.5 1.5,6"/>
429
429
-
</pattern>
430
430
-
<pattern height="12.2" id="pattern-hatched-45deg-white-6.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.1,6.1" width="12.2">
337
337
+
</pattern><pattern height="12.2" id="pattern-hatched-45deg-white-6.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.1,6.1" width="12.2">
431
338
<polygon fill="#ffffff" points="0,0 1.525,0 0,1.525"/>
432
339
<polygon fill="#ffffff" points="0,6.1 6.1,0 6.1,1.525 1.525,6.1"/>
433
433
-
</pattern>
434
434
-
<pattern height="12.4" id="pattern-hatched-45deg-white-6.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.2,6.2" width="12.4">
340
340
+
</pattern><pattern height="12.4" id="pattern-hatched-45deg-white-6.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.2,6.2" width="12.4">
435
341
<polygon fill="#ffffff" points="0,0 1.55,0 0,1.55"/>
436
342
<polygon fill="#ffffff" points="0,6.2 6.2,0 6.2,1.55 1.55,6.2"/>
437
437
-
</pattern>
438
438
-
<pattern height="12.6" id="pattern-hatched-45deg-white-6.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.3,6.3" width="12.6">
343
343
+
</pattern><pattern height="12.6" id="pattern-hatched-45deg-white-6.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.3,6.3" width="12.6">
439
344
<polygon fill="#ffffff" points="0,0 1.575,0 0,1.575"/>
440
345
<polygon fill="#ffffff" points="0,6.3 6.3,0 6.3,1.575 1.575,6.3"/>
441
441
-
</pattern>
442
442
-
<pattern height="12.8" id="pattern-hatched-45deg-white-6.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.4,6.4" width="12.8">
346
346
+
</pattern><pattern height="12.8" id="pattern-hatched-45deg-white-6.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.4,6.4" width="12.8">
443
347
<polygon fill="#ffffff" points="0,0 1.6,0 0,1.6"/>
444
348
<polygon fill="#ffffff" points="0,6.4 6.4,0 6.4,1.6 1.6,6.4"/>
445
445
-
</pattern>
446
446
-
<pattern height="13" id="pattern-hatched-45deg-white-6.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.5,6.5" width="13">
349
349
+
</pattern><pattern height="13" id="pattern-hatched-45deg-white-6.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.5,6.5" width="13">
447
350
<polygon fill="#ffffff" points="0,0 1.625,0 0,1.625"/>
448
351
<polygon fill="#ffffff" points="0,6.5 6.5,0 6.5,1.625 1.625,6.5"/>
449
449
-
</pattern>
450
450
-
<pattern height="13.2" id="pattern-hatched-45deg-white-6.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.6,6.6" width="13.2">
352
352
+
</pattern><pattern height="13.2" id="pattern-hatched-45deg-white-6.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.6,6.6" width="13.2">
451
353
<polygon fill="#ffffff" points="0,0 1.65,0 0,1.65"/>
452
354
<polygon fill="#ffffff" points="0,6.6 6.6,0 6.6,1.65 1.65,6.6"/>
453
453
-
</pattern>
454
454
-
<pattern height="13.4" id="pattern-hatched-45deg-white-6.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.7,6.7" width="13.4">
355
355
+
</pattern><pattern height="13.4" id="pattern-hatched-45deg-white-6.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.7,6.7" width="13.4">
455
356
<polygon fill="#ffffff" points="0,0 1.675,0 0,1.675"/>
456
357
<polygon fill="#ffffff" points="0,6.7 6.7,0 6.7,1.675 1.675,6.7"/>
457
457
-
</pattern>
458
458
-
<pattern height="13.6" id="pattern-hatched-45deg-white-6.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.8,6.8" width="13.6">
358
358
+
</pattern><pattern height="13.6" id="pattern-hatched-45deg-white-6.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.8,6.8" width="13.6">
459
359
<polygon fill="#ffffff" points="0,0 1.7,0 0,1.7"/>
460
360
<polygon fill="#ffffff" points="0,6.8 6.8,0 6.8,1.7 1.7,6.8"/>
461
461
-
</pattern>
462
462
-
<pattern height="13.8" id="pattern-hatched-45deg-white-6.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.9,6.9" width="13.8">
361
361
+
</pattern><pattern height="13.8" id="pattern-hatched-45deg-white-6.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.9,6.9" width="13.8">
463
362
<polygon fill="#ffffff" points="0,0 1.725,0 0,1.725"/>
464
363
<polygon fill="#ffffff" points="0,6.9 6.9,0 6.9,1.725 1.725,6.9"/>
465
465
-
</pattern>
466
466
-
<pattern height="14" id="pattern-hatched-45deg-white-7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7,7" width="14">
364
364
+
</pattern><pattern height="14" id="pattern-hatched-45deg-white-7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7,7" width="14">
467
365
<polygon fill="#ffffff" points="0,0 1.75,0 0,1.75"/>
468
366
<polygon fill="#ffffff" points="0,7 7,0 7,1.75 1.75,7"/>
469
469
-
</pattern>
470
470
-
<pattern height="14.2" id="pattern-hatched-45deg-white-7.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.1,7.1" width="14.2">
367
367
+
</pattern><pattern height="14.2" id="pattern-hatched-45deg-white-7.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.1,7.1" width="14.2">
471
368
<polygon fill="#ffffff" points="0,0 1.775,0 0,1.775"/>
472
369
<polygon fill="#ffffff" points="0,7.1 7.1,0 7.1,1.775 1.775,7.1"/>
473
473
-
</pattern>
474
474
-
<pattern height="14.4" id="pattern-hatched-45deg-white-7.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.2,7.2" width="14.4">
370
370
+
</pattern><pattern height="14.4" id="pattern-hatched-45deg-white-7.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.2,7.2" width="14.4">
475
371
<polygon fill="#ffffff" points="0,0 1.8,0 0,1.8"/>
476
372
<polygon fill="#ffffff" points="0,7.2 7.2,0 7.2,1.8 1.8,7.2"/>
477
477
-
</pattern>
478
478
-
<pattern height="14.6" id="pattern-hatched-45deg-white-7.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.3,7.3" width="14.6">
373
373
+
</pattern><pattern height="14.6" id="pattern-hatched-45deg-white-7.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.3,7.3" width="14.6">
479
374
<polygon fill="#ffffff" points="0,0 1.825,0 0,1.825"/>
480
375
<polygon fill="#ffffff" points="0,7.3 7.3,0 7.3,1.825 1.825,7.3"/>
481
481
-
</pattern>
482
482
-
<pattern height="14.8" id="pattern-hatched-45deg-white-7.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.4,7.4" width="14.8">
376
376
+
</pattern><pattern height="14.8" id="pattern-hatched-45deg-white-7.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.4,7.4" width="14.8">
483
377
<polygon fill="#ffffff" points="0,0 1.85,0 0,1.85"/>
484
378
<polygon fill="#ffffff" points="0,7.4 7.4,0 7.4,1.85 1.85,7.4"/>
485
485
-
</pattern>
486
486
-
<pattern height="15" id="pattern-hatched-45deg-white-7.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.5,7.5" width="15">
379
379
+
</pattern><pattern height="15" id="pattern-hatched-45deg-white-7.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.5,7.5" width="15">
487
380
<polygon fill="#ffffff" points="0,0 1.875,0 0,1.875"/>
488
381
<polygon fill="#ffffff" points="0,7.5 7.5,0 7.5,1.875 1.875,7.5"/>
489
489
-
</pattern>
490
490
-
<pattern height="15.2" id="pattern-hatched-45deg-white-7.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.6,7.6" width="15.2">
382
382
+
</pattern><pattern height="15.2" id="pattern-hatched-45deg-white-7.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.6,7.6" width="15.2">
491
383
<polygon fill="#ffffff" points="0,0 1.9,0 0,1.9"/>
492
384
<polygon fill="#ffffff" points="0,7.6 7.6,0 7.6,1.9 1.9,7.6"/>
493
493
-
</pattern>
494
494
-
<pattern height="15.4" id="pattern-hatched-45deg-white-7.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.7,7.7" width="15.4">
385
385
+
</pattern><pattern height="15.4" id="pattern-hatched-45deg-white-7.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.7,7.7" width="15.4">
495
386
<polygon fill="#ffffff" points="0,0 1.925,0 0,1.925"/>
496
387
<polygon fill="#ffffff" points="0,7.7 7.7,0 7.7,1.925 1.925,7.7"/>
497
497
-
</pattern>
498
498
-
<pattern height="15.6" id="pattern-hatched-45deg-white-7.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.8,7.8" width="15.6">
388
388
+
</pattern><pattern height="15.6" id="pattern-hatched-45deg-white-7.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.8,7.8" width="15.6">
499
389
<polygon fill="#ffffff" points="0,0 1.95,0 0,1.95"/>
500
390
<polygon fill="#ffffff" points="0,7.8 7.8,0 7.8,1.95 1.95,7.8"/>
501
501
-
</pattern>
502
502
-
<pattern height="15.8" id="pattern-hatched-45deg-white-7.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.9,7.9" width="15.8">
391
391
+
</pattern><pattern height="15.8" id="pattern-hatched-45deg-white-7.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.9,7.9" width="15.8">
503
392
<polygon fill="#ffffff" points="0,0 1.975,0 0,1.975"/>
504
393
<polygon fill="#ffffff" points="0,7.9 7.9,0 7.9,1.975 1.975,7.9"/>
505
505
-
</pattern>
506
506
-
<pattern height="16" id="pattern-hatched-45deg-white-8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8,8" width="16">
394
394
+
</pattern><pattern height="16" id="pattern-hatched-45deg-white-8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8,8" width="16">
507
395
<polygon fill="#ffffff" points="0,0 2,0 0,2"/>
508
396
<polygon fill="#ffffff" points="0,8 8,0 8,2 2,8"/>
509
509
-
</pattern>
510
510
-
<pattern height="16.2" id="pattern-hatched-45deg-white-8.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.1,8.1" width="16.2">
397
397
+
</pattern><pattern height="16.2" id="pattern-hatched-45deg-white-8.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.1,8.1" width="16.2">
511
398
<polygon fill="#ffffff" points="0,0 2.025,0 0,2.025"/>
512
399
<polygon fill="#ffffff" points="0,8.1 8.1,0 8.1,2.025 2.025,8.1"/>
513
513
-
</pattern>
514
514
-
<pattern height="16.4" id="pattern-hatched-45deg-white-8.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.2,8.2" width="16.4">
400
400
+
</pattern><pattern height="16.4" id="pattern-hatched-45deg-white-8.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.2,8.2" width="16.4">
515
401
<polygon fill="#ffffff" points="0,0 2.05,0 0,2.05"/>
516
402
<polygon fill="#ffffff" points="0,8.2 8.2,0 8.2,2.05 2.05,8.2"/>
517
517
-
</pattern>
518
518
-
<pattern height="16.6" id="pattern-hatched-45deg-white-8.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.3,8.3" width="16.6">
403
403
+
</pattern><pattern height="16.6" id="pattern-hatched-45deg-white-8.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.3,8.3" width="16.6">
519
404
<polygon fill="#ffffff" points="0,0 2.075,0 0,2.075"/>
520
405
<polygon fill="#ffffff" points="0,8.3 8.3,0 8.3,2.075 2.075,8.3"/>
521
521
-
</pattern>
522
522
-
<pattern height="16.8" id="pattern-hatched-45deg-white-8.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.4,8.4" width="16.8">
406
406
+
</pattern><pattern height="16.8" id="pattern-hatched-45deg-white-8.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.4,8.4" width="16.8">
523
407
<polygon fill="#ffffff" points="0,0 2.1,0 0,2.1"/>
524
408
<polygon fill="#ffffff" points="0,8.4 8.4,0 8.4,2.1 2.1,8.4"/>
525
525
-
</pattern>
526
526
-
<pattern height="17" id="pattern-hatched-45deg-white-8.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.5,8.5" width="17">
409
409
+
</pattern><pattern height="17" id="pattern-hatched-45deg-white-8.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.5,8.5" width="17">
527
410
<polygon fill="#ffffff" points="0,0 2.125,0 0,2.125"/>
528
411
<polygon fill="#ffffff" points="0,8.5 8.5,0 8.5,2.125 2.125,8.5"/>
529
529
-
</pattern>
530
530
-
<pattern height="17.2" id="pattern-hatched-45deg-white-8.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.6,8.6" width="17.2">
412
412
+
</pattern><pattern height="17.2" id="pattern-hatched-45deg-white-8.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.6,8.6" width="17.2">
531
413
<polygon fill="#ffffff" points="0,0 2.15,0 0,2.15"/>
532
414
<polygon fill="#ffffff" points="0,8.6 8.6,0 8.6,2.15 2.15,8.6"/>
533
533
-
</pattern>
534
534
-
<pattern height="17.4" id="pattern-hatched-45deg-white-8.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.7,8.7" width="17.4">
415
415
+
</pattern><pattern height="17.4" id="pattern-hatched-45deg-white-8.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.7,8.7" width="17.4">
535
416
<polygon fill="#ffffff" points="0,0 2.175,0 0,2.175"/>
536
417
<polygon fill="#ffffff" points="0,8.7 8.7,0 8.7,2.175 2.175,8.7"/>
537
537
-
</pattern>
538
538
-
<pattern height="17.6" id="pattern-hatched-45deg-white-8.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.8,8.8" width="17.6">
418
418
+
</pattern><pattern height="17.6" id="pattern-hatched-45deg-white-8.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.8,8.8" width="17.6">
539
419
<polygon fill="#ffffff" points="0,0 2.2,0 0,2.2"/>
540
420
<polygon fill="#ffffff" points="0,8.8 8.8,0 8.8,2.2 2.2,8.8"/>
541
541
-
</pattern>
542
542
-
<pattern height="17.8" id="pattern-hatched-45deg-white-8.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.9,8.9" width="17.8">
421
421
+
</pattern><pattern height="17.8" id="pattern-hatched-45deg-white-8.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.9,8.9" width="17.8">
543
422
<polygon fill="#ffffff" points="0,0 2.225,0 0,2.225"/>
544
423
<polygon fill="#ffffff" points="0,8.9 8.9,0 8.9,2.225 2.225,8.9"/>
545
545
-
</pattern>
546
546
-
<pattern height="18" id="pattern-hatched-45deg-white-9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9,9" width="18">
424
424
+
</pattern><pattern height="18" id="pattern-hatched-45deg-white-9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9,9" width="18">
547
425
<polygon fill="#ffffff" points="0,0 2.25,0 0,2.25"/>
548
426
<polygon fill="#ffffff" points="0,9 9,0 9,2.25 2.25,9"/>
549
549
-
</pattern>
550
550
-
<pattern height="18.2" id="pattern-hatched-45deg-white-9.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.1,9.1" width="18.2">
427
427
+
</pattern><pattern height="18.2" id="pattern-hatched-45deg-white-9.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.1,9.1" width="18.2">
551
428
<polygon fill="#ffffff" points="0,0 2.275,0 0,2.275"/>
552
429
<polygon fill="#ffffff" points="0,9.1 9.1,0 9.1,2.275 2.275,9.1"/>
553
553
-
</pattern>
554
554
-
<pattern height="18.4" id="pattern-hatched-45deg-white-9.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.2,9.2" width="18.4">
430
430
+
</pattern><pattern height="18.4" id="pattern-hatched-45deg-white-9.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.2,9.2" width="18.4">
555
431
<polygon fill="#ffffff" points="0,0 2.3,0 0,2.3"/>
556
432
<polygon fill="#ffffff" points="0,9.2 9.2,0 9.2,2.3 2.3,9.2"/>
557
557
-
</pattern>
558
558
-
<pattern height="18.6" id="pattern-hatched-45deg-white-9.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.3,9.3" width="18.6">
433
433
+
</pattern><pattern height="18.6" id="pattern-hatched-45deg-white-9.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.3,9.3" width="18.6">
559
434
<polygon fill="#ffffff" points="0,0 2.325,0 0,2.325"/>
560
435
<polygon fill="#ffffff" points="0,9.3 9.3,0 9.3,2.325 2.325,9.3"/>
561
561
-
</pattern>
562
562
-
</defs>
563
563
-
</svg>
436
436
+
</pattern></defs></svg>
+11
-12
examples/specimen/src/snapshots/specimen__colors_shed.snap
Reviewed
···
5
5
<svg height="150" viewBox="0 0 150 150" width="150" xmlns="http://www.w3.org/2000/svg">
6
6
<rect fill="white" height="150" width="150" x="0" y="0"/>
7
7
<g class="layer" data-layer="root">
8
8
-
<rect data-object="root--anon-0" height="50" style="fill: blue;" width="50" x="0" y="0"/>
9
9
-
<rect data-object="root--anon-1" height="50" style="fill: cyan;" width="50" x="50" y="0"/>
10
10
-
<rect data-object="root--anon-2" height="50" style="fill: yellow;" width="50" x="100" y="0"/>
11
11
-
<rect data-object="root--anon-3" height="50" style="fill: orange;" width="50" x="0" y="50"/>
12
12
-
<rect data-object="root--anon-4" height="50" style="fill: red;" width="50" x="50" y="50"/>
13
13
-
<rect data-object="root--anon-5" height="50" style="fill: brown;" width="50" x="100" y="50"/>
14
14
-
<rect data-object="root--anon-6" height="50" style="fill: purple;" width="50" x="0" y="100"/>
15
15
-
<rect data-object="root--anon-7" height="50" style="fill: pink;" width="50" x="50" y="100"/>
16
16
-
<rect data-object="root--anon-8" height="50" style="fill: green;" width="50" x="100" y="100"/>
17
17
-
</g>
18
18
-
<g class="layer" data-layer="circles"/>
19
19
-
<defs/>
8
8
+
<rect data-object="root--anon-0" height="50" width="50" x="0" y="0" style="fill: blue;"/>
9
9
+
<rect data-object="root--anon-1" height="50" width="50" x="50" y="0" style="fill: cyan;"/>
10
10
+
<rect data-object="root--anon-2" height="50" width="50" x="100" y="0" style="fill: yellow;"/>
11
11
+
<rect data-object="root--anon-3" height="50" width="50" x="0" y="50" style="fill: orange;"/>
12
12
+
<rect data-object="root--anon-4" height="50" width="50" x="50" y="50" style="fill: red;"/>
13
13
+
<rect data-object="root--anon-5" height="50" width="50" x="100" y="50" style="fill: brown;"/>
14
14
+
<rect data-object="root--anon-6" height="50" width="50" x="0" y="100" style="fill: purple;"/>
15
15
+
<rect data-object="root--anon-7" height="50" width="50" x="50" y="100" style="fill: pink;"/>
16
16
+
<rect data-object="root--anon-8" height="50" width="50" x="100" y="100" style="fill: green;"/>
17
17
+
</g><g class="layer" data-layer="circles"/>
18
18
+
<defs />
20
19
</svg>
+1
-2
examples/specimen/src/snapshots/specimen__grid.snap
Reviewed
···
14
14
<circle cx="0" cy="100" data-object="root--anon-6" r="2" style="fill: black;"/>
15
15
<circle cx="50" cy="100" data-object="root--anon-7" r="2" style="fill: black;"/>
16
16
<circle cx="100" cy="100" data-object="root--anon-8" r="2" style="fill: black;"/>
17
17
-
</g>
18
18
-
<defs/>
17
17
+
</g><defs />
19
18
</svg>
+7
-8
examples/specimen/src/snapshots/specimen__shapes_shed.snap
Reviewed
···
6
6
<rect fill="white" height="170" width="170" x="-10" y="-10"/>
7
7
<g class="layer" data-layer="root">
8
8
<circle cx="25" cy="25" data-object="root--anon-0" r="25" style="fill: black;"/>
9
9
-
<path d="M50,50 Q100,50,100,0" data-object="root--anon-1" stroke-width="5" style="stroke: black; fill: transparent;"/>
10
10
-
<path d="M100,50 Q100,0,150,0" data-object="root--anon-2" stroke-width="5" style="stroke: black; fill: transparent;"/>
9
9
+
<path d="M 50 50 Q 100 50 100 0" data-object="root--anon-1" stroke-width="5" style="stroke: black; fill: transparent;"/>
10
10
+
<path d="M 100 50 Q 100 0 150 0" data-object="root--anon-2" stroke-width="5" style="stroke: black; fill: transparent;"/>
11
11
<circle cx="0" cy="50" data-object="root--anon-3" r="5" style="fill: black;"/>
12
12
-
<line data-object="root--anon-4" stroke-width="5" style="stroke: black; fill: transparent;" x1="50" x2="100" y1="50" y2="100"/>
13
13
-
<rect data-object="root--anon-5" height="50" style="fill: black;" width="50" x="0" y="100"/>
12
12
+
<line data-object="root--anon-4" stroke-width="5" x1="50" x2="100" y1="50" y2="100" style="stroke: black; fill: transparent;"/>
13
13
+
<rect data-object="root--anon-5" height="50" width="50" x="0" y="100" style="fill: black;"/>
14
14
<circle cx="100" cy="150" data-object="root--anon-6" r="2" style="fill: black;"/>
15
15
-
<path d="M100,50 L150,50 L150,100 z" data-object="root--anon-7" style="fill: black;"/>
16
16
-
<text data-object="root--anon-8" dominant-baseline="hanging" font-family="Inconsolata" font-size="5pt" style="fill: black;" x="0" y="0">test</text>
17
17
-
</g>
18
18
-
<defs/>
15
15
+
<path d="M 100 50 L 150 50 L 150 100 Z" data-object="root--anon-7" style="fill: black;"/>
16
16
+
<text data-object="root--anon-8" dominant-baseline="hanging" font-family="Inconsolata" font-size="5pt" text-anchor="start" x="0" y="0" style="fill: black;">
17
17
+
test</text></g><defs />
19
18
</svg>
+44
-50
src/graphics/fill.rs
Reviewed
···
1
1
-
use crate::{Angle, Color, ColorMapping};
1
1
+
use crate::{rendering::svg, Angle, Color, ColorMapping};
2
2
3
3
#[derive(Debug, Clone, Copy)]
4
4
pub enum Fill {
···
78
78
pub fn pattern_definition(
79
79
&self,
80
80
colormapping: &ColorMapping,
81
81
-
) -> Option<svg::node::element::Pattern> {
81
81
+
) -> Option<svg::Node> {
82
82
match self {
83
83
Fill::Hatches(color, angle, size, thickness_ratio) => {
84
84
let thickness = size * (2.0 * thickness_ratio);
85
85
86
86
-
let pattern = svg::node::element::Pattern::new()
87
87
-
.set("id", self.pattern_id())
88
88
-
.set("patternUnits", "userSpaceOnUse")
89
89
-
.set("height", size * 2.0)
90
90
-
.set("width", size * 2.0)
91
91
-
.set("viewBox", format!("0,0,{},{}", size, size))
92
92
-
.set(
86
86
+
let pattern = svg::tag("pattern")
87
87
+
.attr("id", self.pattern_id())
88
88
+
.attr("patternUnits", "userSpaceOnUse")
89
89
+
.attr("height", size * 2.0)
90
90
+
.attr("width", size * 2.0)
91
91
+
.attr("viewBox", format!("0,0,{},{}", size, size))
92
92
+
.attr(
93
93
"patternTransform",
94
94
format!("rotate({})", (*angle - Angle(45.0)).degrees()),
95
95
)
96
96
// https://stackoverflow.com/a/55104220/9943464
97
97
-
.add(
98
98
-
svg::node::element::Polygon::new()
99
99
-
.set(
100
100
-
"points",
101
101
-
format!(
102
102
-
"0,0 {},0 0,{}",
103
103
-
thickness / 2.0,
104
104
-
thickness / 2.0
105
105
-
),
106
106
-
)
107
107
-
.set("fill", color.render(colormapping)),
108
108
-
)
109
109
-
.add(
110
110
-
svg::node::element::Polygon::new()
111
111
-
.set(
112
112
-
"points",
113
113
-
format!(
114
114
-
"0,{} {},0 {},{} {},{}",
115
115
-
size,
116
116
-
size,
117
117
-
size,
118
118
-
thickness / 2.0,
119
119
-
thickness / 2.0,
120
120
-
size,
121
121
-
),
122
122
-
)
123
123
-
.set("fill", color.render(colormapping)),
124
124
-
);
97
97
+
.wrapping(vec![
98
98
+
svg::tag("polygon").fill(*color, colormapping).attr(
99
99
+
"points",
100
100
+
format!(
101
101
+
"0,0 {},0 0,{}",
102
102
+
thickness / 2.0,
103
103
+
thickness / 2.0
104
104
+
),
105
105
+
),
106
106
+
svg::tag("polygon").fill(*color, colormapping).attr(
107
107
+
"points",
108
108
+
format!(
109
109
+
"0,{} {},0 {},{} {},{}",
110
110
+
size,
111
111
+
size,
112
112
+
size,
113
113
+
thickness / 2.0,
114
114
+
thickness / 2.0,
115
115
+
size,
116
116
+
),
117
117
+
),
118
118
+
])
119
119
+
.node();
125
120
126
121
Some(pattern)
127
122
}
128
123
Fill::Dotted(color, diameter, spacing) => {
129
124
let box_size = diameter + 2.0 * spacing;
130
130
-
let pattern = svg::node::element::Pattern::new()
131
131
-
.set("id", self.pattern_id())
132
132
-
.set("patternUnits", "userSpaceOnUse")
133
133
-
.set("height", box_size)
134
134
-
.set("width", box_size)
135
135
-
.set("viewBox", format!("0,0,{},{}", box_size, box_size))
136
136
-
.add(
137
137
-
svg::node::element::Circle::new()
138
138
-
.set("cx", box_size / 2.0)
139
139
-
.set("cy", box_size / 2.0)
140
140
-
.set("r", diameter / 2.0)
141
141
-
.set("fill", color.render(colormapping)),
142
142
-
);
125
125
+
let pattern = svg::tag("pattern")
126
126
+
.attr("id", self.pattern_id())
127
127
+
.attr("patternUnits", "userSpaceOnUse")
128
128
+
.attr("height", box_size)
129
129
+
.attr("width", box_size)
130
130
+
.attr("viewBox", format!("0,0,{},{}", box_size, box_size))
131
131
+
.wrapping(vec![svg::tag("circle")
132
132
+
.fill(*color, colormapping)
133
133
+
.attr("cx", box_size / 2.0)
134
134
+
.attr("cy", box_size / 2.0)
135
135
+
.attr("r", diameter / 2.0)])
136
136
+
.node();
143
137
144
138
Some(pattern)
145
139
}
+1
-1
src/graphics/objects.rs
Reviewed
···
25
25
// FittedText(Region, String),
26
26
Rectangle(Point, Point),
27
27
Image(Region, String),
28
28
-
RawSVG(svg::node::element::Element),
28
28
+
RawSVG(String),
29
29
// Tiling(Region, Box<Object>),
30
30
}
31
31
+20
-18
src/rendering/canvas.rs
Reviewed
···
1
1
use super::renderable::SVGRenderable;
2
2
-
use crate::graphics::canvas::Canvas;
2
2
+
use crate::{graphics::canvas::Canvas, rendering::svg};
3
3
use measure_time::debug_time;
4
4
use resvg::usvg;
5
5
use std::sync::Arc;
···
11
11
cell_size: usize,
12
12
object_sizes: crate::graphics::objects::ObjectSizes,
13
13
_id: &str,
14
14
-
) -> anyhow::Result<svg::node::element::Element> {
14
14
+
) -> anyhow::Result<svg::Node> {
15
15
debug_time!("render_to_svg/canvas");
16
16
let background_color = self.background.unwrap_or_default();
17
17
-
let mut svg = svg::Document::new();
18
18
-
svg = svg.add(
19
19
-
svg::node::element::Rectangle::new()
20
20
-
.set("x", -(self.canvas_outter_padding as i32))
21
21
-
.set("y", -(self.canvas_outter_padding as i32))
22
22
-
.set("width", self.width())
23
23
-
.set("height", self.height())
24
24
-
.set("fill", background_color.render(&self.colormap)),
17
17
+
let mut svg = svg::tag("svg").attr("xmlns", "http://www.w3.org/2000/svg");
18
18
+
19
19
+
svg.add(
20
20
+
svg::tag("rect")
21
21
+
.attr("x", -(self.canvas_outter_padding as i32))
22
22
+
.attr("y", -(self.canvas_outter_padding as i32))
23
23
+
.attr("width", self.width())
24
24
+
.attr("height", self.height())
25
25
+
.attr("fill", background_color.render(&self.colormap)),
25
26
);
26
27
27
28
for layer in self.layers.iter().filter(|layer| !layer.hidden).rev() {
28
28
-
svg = svg.add(layer.render_to_svg(
29
29
+
svg.add(layer.render_to_svg(
29
30
colormap.clone(),
30
31
cell_size,
31
32
layer.object_sizes,
···
33
34
)?);
34
35
}
35
36
36
36
-
let mut defs = svg::node::element::Definitions::new();
37
37
+
let mut defs = svg::tag("defs");
37
38
for filter in self.unique_filters() {
38
38
-
defs = defs.add(filter.render_to_svg(
39
39
+
defs.add(filter.render_to_svg(
39
40
colormap.clone(),
40
41
cell_size,
41
42
object_sizes,
···
47
48
if let Some(patterndef) =
48
49
pattern_fill.pattern_definition(&self.colormap)
49
50
{
50
50
-
defs = defs.add(patterndef)
51
51
+
defs.add(patterndef);
51
52
}
52
53
}
53
54
55
55
+
svg.add(defs);
56
56
+
54
57
Ok(svg
55
55
-
.add(defs)
56
56
-
.set(
58
58
+
.attr(
57
59
"viewBox",
58
60
format!(
59
61
"{0} {0} {1} {2}",
···
62
64
self.height()
63
65
),
64
66
)
65
65
-
.set("width", self.width())
66
66
-
.set("height", self.height())
67
67
+
.attr("width", self.width())
68
68
+
.attr("height", self.height())
67
69
.into())
68
70
}
69
71
}
+30
-50
src/rendering/filter.rs
Reviewed
···
2
2
3
3
use crate::{ColorMapping, Filter, FilterType};
4
4
5
5
-
use super::{renderable::SVGRenderable, CSSRenderable};
5
5
+
use super::{renderable::SVGRenderable, svg, CSSRenderable};
6
6
7
7
impl SVGRenderable for Filter {
8
8
fn render_to_svg(
···
11
11
_cell_size: usize,
12
12
_object_sizes: crate::graphics::objects::ObjectSizes,
13
13
_id: &str,
14
14
-
) -> anyhow::Result<svg::node::element::Element> {
14
14
+
) -> anyhow::Result<svg::Node> {
15
15
{
16
16
debug_time!("render_to_svg/filter");
17
17
Ok(match self.kind {
···
28
28
// "#,
29
29
// 2.5
30
30
// ) // TODO parameterize stdDeviation
31
31
-
svg::node::element::Filter::new()
32
32
-
.add(
33
33
-
// TODO parameterize stdDeviation
34
34
-
svg::node::element::FilterEffectGaussianBlur::new()
35
35
-
.set("stdDeviation", self.parameter)
36
36
-
.set("result", "coloredBlur"),
37
37
-
)
38
38
-
.add(
39
39
-
svg::node::element::FilterEffectMerge::new()
40
40
-
.add(
41
41
-
svg::node::element::FilterEffectMergeNode::new()
42
42
-
.set("in", "coloredBlur"),
43
43
-
)
44
44
-
.add(
45
45
-
svg::node::element::FilterEffectMergeNode::new()
46
46
-
.set("in", "SourceGraphic"),
47
47
-
),
48
48
-
)
31
31
+
svg::tag("filter").wrapping(vec![
32
32
+
// TODO parameterize stdDeviation
33
33
+
svg::tag("feGaussianBlur")
34
34
+
.attr("stdDeviation", self.parameter)
35
35
+
.attr("result", "coloredBlur"),
36
36
+
svg::tag("feMerge").wrapping(vec![
37
37
+
svg::tag("feMergeNode").attr("in", "coloredBlur"),
38
38
+
svg::tag("feMergeNode").attr("in", "SourceGraphic"),
39
39
+
]),
40
40
+
])
49
41
}
50
42
FilterType::NaturalShadow => {
51
43
/*
···
58
50
</feMerge>
59
51
</filter>
60
52
*/
61
61
-
svg::node::element::Filter::new()
62
62
-
.add(
63
63
-
svg::node::element::FilterEffectOffset::new()
64
64
-
.set("in", "SourceGraphic")
65
65
-
.set("dx", self.parameter)
66
66
-
.set("dy", self.parameter),
67
67
-
)
68
68
-
.add(
69
69
-
svg::node::element::FilterEffectGaussianBlur::new()
70
70
-
.set("stdDeviation", self.parameter * 4.0)
71
71
-
.set("result", "blur"),
72
72
-
)
73
73
-
.add(
74
74
-
svg::node::element::FilterEffectMerge::new()
75
75
-
.add(
76
76
-
svg::node::element::FilterEffectMergeNode::new()
77
77
-
.set("in", "blur"),
78
78
-
)
79
79
-
.add(
80
80
-
svg::node::element::FilterEffectMergeNode::new()
81
81
-
.set("in", "SourceGraphic"),
82
82
-
),
83
83
-
)
53
53
+
svg::tag("filter").wrapping(vec![
54
54
+
svg::tag("feOffset")
55
55
+
.attr("in", "SourceGraphic")
56
56
+
.attr("dx", self.parameter)
57
57
+
.attr("dy", self.parameter),
58
58
+
svg::tag("feGaussianBlur")
59
59
+
.attr("stdDeviation", self.parameter * 4.0)
60
60
+
.attr("result", "blur"),
61
61
+
svg::tag("feMerge").wrapping(vec![
62
62
+
svg::tag("feMergeNode").attr("in", "blur"),
63
63
+
svg::tag("feMergeNode").attr("in", "SourceGraphic"),
64
64
+
]),
65
65
+
])
84
66
}
85
67
FilterType::Saturation => {
86
68
/*
···
88
70
<feColorMatrix type="saturate" values="0.5"/>
89
71
</filter>
90
72
*/
91
91
-
svg::node::element::Filter::new().add(
92
92
-
svg::node::element::FilterEffectColorMatrix::new()
93
93
-
.set("type", "saturate")
94
94
-
.set("values", self.parameter),
95
95
-
)
73
73
+
svg::tag("filter").wrapping(vec![svg::tag("feColorMatrix")
74
74
+
.attr("type", "saturate")
75
75
+
.attr("values", self.parameter)])
96
76
}
97
77
}
98
98
-
.set("id", self.id())
99
99
-
.set("filterUnit", "userSpaceOnUse")
78
78
+
.attr("id", self.id())
79
79
+
.attr("filterUnit", "userSpaceOnUse")
100
80
.into())
101
81
}
102
82
}
+8
-13
src/rendering/layer.rs
Reviewed
···
1
1
use itertools::Itertools;
2
2
use measure_time::debug_time;
3
3
4
4
-
use super::renderable::SVGRenderable;
4
4
+
use super::{renderable::SVGRenderable, svg};
5
5
use crate::Layer;
6
6
7
7
impl SVGRenderable for Layer {
···
11
11
cell_size: usize,
12
12
object_sizes: crate::graphics::objects::ObjectSizes,
13
13
id: &str,
14
14
-
) -> anyhow::Result<svg::node::element::Element> {
14
14
+
) -> anyhow::Result<svg::Node> {
15
15
debug_time!("render_to_svg/layer");
16
16
-
let mut layer_group = svg::node::element::Group::new()
17
17
-
.set("class", "layer")
18
18
-
.set("data-layer", self.name.clone());
19
19
-
20
20
-
for (object_id, obj) in
21
21
-
self.objects.iter().sorted_by_key(|(oid, _)| (*oid).clone())
22
22
-
{
23
23
-
layer_group = layer_group.add(obj.render_to_svg(
16
16
+
let mut group = svg::tag("g").class("layer").dataset("layer", &self.name);
17
17
+
for (object_id, object) in
18
18
+
self.objects.iter().sorted_by_key(|(oid, _)| (*oid).clone()) {
19
19
+
group.add(object.render_to_svg(
24
20
colormap.clone(),
25
21
cell_size,
26
22
object_sizes,
27
27
-
&[id, object_id].join("--"),
23
23
+
&format!("{}--{}", id, object_id),
28
24
)?);
29
25
}
30
30
-
31
31
-
Ok(layer_group.into())
26
26
+
Ok(group.into())
32
27
}
33
28
}
+2
-1
src/rendering/mod.rs
Reviewed
···
1
1
pub mod canvas;
2
2
+
pub mod svg;
2
3
pub mod fill;
3
4
pub mod filter;
4
5
pub mod fonts;
···
10
11
use measure_time::debug_time;
11
12
pub use renderable::{CSSRenderable, SVGAttributesRenderable, SVGRenderable};
12
13
13
13
-
pub fn stringify_svg(element: svg::node::element::Element) -> String {
14
14
+
pub fn stringify_svg(element: svg::Node) -> String {
14
15
debug_time!("stringify_svg");
15
16
16
17
return element.to_string();
+119
-132
src/rendering/objects.rs
Reviewed
···
6
6
ColoredObject, Object,
7
7
};
8
8
9
9
-
use super::{renderable::SVGRenderable, CSSRenderable, SVGAttributesRenderable};
9
9
+
use super::{
10
10
+
renderable::SVGRenderable, svg, CSSRenderable, SVGAttributesRenderable,
11
11
+
};
10
12
11
13
impl SVGRenderable for ColoredObject {
12
14
fn render_to_svg(
···
15
17
cell_size: usize,
16
18
object_sizes: crate::graphics::objects::ObjectSizes,
17
19
id: &str,
18
18
-
) -> anyhow::Result<svg::node::element::Element> {
20
20
+
) -> anyhow::Result<svg::Node> {
19
21
debug_time!("render_to_svg/colored_object");
20
20
-
let mut obj = self.object.render_to_svg(
22
22
+
let plain_obj = self.object.render_to_svg(
21
23
colormap.clone(),
22
24
cell_size,
23
25
object_sizes,
24
26
id,
25
27
)?;
26
28
27
27
-
let mut css = String::new();
28
28
-
if !matches!(self.object, Object::RawSVG(..)) {
29
29
-
css = self
30
30
-
.fill
31
31
-
.render_to_css(&colormap.clone(), !self.object.fillable());
32
32
-
}
29
29
+
let mut css = self
30
30
+
.fill
31
31
+
.render_to_css(&colormap.clone(), !self.object.fillable());
33
32
34
33
if !self.transformations.is_empty() || !self.filters.is_empty() {
35
35
-
obj = svg::node::element::Group::new()
36
36
-
.set("data-object", id)
37
37
-
.add(obj)
38
38
-
.into();
39
39
-
40
40
-
let attributes = obj.get_attributes_mut();
41
41
-
42
42
-
for (key, value) in self.transformations.render_to_svg_attributes(
43
43
-
colormap.clone(),
44
44
-
cell_size,
45
45
-
object_sizes,
46
46
-
id,
47
47
-
)? {
48
48
-
attributes.insert(key, value.into());
49
49
-
}
50
50
-
51
34
let start = self.object.region().start.coords(cell_size);
52
35
let (w, h) = (
53
36
self.object.region().width() * cell_size,
54
37
self.object.region().height() * cell_size,
55
38
);
56
39
57
57
-
attributes.insert(
58
58
-
"transform-origin".to_string(),
59
59
-
format!(
60
60
-
"{} {}",
61
61
-
start.0 + (w as f32 / 2.0),
62
62
-
start.1 + (h as f32 / 2.0)
63
63
-
)
64
64
-
.into(),
65
65
-
);
66
66
-
67
40
css += "transform-box: fill-box;";
68
41
69
42
css += self
···
72
45
.map(|f| f.render_to_css_filled(&colormap))
73
46
.join(" ")
74
47
.as_ref();
75
75
-
}
76
48
77
77
-
obj.get_attributes_mut().insert("style".into(), css.into());
78
78
-
79
79
-
Ok(obj)
49
49
+
Ok(svg::tag("g")
50
50
+
.dataset("object", id)
51
51
+
.attr(
52
52
+
"transform-origin",
53
53
+
&format!(
54
54
+
"{} {}",
55
55
+
start.0 + (w as f32 / 2.0),
56
56
+
start.1 + (h as f32 / 2.0)
57
57
+
),
58
58
+
)
59
59
+
.with_attributes(self.transformations.render_to_svg_attributes(
60
60
+
colormap,
61
61
+
cell_size,
62
62
+
object_sizes,
63
63
+
id,
64
64
+
)?)
65
65
+
.wrapping(vec![plain_obj])
66
66
+
.attr("style", &css)
67
67
+
.into())
68
68
+
} else {
69
69
+
Ok(match plain_obj {
70
70
+
svg::Node::Element(el) => el.attr("style", &css).into(),
71
71
+
_ => plain_obj,
72
72
+
})
73
73
+
}
80
74
}
81
75
}
82
76
···
87
81
cell_size: usize,
88
82
object_sizes: crate::graphics::objects::ObjectSizes,
89
83
id: &str,
90
90
-
) -> anyhow::Result<svg::node::element::Element> {
84
84
+
) -> anyhow::Result<svg::Node> {
91
85
debug_time!("render_to_svg/object");
92
92
-
let mut rendered = match self {
86
86
+
let rendered = match self {
93
87
Object::Text(..) | Object::CenteredText(..) => {
94
88
self.render_text(cell_size)
95
89
}
···
108
102
Object::RawSVG(..) => self.render_raw_svg(),
109
103
};
110
104
111
111
-
// Ok(group.set("data-object", id).add(rendered).into())
112
112
-
rendered
113
113
-
.get_attributes_mut()
114
114
-
.insert("data-object".into(), id.into());
115
115
-
Ok(rendered)
105
105
+
Ok(match rendered {
106
106
+
svg::Node::Element(el) => el.dataset("object", id).into(),
107
107
+
svg::Node::SVG(svg) => {
108
108
+
if svg.trim().starts_with("<") {
109
109
+
let (before, after) =
110
110
+
svg.split_once(' ').unwrap_or(svg.split_once(">").expect("Malformed SVG tag, {svg} starts with < but doesn't contain a space or >"));
111
111
+
svg::Node::SVG(format!(
112
112
+
r#"{before} data-object="{id}" {after}"#
113
113
+
))
114
114
+
} else {
115
115
+
eprintln!("Malformed raw SVG, {svg} doesn't start with <");
116
116
+
svg::Node::SVG(svg)
117
117
+
}
118
118
+
}
119
119
+
_ => {
120
120
+
panic!("Expected Element or SVG, got {:?}", rendered);
121
121
+
}
122
122
+
})
116
123
}
117
124
}
118
125
119
126
impl Object {
120
120
-
fn render_image(&self, cell_size: usize) -> svg::node::element::Element {
127
127
+
fn render_image(&self, cell_size: usize) -> svg::Node {
121
128
if let Object::Image(region, path) = self {
122
122
-
let (x, y) = region.start.coords(cell_size);
123
123
-
return svg::node::element::Image::new()
124
124
-
.set("x", x)
125
125
-
.set("y", y)
126
126
-
.set("width", region.width() * cell_size)
127
127
-
.set("height", region.height() * cell_size)
128
128
-
.set("href", path.clone())
129
129
+
return svg::tag("image")
130
130
+
.coords(region.start.coords(cell_size))
131
131
+
.attr("width", region.width() * cell_size)
132
132
+
.attr("height", region.height() * cell_size)
133
133
+
.attr("href", path.clone())
129
134
.into();
130
135
}
131
136
132
137
panic!("Expected Image, got {:?}", self);
133
138
}
134
139
135
135
-
fn render_raw_svg(&self) -> svg::node::element::Element {
140
140
+
fn render_raw_svg(&self) -> svg::Node {
136
141
if let Object::RawSVG(svg) = self {
137
137
-
return svg.clone();
142
142
+
return svg::Node::SVG(svg.clone());
138
143
}
139
144
140
145
panic!("Expected RawSVG, got {:?}", self);
141
146
}
142
147
143
143
-
fn render_text(&self, cell_size: usize) -> svg::node::element::Element {
144
144
-
if let Object::Text(position, content, font_size)
145
145
-
| Object::CenteredText(position, content, font_size) = self
146
146
-
{
147
147
-
let centered = matches!(self, Object::CenteredText(..));
148
148
+
fn render_text(&self, cell_size: usize) -> svg::Node {
149
149
+
match self {
150
150
+
Object::Text(position, content, font_size)
151
151
+
| Object::CenteredText(position, content, font_size) => {
152
152
+
let centered = matches!(self, Object::CenteredText(..));
148
153
149
149
-
let coords = if centered {
150
150
-
position.center_coords(cell_size)
151
151
-
} else {
152
152
-
position.coords(cell_size)
153
153
-
};
154
154
-
155
155
-
let mut node = svg::node::element::Text::new(content.clone())
156
156
-
.set("x", coords.0)
157
157
-
.set("y", coords.1)
158
158
-
.set("font-size", format!("{}pt", font_size))
159
159
-
.set("font-family", "Inconsolata");
160
160
-
161
161
-
if centered {
162
162
-
node = node
163
163
-
.set("text-anchor", "middle")
164
164
-
// FIXME does not work with imagemagick
165
165
-
.set("dominant-baseline", "middle");
166
166
-
} else {
167
167
-
// FIXME does not work with imagemagick
168
168
-
// see https://legacy.imagemagick.org/discourse-server/viewtopic.php?t=31540
169
169
-
node = node.set("dominant-baseline", "hanging")
154
154
+
svg::tag("text")
155
155
+
.coords(if centered {
156
156
+
position.center_coords(cell_size)
157
157
+
} else {
158
158
+
position.coords(cell_size)
159
159
+
})
160
160
+
.attr("font-size", format!("{}pt", font_size))
161
161
+
.attr("font-family", "Inconsolata")
162
162
+
.attr(
163
163
+
"dominant-baseline",
164
164
+
if centered { "middle" } else { "hanging" },
165
165
+
)
166
166
+
.attr(
167
167
+
"text-anchor",
168
168
+
if centered { "middle" } else { "start" },
169
169
+
)
170
170
+
.wrapping(vec![svg::Node::Text(content.to_string())])
171
171
+
.into()
170
172
}
171
171
-
172
172
-
return node.into();
173
173
+
_ => panic!("Expected Text, got {:?}", self),
173
174
}
174
174
-
175
175
-
panic!("Expected Text, got {:?}", self);
176
175
}
177
176
178
178
-
// fn render_fitted_text(&self, cell_size: usize) -> svg::node::element::Element {
177
177
+
// fn render_fitted_text(&self, cell_size: usize) -> svg::Node {
179
178
// if let Object::FittedText(region, content) = self {
180
179
// let (x, y) = region.start.coords(cell_size);
181
180
// let width = region.width() * cell_size as f32;
···
194
193
// panic!("Expected FittedText, got {:?}", self);
195
194
// }
196
195
197
197
-
fn render_rectangle(&self, cell_size: usize) -> svg::node::element::Element {
196
196
+
fn render_rectangle(&self, cell_size: usize) -> svg::Node {
198
197
if let Object::Rectangle(start, end) = self {
199
199
-
return svg::node::element::Rectangle::new()
200
200
-
.set("x", start.coords(cell_size).0)
201
201
-
.set("y", start.coords(cell_size).1)
202
202
-
.set("width", start.distances(end).0 * cell_size)
203
203
-
.set("height", start.distances(end).1 * cell_size)
204
204
-
.into();
198
198
+
return svg::tag("rect").region((start, end), cell_size).into();
205
199
}
206
200
207
201
panic!("Expected Rectangle, got {:?}", self);
208
202
}
209
203
210
210
-
fn render_polygon(&self, cell_size: usize) -> svg::node::element::Element {
204
204
+
fn render_polygon(&self, cell_size: usize) -> svg::Node {
211
205
if let Object::Polygon(start, lines) = self {
212
212
-
let mut path = svg::node::element::path::Data::new();
213
213
-
path = path.move_to(start.coords(cell_size));
206
206
+
let mut path = svg::Path::new();
207
207
+
path.move_to(*start, cell_size);
214
208
for line in lines {
215
215
-
path = match line {
209
209
+
match line {
216
210
LineSegment::Straight(end)
217
211
| LineSegment::InwardCurve(end)
218
212
| LineSegment::OutwardCurve(end) => {
219
219
-
path.line_to(end.coords(cell_size))
213
213
+
path.line_to(*end, cell_size);
220
214
}
221
215
};
222
216
}
223
223
-
path = path.close();
224
224
-
return svg::node::element::Path::new().set("d", path).into();
217
217
+
path.close();
218
218
+
return path.node();
225
219
}
226
220
227
221
panic!("Expected Polygon, got {:?}", self);
228
222
}
229
223
230
230
-
fn render_line(&self, cell_size: usize) -> svg::node::element::Element {
224
224
+
fn render_line(&self, cell_size: usize) -> svg::Node {
231
225
if let Object::Line(start, end, width) = self {
232
232
-
return svg::node::element::Line::new()
233
233
-
.set("x1", start.coords(cell_size).0)
234
234
-
.set("y1", start.coords(cell_size).1)
235
235
-
.set("x2", end.coords(cell_size).0)
236
236
-
.set("y2", end.coords(cell_size).1)
237
237
-
.set("stroke-width", *width)
226
226
+
return svg::tag("line")
227
227
+
.position_pair(*start, *end, cell_size)
228
228
+
.attr("stroke-width", *width)
238
229
.into();
239
230
}
240
231
241
232
panic!("Expected Line, got {:?}", self);
242
233
}
243
234
244
244
-
fn render_curve(&self, cell_size: usize) -> svg::node::element::Element {
235
235
+
fn render_curve(&self, cell_size: usize) -> svg::Node {
245
236
if let Object::CurveOutward(start, end, stroke_width)
246
237
| Object::CurveInward(start, end, stroke_width) = self
247
238
{
···
309
300
}
310
301
};
311
302
312
312
-
return svg::node::element::Path::new()
313
313
-
.set(
314
314
-
"d",
315
315
-
svg::node::element::path::Data::new()
316
316
-
.move_to(start.coords(cell_size))
317
317
-
.quadratic_curve_to((control, end.coords(cell_size))),
318
318
-
)
319
319
-
.set("stroke-width", format!("{stroke_width}"))
303
303
+
let mut path = svg::Path::new();
304
304
+
path.move_to(*start, cell_size);
305
305
+
path.quadratic_curve_to(control, *end, cell_size);
306
306
+
return path
307
307
+
.element()
308
308
+
.attr("stroke-width", format!("{stroke_width}"))
320
309
.into();
321
310
}
322
311
···
327
316
&self,
328
317
cell_size: usize,
329
318
object_sizes: ObjectSizes,
330
330
-
) -> svg::node::element::Element {
319
319
+
) -> svg::Node {
331
320
if let Object::SmallCircle(center) = self {
332
332
-
return svg::node::element::Circle::new()
333
333
-
.set("cx", center.coords(cell_size).0)
334
334
-
.set("cy", center.coords(cell_size).1)
335
335
-
.set("r", object_sizes.small_circle_radius)
321
321
+
return svg::tag("circle")
322
322
+
.center_position(*center, cell_size)
323
323
+
.attr("r", object_sizes.small_circle_radius)
336
324
.into();
337
325
}
338
326
···
343
331
&self,
344
332
cell_size: usize,
345
333
object_sizes: ObjectSizes,
346
346
-
) -> svg::node::element::Element {
334
334
+
) -> svg::Node {
347
335
if let Object::Dot(center) = self {
348
348
-
return svg::node::element::Circle::new()
349
349
-
.set("cx", center.coords(cell_size).0)
350
350
-
.set("cy", center.coords(cell_size).1)
351
351
-
.set("r", object_sizes.dot_radius)
336
336
+
return svg::tag("circle")
337
337
+
.center_position(*center, cell_size)
338
338
+
.attr("r", object_sizes.dot_radius)
352
339
.into();
353
340
}
354
341
355
342
panic!("Expected Dot, got {:?}", self);
356
343
}
357
344
358
358
-
fn render_big_circle(&self, cell_size: usize) -> svg::node::element::Element {
345
345
+
fn render_big_circle(&self, cell_size: usize) -> svg::Node {
359
346
if let Object::BigCircle(topleft) = self {
360
347
let (cx, cy) = {
361
348
let (x, y) = topleft.coords(cell_size);
362
349
(x + cell_size as f32 / 2.0, y + cell_size as f32 / 2.0)
363
350
};
364
351
365
365
-
return svg::node::element::Circle::new()
366
366
-
.set("cx", cx)
367
367
-
.set("cy", cy)
368
368
-
.set("r", cell_size / 2)
352
352
+
return svg::tag("circle")
353
353
+
.attr("cx", cx)
354
354
+
.attr("cy", cy)
355
355
+
.attr("r", cell_size / 2)
369
356
.into();
370
357
}
371
358
+2
-1
src/rendering/renderable.rs
Reviewed
···
1
1
+
use super::svg;
1
2
use crate::{graphics::objects::ObjectSizes, ColorMapping};
2
3
use anyhow::Result;
3
4
use itertools::Itertools;
···
11
12
cell_size: usize,
12
13
object_sizes: ObjectSizes,
13
14
id: &str,
14
14
-
) -> Result<svg::node::element::Element>;
15
15
+
) -> Result<svg::Node>;
15
16
}
16
17
17
18
/// Struct can be rendered as attributes of a SVG element
+343
src/rendering/svg.rs
Reviewed
···
1
1
+
use std::{collections::HashMap, fmt::Display};
2
2
+
3
3
+
use itertools::Itertools;
4
4
+
5
5
+
use crate::{Color, ColorMapping, Point, Region};
6
6
+
7
7
+
#[derive(Debug, Clone)]
8
8
+
pub struct Element {
9
9
+
pub tag: String,
10
10
+
pub attributes: HashMap<String, String>,
11
11
+
pub styles: HashMap<String, String>,
12
12
+
pub children: Vec<Node>,
13
13
+
}
14
14
+
15
15
+
#[derive(Debug, Clone)]
16
16
+
pub enum Node {
17
17
+
Element(Element),
18
18
+
Text(String),
19
19
+
SVG(String),
20
20
+
}
21
21
+
22
22
+
impl Into<Node> for Element {
23
23
+
fn into(self) -> Node {
24
24
+
self.node()
25
25
+
}
26
26
+
}
27
27
+
28
28
+
pub fn tag(tag: &str) -> Element {
29
29
+
Element::new(tag)
30
30
+
}
31
31
+
32
32
+
impl Element {
33
33
+
pub fn node(self) -> Node {
34
34
+
Node::Element(self)
35
35
+
}
36
36
+
37
37
+
pub fn new(tag: &str) -> Self {
38
38
+
Element {
39
39
+
tag: tag.to_string(),
40
40
+
attributes: HashMap::new(),
41
41
+
styles: HashMap::new(),
42
42
+
children: Vec::new(),
43
43
+
}
44
44
+
}
45
45
+
46
46
+
pub fn attr(self, key: &str, value: impl Display) -> Self {
47
47
+
// assert!(
48
48
+
// key != "style",
49
49
+
// "Use `style` method instead of `attr` for style attributes."
50
50
+
// );
51
51
+
let mut attributes = self.attributes.clone();
52
52
+
attributes.insert(key.to_string(), value.to_string());
53
53
+
Element { attributes, ..self }
54
54
+
}
55
55
+
56
56
+
/// Sets x and y
57
57
+
pub fn coords(self, p: impl Into<(f32, f32)>) -> Self {
58
58
+
let (x, y) = p.into();
59
59
+
self.attr("x", x).attr("y", y)
60
60
+
}
61
61
+
62
62
+
pub fn fill(self, c: Color, colormap: &ColorMapping) -> Self {
63
63
+
self.attr("fill", c.render(colormap))
64
64
+
}
65
65
+
66
66
+
/// Sets cx and cy
67
67
+
pub fn center_position(self, p: impl Into<Point>, cell_size: usize) -> Self {
68
68
+
let (x, y) = p.into().coords(cell_size);
69
69
+
self.attr("cx", x).attr("cy", y)
70
70
+
}
71
71
+
72
72
+
/// Sets x1, y1 and x2, y2
73
73
+
pub fn position_pair(
74
74
+
self,
75
75
+
p1: impl Into<Point>,
76
76
+
p2: impl Into<Point>,
77
77
+
cell_size: usize,
78
78
+
) -> Self {
79
79
+
let (x1, y1) = p1.into().coords(cell_size);
80
80
+
let (x2, y2) = p2.into().coords(cell_size);
81
81
+
self.attr("x1", x1)
82
82
+
.attr("y1", y1)
83
83
+
.attr("x2", x2)
84
84
+
.attr("y2", y2)
85
85
+
}
86
86
+
87
87
+
/// Sets x and y
88
88
+
pub fn position(self, p: impl Into<Point>, cell_size: usize) -> Self {
89
89
+
self.coords(p.into().coords(cell_size))
90
90
+
}
91
91
+
92
92
+
/// Sets width and height
93
93
+
pub fn dimensions(self, p: impl Into<(usize, usize)>) -> Self {
94
94
+
let (w, h) = p.into();
95
95
+
self.attr("width", w).attr("height", h)
96
96
+
}
97
97
+
98
98
+
/// Sets width and height
99
99
+
pub fn size(self, r: impl Into<Region>, cell_size: usize) -> Self {
100
100
+
self.dimensions(r.into().size(cell_size))
101
101
+
}
102
102
+
103
103
+
/// Sets x, y, width and height according to the region
104
104
+
pub fn region(self, r: impl Into<Region>, cell_size: usize) -> Self {
105
105
+
let region: Region = r.into();
106
106
+
self.position(region.start, cell_size)
107
107
+
.size(region, cell_size)
108
108
+
}
109
109
+
110
110
+
pub fn style(self, key: &str, value: &str) -> Self {
111
111
+
let mut styles = self.styles.clone();
112
112
+
styles.insert(key.to_string(), value.to_string());
113
113
+
Element { styles, ..self }
114
114
+
}
115
115
+
116
116
+
pub fn dataset(self, key: &str, value: &str) -> Self {
117
117
+
let mut attributes = self.attributes.clone();
118
118
+
attributes.insert(format!("data-{key}"), value.to_string());
119
119
+
Element { attributes, ..self }
120
120
+
}
121
121
+
122
122
+
pub fn class(self, class: &str) -> Self {
123
123
+
self.attr("class", class)
124
124
+
}
125
125
+
126
126
+
pub fn add(&mut self, child: impl Into<Node>) -> &mut Self {
127
127
+
self.children.push(child.into());
128
128
+
self
129
129
+
}
130
130
+
131
131
+
pub fn with_attributes(self, attributes: HashMap<String, String>) -> Self {
132
132
+
Element { attributes, ..self }
133
133
+
}
134
134
+
135
135
+
pub fn wrapping(
136
136
+
self,
137
137
+
children: impl IntoIterator<Item = impl Into<Node>>,
138
138
+
) -> Self {
139
139
+
Element {
140
140
+
children: children.into_iter().map(|n| n.into()).collect(),
141
141
+
..self
142
142
+
}
143
143
+
}
144
144
+
145
145
+
pub fn wrap(self, tag: &str, attrs: HashMap<String, String>) -> Self {
146
146
+
Element {
147
147
+
tag: tag.to_string(),
148
148
+
styles: HashMap::new(),
149
149
+
attributes: attrs,
150
150
+
children: vec![Node::Element(self)],
151
151
+
}
152
152
+
}
153
153
+
}
154
154
+
155
155
+
pub enum PathInstruction {
156
156
+
MoveTo((f32, f32)),
157
157
+
LineTo((f32, f32)),
158
158
+
HorizontalLineTo(f32),
159
159
+
VerticalLineTo(f32),
160
160
+
CurveTo((f32, f32), (f32, f32), (f32, f32)),
161
161
+
SmoothCurveTo((f32, f32), (f32, f32)),
162
162
+
QuadraticCurveTo((f32, f32), (f32, f32)),
163
163
+
SmoothQuadraticCurveTo((f32, f32)),
164
164
+
ArcTo((f32, f32), f32, bool, bool, (f32, f32)),
165
165
+
ClosePath,
166
166
+
}
167
167
+
168
168
+
pub struct Path(Vec<PathInstruction>);
169
169
+
170
170
+
impl Path {
171
171
+
pub fn new() -> Self {
172
172
+
Path(Vec::new())
173
173
+
}
174
174
+
175
175
+
pub fn node(self) -> Node {
176
176
+
self.element().node()
177
177
+
}
178
178
+
179
179
+
pub fn element(self) -> Element {
180
180
+
tag("path").attr("d", self.to_string())
181
181
+
}
182
182
+
183
183
+
pub fn move_to(
184
184
+
&mut self,
185
185
+
p: impl Into<Point>,
186
186
+
cell_size: usize,
187
187
+
) -> &mut Self {
188
188
+
self.0
189
189
+
.push(PathInstruction::MoveTo(p.into().coords(cell_size)));
190
190
+
self
191
191
+
}
192
192
+
193
193
+
pub fn line_to(
194
194
+
&mut self,
195
195
+
p: impl Into<Point>,
196
196
+
cell_size: usize,
197
197
+
) -> &mut Self {
198
198
+
self.0
199
199
+
.push(PathInstruction::LineTo(p.into().coords(cell_size)));
200
200
+
self
201
201
+
}
202
202
+
203
203
+
pub fn quadratic_curve_to(
204
204
+
&mut self,
205
205
+
control: impl Into<(f32, f32)>,
206
206
+
end: impl Into<Point>,
207
207
+
cell_size: usize,
208
208
+
) -> &mut Self {
209
209
+
self.0.push(PathInstruction::QuadraticCurveTo(
210
210
+
control.into(),
211
211
+
end.into().coords(cell_size),
212
212
+
));
213
213
+
self
214
214
+
}
215
215
+
216
216
+
pub fn close(&mut self) -> &mut Self {
217
217
+
self.0.push(PathInstruction::ClosePath);
218
218
+
self
219
219
+
}
220
220
+
}
221
221
+
222
222
+
impl Display for Path {
223
223
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224
224
+
f.write_str(
225
225
+
&self
226
226
+
.0
227
227
+
.iter()
228
228
+
.map(|i| i.to_string())
229
229
+
.collect::<Vec<_>>()
230
230
+
.join(" "),
231
231
+
)
232
232
+
}
233
233
+
}
234
234
+
235
235
+
impl Display for PathInstruction {
236
236
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237
237
+
match self {
238
238
+
Self::MoveTo((x, y)) => write!(f, "M {} {}", x, y),
239
239
+
Self::LineTo((x, y)) => write!(f, "L {} {}", x, y),
240
240
+
Self::HorizontalLineTo(x) => write!(f, "H {}", x),
241
241
+
Self::VerticalLineTo(y) => write!(f, "V {}", y),
242
242
+
Self::CurveTo((x1, y1), (x2, y2), (x3, y3)) => {
243
243
+
write!(f, "C {} {} {} {} {} {}", x1, y1, x2, y2, x3, y3)
244
244
+
}
245
245
+
Self::SmoothCurveTo((x2, y2), (x3, y3)) => {
246
246
+
write!(f, "S {} {} {} {}", x2, y2, x3, y3)
247
247
+
}
248
248
+
Self::QuadraticCurveTo((x1, y1), (x2, y2)) => {
249
249
+
write!(f, "Q {} {} {} {}", x1, y1, x2, y2)
250
250
+
}
251
251
+
Self::SmoothQuadraticCurveTo((x2, y2)) => {
252
252
+
write!(f, "T {} {}", x2, y2)
253
253
+
}
254
254
+
Self::ArcTo(
255
255
+
(rx, ry),
256
256
+
angle,
257
257
+
large_arc_flag,
258
258
+
sweep_flag,
259
259
+
(x2, y2),
260
260
+
) => {
261
261
+
write!(
262
262
+
f,
263
263
+
"A {rx} {ry} {angle} {large_arc_flag} {sweep_flag} {x2} {y2}"
264
264
+
)
265
265
+
}
266
266
+
Self::ClosePath => write!(f, "Z"),
267
267
+
}
268
268
+
}
269
269
+
}
270
270
+
271
271
+
fn space_if(add_space: bool) -> &'static str {
272
272
+
if add_space {
273
273
+
" "
274
274
+
} else {
275
275
+
""
276
276
+
}
277
277
+
}
278
278
+
279
279
+
impl Display for Node {
280
280
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281
281
+
match self {
282
282
+
Node::Text(text) => write!(f, "{}", quick_xml::escape::escape(text)),
283
283
+
Node::SVG(svg) => write!(f, "{}", svg),
284
284
+
Node::Element(Element {
285
285
+
tag,
286
286
+
attributes,
287
287
+
styles,
288
288
+
children,
289
289
+
}) => {
290
290
+
write!(f, "<{tag} ")?;
291
291
+
292
292
+
let non_style_attributes: Vec<_> = attributes
293
293
+
.iter()
294
294
+
.filter(|(k, _)| *k != "style")
295
295
+
.sorted_by_key(|(k, _)| *k)
296
296
+
.collect();
297
297
+
298
298
+
for (i, (key, value)) in non_style_attributes.iter().enumerate() {
299
299
+
write!(
300
300
+
f,
301
301
+
r#"{spacing}{key}="{value}""#,
302
302
+
spacing = space_if(i > 0),
303
303
+
key = key,
304
304
+
value = value
305
305
+
.replace("&", "&")
306
306
+
.replace('"', """)
307
307
+
.replace("'", "'")
308
308
+
)?;
309
309
+
}
310
310
+
311
311
+
if attributes.contains_key("style") || !styles.is_empty() {
312
312
+
write!(
313
313
+
f,
314
314
+
r#"{spacing}style="{value}""#,
315
315
+
spacing = space_if(non_style_attributes.len() > 0),
316
316
+
value = styles
317
317
+
.iter()
318
318
+
.map(|(k, v)| format!("{k}: {v};"))
319
319
+
.chain::<Option<String>>(
320
320
+
attributes.get("style").map(|s| s.to_string()),
321
321
+
)
322
322
+
.collect::<Vec<_>>()
323
323
+
.join(" ")
324
324
+
)?;
325
325
+
}
326
326
+
327
327
+
if children.is_empty() {
328
328
+
write!(f, "/>\n")?;
329
329
+
} else {
330
330
+
write!(f, ">\n")?;
331
331
+
332
332
+
for child in children {
333
333
+
write!(f, "{}", child)?;
334
334
+
}
335
335
+
336
336
+
write!(f, "</{tag}>")?;
337
337
+
}
338
338
+
339
339
+
Ok(())
340
340
+
}
341
341
+
}
342
342
+
}
343
343
+
}