diff options
author | Minijackson <minijackson@riseup.net> | 2022-12-22 12:19:59 +0100 |
---|---|---|
committer | Minijackson <minijackson@riseup.net> | 2022-12-22 12:19:59 +0100 |
commit | 92a02c34628343153b33602eae00cef46e28d191 (patch) | |
tree | 8622ec528d24e456be22d984d93aa9bcafc97399 | |
download | diaphragm-92a02c34628343153b33602eae00cef46e28d191.tar.gz diaphragm-92a02c34628343153b33602eae00cef46e28d191.zip |
WIP
47 files changed, 5725 insertions, 0 deletions
@@ -0,0 +1 @@ | |||
eval "$(lorri direnv)" | |||
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1 @@ | |||
/target | |||
diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..e1b9d70 --- /dev/null +++ b/.luarc.json | |||
@@ -0,0 +1,4 @@ | |||
1 | { | ||
2 | "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", | ||
3 | "Lua.workspace.checkThirdParty": false | ||
4 | } \ No newline at end of file | ||
diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f39c0de --- /dev/null +++ b/Cargo.lock | |||
@@ -0,0 +1,759 @@ | |||
1 | # This file is automatically @generated by Cargo. | ||
2 | # It is not intended for manual editing. | ||
3 | version = 3 | ||
4 | |||
5 | [[package]] | ||
6 | name = "anyhow" | ||
7 | version = "1.0.36" | ||
8 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
9 | checksum = "68803225a7b13e47191bab76f2687382b60d259e8cf37f6e1893658b84bb9479" | ||
10 | |||
11 | [[package]] | ||
12 | name = "approx" | ||
13 | version = "0.3.2" | ||
14 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
15 | checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" | ||
16 | dependencies = [ | ||
17 | "num-traits", | ||
18 | ] | ||
19 | |||
20 | [[package]] | ||
21 | name = "autocfg" | ||
22 | version = "1.0.1" | ||
23 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
24 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" | ||
25 | |||
26 | [[package]] | ||
27 | name = "bitflags" | ||
28 | version = "1.2.1" | ||
29 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
30 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | ||
31 | |||
32 | [[package]] | ||
33 | name = "bstr" | ||
34 | version = "0.2.17" | ||
35 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
36 | checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" | ||
37 | dependencies = [ | ||
38 | "memchr", | ||
39 | ] | ||
40 | |||
41 | [[package]] | ||
42 | name = "cairo-rs" | ||
43 | version = "0.9.1" | ||
44 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
45 | checksum = "c5c0f2e047e8ca53d0ff249c54ae047931d7a6ebe05d00af73e0ffeb6e34bdb8" | ||
46 | dependencies = [ | ||
47 | "bitflags", | ||
48 | "cairo-sys-rs", | ||
49 | "glib", | ||
50 | "glib-sys", | ||
51 | "gobject-sys", | ||
52 | "libc", | ||
53 | "thiserror", | ||
54 | ] | ||
55 | |||
56 | [[package]] | ||
57 | name = "cairo-sys-rs" | ||
58 | version = "0.10.0" | ||
59 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
60 | checksum = "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7" | ||
61 | dependencies = [ | ||
62 | "glib-sys", | ||
63 | "libc", | ||
64 | "system-deps", | ||
65 | ] | ||
66 | |||
67 | [[package]] | ||
68 | name = "cc" | ||
69 | version = "1.0.77" | ||
70 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
71 | checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" | ||
72 | |||
73 | [[package]] | ||
74 | name = "cfg-if" | ||
75 | version = "0.1.10" | ||
76 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
77 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" | ||
78 | |||
79 | [[package]] | ||
80 | name = "diaphragm-cairo-renderer" | ||
81 | version = "0.1.0" | ||
82 | dependencies = [ | ||
83 | "cairo-rs", | ||
84 | "diaphragm-core", | ||
85 | "pango", | ||
86 | "pangocairo", | ||
87 | ] | ||
88 | |||
89 | [[package]] | ||
90 | name = "diaphragm-core" | ||
91 | version = "0.1.0" | ||
92 | dependencies = [ | ||
93 | "palette", | ||
94 | ] | ||
95 | |||
96 | [[package]] | ||
97 | name = "diaphragm-examples-lib-dfscq-log" | ||
98 | version = "0.1.0" | ||
99 | dependencies = [ | ||
100 | "diaphragm-cairo-renderer", | ||
101 | "diaphragm-core", | ||
102 | "diaphragm-z3-solver", | ||
103 | ] | ||
104 | |||
105 | [[package]] | ||
106 | name = "diaphragm-lua-bindings" | ||
107 | version = "0.1.0" | ||
108 | dependencies = [ | ||
109 | "diaphragm-cairo-renderer", | ||
110 | "diaphragm-core", | ||
111 | "diaphragm-z3-solver", | ||
112 | "mlua", | ||
113 | ] | ||
114 | |||
115 | [[package]] | ||
116 | name = "diaphragm-z3-solver" | ||
117 | version = "0.1.0" | ||
118 | dependencies = [ | ||
119 | "diaphragm-core", | ||
120 | "z3", | ||
121 | ] | ||
122 | |||
123 | [[package]] | ||
124 | name = "either" | ||
125 | version = "1.6.1" | ||
126 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
127 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" | ||
128 | |||
129 | [[package]] | ||
130 | name = "futures-channel" | ||
131 | version = "0.3.8" | ||
132 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
133 | checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64" | ||
134 | dependencies = [ | ||
135 | "futures-core", | ||
136 | ] | ||
137 | |||
138 | [[package]] | ||
139 | name = "futures-core" | ||
140 | version = "0.3.8" | ||
141 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
142 | checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748" | ||
143 | |||
144 | [[package]] | ||
145 | name = "futures-executor" | ||
146 | version = "0.3.8" | ||
147 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
148 | checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65" | ||
149 | dependencies = [ | ||
150 | "futures-core", | ||
151 | "futures-task", | ||
152 | "futures-util", | ||
153 | ] | ||
154 | |||
155 | [[package]] | ||
156 | name = "futures-macro" | ||
157 | version = "0.3.8" | ||
158 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
159 | checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556" | ||
160 | dependencies = [ | ||
161 | "proc-macro-hack", | ||
162 | "proc-macro2", | ||
163 | "quote", | ||
164 | "syn", | ||
165 | ] | ||
166 | |||
167 | [[package]] | ||
168 | name = "futures-task" | ||
169 | version = "0.3.8" | ||
170 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
171 | checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d" | ||
172 | dependencies = [ | ||
173 | "once_cell", | ||
174 | ] | ||
175 | |||
176 | [[package]] | ||
177 | name = "futures-util" | ||
178 | version = "0.3.8" | ||
179 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
180 | checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2" | ||
181 | dependencies = [ | ||
182 | "futures-core", | ||
183 | "futures-macro", | ||
184 | "futures-task", | ||
185 | "pin-project", | ||
186 | "pin-utils", | ||
187 | "proc-macro-hack", | ||
188 | "proc-macro-nested", | ||
189 | "slab", | ||
190 | ] | ||
191 | |||
192 | [[package]] | ||
193 | name = "getrandom" | ||
194 | version = "0.1.15" | ||
195 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
196 | checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" | ||
197 | dependencies = [ | ||
198 | "cfg-if", | ||
199 | "libc", | ||
200 | "wasi", | ||
201 | ] | ||
202 | |||
203 | [[package]] | ||
204 | name = "glib" | ||
205 | version = "0.10.3" | ||
206 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
207 | checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" | ||
208 | dependencies = [ | ||
209 | "bitflags", | ||
210 | "futures-channel", | ||
211 | "futures-core", | ||
212 | "futures-executor", | ||
213 | "futures-task", | ||
214 | "futures-util", | ||
215 | "glib-macros", | ||
216 | "glib-sys", | ||
217 | "gobject-sys", | ||
218 | "libc", | ||
219 | "once_cell", | ||
220 | ] | ||
221 | |||
222 | [[package]] | ||
223 | name = "glib-macros" | ||
224 | version = "0.10.1" | ||
225 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
226 | checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" | ||
227 | dependencies = [ | ||
228 | "anyhow", | ||
229 | "heck", | ||
230 | "itertools", | ||
231 | "proc-macro-crate", | ||
232 | "proc-macro-error", | ||
233 | "proc-macro2", | ||
234 | "quote", | ||
235 | "syn", | ||
236 | ] | ||
237 | |||
238 | [[package]] | ||
239 | name = "glib-sys" | ||
240 | version = "0.10.1" | ||
241 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
242 | checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" | ||
243 | dependencies = [ | ||
244 | "libc", | ||
245 | "system-deps", | ||
246 | ] | ||
247 | |||
248 | [[package]] | ||
249 | name = "gobject-sys" | ||
250 | version = "0.10.0" | ||
251 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
252 | checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" | ||
253 | dependencies = [ | ||
254 | "glib-sys", | ||
255 | "libc", | ||
256 | "system-deps", | ||
257 | ] | ||
258 | |||
259 | [[package]] | ||
260 | name = "heck" | ||
261 | version = "0.3.2" | ||
262 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
263 | checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" | ||
264 | dependencies = [ | ||
265 | "unicode-segmentation", | ||
266 | ] | ||
267 | |||
268 | [[package]] | ||
269 | name = "itertools" | ||
270 | version = "0.9.0" | ||
271 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
272 | checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" | ||
273 | dependencies = [ | ||
274 | "either", | ||
275 | ] | ||
276 | |||
277 | [[package]] | ||
278 | name = "lazy_static" | ||
279 | version = "1.4.0" | ||
280 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
281 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||
282 | |||
283 | [[package]] | ||
284 | name = "libc" | ||
285 | version = "0.2.81" | ||
286 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
287 | checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" | ||
288 | |||
289 | [[package]] | ||
290 | name = "log" | ||
291 | version = "0.4.11" | ||
292 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
293 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" | ||
294 | dependencies = [ | ||
295 | "cfg-if", | ||
296 | ] | ||
297 | |||
298 | [[package]] | ||
299 | name = "memchr" | ||
300 | version = "2.5.0" | ||
301 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
302 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" | ||
303 | |||
304 | [[package]] | ||
305 | name = "mlua" | ||
306 | version = "0.8.6" | ||
307 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
308 | checksum = "4351dbcc863fb6249c81b3bd0c8001214e9d4d44d22cabda17026353a77fe612" | ||
309 | dependencies = [ | ||
310 | "bstr", | ||
311 | "cc", | ||
312 | "mlua_derive", | ||
313 | "num-traits", | ||
314 | "once_cell", | ||
315 | "pkg-config", | ||
316 | "rustc-hash", | ||
317 | ] | ||
318 | |||
319 | [[package]] | ||
320 | name = "mlua_derive" | ||
321 | version = "0.8.0" | ||
322 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
323 | checksum = "b9214e60d3cf1643013b107330fcd374ccec1e4ba1eef76e7e5da5e8202e71c0" | ||
324 | dependencies = [ | ||
325 | "proc-macro2", | ||
326 | "quote", | ||
327 | "syn", | ||
328 | ] | ||
329 | |||
330 | [[package]] | ||
331 | name = "num-traits" | ||
332 | version = "0.2.14" | ||
333 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
334 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" | ||
335 | dependencies = [ | ||
336 | "autocfg", | ||
337 | ] | ||
338 | |||
339 | [[package]] | ||
340 | name = "once_cell" | ||
341 | version = "1.5.2" | ||
342 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
343 | checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" | ||
344 | |||
345 | [[package]] | ||
346 | name = "palette" | ||
347 | version = "0.5.0" | ||
348 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
349 | checksum = "a05c0334468e62a4dfbda34b29110aa7d70d58c7fdb2c9857b5874dd9827cc59" | ||
350 | dependencies = [ | ||
351 | "approx", | ||
352 | "num-traits", | ||
353 | "palette_derive", | ||
354 | "phf", | ||
355 | "phf_codegen", | ||
356 | ] | ||
357 | |||
358 | [[package]] | ||
359 | name = "palette_derive" | ||
360 | version = "0.5.0" | ||
361 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
362 | checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" | ||
363 | dependencies = [ | ||
364 | "proc-macro2", | ||
365 | "quote", | ||
366 | "syn", | ||
367 | ] | ||
368 | |||
369 | [[package]] | ||
370 | name = "pango" | ||
371 | version = "0.9.1" | ||
372 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
373 | checksum = "9937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438" | ||
374 | dependencies = [ | ||
375 | "bitflags", | ||
376 | "glib", | ||
377 | "glib-sys", | ||
378 | "gobject-sys", | ||
379 | "libc", | ||
380 | "once_cell", | ||
381 | "pango-sys", | ||
382 | ] | ||
383 | |||
384 | [[package]] | ||
385 | name = "pango-sys" | ||
386 | version = "0.10.0" | ||
387 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
388 | checksum = "24d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890" | ||
389 | dependencies = [ | ||
390 | "glib-sys", | ||
391 | "gobject-sys", | ||
392 | "libc", | ||
393 | "system-deps", | ||
394 | ] | ||
395 | |||
396 | [[package]] | ||
397 | name = "pangocairo" | ||
398 | version = "0.10.0" | ||
399 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
400 | checksum = "00f5ae67a05a5e023f09f64e9a71c845274d4b82dedee237b70425811885e883" | ||
401 | dependencies = [ | ||
402 | "bitflags", | ||
403 | "cairo-rs", | ||
404 | "cairo-sys-rs", | ||
405 | "glib", | ||
406 | "glib-sys", | ||
407 | "gobject-sys", | ||
408 | "libc", | ||
409 | "pango", | ||
410 | "pango-sys", | ||
411 | "pangocairo-sys", | ||
412 | ] | ||
413 | |||
414 | [[package]] | ||
415 | name = "pangocairo-sys" | ||
416 | version = "0.11.0" | ||
417 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
418 | checksum = "94ccc97f698c2f0233b84e5ca676893a1e676785b60eec700b9c0e6dcd0feb98" | ||
419 | dependencies = [ | ||
420 | "cairo-sys-rs", | ||
421 | "glib-sys", | ||
422 | "libc", | ||
423 | "pango-sys", | ||
424 | "system-deps", | ||
425 | ] | ||
426 | |||
427 | [[package]] | ||
428 | name = "phf" | ||
429 | version = "0.8.0" | ||
430 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
431 | checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" | ||
432 | dependencies = [ | ||
433 | "phf_shared", | ||
434 | ] | ||
435 | |||
436 | [[package]] | ||
437 | name = "phf_codegen" | ||
438 | version = "0.8.0" | ||
439 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
440 | checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" | ||
441 | dependencies = [ | ||
442 | "phf_generator", | ||
443 | "phf_shared", | ||
444 | ] | ||
445 | |||
446 | [[package]] | ||
447 | name = "phf_generator" | ||
448 | version = "0.8.0" | ||
449 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
450 | checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" | ||
451 | dependencies = [ | ||
452 | "phf_shared", | ||
453 | "rand", | ||
454 | ] | ||
455 | |||
456 | [[package]] | ||
457 | name = "phf_shared" | ||
458 | version = "0.8.0" | ||
459 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
460 | checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" | ||
461 | dependencies = [ | ||
462 | "siphasher", | ||
463 | ] | ||
464 | |||
465 | [[package]] | ||
466 | name = "pin-project" | ||
467 | version = "1.0.2" | ||
468 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
469 | checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" | ||
470 | dependencies = [ | ||
471 | "pin-project-internal", | ||
472 | ] | ||
473 | |||
474 | [[package]] | ||
475 | name = "pin-project-internal" | ||
476 | version = "1.0.2" | ||
477 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
478 | checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" | ||
479 | dependencies = [ | ||
480 | "proc-macro2", | ||
481 | "quote", | ||
482 | "syn", | ||
483 | ] | ||
484 | |||
485 | [[package]] | ||
486 | name = "pin-utils" | ||
487 | version = "0.1.0" | ||
488 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
489 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" | ||
490 | |||
491 | [[package]] | ||
492 | name = "pkg-config" | ||
493 | version = "0.3.19" | ||
494 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
495 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" | ||
496 | |||
497 | [[package]] | ||
498 | name = "ppv-lite86" | ||
499 | version = "0.2.10" | ||
500 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
501 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" | ||
502 | |||
503 | [[package]] | ||
504 | name = "proc-macro-crate" | ||
505 | version = "0.1.5" | ||
506 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
507 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" | ||
508 | dependencies = [ | ||
509 | "toml", | ||
510 | ] | ||
511 | |||
512 | [[package]] | ||
513 | name = "proc-macro-error" | ||
514 | version = "1.0.4" | ||
515 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
516 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" | ||
517 | dependencies = [ | ||
518 | "proc-macro-error-attr", | ||
519 | "proc-macro2", | ||
520 | "quote", | ||
521 | "syn", | ||
522 | "version_check", | ||
523 | ] | ||
524 | |||
525 | [[package]] | ||
526 | name = "proc-macro-error-attr" | ||
527 | version = "1.0.4" | ||
528 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
529 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" | ||
530 | dependencies = [ | ||
531 | "proc-macro2", | ||
532 | "quote", | ||
533 | "version_check", | ||
534 | ] | ||
535 | |||
536 | [[package]] | ||
537 | name = "proc-macro-hack" | ||
538 | version = "0.5.19" | ||
539 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
540 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" | ||
541 | |||
542 | [[package]] | ||
543 | name = "proc-macro-nested" | ||
544 | version = "0.1.6" | ||
545 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
546 | checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" | ||
547 | |||
548 | [[package]] | ||
549 | name = "proc-macro2" | ||
550 | version = "1.0.24" | ||
551 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
552 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" | ||
553 | dependencies = [ | ||
554 | "unicode-xid", | ||
555 | ] | ||
556 | |||
557 | [[package]] | ||
558 | name = "quote" | ||
559 | version = "1.0.8" | ||
560 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
561 | checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" | ||
562 | dependencies = [ | ||
563 | "proc-macro2", | ||
564 | ] | ||
565 | |||
566 | [[package]] | ||
567 | name = "rand" | ||
568 | version = "0.7.3" | ||
569 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
570 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" | ||
571 | dependencies = [ | ||
572 | "getrandom", | ||
573 | "libc", | ||
574 | "rand_chacha", | ||
575 | "rand_core", | ||
576 | "rand_hc", | ||
577 | "rand_pcg", | ||
578 | ] | ||
579 | |||
580 | [[package]] | ||
581 | name = "rand_chacha" | ||
582 | version = "0.2.2" | ||
583 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
584 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" | ||
585 | dependencies = [ | ||
586 | "ppv-lite86", | ||
587 | "rand_core", | ||
588 | ] | ||
589 | |||
590 | [[package]] | ||
591 | name = "rand_core" | ||
592 | version = "0.5.1" | ||
593 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
594 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" | ||
595 | dependencies = [ | ||
596 | "getrandom", | ||
597 | ] | ||
598 | |||
599 | [[package]] | ||
600 | name = "rand_hc" | ||
601 | version = "0.2.0" | ||
602 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
603 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" | ||
604 | dependencies = [ | ||
605 | "rand_core", | ||
606 | ] | ||
607 | |||
608 | [[package]] | ||
609 | name = "rand_pcg" | ||
610 | version = "0.2.1" | ||
611 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
612 | checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" | ||
613 | dependencies = [ | ||
614 | "rand_core", | ||
615 | ] | ||
616 | |||
617 | [[package]] | ||
618 | name = "rustc-hash" | ||
619 | version = "1.1.0" | ||
620 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
621 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | ||
622 | |||
623 | [[package]] | ||
624 | name = "serde" | ||
625 | version = "1.0.118" | ||
626 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
627 | checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" | ||
628 | |||
629 | [[package]] | ||
630 | name = "siphasher" | ||
631 | version = "0.3.3" | ||
632 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
633 | checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" | ||
634 | |||
635 | [[package]] | ||
636 | name = "slab" | ||
637 | version = "0.4.2" | ||
638 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
639 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | ||
640 | |||
641 | [[package]] | ||
642 | name = "strum" | ||
643 | version = "0.18.0" | ||
644 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
645 | checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" | ||
646 | |||
647 | [[package]] | ||
648 | name = "strum_macros" | ||
649 | version = "0.18.0" | ||
650 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
651 | checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" | ||
652 | dependencies = [ | ||
653 | "heck", | ||
654 | "proc-macro2", | ||
655 | "quote", | ||
656 | "syn", | ||
657 | ] | ||
658 | |||
659 | [[package]] | ||
660 | name = "syn" | ||
661 | version = "1.0.55" | ||
662 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
663 | checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" | ||
664 | dependencies = [ | ||
665 | "proc-macro2", | ||
666 | "quote", | ||
667 | "unicode-xid", | ||
668 | ] | ||
669 | |||
670 | [[package]] | ||
671 | name = "system-deps" | ||
672 | version = "1.3.2" | ||
673 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
674 | checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" | ||
675 | dependencies = [ | ||
676 | "heck", | ||
677 | "pkg-config", | ||
678 | "strum", | ||
679 | "strum_macros", | ||
680 | "thiserror", | ||
681 | "toml", | ||
682 | "version-compare", | ||
683 | ] | ||
684 | |||
685 | [[package]] | ||
686 | name = "thiserror" | ||
687 | version = "1.0.22" | ||
688 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
689 | checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" | ||
690 | dependencies = [ | ||
691 | "thiserror-impl", | ||
692 | ] | ||
693 | |||
694 | [[package]] | ||
695 | name = "thiserror-impl" | ||
696 | version = "1.0.22" | ||
697 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
698 | checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" | ||
699 | dependencies = [ | ||
700 | "proc-macro2", | ||
701 | "quote", | ||
702 | "syn", | ||
703 | ] | ||
704 | |||
705 | [[package]] | ||
706 | name = "toml" | ||
707 | version = "0.5.8" | ||
708 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
709 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" | ||
710 | dependencies = [ | ||
711 | "serde", | ||
712 | ] | ||
713 | |||
714 | [[package]] | ||
715 | name = "unicode-segmentation" | ||
716 | version = "1.7.1" | ||
717 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
718 | checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" | ||
719 | |||
720 | [[package]] | ||
721 | name = "unicode-xid" | ||
722 | version = "0.2.1" | ||
723 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
724 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" | ||
725 | |||
726 | [[package]] | ||
727 | name = "version-compare" | ||
728 | version = "0.0.10" | ||
729 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
730 | checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" | ||
731 | |||
732 | [[package]] | ||
733 | name = "version_check" | ||
734 | version = "0.9.2" | ||
735 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
736 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" | ||
737 | |||
738 | [[package]] | ||
739 | name = "wasi" | ||
740 | version = "0.9.0+wasi-snapshot-preview1" | ||
741 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
742 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" | ||
743 | |||
744 | [[package]] | ||
745 | name = "z3" | ||
746 | version = "0.9.0" | ||
747 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
748 | checksum = "0c5bdc8c9e19d1b983c5584cd4baf6fbd71f3ca5c83283b9d46ad7780d67bd3b" | ||
749 | dependencies = [ | ||
750 | "lazy_static", | ||
751 | "log", | ||
752 | "z3-sys", | ||
753 | ] | ||
754 | |||
755 | [[package]] | ||
756 | name = "z3-sys" | ||
757 | version = "0.6.3" | ||
758 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
759 | checksum = "afa18ba5fbd4933e41ffb440c3fd91f91fe9cdb7310cce3ddfb6648563811de0" | ||
diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..91eae68 --- /dev/null +++ b/Cargo.toml | |||
@@ -0,0 +1,10 @@ | |||
1 | [workspace] | ||
2 | members = [ | ||
3 | "cairo-renderer", | ||
4 | # "cli", | ||
5 | "core", | ||
6 | "lua-bindings", | ||
7 | "z3-solver", | ||
8 | |||
9 | "examples/lib-dfscq-log", | ||
10 | ] | ||
@@ -0,0 +1,4 @@ | |||
1 | - Add the diaphragm language | ||
2 | - Add a piet-based renderer | ||
3 | - Add a web-based renderer? (maybe piet) | ||
4 | - Add a live renderer (maybe druid) | ||
diff --git a/cairo-renderer/Cargo.toml b/cairo-renderer/Cargo.toml new file mode 100644 index 0000000..9d7d818 --- /dev/null +++ b/cairo-renderer/Cargo.toml | |||
@@ -0,0 +1,14 @@ | |||
1 | [package] | ||
2 | name = "diaphragm-cairo-renderer" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Minijackson <minijackson@riseup.net>"] | ||
5 | edition = "2021" | ||
6 | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
8 | |||
9 | [dependencies] | ||
10 | diaphragm-core = { path = "../core" } | ||
11 | |||
12 | cairo-rs = { version = "0.9", features = ["svg", "png"] } | ||
13 | pango = "0.9" | ||
14 | pangocairo = "0.10" | ||
diff --git a/cairo-renderer/src/drawing/cairo/mod.rs b/cairo-renderer/src/drawing/cairo/mod.rs new file mode 100644 index 0000000..09baa9c --- /dev/null +++ b/cairo-renderer/src/drawing/cairo/mod.rs | |||
@@ -0,0 +1,35 @@ | |||
1 | use super::Engine; | ||
2 | use crate::core::{shapes::Shape as CoreShape, types::DefinitelyBounded}; | ||
3 | |||
4 | use cairo::Context; | ||
5 | |||
6 | pub struct CairoEngine { | ||
7 | ctx: Context, | ||
8 | } | ||
9 | |||
10 | impl Engine for CairoEngine { | ||
11 | fn new() -> Self { | ||
12 | let surface = cairo::SvgSurface::for_stream(200., 100., std::io::stdout()).unwrap(); | ||
13 | let ctx = cairo::Context::new(&surface); | ||
14 | |||
15 | CairoEngine { ctx } | ||
16 | } | ||
17 | |||
18 | fn draw(&mut self, shape: &DefinitelyBounded<CoreShape>) { | ||
19 | let bounds = &shape.bounds; | ||
20 | |||
21 | self.ctx.move_to(bounds.left, bounds.top); | ||
22 | |||
23 | match &shape.shape { | ||
24 | CoreShape::Rectangle(_rectangle) => { | ||
25 | self.ctx | ||
26 | .rectangle(bounds.left, bounds.top, bounds.width, bounds.height); | ||
27 | self.ctx.stroke(); | ||
28 | } | ||
29 | CoreShape::Text(text) => { | ||
30 | // TODO: properly shape it, with font, etc. | ||
31 | self.ctx.show_text(&text.content); | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | } | ||
diff --git a/cairo-renderer/src/drawing/mod.rs b/cairo-renderer/src/drawing/mod.rs new file mode 100644 index 0000000..1c32fb1 --- /dev/null +++ b/cairo-renderer/src/drawing/mod.rs | |||
@@ -0,0 +1,8 @@ | |||
1 | pub mod cairo; | ||
2 | |||
3 | use crate::core::{shapes::Shape as CoreShape, types::DefinitelyBounded}; | ||
4 | |||
5 | pub trait Engine { | ||
6 | fn new() -> Self; | ||
7 | fn draw(&mut self, shape: &DefinitelyBounded<CoreShape>); | ||
8 | } | ||
diff --git a/cairo-renderer/src/lib.rs b/cairo-renderer/src/lib.rs new file mode 100644 index 0000000..26ca089 --- /dev/null +++ b/cairo-renderer/src/lib.rs | |||
@@ -0,0 +1,111 @@ | |||
1 | use diaphragm_core::{ | ||
2 | styles::{Pattern, DefinedDashStyle}, | ||
3 | text::{DefinedFontDescription, FontDescription}, | ||
4 | Renderer, | ||
5 | }; | ||
6 | |||
7 | pub struct CairoRenderer { | ||
8 | ctx: cairo::Context, | ||
9 | } | ||
10 | |||
11 | impl CairoRenderer { | ||
12 | pub fn new() -> Self { | ||
13 | // TODO: properly | ||
14 | let surface = cairo::SvgSurface::for_stream(1920., 1080., std::io::stdout()).unwrap(); | ||
15 | let ctx = cairo::Context::new(&surface); | ||
16 | |||
17 | Self { ctx } | ||
18 | } | ||
19 | } | ||
20 | |||
21 | impl Renderer for CairoRenderer { | ||
22 | fn move_to(&mut self, x: f64, y: f64) { | ||
23 | self.ctx.move_to(x, y) | ||
24 | } | ||
25 | |||
26 | fn stroke(&mut self) { | ||
27 | self.ctx.stroke(); | ||
28 | } | ||
29 | |||
30 | fn fill(&mut self) { | ||
31 | self.ctx.fill(); | ||
32 | } | ||
33 | |||
34 | fn fill_preserve(&mut self) { | ||
35 | self.ctx.fill_preserve(); | ||
36 | } | ||
37 | |||
38 | fn set_pattern(&mut self, pattern: &Pattern) { | ||
39 | match pattern { | ||
40 | Pattern::Solid(color) => { | ||
41 | let (red, green, blue, alpha) = color.rgba(); | ||
42 | self.ctx.set_source_rgba(red, green, blue, alpha) | ||
43 | } | ||
44 | Pattern::None => {} | ||
45 | _ => panic!("Unhandled pattern"), | ||
46 | } | ||
47 | } | ||
48 | |||
49 | fn set_dash(&mut self, dash: &DefinedDashStyle) { | ||
50 | self.ctx.set_dash(&dash.dashes(), dash.offset()); | ||
51 | } | ||
52 | |||
53 | fn clear_dash(&mut self) { | ||
54 | self.ctx.set_dash(&[], 0.); | ||
55 | } | ||
56 | |||
57 | fn set_line_width(&mut self, width: f64) { | ||
58 | self.ctx.set_line_width(width); | ||
59 | } | ||
60 | |||
61 | fn line_to(&mut self, x: f64, y: f64) { | ||
62 | self.ctx.line_to(x, y) | ||
63 | } | ||
64 | |||
65 | fn rectangle(&mut self, x: f64, y: f64, width: f64, height: f64) { | ||
66 | self.ctx.rectangle(x, y, width, height); | ||
67 | } | ||
68 | |||
69 | fn text_extents(&self, text: &str, font: &FontDescription) -> (f64, f64) { | ||
70 | let layout = pangocairo::create_layout(&self.ctx).expect("Couldn't create layout"); | ||
71 | let font_desc = pango::FontDescription::from_string(&font.family); | ||
72 | layout.set_font_description(Some(&font_desc)); | ||
73 | layout.set_markup(text); | ||
74 | |||
75 | //let (extents, _) = layout.get_pixel_extents(); | ||
76 | //(extents.width as f64, extents.height as f64) | ||
77 | |||
78 | // TODO: get height from the baseline | ||
79 | let mut layout_iter = layout.get_iter().unwrap(); | ||
80 | let _height = loop { | ||
81 | if layout_iter.at_last_line() { | ||
82 | break layout_iter.get_baseline(); | ||
83 | } | ||
84 | |||
85 | layout_iter.next_line(); | ||
86 | }; | ||
87 | |||
88 | // TODO: Probably should use the logical extents, but it has weird width | ||
89 | let (_, extents) = layout.get_pixel_extents(); | ||
90 | //let (extents, _) = layout.get_pixel_extents(); | ||
91 | (extents.width as f64, extents.height as f64) | ||
92 | |||
93 | //let (width, height) = layout.get_pixel_size(); | ||
94 | //(width as f64, height as f64) | ||
95 | } | ||
96 | |||
97 | fn show_text(&mut self, text: &str, font: &DefinedFontDescription) { | ||
98 | let layout = pangocairo::create_layout(&self.ctx).expect("Couldn't create layout"); | ||
99 | let mut font_desc = pango::FontDescription::from_string(&font.family); | ||
100 | |||
101 | // TODO: I have no fucking idea why | ||
102 | font_desc.set_size((font.size * 600.) as _); | ||
103 | //font_desc.set_size((font.size * 700.) as _); | ||
104 | //font_desc.set_absolute_size(font.size * 800.); | ||
105 | layout.set_font_description(Some(&font_desc)); | ||
106 | layout.set_markup(text); | ||
107 | |||
108 | //self.ctx.set_font_size(dbg!(font.size)); | ||
109 | pangocairo::show_layout(&self.ctx, &layout); | ||
110 | } | ||
111 | } | ||
diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 0000000..c02a484 --- /dev/null +++ b/cli/Cargo.toml | |||
@@ -0,0 +1,12 @@ | |||
1 | [package] | ||
2 | name = "diaphragm-cli" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Minijackson <minijackson@riseup.net>"] | ||
5 | edition = "2021" | ||
6 | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
8 | |||
9 | [dependencies] | ||
10 | diaphragm-core = { path = "../core" } | ||
11 | diaphragm-z3-solver = { path = "../z3-solver" } | ||
12 | diaphragm-cairo-renderer = { path = "../cairo-renderer" } | ||
diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 0000000..d2ec038 --- /dev/null +++ b/cli/src/main.rs | |||
@@ -0,0 +1,188 @@ | |||
1 | use diaphragm_cairo_renderer::CairoRenderer; | ||
2 | use diaphragm_core::{styles::*, types::*, *}; | ||
3 | use diaphragm_z3_solver::{z3, Z3Context}; | ||
4 | |||
5 | // drawing::{cairo::CairoEngine, Engine}, | ||
6 | // z3::{self, ast::Ast}, | ||
7 | |||
8 | fn main() { | ||
9 | let z3_cfg = z3::Config::new(); | ||
10 | let z3_ctx = z3::Context::new(&z3_cfg); | ||
11 | let ctx = Z3Context::new(&z3_ctx); | ||
12 | |||
13 | let cairo_renderer = CairoRenderer::new(); | ||
14 | |||
15 | let mut runtime = Runtime::new(Box::new(ctx), Box::new(cairo_renderer)); | ||
16 | |||
17 | let ctx = runtime.solver_ctx(); | ||
18 | |||
19 | let rect1_height = ctx.new_free_float(); | ||
20 | let rect1_width = ctx.new_free_float(); | ||
21 | |||
22 | let rect1_ctx = ShapeContext { | ||
23 | bounds: Bounds { | ||
24 | top: ctx.new_fixed_float(10.), | ||
25 | left: ctx.new_fixed_float(10.), | ||
26 | height: rect1_height, | ||
27 | width: rect1_width, | ||
28 | }, | ||
29 | fill: FillStyle::default(), | ||
30 | stroke: StrokeStyle::default(), | ||
31 | }; | ||
32 | |||
33 | let text_bounds = rect1_ctx.bounds.clone(); | ||
34 | |||
35 | let rect1 = core_shapes::Rectangle {}; | ||
36 | |||
37 | let rect2_top = ctx.new_free_float(); | ||
38 | let rect2_left = ctx.new_free_float(); | ||
39 | |||
40 | let rect2_ctx = ShapeContext { | ||
41 | bounds: Bounds { | ||
42 | top: rect2_top, | ||
43 | left: rect2_left, | ||
44 | height: rect1_width, | ||
45 | width: rect1_height, | ||
46 | }, | ||
47 | fill: FillStyle::default(), | ||
48 | stroke: StrokeStyle::default(), | ||
49 | }; | ||
50 | |||
51 | let rect2 = core_shapes::Rectangle {}; | ||
52 | |||
53 | let _2 = ctx.new_fixed_float(2.); | ||
54 | let double_height = ctx.float_mul(&[rect1_height, _2]); | ||
55 | let width_constraint = ctx.float_eq(rect1_width, double_height); | ||
56 | ctx.constrain(width_constraint); | ||
57 | |||
58 | let _42 = ctx.new_fixed_float(42.); | ||
59 | let width_constraint2 = ctx.float_eq(rect1_width, _42); | ||
60 | ctx.constrain(width_constraint2); | ||
61 | |||
62 | let _10 = ctx.new_fixed_float(10.); | ||
63 | let top_constraint = ctx.float_eq(rect2_top, _10); | ||
64 | ctx.constrain(top_constraint); | ||
65 | |||
66 | let bigger_width = ctx.float_add(&[rect1_width, _10]); | ||
67 | let left_constraint = ctx.float_eq(rect2_left, bigger_width); | ||
68 | ctx.constrain(left_constraint); | ||
69 | |||
70 | let text = core_shapes::Text { | ||
71 | content: String::from("Hello, World!"), | ||
72 | font: text::FontDescription { | ||
73 | family: String::from("mono"), | ||
74 | style: Default::default(), | ||
75 | weight: Default::default(), | ||
76 | size: rect1_height, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | let text_ctx = ShapeContext { | ||
81 | bounds: text_bounds, | ||
82 | fill: FillStyle::default(), | ||
83 | stroke: StrokeStyle::default(), | ||
84 | }; | ||
85 | |||
86 | runtime.add_shape(rect1, rect1_ctx); | ||
87 | runtime.add_shape(rect2, rect2_ctx); | ||
88 | runtime.add_shape(text, text_ctx); | ||
89 | |||
90 | runtime.render(); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | fn main() { | ||
95 | // simple_test() | ||
96 | |||
97 | let z3_cfg = z3::Config::new(); | ||
98 | let z3_ctx = z3::Context::new(&z3_cfg); | ||
99 | |||
100 | let mut ctx = Context::new(); | ||
101 | |||
102 | let rect1_height = z3::ast::Real::new_const(&z3_ctx, "rect1_height"); | ||
103 | let rect1_width = z3::ast::Real::new_const(&z3_ctx, "rect1_width"); | ||
104 | |||
105 | let rect1_bounds = Bounds { | ||
106 | top: Float::Defined(10.), | ||
107 | left: Float::Defined(10.), | ||
108 | height: Float::Constrained(rect1_height.clone()), | ||
109 | width: Float::Constrained(rect1_width.clone()), | ||
110 | }; | ||
111 | |||
112 | let rect1 = Bounded::<Box<dyn Drawable>> { | ||
113 | bounds: rect1_bounds, | ||
114 | shape: Box::new(Shape::Rectangle(Rectangle {})), | ||
115 | }; | ||
116 | |||
117 | let rect2_top = z3::ast::Real::new_const(&z3_ctx, "rect2_top"); | ||
118 | let rect2_left = z3::ast::Real::new_const(&z3_ctx, "rect2_left"); | ||
119 | |||
120 | let rect2_bounds = Bounds { | ||
121 | top: Float::Constrained(rect2_top.clone()), | ||
122 | left: Float::Constrained(rect2_left.clone()), | ||
123 | height: Float::Constrained(rect1_width.clone()), | ||
124 | width: Float::Constrained(rect1_height.clone()), | ||
125 | }; | ||
126 | |||
127 | let rect2 = Bounded::<Box<dyn Drawable>> { | ||
128 | bounds: rect2_bounds, | ||
129 | shape: Box::new(Shape::Rectangle(Rectangle {})), | ||
130 | }; | ||
131 | |||
132 | let solver = z3::Solver::new(&z3_ctx); | ||
133 | |||
134 | solver.assert(&rect1_width._eq(&(rect1_height * z3::ast::Real::from_real(&z3_ctx, 2, 1)))); | ||
135 | solver.assert(&rect1_width._eq(&z3::ast::Real::from_real(&z3_ctx, 42, 1))); | ||
136 | |||
137 | solver.assert(&rect2_top._eq(&z3::ast::Real::from_real(&z3_ctx, 10, 1))); | ||
138 | solver.assert(&rect2_left._eq(&(rect1_width + z3::ast::Real::from_real(&z3_ctx, 10, 1)))); | ||
139 | |||
140 | ctx.add_shape(rect1); | ||
141 | ctx.add_shape(rect2); | ||
142 | ctx.set_constraints(&z3_ctx, &solver); | ||
143 | |||
144 | solver.check(); | ||
145 | let model = solver.get_model().expect("Failed to get model"); | ||
146 | |||
147 | let shapes = ctx.draw(&model); | ||
148 | |||
149 | let mut cairo = CairoEngine::new(); | ||
150 | |||
151 | for shape in shapes { | ||
152 | cairo.draw(&shape); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | #[allow(dead_code)] | ||
157 | fn simple_test() { | ||
158 | let mut cairo = CairoEngine::new(); | ||
159 | |||
160 | cairo.draw(&DefinitelyBounded { | ||
161 | bounds: DefinedBounds { | ||
162 | top: 10., | ||
163 | left: 10., | ||
164 | height: 40., | ||
165 | width: 40., | ||
166 | }, | ||
167 | shape: Shape::Rectangle(Rectangle {}), | ||
168 | }); | ||
169 | |||
170 | cairo.draw(&DefinitelyBounded { | ||
171 | bounds: DefinedBounds { | ||
172 | top: 20., | ||
173 | left: 20., | ||
174 | height: 40., | ||
175 | width: 40., | ||
176 | }, | ||
177 | shape: Shape::Text(Text { | ||
178 | content: String::from("Hello, World!"), | ||
179 | font: FontDescription { | ||
180 | family: String::from("Fira Code"), | ||
181 | size: 21, | ||
182 | style: FontStyle::Normal, | ||
183 | weight: FontWeight::Normal, | ||
184 | }, | ||
185 | }), | ||
186 | }); | ||
187 | } | ||
188 | */ | ||
diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 0000000..37fb207 --- /dev/null +++ b/core/Cargo.toml | |||
@@ -0,0 +1,10 @@ | |||
1 | [package] | ||
2 | name = "diaphragm-core" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Minijackson <minijackson@riseup.net>"] | ||
5 | edition = "2021" | ||
6 | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
8 | |||
9 | [dependencies] | ||
10 | palette = "0.5" | ||
diff --git a/core/src/colors.rs b/core/src/colors.rs new file mode 100644 index 0000000..ba78fa3 --- /dev/null +++ b/core/src/colors.rs | |||
@@ -0,0 +1,34 @@ | |||
1 | type Srgba = palette::Srgba<f64>; | ||
2 | |||
3 | #[derive(Copy, Clone, PartialEq, Debug, Default)] | ||
4 | pub struct Color(Srgba); | ||
5 | |||
6 | impl Color { | ||
7 | pub fn transparent() -> Self { | ||
8 | Color(Srgba::new(0., 0., 0., 0.)) | ||
9 | } | ||
10 | |||
11 | pub fn white() -> Self { | ||
12 | Color(Srgba::new(1., 1., 1., 1.)) | ||
13 | } | ||
14 | |||
15 | pub fn black() -> Self { | ||
16 | Color(Srgba::new(0., 0., 0., 1.)) | ||
17 | } | ||
18 | |||
19 | pub fn from_rgb(r: f64, g: f64, b: f64) -> Self { | ||
20 | Color(Srgba::new(r, g, b, 1.0)) | ||
21 | } | ||
22 | |||
23 | pub fn from_rgba(r: f64, g: f64, b: f64, a: f64) -> Self { | ||
24 | Color(Srgba::new(r, g, b, a)) | ||
25 | } | ||
26 | |||
27 | pub fn rgb(&self) -> (f64, f64, f64) { | ||
28 | (self.0.red, self.0.green, self.0.blue) | ||
29 | } | ||
30 | |||
31 | pub fn rgba(&self) -> (f64, f64, f64, f64) { | ||
32 | (self.0.red, self.0.green, self.0.blue, self.0.alpha) | ||
33 | } | ||
34 | } | ||
diff --git a/core/src/complex_shapes.rs b/core/src/complex_shapes.rs new file mode 100644 index 0000000..e23881d --- /dev/null +++ b/core/src/complex_shapes.rs | |||
@@ -0,0 +1,285 @@ | |||
1 | use super::core_shapes::CoreShape; | ||
2 | use super::solving::SolverContext; | ||
3 | use super::styles::{FillStyle, StrokeStyle}; | ||
4 | use super::types::{Bounds, ShapeContext, ShapeContextBuilder}; | ||
5 | |||
6 | pub trait ComplexShape: DynClone { | ||
7 | fn as_core_shape(&self) -> Option<&dyn CoreShape> { | ||
8 | None | ||
9 | } | ||
10 | |||
11 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult; | ||
12 | } | ||
13 | |||
14 | pub trait DynClone { | ||
15 | fn dyn_clone(&self) -> Box<dyn ComplexShape>; | ||
16 | } | ||
17 | |||
18 | impl<T: Clone + ComplexShape + 'static> DynClone for T { | ||
19 | fn dyn_clone(&self) -> Box<dyn ComplexShape> { | ||
20 | Box::new(self.clone()) | ||
21 | } | ||
22 | } | ||
23 | |||
24 | #[derive(Debug, Clone)] | ||
25 | pub struct Drawable<T: ComplexShape> { | ||
26 | pub(crate) context: ShapeContext, | ||
27 | pub(crate) shape: T, | ||
28 | } | ||
29 | |||
30 | impl<T: ComplexShape> Drawable<T> { | ||
31 | pub fn new(shape: T, context: ShapeContext) -> Self { | ||
32 | Self { context, shape } | ||
33 | } | ||
34 | |||
35 | pub fn from_shape(shape: T, solver: &mut dyn SolverContext) -> Self { | ||
36 | Self { | ||
37 | context: ShapeContext::builder().build(solver), | ||
38 | shape, | ||
39 | } | ||
40 | } | ||
41 | |||
42 | pub fn builder(shape: T) -> DrawableBuilder<T> | ||
43 | where | ||
44 | T: Clone, | ||
45 | { | ||
46 | DrawableBuilder::new(shape) | ||
47 | } | ||
48 | |||
49 | pub fn shape(&self) -> &T { | ||
50 | &self.shape | ||
51 | } | ||
52 | |||
53 | pub fn shape_mut(&mut self) -> &mut T { | ||
54 | &mut self.shape | ||
55 | } | ||
56 | |||
57 | pub fn bounds(&self) -> &Bounds { | ||
58 | &self.context.bounds | ||
59 | } | ||
60 | |||
61 | pub fn bounds_mut(&mut self) -> &mut Bounds { | ||
62 | &mut self.context.bounds | ||
63 | } | ||
64 | |||
65 | pub fn fill_style(&mut self) -> &mut FillStyle { | ||
66 | &mut self.context.fill | ||
67 | } | ||
68 | |||
69 | pub fn stroke_style(&mut self) -> &mut StrokeStyle { | ||
70 | &mut self.context.stroke | ||
71 | } | ||
72 | } | ||
73 | |||
74 | pub struct DrawableBuilder<T: ComplexShape> { | ||
75 | context: ShapeContextBuilder, | ||
76 | shape: T, | ||
77 | } | ||
78 | |||
79 | impl<T: ComplexShape + Clone> DrawableBuilder<T> { | ||
80 | pub fn new(shape: T) -> Self { | ||
81 | Self { | ||
82 | context: ShapeContext::builder(), | ||
83 | shape, | ||
84 | } | ||
85 | } | ||
86 | |||
87 | pub fn bounds(&mut self, bounds: Bounds) -> &mut Self { | ||
88 | self.context.bounds(bounds); | ||
89 | self | ||
90 | } | ||
91 | |||
92 | pub fn fill(&mut self, fill: FillStyle) -> &mut Self { | ||
93 | self.context.fill(fill); | ||
94 | self | ||
95 | } | ||
96 | |||
97 | pub fn stroke(&mut self, stroke: StrokeStyle) -> &mut Self { | ||
98 | self.context.stroke(stroke); | ||
99 | self | ||
100 | } | ||
101 | |||
102 | pub fn build(&self, solver: &mut dyn SolverContext) -> Drawable<T> { | ||
103 | Drawable { | ||
104 | shape: self.shape.clone(), | ||
105 | context: self.context.build(solver), | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | pub struct DynDrawable { | ||
111 | pub(crate) context: ShapeContext, | ||
112 | pub(crate) shape: Box<dyn ComplexShape>, | ||
113 | } | ||
114 | |||
115 | // TODO: copy paste is bad? | ||
116 | impl DynDrawable { | ||
117 | pub fn new<T: ComplexShape + 'static>(shape: T, context: ShapeContext) -> Self { | ||
118 | Self { | ||
119 | context, | ||
120 | shape: Box::new(shape), | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub fn new_dyn(shape: Box<dyn ComplexShape>, context: ShapeContext) -> Self { | ||
125 | Self { context, shape } | ||
126 | } | ||
127 | |||
128 | pub fn from_shape<T: ComplexShape + 'static>(shape: T, solver: &mut dyn SolverContext) -> Self { | ||
129 | Self { | ||
130 | context: ShapeContext::builder().build(solver), | ||
131 | shape: Box::new(shape), | ||
132 | } | ||
133 | } | ||
134 | |||
135 | pub fn from_dyn(shape: Box<dyn ComplexShape>, solver: &mut dyn SolverContext) -> Self { | ||
136 | Self { | ||
137 | context: ShapeContext::builder().build(solver), | ||
138 | shape, | ||
139 | } | ||
140 | } | ||
141 | |||
142 | pub fn shape(&self) -> &dyn ComplexShape { | ||
143 | &*self.shape | ||
144 | } | ||
145 | |||
146 | pub fn shape_mut(&mut self) -> &mut dyn ComplexShape { | ||
147 | &mut *self.shape | ||
148 | } | ||
149 | |||
150 | pub fn bounds(&self) -> &Bounds { | ||
151 | &self.context.bounds | ||
152 | } | ||
153 | |||
154 | pub fn bounds_mut(&mut self) -> &mut Bounds { | ||
155 | &mut self.context.bounds | ||
156 | } | ||
157 | |||
158 | pub fn fill_style(&mut self) -> &mut FillStyle { | ||
159 | &mut self.context.fill | ||
160 | } | ||
161 | |||
162 | pub fn stroke_mut(&mut self) -> &mut StrokeStyle { | ||
163 | &mut self.context.stroke | ||
164 | } | ||
165 | } | ||
166 | |||
167 | impl Clone for DynDrawable { | ||
168 | fn clone(&self) -> Self { | ||
169 | DynDrawable { | ||
170 | context: self.context.clone(), | ||
171 | shape: self.shape.dyn_clone(), | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | impl<T: ComplexShape + 'static> From<Drawable<T>> for DynDrawable { | ||
177 | fn from(drawable: Drawable<T>) -> Self { | ||
178 | DynDrawable { | ||
179 | context: drawable.context, | ||
180 | shape: Box::new(drawable.shape), | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | pub struct DrawResult { | ||
186 | pub(crate) subshapes: Vec<DynDrawable>, | ||
187 | pub(crate) waiting_on: Vec<()>, | ||
188 | } | ||
189 | |||
190 | impl DrawResult { | ||
191 | pub fn new() -> Self { | ||
192 | Self { | ||
193 | subshapes: Vec::new(), | ||
194 | waiting_on: Vec::new(), | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | pub fn push_shape<T: ComplexShape + 'static>(&mut self, shape: T, context: ShapeContext) { | ||
200 | self.subshapes.push(DynDrawable { | ||
201 | context, | ||
202 | shape: Box::new(shape), | ||
203 | }) | ||
204 | } | ||
205 | |||
206 | pub fn push_boxed_shape(&mut self, shape: Box<dyn ComplexShape>, context: ShapeContext) { | ||
207 | self.subshapes.push(DynDrawable { context, shape }) | ||
208 | } | ||
209 | */ | ||
210 | |||
211 | pub fn push<T: ComplexShape + 'static>(&mut self, drawable: Drawable<T>) { | ||
212 | self.subshapes.push(drawable.into()) | ||
213 | } | ||
214 | |||
215 | pub fn push_dyn(&mut self, drawable: DynDrawable) { | ||
216 | self.subshapes.push(drawable) | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | pub trait Drawable { | ||
222 | fn draw<'z3>(&self, bounds: &Bounds<'z3>, z3_ctx: &z3::Context) -> DrawResult; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | impl Drawable for Box<dyn Drawable> { | ||
227 | fn draw<'z3>(&self, bounds: &Bounds<'z3>, z3_ctx: &z3::Context) -> DrawResult { | ||
228 | (**self).draw(bounds, z3_ctx) | ||
229 | } | ||
230 | } | ||
231 | */ | ||
232 | |||
233 | impl Drawable for CoreShape { | ||
234 | fn draw<'z3>( | ||
235 | &self, | ||
236 | bounds: &Bounds<'z3>, | ||
237 | ) -> ( | ||
238 | Vec<Bounded<'z3, CoreShape>>, | ||
239 | Vec<Bounded<'z3, Box<dyn Drawable>>>, | ||
240 | ) { | ||
241 | // TODO: clone, really? | ||
242 | ( | ||
243 | vec![Bounded::<CoreShape> { | ||
244 | bounds: bounds.clone(), | ||
245 | shape: self.clone(), | ||
246 | }], | ||
247 | vec![], | ||
248 | ) | ||
249 | } | ||
250 | |||
251 | fn constraints(&self, _bounds: &Bounds, _z3_ctx: &z3::Context) -> Vec<z3::ast::Bool> { | ||
252 | vec![] | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | impl<'a, T: Drawable> Drawable for Vec<Bounded<'a, T>> { | ||
258 | fn draw<'z3>( | ||
259 | &self, | ||
260 | _bounds: &Bounds<'z3>, | ||
261 | as_render Vec<Bounded<'z3, CoreShape>>, | ||
262 | Vec<Bounded<'z3, Box<dyn Drawable>>>, | ||
263 | ) { | ||
264 | let mut core_shapes = Vec::new(); | ||
265 | let mut complex_drawables = Vec::new(); | ||
266 | |||
267 | for drawable in self.iter() { | ||
268 | let (mut inner_core_shapes, mut inner_complex_drawables) = | ||
269 | drawable.shape.draw(&drawable.bounds); | ||
270 | |||
271 | core_shapes.append(&mut inner_core_shapes); | ||
272 | complex_drawables.append(&mut inner_complex_drawables); | ||
273 | } | ||
274 | |||
275 | (core_shapes, complex_drawables) | ||
276 | } | ||
277 | |||
278 | fn constraints(&self, _bounds: &Bounds, z3_ctx: &z3::Context) -> Vec<z3::ast::Bool> { | ||
279 | self.iter() | ||
280 | .flat_map(|drawable| drawable.shape.constraints(&drawable.bounds, z3_ctx)) | ||
281 | .collect() | ||
282 | } | ||
283 | } | ||
284 | */ | ||
285 | */ | ||
diff --git a/core/src/core_shapes.rs b/core/src/core_shapes.rs new file mode 100644 index 0000000..c3d3cae --- /dev/null +++ b/core/src/core_shapes.rs | |||
@@ -0,0 +1,86 @@ | |||
1 | use super::complex_shapes::{ComplexShape, DrawResult}; | ||
2 | use super::rendering::{Render, Renderer}; | ||
3 | use super::solving::{Constrainable, SolverContext, SolverModel}; | ||
4 | use super::types::*; | ||
5 | |||
6 | pub trait CoreShape { | ||
7 | fn constrain( | ||
8 | &self, | ||
9 | _context: &ShapeContext, | ||
10 | _solver: &mut dyn SolverContext, | ||
11 | _renderer: &dyn Renderer, | ||
12 | ) { | ||
13 | } | ||
14 | fn to_render(&self, model: &dyn SolverModel) -> Option<Box<dyn Render>>; | ||
15 | } | ||
16 | |||
17 | impl<T: CoreShape + Clone + 'static> ComplexShape for T { | ||
18 | fn as_core_shape(&self) -> Option<&dyn CoreShape> { | ||
19 | Some(self) | ||
20 | } | ||
21 | |||
22 | fn draw(&self, _context: &ShapeContext, _solver: &mut dyn SolverContext) -> DrawResult { | ||
23 | panic!("Tried to decompose core shape") | ||
24 | } | ||
25 | } | ||
26 | |||
27 | // TODO: add default | ||
28 | #[derive(Copy, Clone, Debug, Default)] | ||
29 | pub struct Rectangle {} | ||
30 | |||
31 | impl CoreShape for Rectangle { | ||
32 | fn to_render(&self, _model: &dyn SolverModel) -> Option<Box<dyn Render>> { | ||
33 | Some(Box::new(self.clone())) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | pub use super::text::{DefinedText, Text}; | ||
38 | |||
39 | impl CoreShape for Text { | ||
40 | fn constrain( | ||
41 | &self, | ||
42 | context: &ShapeContext, | ||
43 | solver: &mut dyn SolverContext, | ||
44 | renderer: &dyn Renderer, | ||
45 | ) { | ||
46 | let height_constraint = solver.float_eq(context.bounds.height, self.font.size); | ||
47 | solver.constrain(height_constraint); | ||
48 | |||
49 | // TODO: handle multiline | ||
50 | let (width, height) = renderer.text_extents(&self.content, &self.font); | ||
51 | dbg!(height); | ||
52 | |||
53 | let scale = solver.float_div(self.font.size, Float::Fixed(height)); | ||
54 | |||
55 | let calculated_width = solver.float_mul(&[Float::Fixed(width), scale]); | ||
56 | let width_constraint = solver.float_eq(context.bounds.width, calculated_width); | ||
57 | solver.constrain(width_constraint); | ||
58 | } | ||
59 | |||
60 | fn to_render(&self, model: &dyn SolverModel) -> Option<Box<dyn Render>> { | ||
61 | self.fixate(model) | ||
62 | .map(|path| -> Box<dyn Render> { Box::new(path) }) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | #[derive(Clone, Debug, Default)] | ||
67 | pub struct StraightPath { | ||
68 | pub(crate) points: Vec<Point2D>, | ||
69 | } | ||
70 | |||
71 | impl StraightPath { | ||
72 | pub fn new(points: Vec<Point2D>) -> Self { | ||
73 | Self { points } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub struct DefinedStraightPath { | ||
78 | pub(crate) points: Vec<DefinedPoint2D>, | ||
79 | } | ||
80 | |||
81 | impl CoreShape for StraightPath { | ||
82 | fn to_render(&self, model: &dyn SolverModel) -> Option<Box<dyn Render>> { | ||
83 | self.fixate(model) | ||
84 | .map(|path| -> Box<dyn Render> { Box::new(path) }) | ||
85 | } | ||
86 | } | ||
diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 0000000..57e45df --- /dev/null +++ b/core/src/lib.rs | |||
@@ -0,0 +1,19 @@ | |||
1 | #![warn(clippy::all)] | ||
2 | #![deny(unsafe_code)] | ||
3 | |||
4 | pub mod colors; | ||
5 | mod complex_shapes; | ||
6 | pub mod core_shapes; | ||
7 | mod rendering; | ||
8 | mod runtime; | ||
9 | pub mod solving; | ||
10 | pub mod styles; | ||
11 | pub mod text; | ||
12 | pub mod types; | ||
13 | |||
14 | pub use complex_shapes::{ | ||
15 | ComplexShape, DrawResult, Drawable, DrawableBuilder, DynClone, DynDrawable, | ||
16 | }; | ||
17 | pub use rendering::Renderer; | ||
18 | pub use runtime::Runtime; | ||
19 | pub use solving::{SolverContext, SolverModel}; | ||
diff --git a/core/src/mod.rs b/core/src/mod.rs new file mode 100644 index 0000000..40fe74f --- /dev/null +++ b/core/src/mod.rs | |||
@@ -0,0 +1,90 @@ | |||
1 | pub mod constraints; | ||
2 | pub mod drawable; | ||
3 | pub mod shapes; | ||
4 | pub mod text; | ||
5 | pub mod types; | ||
6 | |||
7 | pub use self::drawable::Drawable; | ||
8 | pub use self::shapes::Shape as CoreShape; | ||
9 | pub use self::types::{Bounded, Bounds, DefinitelyBounded}; | ||
10 | |||
11 | use self::constraints::Constrainable; | ||
12 | |||
13 | const RECURSION_LIMIT: u64 = 10_000; | ||
14 | |||
15 | pub struct Context<'z3> { | ||
16 | drawables: Vec<Bounded<'z3, Box<dyn Drawable>>>, | ||
17 | } | ||
18 | |||
19 | impl<'z3> Context<'z3> { | ||
20 | pub fn new() -> Self { | ||
21 | Self { drawables: vec![] } | ||
22 | } | ||
23 | |||
24 | pub fn add_shape(&mut self, shape: Bounded<'z3, Box<dyn Drawable>>) { | ||
25 | self.drawables.push(shape); | ||
26 | } | ||
27 | |||
28 | pub fn set_constraints(&self, z3_ctx: &z3::Context, solver: &z3::Solver) { | ||
29 | for drawable in &self.drawables { | ||
30 | for constraint in drawable.shape.constraints(&drawable.bounds, &z3_ctx) { | ||
31 | solver.assert(&constraint); | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | |||
36 | // TODO: simplify until not possible? | ||
37 | |||
38 | pub fn draw(&self, model: &z3::Model) -> Vec<DefinitelyBounded<CoreShape>> { | ||
39 | let mut acc_core_drawables = Vec::new(); | ||
40 | let mut acc_complex_drawables = Vec::new(); | ||
41 | |||
42 | for drawable in &self.drawables { | ||
43 | let bounds = &drawable.bounds; | ||
44 | let shape = &drawable.shape; | ||
45 | |||
46 | let (core_drawables, mut complex_drawables) = shape.draw(bounds); | ||
47 | |||
48 | acc_core_drawables.extend(core_drawables.iter().map(|Bounded { bounds, shape }| { | ||
49 | DefinitelyBounded { | ||
50 | bounds: bounds.fixate(model), | ||
51 | shape: shape.clone(), | ||
52 | } | ||
53 | })); | ||
54 | |||
55 | acc_complex_drawables.append(&mut complex_drawables); | ||
56 | } | ||
57 | |||
58 | let mut recursion_count = 0; | ||
59 | |||
60 | while !acc_complex_drawables.is_empty() { | ||
61 | recursion_count += 1; | ||
62 | |||
63 | let mut tmp_complex_drawables = Vec::new(); | ||
64 | |||
65 | for drawable in acc_complex_drawables.drain(..) { | ||
66 | let bounds = drawable.bounds; | ||
67 | let shape = drawable.shape; | ||
68 | |||
69 | let (core_drawables, mut complex_drawables) = shape.draw(&bounds); | ||
70 | |||
71 | acc_core_drawables.extend(core_drawables.into_iter().map( | ||
72 | |Bounded { bounds, shape }| DefinitelyBounded { | ||
73 | bounds: bounds.fixate(model), | ||
74 | shape, | ||
75 | }, | ||
76 | )); | ||
77 | |||
78 | tmp_complex_drawables.append(&mut complex_drawables); | ||
79 | } | ||
80 | |||
81 | acc_complex_drawables = tmp_complex_drawables; | ||
82 | |||
83 | if recursion_count > RECURSION_LIMIT { | ||
84 | panic!("Recursion limit reached"); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | acc_core_drawables | ||
89 | } | ||
90 | } | ||
diff --git a/core/src/rendering.rs b/core/src/rendering.rs new file mode 100644 index 0000000..f7a0189 --- /dev/null +++ b/core/src/rendering.rs | |||
@@ -0,0 +1,86 @@ | |||
1 | use super::core_shapes::*; | ||
2 | use super::styles::{DefinedDashStyle, DefinedStrokeStyle, FillStyle, Pattern}; | ||
3 | use super::text::{DefinedFontDescription, FontDescription}; | ||
4 | use super::types::DefinedShapeContext; | ||
5 | |||
6 | pub trait Renderer { | ||
7 | fn move_to(&mut self, x: f64, y: f64); | ||
8 | fn stroke(&mut self); | ||
9 | fn fill(&mut self); | ||
10 | fn fill_preserve(&mut self); | ||
11 | fn set_pattern(&mut self, pattern: &Pattern); | ||
12 | fn set_dash(&mut self, dash: &DefinedDashStyle); | ||
13 | fn clear_dash(&mut self); | ||
14 | fn set_line_width(&mut self, width: f64); | ||
15 | fn line_to(&mut self, x: f64, y: f64); | ||
16 | fn rectangle(&mut self, x: f64, y: f64, width: f64, height: f64); | ||
17 | // For a font of size 1. | ||
18 | fn text_extents(&self, text: &str, font: &FontDescription) -> (f64, f64); | ||
19 | fn show_text(&mut self, text: &str, font: &DefinedFontDescription); | ||
20 | } | ||
21 | |||
22 | pub trait Render { | ||
23 | fn render(&self, context: DefinedShapeContext, renderer: &mut dyn Renderer); | ||
24 | } | ||
25 | |||
26 | fn draw(fill: &FillStyle, stroke: &DefinedStrokeStyle, renderer: &mut dyn Renderer) { | ||
27 | let stroking = !stroke.pattern.is_none(); | ||
28 | |||
29 | if !fill.pattern.is_none() { | ||
30 | renderer.set_pattern(&fill.pattern); | ||
31 | if stroking { | ||
32 | renderer.fill_preserve(); | ||
33 | } else { | ||
34 | renderer.fill(); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | if !stroke.pattern.is_none() { | ||
39 | renderer.set_pattern(&stroke.pattern); | ||
40 | renderer.set_line_width(stroke.line_width); | ||
41 | if let Some(dash) = &stroke.dash { | ||
42 | renderer.set_dash(dash); | ||
43 | } | ||
44 | renderer.stroke(); | ||
45 | renderer.clear_dash(); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl Render for Rectangle { | ||
50 | fn render(&self, context: DefinedShapeContext, renderer: &mut dyn Renderer) { | ||
51 | let bounds = &context.bounds; | ||
52 | renderer.rectangle(bounds.left, bounds.top, bounds.width, bounds.height); | ||
53 | draw(&context.fill, &context.stroke, renderer); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl Render for DefinedText { | ||
58 | fn render(&self, context: DefinedShapeContext, renderer: &mut dyn Renderer) { | ||
59 | // TODO: select font, style, text shaping (renderer specific), etc. | ||
60 | let bounds = &context.bounds; | ||
61 | //renderer.move_to(bounds.left, bounds.top + self.font.size); | ||
62 | renderer.move_to(bounds.left, bounds.top); | ||
63 | // TODO: ??? | ||
64 | //draw(&context.fill, &context.stroke, renderer); | ||
65 | renderer.show_text(&self.content, &self.font); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl Render for DefinedStraightPath { | ||
70 | fn render(&self, context: DefinedShapeContext, renderer: &mut dyn Renderer) { | ||
71 | let mut iter = self.points.iter(); | ||
72 | |||
73 | let first_point = match iter.next() { | ||
74 | Some(point) => point, | ||
75 | None => return, | ||
76 | }; | ||
77 | |||
78 | renderer.move_to(first_point.x, first_point.y); | ||
79 | |||
80 | for point in iter { | ||
81 | renderer.line_to(point.x, point.y); | ||
82 | } | ||
83 | |||
84 | draw(&context.fill, &context.stroke, renderer); | ||
85 | } | ||
86 | } | ||
diff --git a/core/src/runtime.rs b/core/src/runtime.rs new file mode 100644 index 0000000..bfb31fa --- /dev/null +++ b/core/src/runtime.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | use super::complex_shapes::{ComplexShape, Drawable, DynDrawable}; | ||
2 | use super::rendering::Renderer; | ||
3 | use super::solving::{Constrainable, SolverContext}; | ||
4 | |||
5 | const RECURSION_LIMIT: u64 = 10_000; | ||
6 | |||
7 | pub struct Runtime<'a> { | ||
8 | solver_ctx: Box<dyn SolverContext + 'a>, | ||
9 | renderer: Box<dyn Renderer>, | ||
10 | drawables: Vec<DynDrawable>, | ||
11 | } | ||
12 | |||
13 | impl<'a> Runtime<'a> { | ||
14 | pub fn new(solver_ctx: Box<dyn SolverContext + 'a>, renderer: Box<dyn Renderer>) -> Self { | ||
15 | Self { | ||
16 | solver_ctx, | ||
17 | renderer, | ||
18 | drawables: Vec::new(), | ||
19 | } | ||
20 | } | ||
21 | |||
22 | pub fn add_drawable<T: ComplexShape + 'static>(&mut self, drawable: Drawable<T>) { | ||
23 | self.drawables.push(drawable.into()) | ||
24 | } | ||
25 | |||
26 | pub fn solver_ctx(&mut self) -> &mut (dyn SolverContext + 'a) { | ||
27 | &mut *self.solver_ctx | ||
28 | } | ||
29 | |||
30 | // TODO: preserve ordering of shapes | ||
31 | pub fn render(mut self) { | ||
32 | let mut drawables = self.drawables; | ||
33 | let mut waited_on_variables = Vec::new(); | ||
34 | let mut core_shapes = Vec::new(); | ||
35 | |||
36 | /* | ||
37 | for drawable in &self.shapes { | ||
38 | let bounds = &drawable.bounds; | ||
39 | let shape = &drawable.shape; | ||
40 | |||
41 | if let Some(core_shape) = shape.to_render() { | ||
42 | drawables.push((*drawable).clone()); | ||
43 | continue; | ||
44 | } | ||
45 | |||
46 | let mut result = shape.draw(bounds); | ||
47 | drawables.append(&mut result.subshapes); | ||
48 | waited_on_variables.append(&mut result.waiting_on); | ||
49 | } | ||
50 | */ | ||
51 | |||
52 | let mut recursion_count = 0; | ||
53 | |||
54 | while !drawables.is_empty() { | ||
55 | recursion_count += 1; | ||
56 | |||
57 | if recursion_count > RECURSION_LIMIT { | ||
58 | panic!("Recursion limit reached"); | ||
59 | } | ||
60 | |||
61 | let mut tmp_drawables = Vec::new(); | ||
62 | |||
63 | for drawable in drawables.drain(..) { | ||
64 | let shape_ctx = &drawable.context; | ||
65 | let shape = &drawable.shape; | ||
66 | |||
67 | if let Some(core_shape) = shape.as_core_shape() { | ||
68 | core_shape.constrain(shape_ctx, &mut *self.solver_ctx, &*self.renderer); | ||
69 | core_shapes.push((shape.dyn_clone(), shape_ctx.clone())); // Better to Arc? Cow? | ||
70 | continue; | ||
71 | } | ||
72 | |||
73 | let mut result = shape.draw(shape_ctx, &mut *self.solver_ctx); | ||
74 | tmp_drawables.append(&mut result.subshapes); | ||
75 | waited_on_variables.append(&mut result.waiting_on); | ||
76 | } | ||
77 | |||
78 | drawables = tmp_drawables; | ||
79 | } | ||
80 | |||
81 | let model = self.solver_ctx.solve(); | ||
82 | |||
83 | // Delay rendering core shapes until later to have all the constraints | ||
84 | for (core_shape, shape_ctx) in core_shapes { | ||
85 | let core_shape = core_shape.as_core_shape().unwrap(); | ||
86 | |||
87 | match (core_shape.to_render(&*model), shape_ctx.fixate(&*model)) { | ||
88 | (Some(defined_shape), Some(shape_ctx)) => { | ||
89 | defined_shape.render(shape_ctx, &mut *self.renderer) | ||
90 | } | ||
91 | _ => panic!("Failed to fixate core shape"), | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | } | ||
diff --git a/core/src/solving.rs b/core/src/solving.rs new file mode 100644 index 0000000..c7e94ba --- /dev/null +++ b/core/src/solving.rs | |||
@@ -0,0 +1,279 @@ | |||
1 | use super::core_shapes::*; | ||
2 | use super::styles::*; | ||
3 | use super::text::*; | ||
4 | use super::types::{Bool, Float}; | ||
5 | |||
6 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||
7 | pub struct VariableHandle(usize); | ||
8 | |||
9 | impl VariableHandle { | ||
10 | pub fn new(id: usize) -> Self { | ||
11 | Self(id) | ||
12 | } | ||
13 | |||
14 | pub fn id(&self) -> usize { | ||
15 | self.0 | ||
16 | } | ||
17 | } | ||
18 | |||
19 | /* | ||
20 | pub trait VariableFloat<'a> { | ||
21 | fn id(&self) -> usize; | ||
22 | fn dyn_clone(&self) -> Box<dyn VariableFloat<'a> + 'a>; | ||
23 | |||
24 | fn eq(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
25 | fn neq(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
26 | fn gt(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
27 | fn ge(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
28 | fn lt(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
29 | fn le(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
30 | |||
31 | fn add(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
32 | fn sub(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
33 | fn mul(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
34 | fn div(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
35 | |||
36 | fn neg(&self) -> Float<'a>; | ||
37 | } | ||
38 | |||
39 | pub trait VariableBool<'a> { | ||
40 | fn id(&self) -> usize; | ||
41 | fn dyn_clone(&self) -> Box<dyn VariableBool<'a> + 'a>; | ||
42 | |||
43 | fn eq(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
44 | fn neq(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
45 | |||
46 | fn and(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
47 | fn or(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
48 | |||
49 | fn not(&self) -> Bool<'a>; | ||
50 | } | ||
51 | */ | ||
52 | |||
53 | pub trait SolverContext { | ||
54 | fn solve<'a>(&'a self) -> Box<dyn SolverModel + 'a>; | ||
55 | fn constrain(&mut self, assertion: Bool); | ||
56 | |||
57 | // Floats | ||
58 | |||
59 | fn new_free_float(&mut self) -> Float; | ||
60 | fn new_fixed_float(&mut self, value: f64) -> Float; | ||
61 | |||
62 | fn float_add(&mut self, values: &[Float]) -> Float; | ||
63 | fn float_sub(&mut self, values: &[Float]) -> Float; | ||
64 | fn float_mul(&mut self, values: &[Float]) -> Float; | ||
65 | fn float_div(&mut self, lhs: Float, rhs: Float) -> Float; | ||
66 | fn float_neg(&mut self, value: Float) -> Float; | ||
67 | |||
68 | fn float_eq(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
69 | fn float_ne(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
70 | fn float_gt(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
71 | fn float_ge(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
72 | fn float_lt(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
73 | fn float_le(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
74 | |||
75 | fn float_max(&mut self, values: &[Float]) -> Float { | ||
76 | let result = self.new_free_float(); | ||
77 | |||
78 | for (index, &candidate) in values.iter().enumerate() { | ||
79 | let comparisons: Vec<_> = values | ||
80 | .iter() | ||
81 | .enumerate() | ||
82 | .filter(|(other_index, _)| *other_index != index) | ||
83 | .map(|(_, &other)| self.float_ge(candidate, other)) | ||
84 | .collect(); | ||
85 | |||
86 | let premise = self.bool_and(&comparisons); | ||
87 | let conclusion = self.float_eq(candidate, result); | ||
88 | let implication = self.bool_implies(premise, conclusion); | ||
89 | self.constrain(implication); | ||
90 | } | ||
91 | |||
92 | result | ||
93 | } | ||
94 | |||
95 | fn float_min(&mut self, values: &[Float]) -> Float { | ||
96 | let result = self.new_free_float(); | ||
97 | |||
98 | for (index, &candidate) in values.iter().enumerate() { | ||
99 | let comparisons: Vec<_> = values | ||
100 | .iter() | ||
101 | .enumerate() | ||
102 | .filter(|(other_index, _)| *other_index != index) | ||
103 | .map(|(_, &other)| self.float_le(candidate, other)) | ||
104 | .collect(); | ||
105 | |||
106 | let premise = self.bool_and(&comparisons); | ||
107 | let conclusion = self.float_eq(candidate, result); | ||
108 | let implication = self.bool_implies(premise, conclusion); | ||
109 | self.constrain(implication); | ||
110 | } | ||
111 | |||
112 | result | ||
113 | } | ||
114 | |||
115 | // Bools | ||
116 | |||
117 | fn new_free_bool(&mut self) -> Bool; | ||
118 | fn new_fixed_bool(&mut self, value: bool) -> Bool; | ||
119 | |||
120 | fn bool_eq(&mut self, lhs: Bool, rhs: Bool) -> Bool; | ||
121 | fn bool_ne(&mut self, lhs: Bool, rhs: Bool) -> Bool; | ||
122 | |||
123 | fn bool_and(&mut self, values: &[Bool]) -> Bool; | ||
124 | fn bool_or(&mut self, values: &[Bool]) -> Bool; | ||
125 | fn bool_not(&mut self, value: Bool) -> Bool; | ||
126 | |||
127 | fn bool_implies(&mut self, lhs: Bool, rhs: Bool) -> Bool; | ||
128 | } | ||
129 | |||
130 | pub trait SolverModel { | ||
131 | fn eval_float(&self, f: Float) -> Option<f64>; | ||
132 | fn eval_bool(&self, b: Bool) -> Option<bool>; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | pub trait Solver { | ||
137 | fn constrain(&mut self, assertion: &Bool); | ||
138 | fn solve(&self) -> Box<dyn SolverModel>; | ||
139 | } | ||
140 | */ | ||
141 | |||
142 | use super::types::*; | ||
143 | |||
144 | pub trait Constrainable { | ||
145 | type Fixated; | ||
146 | |||
147 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated>; | ||
148 | } | ||
149 | |||
150 | impl Constrainable for Float { | ||
151 | type Fixated = f64; | ||
152 | |||
153 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
154 | model.eval_float(*self) | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | fn fixate(&self, model: &Model) -> Self::Fixated { | ||
159 | match self { | ||
160 | Float::Defined(float) => *float, | ||
161 | Float::Constrained(variable) => { | ||
162 | let (num, den) = model | ||
163 | .eval::<z3::ast::Real>(variable) | ||
164 | .expect("Couldn't eval variable") | ||
165 | .as_real() | ||
166 | .expect("Couldn't get value from variable"); | ||
167 | |||
168 | num as f64 / den as f64 | ||
169 | } | ||
170 | Float::Undefined => panic!("Undefined float"), | ||
171 | } | ||
172 | } | ||
173 | */ | ||
174 | } | ||
175 | |||
176 | impl Constrainable for Bounds { | ||
177 | type Fixated = DefinedBounds; | ||
178 | |||
179 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
180 | Some(DefinedBounds { | ||
181 | top: self.top.fixate(model)?, | ||
182 | left: self.left.fixate(model)?, | ||
183 | width: self.width.fixate(model)?, | ||
184 | height: self.height.fixate(model)?, | ||
185 | }) | ||
186 | } | ||
187 | } | ||
188 | |||
189 | impl Constrainable for StrokeStyle { | ||
190 | type Fixated = DefinedStrokeStyle; | ||
191 | |||
192 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
193 | let dash = match &self.dash { | ||
194 | Some(dash) => Some(dash.fixate(model)?), | ||
195 | None => None, | ||
196 | }; | ||
197 | |||
198 | Some(DefinedStrokeStyle { | ||
199 | pattern: self.pattern.clone(), | ||
200 | dash, | ||
201 | line_width: self.line_width.fixate(model)?, | ||
202 | }) | ||
203 | } | ||
204 | } | ||
205 | |||
206 | impl Constrainable for DashStyle { | ||
207 | type Fixated = DefinedDashStyle; | ||
208 | |||
209 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
210 | Some(DefinedDashStyle { | ||
211 | dashes: self | ||
212 | .dashes | ||
213 | .iter() | ||
214 | .map(|value| value.fixate(model)) | ||
215 | .collect::<Option<_>>()?, | ||
216 | offset: self.offset.fixate(model)?, | ||
217 | }) | ||
218 | } | ||
219 | } | ||
220 | |||
221 | impl Constrainable for ShapeContext { | ||
222 | type Fixated = DefinedShapeContext; | ||
223 | |||
224 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
225 | Some(DefinedShapeContext { | ||
226 | bounds: self.bounds.fixate(model)?, | ||
227 | fill: self.fill.clone(), | ||
228 | stroke: self.stroke.fixate(model)?, | ||
229 | }) | ||
230 | } | ||
231 | } | ||
232 | |||
233 | impl Constrainable for Point2D { | ||
234 | type Fixated = DefinedPoint2D; | ||
235 | |||
236 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
237 | Some(DefinedPoint2D { | ||
238 | x: self.x.fixate(model)?, | ||
239 | y: self.y.fixate(model)?, | ||
240 | }) | ||
241 | } | ||
242 | } | ||
243 | |||
244 | impl Constrainable for FontDescription { | ||
245 | type Fixated = DefinedFontDescription; | ||
246 | |||
247 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
248 | Some(DefinedFontDescription { | ||
249 | family: self.family.clone(), | ||
250 | style: self.style, | ||
251 | weight: self.weight, | ||
252 | size: self.size.fixate(&*model)?, | ||
253 | }) | ||
254 | } | ||
255 | } | ||
256 | |||
257 | impl Constrainable for Text { | ||
258 | type Fixated = DefinedText; | ||
259 | |||
260 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
261 | Some(DefinedText { | ||
262 | content: self.content.clone(), | ||
263 | font: self.font.fixate(&*model)?, | ||
264 | }) | ||
265 | } | ||
266 | } | ||
267 | |||
268 | impl Constrainable for StraightPath { | ||
269 | type Fixated = DefinedStraightPath; | ||
270 | |||
271 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
272 | let points: Option<_> = self | ||
273 | .points | ||
274 | .iter() | ||
275 | .map(|point| point.fixate(model)) | ||
276 | .collect(); | ||
277 | Some(DefinedStraightPath { points: points? }) | ||
278 | } | ||
279 | } | ||
diff --git a/core/src/styles.rs b/core/src/styles.rs new file mode 100644 index 0000000..c061c58 --- /dev/null +++ b/core/src/styles.rs | |||
@@ -0,0 +1,161 @@ | |||
1 | use super::colors::Color; | ||
2 | use super::types::Float; | ||
3 | |||
4 | #[derive(Copy, Clone, PartialEq, Debug)] | ||
5 | #[non_exhaustive] | ||
6 | pub enum Pattern { | ||
7 | Solid(Color), | ||
8 | None, | ||
9 | } | ||
10 | |||
11 | impl Pattern { | ||
12 | pub fn is_none(&self) -> bool { | ||
13 | match self { | ||
14 | Pattern::None => true, | ||
15 | _ => false, | ||
16 | } | ||
17 | } | ||
18 | } | ||
19 | |||
20 | impl Default for Pattern { | ||
21 | fn default() -> Self { | ||
22 | Pattern::Solid(Color::default()) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | #[derive(Clone, PartialEq, Debug)] | ||
27 | pub struct FillStyle { | ||
28 | pub(crate) pattern: Pattern, | ||
29 | } | ||
30 | |||
31 | impl FillStyle { | ||
32 | pub fn solid(color: Color) -> Self { | ||
33 | FillStyle { | ||
34 | pattern: Pattern::Solid(color), | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | impl Default for FillStyle { | ||
40 | fn default() -> Self { | ||
41 | FillStyle { | ||
42 | pattern: Pattern::None, | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | |||
47 | // TODO: probably move Float into an enum with Defined(f64) and Variable(handle) | ||
48 | #[derive(Clone, Debug)] | ||
49 | pub struct StrokeStyle { | ||
50 | pub(crate) pattern: Pattern, | ||
51 | pub(crate) dash: Option<DashStyle>, | ||
52 | pub(crate) line_width: Float, | ||
53 | } | ||
54 | |||
55 | impl StrokeStyle { | ||
56 | pub fn solid(color: Color) -> Self { | ||
57 | StrokeStyle { | ||
58 | pattern: Pattern::Solid(color), | ||
59 | dash: None, | ||
60 | line_width: Float::Fixed(0.), | ||
61 | } | ||
62 | } | ||
63 | |||
64 | pub fn builder() -> StrokeStyleBuilder { | ||
65 | StrokeStyleBuilder::default() | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl Default for StrokeStyle { | ||
70 | fn default() -> Self { | ||
71 | Self::builder().build() | ||
72 | } | ||
73 | } | ||
74 | |||
75 | #[derive(Clone, Default)] | ||
76 | pub struct StrokeStyleBuilder { | ||
77 | pattern: Option<Pattern>, | ||
78 | dash: Option<DashStyle>, | ||
79 | line_width: Option<Float>, | ||
80 | } | ||
81 | |||
82 | impl StrokeStyleBuilder { | ||
83 | pub fn pattern(&mut self, pattern: Pattern) -> &mut Self { | ||
84 | self.pattern = Some(pattern); | ||
85 | self | ||
86 | } | ||
87 | |||
88 | pub fn dash(&mut self, dash: DashStyle) -> &mut Self { | ||
89 | self.dash = Some(dash); | ||
90 | self | ||
91 | } | ||
92 | |||
93 | pub fn line_width(&mut self, width: Float) -> &mut Self { | ||
94 | self.line_width = Some(width); | ||
95 | self | ||
96 | } | ||
97 | |||
98 | pub fn build(&mut self) -> StrokeStyle { | ||
99 | StrokeStyle { | ||
100 | pattern: self.pattern.clone().unwrap_or_default(), | ||
101 | dash: self.dash.clone(), | ||
102 | line_width: self.line_width.unwrap_or(Float::Fixed(2.)), | ||
103 | } | ||
104 | } | ||
105 | |||
106 | } | ||
107 | |||
108 | |||
109 | |||
110 | |||
111 | #[derive(Clone, Debug, Default)] | ||
112 | pub struct DashStyle { | ||
113 | pub(crate) dashes: Vec<Float>, | ||
114 | pub(crate) offset: Float, | ||
115 | } | ||
116 | |||
117 | impl DashStyle { | ||
118 | pub fn new(dashes: Vec<Float>, offset: Float) -> Self { | ||
119 | Self { dashes, offset } | ||
120 | } | ||
121 | |||
122 | pub fn dashes(&self) -> &[Float] { | ||
123 | &self.dashes | ||
124 | } | ||
125 | |||
126 | pub fn dashes_mut(&mut self) -> &mut Vec<Float> { | ||
127 | &mut self.dashes | ||
128 | } | ||
129 | |||
130 | pub fn offset(&self) -> Float { | ||
131 | self.offset | ||
132 | } | ||
133 | |||
134 | // TODO: does this makes sense? | ||
135 | pub fn offset_mut(&mut self) -> &mut Float { | ||
136 | &mut self.offset | ||
137 | } | ||
138 | } | ||
139 | |||
140 | #[derive(Clone, PartialEq, Debug, Default)] | ||
141 | pub struct DefinedStrokeStyle { | ||
142 | pub(crate) pattern: Pattern, | ||
143 | pub(crate) dash: Option<DefinedDashStyle>, | ||
144 | pub(crate) line_width: f64, | ||
145 | } | ||
146 | |||
147 | #[derive(Clone, PartialEq, Debug, Default)] | ||
148 | pub struct DefinedDashStyle { | ||
149 | pub(crate) dashes: Vec<f64>, | ||
150 | pub(crate) offset: f64, | ||
151 | } | ||
152 | |||
153 | impl DefinedDashStyle { | ||
154 | pub fn dashes(&self) -> &[f64] { | ||
155 | &self.dashes | ||
156 | } | ||
157 | |||
158 | pub fn offset(&self) -> f64 { | ||
159 | self.offset | ||
160 | } | ||
161 | } | ||
diff --git a/core/src/text.rs b/core/src/text.rs new file mode 100644 index 0000000..3110030 --- /dev/null +++ b/core/src/text.rs | |||
@@ -0,0 +1,81 @@ | |||
1 | use super::types::Float; | ||
2 | |||
3 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] | ||
4 | #[non_exhaustive] | ||
5 | pub enum FontStyle { | ||
6 | Normal, | ||
7 | Oblique, | ||
8 | Italic, | ||
9 | } | ||
10 | |||
11 | impl Default for FontStyle { | ||
12 | fn default() -> Self { | ||
13 | Self::Normal | ||
14 | } | ||
15 | } | ||
16 | |||
17 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] | ||
18 | #[non_exhaustive] | ||
19 | pub enum FontVariant { | ||
20 | Normal, | ||
21 | SmallCaps, | ||
22 | } | ||
23 | |||
24 | impl Default for FontVariant { | ||
25 | fn default() -> Self { | ||
26 | Self::Normal | ||
27 | } | ||
28 | } | ||
29 | |||
30 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] | ||
31 | #[non_exhaustive] | ||
32 | pub enum FontWeight { | ||
33 | Thin, | ||
34 | Ultralight, | ||
35 | Light, | ||
36 | Semilight, | ||
37 | Book, | ||
38 | Normal, | ||
39 | Medium, | ||
40 | Semibold, | ||
41 | Bold, | ||
42 | Ultrabold, | ||
43 | Heavy, | ||
44 | Ultraheavy, | ||
45 | } | ||
46 | |||
47 | impl Default for FontWeight { | ||
48 | fn default() -> Self { | ||
49 | Self::Normal | ||
50 | } | ||
51 | } | ||
52 | |||
53 | #[derive(Clone, Debug)] | ||
54 | pub struct FontDescription { | ||
55 | pub family: String, | ||
56 | pub style: FontStyle, | ||
57 | pub weight: FontWeight, | ||
58 | // TODO: handles weirdly with bounds that specifies both top and bottom | ||
59 | pub size: Float, | ||
60 | } | ||
61 | |||
62 | // TODO: automate creation of Defined* structs | ||
63 | #[derive(Clone, Debug)] | ||
64 | pub struct DefinedFontDescription { | ||
65 | pub family: String, | ||
66 | pub style: FontStyle, | ||
67 | pub weight: FontWeight, | ||
68 | pub size: f64, | ||
69 | } | ||
70 | |||
71 | #[derive(Clone, Debug)] | ||
72 | pub struct Text { | ||
73 | pub content: String, | ||
74 | pub font: FontDescription, | ||
75 | } | ||
76 | |||
77 | #[derive(Clone, Debug)] | ||
78 | pub struct DefinedText { | ||
79 | pub content: String, | ||
80 | pub font: DefinedFontDescription, | ||
81 | } | ||
diff --git a/core/src/types.rs b/core/src/types.rs new file mode 100644 index 0000000..1b7623a --- /dev/null +++ b/core/src/types.rs | |||
@@ -0,0 +1,316 @@ | |||
1 | use super::solving::{SolverContext, VariableHandle}; | ||
2 | use super::styles::{DefinedStrokeStyle, FillStyle, StrokeStyle}; | ||
3 | |||
4 | // TODO: if we're so dependent on lifetimes, it's probably better to remove Box, and use raw | ||
5 | // references instead | ||
6 | |||
7 | // Not Eq / Ord to prevent cofusion | ||
8 | #[derive(Copy, Clone, Debug)] | ||
9 | pub enum Float { | ||
10 | Fixed(f64), | ||
11 | Variable(VariableHandle), | ||
12 | } | ||
13 | |||
14 | impl Default for Float { | ||
15 | fn default() -> Self { | ||
16 | Float::Fixed(0.) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | impl Float { | ||
21 | pub fn from_handle(handle: VariableHandle) -> Self { | ||
22 | Float::Variable(handle) | ||
23 | } | ||
24 | |||
25 | /* | ||
26 | pub fn handle(&self) -> Option<VariableHandle> { | ||
27 | match self { | ||
28 | Float::Fixed(_) => None, | ||
29 | Float::Variable(handle) => Some(handle), | ||
30 | } | ||
31 | } | ||
32 | */ | ||
33 | } | ||
34 | |||
35 | #[derive(Clone, Default)] | ||
36 | struct FloatBuilder(Option<Float>); | ||
37 | |||
38 | impl FloatBuilder { | ||
39 | pub fn set(&mut self, value: Float) { | ||
40 | self.0 = Some(value); | ||
41 | } | ||
42 | |||
43 | pub fn build(&self, solver: &mut dyn SolverContext) -> Float { | ||
44 | self.0.unwrap_or_else(|| solver.new_free_float()) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // Not Eq / Ord to prevent cofusion | ||
49 | #[derive(Copy, Clone, Hash, Debug)] | ||
50 | pub struct Bool(VariableHandle); | ||
51 | |||
52 | impl Bool { | ||
53 | pub fn new(handle: VariableHandle) -> Self { | ||
54 | Bool(handle) | ||
55 | } | ||
56 | |||
57 | pub fn handle(&self) -> VariableHandle { | ||
58 | self.0 | ||
59 | } | ||
60 | } | ||
61 | |||
62 | #[derive(Clone, Debug)] | ||
63 | pub struct Point2D { | ||
64 | pub(crate) x: Float, | ||
65 | pub(crate) y: Float, | ||
66 | } | ||
67 | |||
68 | impl Point2D { | ||
69 | pub fn new(x: Float, y: Float) -> Self { | ||
70 | Point2D { x, y } | ||
71 | } | ||
72 | |||
73 | pub fn x(&self) -> Float { | ||
74 | self.x | ||
75 | } | ||
76 | |||
77 | pub fn y(&self) -> Float { | ||
78 | self.y | ||
79 | } | ||
80 | } | ||
81 | |||
82 | #[derive(Clone, PartialEq, PartialOrd, Debug)] | ||
83 | pub struct DefinedPoint2D { | ||
84 | pub(crate) x: f64, | ||
85 | pub(crate) y: f64, | ||
86 | } | ||
87 | |||
88 | #[derive(Clone, Debug)] | ||
89 | pub struct Bounds { | ||
90 | // TODO: really pub? That allows modification, when one might expect constraints | ||
91 | pub(crate) top: Float, | ||
92 | pub(crate) left: Float, | ||
93 | pub(crate) width: Float, | ||
94 | pub(crate) height: Float, | ||
95 | } | ||
96 | |||
97 | impl Bounds { | ||
98 | pub fn builder() -> BoundsBuilder { | ||
99 | BoundsBuilder::default() | ||
100 | } | ||
101 | |||
102 | pub fn top(&self, _ctx: &mut dyn SolverContext) -> Float { | ||
103 | self.top | ||
104 | } | ||
105 | |||
106 | pub fn left(&self, _ctx: &mut dyn SolverContext) -> Float { | ||
107 | self.left | ||
108 | } | ||
109 | |||
110 | pub fn width(&self, _ctx: &mut dyn SolverContext) -> Float { | ||
111 | self.width | ||
112 | } | ||
113 | |||
114 | pub fn height(&self, _ctx: &mut dyn SolverContext) -> Float { | ||
115 | self.height | ||
116 | } | ||
117 | |||
118 | pub fn right(&self, solver: &mut dyn SolverContext) -> Float { | ||
119 | solver.float_add(&[self.left, self.width]) | ||
120 | } | ||
121 | |||
122 | pub fn bottom(&self, solver: &mut dyn SolverContext) -> Float { | ||
123 | solver.float_add(&[self.top, self.height]) | ||
124 | } | ||
125 | |||
126 | pub fn vert_center(&self, solver: &mut dyn SolverContext) -> Float { | ||
127 | let half_height = solver.float_div(self.height, Float::Fixed(2.)); | ||
128 | solver.float_add(&[self.top, half_height]) | ||
129 | } | ||
130 | |||
131 | pub fn horiz_center(&self, solver: &mut dyn SolverContext) -> Float { | ||
132 | let half_width = solver.float_div(self.width, Float::Fixed(2.)); | ||
133 | solver.float_add(&[self.left, half_width]) | ||
134 | } | ||
135 | |||
136 | pub fn top_left(&self, _ctx: &mut dyn SolverContext) -> Point2D { | ||
137 | Point2D::new(self.left, self.top) | ||
138 | } | ||
139 | |||
140 | pub fn top_right(&self, solver: &mut dyn SolverContext) -> Point2D { | ||
141 | Point2D::new(self.right(solver), self.top) | ||
142 | } | ||
143 | |||
144 | pub fn bottom_left(&self, solver: &mut dyn SolverContext) -> Point2D { | ||
145 | Point2D::new(self.left, self.bottom(solver)) | ||
146 | } | ||
147 | |||
148 | pub fn bottom_right(&self, solver: &mut dyn SolverContext) -> Point2D { | ||
149 | Point2D::new(self.right(solver), self.bottom(solver)) | ||
150 | } | ||
151 | |||
152 | pub fn center(&self, solver: &mut dyn SolverContext) -> Point2D { | ||
153 | Point2D::new(self.horiz_center(solver), self.vert_center(solver)) | ||
154 | } | ||
155 | |||
156 | pub fn with_margin(&self, margin: Float, solver: &mut dyn SolverContext) -> Self { | ||
157 | let neg_margin = solver.float_neg(margin); | ||
158 | Bounds { | ||
159 | top: solver.float_add(&[self.top, neg_margin]), | ||
160 | left: solver.float_add(&[self.top, neg_margin]), | ||
161 | height: solver.float_add(&[self.top, margin]), | ||
162 | width: solver.float_add(&[self.top, margin]), | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | #[derive(Clone, Default)] | ||
168 | pub struct BoundsBuilder { | ||
169 | top: FloatBuilder, | ||
170 | left: FloatBuilder, | ||
171 | width: FloatBuilder, | ||
172 | height: FloatBuilder, | ||
173 | } | ||
174 | |||
175 | impl BoundsBuilder { | ||
176 | pub fn top(&mut self, top: Float) -> &mut Self { | ||
177 | self.top.set(top); | ||
178 | self | ||
179 | } | ||
180 | |||
181 | pub fn left(&mut self, left: Float) -> &mut Self { | ||
182 | self.left.set(left); | ||
183 | self | ||
184 | } | ||
185 | |||
186 | pub fn width(&mut self, width: Float) -> &mut Self { | ||
187 | self.width.set(width); | ||
188 | self | ||
189 | } | ||
190 | |||
191 | pub fn height(&mut self, height: Float) -> &mut Self { | ||
192 | self.height.set(height); | ||
193 | self | ||
194 | } | ||
195 | |||
196 | pub fn build(&self, solver: &mut dyn SolverContext) -> Bounds { | ||
197 | let _build_float = | ||
198 | |maybe_float: Option<Float>| maybe_float.unwrap_or_else(|| solver.new_free_float()); | ||
199 | |||
200 | Bounds { | ||
201 | top: self.top.build(solver), | ||
202 | left: self.left.build(solver), | ||
203 | width: self.width.build(solver), | ||
204 | height: self.height.build(solver), | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | #[derive(Clone, Debug)] | ||
210 | pub struct Bounded<Shape> { | ||
211 | pub bounds: Bounds, | ||
212 | pub shape: Shape, | ||
213 | } | ||
214 | |||
215 | #[derive(Clone, PartialEq, PartialOrd, Debug)] | ||
216 | pub struct DefinedBounds { | ||
217 | pub top: f64, | ||
218 | pub left: f64, | ||
219 | pub width: f64, | ||
220 | pub height: f64, | ||
221 | } | ||
222 | |||
223 | #[derive(Clone, PartialEq, PartialOrd, Debug)] | ||
224 | pub struct DefinitelyBounded<Shape> { | ||
225 | pub bounds: DefinedBounds, | ||
226 | pub shape: Shape, | ||
227 | } | ||
228 | |||
229 | #[derive(Clone, Debug)] | ||
230 | pub struct ShapeContext { | ||
231 | pub(crate) bounds: Bounds, | ||
232 | pub(crate) fill: FillStyle, | ||
233 | pub(crate) stroke: StrokeStyle, | ||
234 | } | ||
235 | |||
236 | impl ShapeContext { | ||
237 | pub fn new(solver: &mut dyn SolverContext) -> Self { | ||
238 | Self { | ||
239 | bounds: Bounds { | ||
240 | top: solver.new_free_float(), | ||
241 | left: solver.new_free_float(), | ||
242 | width: solver.new_free_float(), | ||
243 | height: solver.new_free_float(), | ||
244 | }, | ||
245 | fill: FillStyle::default(), | ||
246 | stroke: StrokeStyle::default(), | ||
247 | } | ||
248 | } | ||
249 | |||
250 | pub(crate) fn builder() -> ShapeContextBuilder { | ||
251 | ShapeContextBuilder::default() | ||
252 | } | ||
253 | |||
254 | pub fn bounds(&self) -> &Bounds { | ||
255 | &self.bounds | ||
256 | } | ||
257 | |||
258 | pub fn bounds_mut(&mut self) -> &mut Bounds { | ||
259 | &mut self.bounds | ||
260 | } | ||
261 | |||
262 | pub fn fill(&self) -> &FillStyle { | ||
263 | &self.fill | ||
264 | } | ||
265 | |||
266 | pub fn fill_mut(&mut self) -> &mut FillStyle { | ||
267 | &mut self.fill | ||
268 | } | ||
269 | |||
270 | pub fn stroke(&self) -> &StrokeStyle { | ||
271 | &self.stroke | ||
272 | } | ||
273 | |||
274 | pub fn stroke_mut(&mut self) -> &mut StrokeStyle { | ||
275 | &mut self.stroke | ||
276 | } | ||
277 | } | ||
278 | |||
279 | #[derive(Clone, Default)] | ||
280 | pub(crate) struct ShapeContextBuilder { | ||
281 | bounds: Option<Bounds>, | ||
282 | fill: Option<FillStyle>, | ||
283 | stroke: Option<StrokeStyle>, | ||
284 | } | ||
285 | |||
286 | impl ShapeContextBuilder { | ||
287 | pub fn bounds(&mut self, bounds: Bounds) -> &mut Self { | ||
288 | self.bounds = Some(bounds); | ||
289 | self | ||
290 | } | ||
291 | |||
292 | pub fn fill(&mut self, fill: FillStyle) -> &mut Self { | ||
293 | self.fill = Some(fill); | ||
294 | self | ||
295 | } | ||
296 | |||
297 | pub fn stroke(&mut self, stroke: StrokeStyle) -> &mut Self { | ||
298 | self.stroke = Some(stroke); | ||
299 | self | ||
300 | } | ||
301 | |||
302 | pub fn build(&self, solver: &mut dyn SolverContext) -> ShapeContext { | ||
303 | ShapeContext { | ||
304 | bounds: self.bounds.clone().unwrap_or_else(|| Bounds::builder().build(solver)), | ||
305 | fill: self.fill.clone().unwrap_or_default(), | ||
306 | stroke: self.stroke.clone().unwrap_or_default(), | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | |||
311 | #[derive(Clone, Debug)] | ||
312 | pub struct DefinedShapeContext { | ||
313 | pub bounds: DefinedBounds, | ||
314 | pub fill: FillStyle, | ||
315 | pub stroke: DefinedStrokeStyle, | ||
316 | } | ||
diff --git a/examples/lib-dfscq-log/Cargo.toml b/examples/lib-dfscq-log/Cargo.toml new file mode 100644 index 0000000..8146aa4 --- /dev/null +++ b/examples/lib-dfscq-log/Cargo.toml | |||
@@ -0,0 +1,15 @@ | |||
1 | [package] | ||
2 | name = "diaphragm-examples-lib-dfscq-log" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Minijackson <minijackson@riseup.net>"] | ||
5 | edition = "2021" | ||
6 | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
8 | |||
9 | [package.metadata.riff] | ||
10 | runtime-inputs = ["z3", "cairo"] | ||
11 | |||
12 | [dependencies] | ||
13 | diaphragm-core = { path = "../../core" } | ||
14 | diaphragm-z3-solver = { path = "../../z3-solver" } | ||
15 | diaphragm-cairo-renderer = { path = "../../cairo-renderer" } | ||
diff --git a/examples/lib-dfscq-log/dfscq-log.lua b/examples/lib-dfscq-log/dfscq-log.lua new file mode 100644 index 0000000..c54e4f2 --- /dev/null +++ b/examples/lib-dfscq-log/dfscq-log.lua | |||
@@ -0,0 +1,124 @@ | |||
1 | local diaphragm = require("diaphragm") | ||
2 | |||
3 | -- TODO: anyone can use metatable? | ||
4 | |||
5 | local Blocks = diaphragm.Drawable:new() | ||
6 | Blocks.elements = {} | ||
7 | Blocks.unit_width = diaphragm.float() | ||
8 | |||
9 | function Blocks:draw() | ||
10 | local len = #self.elements | ||
11 | assert(len >= 1, "Blocks must have at least 1 element") | ||
12 | |||
13 | local total_grow = 0 | ||
14 | for el in self.elements do | ||
15 | total_grow = el.grow or 1 | ||
16 | end | ||
17 | |||
18 | diaphragm.constrain(self.width == self.unit_width * total_grow) | ||
19 | |||
20 | local param = self.elements[0] | ||
21 | |||
22 | -- TODO: this would be written with layout.hstack | ||
23 | |||
24 | local block = diaphragm.shape.Rectangle:new() | ||
25 | block.fill(param.color) | ||
26 | diaphragm.constrain(block.left() == self.left()) | ||
27 | diaphragm.constrain(block.top() == self.top()) | ||
28 | diaphragm.constrain(block.bottom() == self.bottom()) | ||
29 | diaphragm.constrain(block.width() == (param.grow or 1) * self.unit_width) | ||
30 | |||
31 | block.draw() | ||
32 | |||
33 | local previous_right = block.right() | ||
34 | |||
35 | for i = 2, len do | ||
36 | param = self.elements[i] | ||
37 | |||
38 | block = diaphragm.shape.Rectangle:new() | ||
39 | block.fill(param.color) | ||
40 | |||
41 | diaphragm.constrain(block.left() == previous_right) | ||
42 | diaphragm.constrain(block.top() == self.top()) | ||
43 | diaphragm.constrain(block.bottom() == self.bottom()) | ||
44 | diaphragm.constrain(block.width() == (param.grow or 1) * self.unit_width) | ||
45 | |||
46 | block.draw() | ||
47 | |||
48 | previous_right = block.right() | ||
49 | end | ||
50 | end | ||
51 | |||
52 | -- Library | ||
53 | ---------- | ||
54 | |||
55 | local function block(color) | ||
56 | local res = diaphragm.shape.Rectangle:new() | ||
57 | res.fill(color) | ||
58 | return res | ||
59 | end | ||
60 | |||
61 | local function blocks_by_len(count, color) | ||
62 | local res = {} | ||
63 | for i = 1, count do | ||
64 | res[i] = block(color) | ||
65 | end | ||
66 | |||
67 | -- TODO: rename cons? Misleading | ||
68 | diaphragm.cons.same_size(res) | ||
69 | return diaphragm.layout.hstack(res) | ||
70 | end | ||
71 | |||
72 | local function layer(config) | ||
73 | local name = config.name or "" | ||
74 | local entries = config.entries or {} | ||
75 | |||
76 | -- TODO: how to do it without box? | ||
77 | -- TODO: implement union or combine | ||
78 | -- probably combine because | ||
79 | -- union could remove some | ||
80 | -- strokes | ||
81 | return diaphragm.layout.box({}) | ||
82 | end | ||
83 | |||
84 | -- Parameters | ||
85 | ------------- | ||
86 | |||
87 | local blue = diaphragm.color.from_rgb(0.35, 0.35, 1.) | ||
88 | |||
89 | local active_txn_count = 5 | ||
90 | |||
91 | -- Log API | ||
92 | ---------- | ||
93 | |||
94 | local log_api = layer({ | ||
95 | name = "LogAPI", | ||
96 | entries = { | ||
97 | { | ||
98 | name = "activeTxn", | ||
99 | content = blocks_by_len(active_txn_count, blue), | ||
100 | }, | ||
101 | }, | ||
102 | }) | ||
103 | |||
104 | -- Group Commit | ||
105 | --------------- | ||
106 | |||
107 | -- local group_commit = nil | ||
108 | |||
109 | -- Disk Log | ||
110 | ----------- | ||
111 | |||
112 | -- local disk_log = nil | ||
113 | |||
114 | -- Applier | ||
115 | ---------- | ||
116 | |||
117 | -- local applier = nil | ||
118 | |||
119 | diaphragm.draw(diaphragm.layout.vstack({ | ||
120 | log_api, | ||
121 | -- group_commit, | ||
122 | -- disk_log, | ||
123 | -- applier, | ||
124 | })) | ||
diff --git a/examples/lib-dfscq-log/src/block_list.rs b/examples/lib-dfscq-log/src/block_list.rs new file mode 100644 index 0000000..be0eee0 --- /dev/null +++ b/examples/lib-dfscq-log/src/block_list.rs | |||
@@ -0,0 +1,183 @@ | |||
1 | use super::blocks::Blocks; | ||
2 | use super::bracket::*; | ||
3 | |||
4 | use diaphragm_core::{ | ||
5 | core_shapes::Text, | ||
6 | text::FontDescription, | ||
7 | types::{Bounds, Float, ShapeContext}, | ||
8 | ComplexShape, DrawResult, Drawable, SolverContext, | ||
9 | }; | ||
10 | |||
11 | #[derive(Clone)] | ||
12 | pub struct BlockList { | ||
13 | pub block_list: Vec<Drawable<Blocks>>, | ||
14 | pub block_unit_width: Float, | ||
15 | pub bracket_width: Float, | ||
16 | pub blocks_vert_padding: Float, | ||
17 | } | ||
18 | |||
19 | impl ComplexShape for BlockList { | ||
20 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
21 | let mut result = DrawResult::new(); | ||
22 | |||
23 | let bounds = context.bounds(); | ||
24 | |||
25 | // Left bracket | ||
26 | let opening_bracket_left = { | ||
27 | let bracket = Drawable::builder(Bracket { | ||
28 | r#type: BracketType::Opening, | ||
29 | }) | ||
30 | .bounds( | ||
31 | Bounds::builder() | ||
32 | .top(bounds.top(solver)) | ||
33 | .left(bounds.left(solver)) | ||
34 | .width(self.bracket_width) | ||
35 | .height(bounds.height(solver)) | ||
36 | .build(solver), | ||
37 | ) | ||
38 | .stroke(context.stroke().clone()) | ||
39 | .build(solver); | ||
40 | |||
41 | let bracket_left = bracket.bounds().left(solver); | ||
42 | |||
43 | result.push(bracket); | ||
44 | |||
45 | bracket_left | ||
46 | }; | ||
47 | |||
48 | let bounds_left = bounds.left(solver); | ||
49 | let mut x_acc = solver.float_add(&[bounds_left, self.bracket_width]); | ||
50 | |||
51 | // Block list | ||
52 | |||
53 | let bounds_top = bounds.top(solver); | ||
54 | let bounds_height = bounds.height(solver); | ||
55 | let wanted_blocks_top = solver.float_add(&[bounds_top, self.blocks_vert_padding]); | ||
56 | let wanted_blocks_height = solver.float_sub(&[ | ||
57 | bounds_height, | ||
58 | self.blocks_vert_padding, | ||
59 | self.blocks_vert_padding, | ||
60 | ]); | ||
61 | |||
62 | let mut block_list_iter = self.block_list.iter(); | ||
63 | |||
64 | // First blocks | ||
65 | if let Some(first_blocks) = block_list_iter.next() { | ||
66 | // TODO: waaay too verbose | ||
67 | |||
68 | let blocks_top = first_blocks.bounds().top(solver); | ||
69 | let blocks_top_constraint = solver.float_eq(blocks_top, wanted_blocks_top); | ||
70 | solver.constrain(blocks_top_constraint); | ||
71 | |||
72 | let blocks_left = first_blocks.bounds().left(solver); | ||
73 | let blocks_left_constraint = solver.float_eq(blocks_left, x_acc); | ||
74 | solver.constrain(blocks_left_constraint); | ||
75 | |||
76 | let blocks_height = first_blocks.bounds().height(solver); | ||
77 | let blocks_height_constraint = solver.float_eq(blocks_height, wanted_blocks_height); | ||
78 | solver.constrain(blocks_height_constraint); | ||
79 | |||
80 | let block_unit_width_constraint = | ||
81 | solver.float_eq(first_blocks.shape().unit_width, self.block_unit_width); | ||
82 | solver.constrain(block_unit_width_constraint); | ||
83 | |||
84 | result.push(first_blocks.clone()); | ||
85 | |||
86 | let blocks_width = first_blocks.bounds().width(solver); | ||
87 | x_acc = solver.float_add(&[x_acc, blocks_width]); | ||
88 | } | ||
89 | |||
90 | // Rest of the blocks | ||
91 | for blocks in block_list_iter { | ||
92 | // Comma | ||
93 | let comma = Drawable::builder(Text { | ||
94 | content: String::from(", "), | ||
95 | font: FontDescription { | ||
96 | family: String::from("mono"), | ||
97 | style: Default::default(), | ||
98 | weight: Default::default(), | ||
99 | size: wanted_blocks_height, | ||
100 | }, | ||
101 | }) | ||
102 | .bounds( | ||
103 | Bounds::builder() | ||
104 | .top(wanted_blocks_top) | ||
105 | .left(x_acc) | ||
106 | .build(solver), | ||
107 | ) | ||
108 | .stroke(context.stroke().clone()) | ||
109 | .build(solver); | ||
110 | |||
111 | let comma_width = comma.bounds().width(solver); | ||
112 | |||
113 | x_acc = solver.float_add(&[x_acc, comma_width]); | ||
114 | |||
115 | result.push(comma); | ||
116 | |||
117 | // Blocks | ||
118 | /* | ||
119 | let blocks_context = ShapeContext { | ||
120 | bounds: Bounds { | ||
121 | top: blocks_top, | ||
122 | left: x_acc, | ||
123 | height: blocks_height, | ||
124 | width: blocks_width, | ||
125 | }, | ||
126 | fill: FillStyle::default(), | ||
127 | stroke: StrokeStyle::default(), | ||
128 | }; | ||
129 | */ | ||
130 | |||
131 | let blocks_top = blocks.bounds().top(solver); | ||
132 | let blocks_top_constraint = solver.float_eq(blocks_top, wanted_blocks_top); | ||
133 | solver.constrain(blocks_top_constraint); | ||
134 | |||
135 | let blocks_left = blocks.bounds().left(solver); | ||
136 | let blocks_left_constraint = solver.float_eq(blocks_left, x_acc); | ||
137 | solver.constrain(blocks_left_constraint); | ||
138 | |||
139 | let blocks_height = blocks.bounds().height(solver); | ||
140 | let blocks_height_constraint = solver.float_eq(blocks_height, wanted_blocks_height); | ||
141 | solver.constrain(blocks_height_constraint); | ||
142 | |||
143 | let block_unit_width_constraint = | ||
144 | solver.float_eq(blocks.shape().unit_width, self.block_unit_width); | ||
145 | solver.constrain(block_unit_width_constraint); | ||
146 | |||
147 | result.push(blocks.clone()); | ||
148 | |||
149 | let blocks_width = blocks.bounds().width(solver); | ||
150 | x_acc = solver.float_add(&[x_acc, blocks_width]); | ||
151 | } | ||
152 | |||
153 | // Right bracket | ||
154 | let closing_bracket_right = { | ||
155 | let bracket = Drawable::builder(Bracket { | ||
156 | r#type: BracketType::Closing, | ||
157 | }) | ||
158 | .bounds( | ||
159 | Bounds::builder() | ||
160 | .top(bounds.top(solver)) | ||
161 | .left(x_acc) | ||
162 | .width(self.bracket_width) | ||
163 | .height(bounds.height(solver)) | ||
164 | .build(solver), | ||
165 | ) | ||
166 | .stroke(context.stroke().clone()) | ||
167 | .build(solver); | ||
168 | |||
169 | let bracket_right = bracket.bounds().right(solver); | ||
170 | |||
171 | result.push(bracket); | ||
172 | |||
173 | bracket_right | ||
174 | }; | ||
175 | |||
176 | let this_width = solver.float_sub(&[closing_bracket_right, opening_bracket_left]); | ||
177 | let bounds_width = bounds.width(solver); | ||
178 | let bounds_width_constraint = solver.float_eq(bounds_width, this_width); | ||
179 | solver.constrain(bounds_width_constraint); | ||
180 | |||
181 | result | ||
182 | } | ||
183 | } | ||
diff --git a/examples/lib-dfscq-log/src/blocks.rs b/examples/lib-dfscq-log/src/blocks.rs new file mode 100644 index 0000000..0576b7d --- /dev/null +++ b/examples/lib-dfscq-log/src/blocks.rs | |||
@@ -0,0 +1,72 @@ | |||
1 | use diaphragm_core::{ | ||
2 | core_shapes::Rectangle, | ||
3 | types::{Float, ShapeContext}, | ||
4 | ComplexShape, DrawResult, Drawable, SolverContext, | ||
5 | }; | ||
6 | |||
7 | #[derive(Debug, Clone)] | ||
8 | pub struct Block { | ||
9 | pub grow: u8, | ||
10 | } | ||
11 | |||
12 | impl ComplexShape for Block { | ||
13 | fn draw(&self, context: &ShapeContext, _solver: &mut dyn SolverContext) -> DrawResult { | ||
14 | let mut result = DrawResult::new(); | ||
15 | |||
16 | // Grow is handled at the upper level | ||
17 | let block = Drawable::new(Rectangle {}, context.clone()); | ||
18 | |||
19 | result.push(block); | ||
20 | |||
21 | result | ||
22 | } | ||
23 | } | ||
24 | |||
25 | #[derive(Debug, Clone)] | ||
26 | pub struct Blocks { | ||
27 | pub blocks: Vec<Drawable<Block>>, | ||
28 | pub unit_width: Float, | ||
29 | } | ||
30 | |||
31 | impl ComplexShape for Blocks { | ||
32 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
33 | let mut result = DrawResult::new(); | ||
34 | |||
35 | let sum: u8 = self.blocks.iter().map(|block| block.shape().grow).sum(); | ||
36 | |||
37 | let mut rect_left = context.bounds().left(solver); | ||
38 | let rect_top = context.bounds().top(solver); | ||
39 | let rect_height = context.bounds().height(solver); | ||
40 | |||
41 | for block in &self.blocks { | ||
42 | let block_top = block.bounds().top(solver); | ||
43 | let rect_top_constraint = solver.float_eq(block_top, rect_top); | ||
44 | solver.constrain(rect_top_constraint); | ||
45 | |||
46 | let block_left = block.bounds().left(solver); | ||
47 | let rect_left_constraint = solver.float_eq(block_left, rect_left); | ||
48 | solver.constrain(rect_left_constraint); | ||
49 | |||
50 | let grow = Float::Fixed(block.shape().grow as f64); | ||
51 | let block_width = block.bounds().width(solver); | ||
52 | let rect_width = solver.float_mul(&[self.unit_width, grow]); | ||
53 | let rect_width_constraint = solver.float_eq(block_width, rect_width); | ||
54 | solver.constrain(rect_width_constraint); | ||
55 | |||
56 | let block_height = block.bounds().height(solver); | ||
57 | let rect_height_constraint = solver.float_eq(block_height, rect_height); | ||
58 | solver.constrain(rect_height_constraint); | ||
59 | |||
60 | result.push(block.clone()); | ||
61 | |||
62 | rect_left = solver.float_add(&[rect_left, rect_width]); | ||
63 | } | ||
64 | |||
65 | let this_width = solver.float_mul(&[self.unit_width, Float::Fixed(sum as f64)]); | ||
66 | let bounds_width = context.bounds().width(solver); | ||
67 | let bounds_width_constraint = solver.float_eq(bounds_width, this_width); | ||
68 | solver.constrain(bounds_width_constraint); | ||
69 | |||
70 | result | ||
71 | } | ||
72 | } | ||
diff --git a/examples/lib-dfscq-log/src/bracket.rs b/examples/lib-dfscq-log/src/bracket.rs new file mode 100644 index 0000000..02bca8d --- /dev/null +++ b/examples/lib-dfscq-log/src/bracket.rs | |||
@@ -0,0 +1,42 @@ | |||
1 | use diaphragm_core::{ | ||
2 | core_shapes::StraightPath, types::ShapeContext, ComplexShape, DrawResult, Drawable, | ||
3 | SolverContext, | ||
4 | }; | ||
5 | |||
6 | #[derive(Copy, Clone)] | ||
7 | pub enum BracketType { | ||
8 | Opening, | ||
9 | Closing, | ||
10 | } | ||
11 | |||
12 | #[derive(Clone)] | ||
13 | pub struct Bracket { | ||
14 | pub r#type: BracketType, | ||
15 | } | ||
16 | |||
17 | impl ComplexShape for Bracket { | ||
18 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
19 | let mut result = DrawResult::new(); | ||
20 | |||
21 | let bounds = context.bounds(); | ||
22 | |||
23 | let path = match self.r#type { | ||
24 | BracketType::Opening => StraightPath::new(vec![ | ||
25 | bounds.top_right(solver), | ||
26 | bounds.top_left(solver), | ||
27 | bounds.bottom_left(solver), | ||
28 | bounds.bottom_right(solver), | ||
29 | ]), | ||
30 | BracketType::Closing => StraightPath::new(vec![ | ||
31 | bounds.top_left(solver), | ||
32 | bounds.top_right(solver), | ||
33 | bounds.bottom_right(solver), | ||
34 | bounds.bottom_left(solver), | ||
35 | ]), | ||
36 | }; | ||
37 | |||
38 | result.push(Drawable::new(path, context.clone())); | ||
39 | |||
40 | result | ||
41 | } | ||
42 | } | ||
diff --git a/examples/lib-dfscq-log/src/explode.rs b/examples/lib-dfscq-log/src/explode.rs new file mode 100644 index 0000000..aeb85bd --- /dev/null +++ b/examples/lib-dfscq-log/src/explode.rs | |||
@@ -0,0 +1,86 @@ | |||
1 | use diaphragm_core::{ | ||
2 | core_shapes::StraightPath, | ||
3 | types::{Float, Point2D, ShapeContext}, | ||
4 | ComplexShape, DrawResult, Drawable, SolverContext, | ||
5 | }; | ||
6 | |||
7 | #[derive(Clone)] | ||
8 | pub struct Explode { | ||
9 | pub top_left: Point2D, | ||
10 | pub top_right: Point2D, | ||
11 | pub bottom_left: Point2D, | ||
12 | pub bottom_right: Point2D, | ||
13 | |||
14 | pub arm_length: Float, | ||
15 | } | ||
16 | |||
17 | impl ComplexShape for Explode { | ||
18 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
19 | let mut result = DrawResult::new(); | ||
20 | |||
21 | let wanted_top = solver.float_min(&[self.top_left.y(), self.top_right.y()]); | ||
22 | let wanted_left = solver.float_min(&[self.top_left.x(), self.bottom_left.x()]); | ||
23 | let wanted_bottom = solver.float_max(&[self.bottom_left.x(), self.bottom_right.x()]); | ||
24 | let wanted_right = solver.float_max(&[self.top_right.y(), self.bottom_right.y()]); | ||
25 | |||
26 | let bounds_top = context.bounds().top(solver); | ||
27 | let bounds_left = context.bounds().left(solver); | ||
28 | let bounds_bottom = context.bounds().bottom(solver); | ||
29 | let bounds_right = context.bounds().right(solver); | ||
30 | |||
31 | // TODO: add a facility to help this? | ||
32 | let bounds_top_constraint = solver.float_eq(bounds_top, wanted_top); | ||
33 | solver.constrain(bounds_top_constraint); | ||
34 | |||
35 | let bounds_left_constraint = solver.float_eq(bounds_left, wanted_left); | ||
36 | solver.constrain(bounds_left_constraint); | ||
37 | |||
38 | let bounds_bottom_constraint = solver.float_eq(bounds_bottom, wanted_bottom); | ||
39 | solver.constrain(bounds_bottom_constraint); | ||
40 | |||
41 | let bounds_right_constraint = solver.float_eq(bounds_right, wanted_right); | ||
42 | solver.constrain(bounds_right_constraint); | ||
43 | |||
44 | let top_left_arm_bottom = Point2D::new( | ||
45 | self.top_left.x(), | ||
46 | solver.float_add(&[self.top_left.y(), self.arm_length]), | ||
47 | ); | ||
48 | |||
49 | let bottom_left_arm_top = Point2D::new( | ||
50 | self.bottom_left.x(), | ||
51 | solver.float_sub(&[self.bottom_left.y(), self.arm_length]), | ||
52 | ); | ||
53 | |||
54 | result.push(Drawable::new( | ||
55 | StraightPath::new(vec![ | ||
56 | self.top_left.clone(), | ||
57 | top_left_arm_bottom, | ||
58 | bottom_left_arm_top, | ||
59 | self.bottom_left.clone(), | ||
60 | ]), | ||
61 | context.clone(), | ||
62 | )); | ||
63 | |||
64 | let top_right_arm_bottom = Point2D::new( | ||
65 | self.top_right.x(), | ||
66 | solver.float_add(&[self.top_right.y(), self.arm_length]), | ||
67 | ); | ||
68 | |||
69 | let bottom_right_arm_top = Point2D::new( | ||
70 | self.bottom_right.x(), | ||
71 | solver.float_sub(&[self.bottom_right.y(), self.arm_length]), | ||
72 | ); | ||
73 | |||
74 | result.push(Drawable::new( | ||
75 | StraightPath::new(vec![ | ||
76 | self.top_right.clone(), | ||
77 | top_right_arm_bottom, | ||
78 | bottom_right_arm_top, | ||
79 | self.bottom_right.clone(), | ||
80 | ]), | ||
81 | context.clone(), | ||
82 | )); | ||
83 | |||
84 | result | ||
85 | } | ||
86 | } | ||
diff --git a/examples/lib-dfscq-log/src/labeled.rs b/examples/lib-dfscq-log/src/labeled.rs new file mode 100644 index 0000000..20aebcd --- /dev/null +++ b/examples/lib-dfscq-log/src/labeled.rs | |||
@@ -0,0 +1,64 @@ | |||
1 | use diaphragm_core::{ | ||
2 | core_shapes::Text, | ||
3 | text::FontDescription, | ||
4 | types::{Bounds, Float, ShapeContext}, | ||
5 | ComplexShape, DrawResult, DynClone, SolverContext, | ||
6 | }; | ||
7 | |||
8 | pub struct Labeled { | ||
9 | pub label: String, | ||
10 | pub label_font: FontDescription, | ||
11 | pub content: Box<dyn ComplexShape>, | ||
12 | pub content_left: Float, | ||
13 | } | ||
14 | |||
15 | impl ComplexShape for Labeled { | ||
16 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
17 | let mut result = DrawResult::new(); | ||
18 | |||
19 | // Label | ||
20 | |||
21 | let label = Text { | ||
22 | content: self.label.clone(), | ||
23 | font: self.label_font.clone(), | ||
24 | }; | ||
25 | |||
26 | let mut label_context = context.clone(); | ||
27 | // TODO: make the text constrain the width | ||
28 | label_context.bounds.width = solver.new_free_float(); | ||
29 | |||
30 | let label_right = solver.float_add(&[context.bounds.left, label_context.bounds.width]); | ||
31 | let content_left_constrain = solver.float_eq(label_right, self.content_left); | ||
32 | solver.constrain(content_left_constrain); | ||
33 | |||
34 | result.push_shape(label, label_context); | ||
35 | |||
36 | // Content | ||
37 | |||
38 | let content_context = ShapeContext { | ||
39 | bounds: Bounds { | ||
40 | top: context.bounds.top, | ||
41 | left: solver.float_add(&[context.bounds.left, self.content_left]), | ||
42 | height: context.bounds.height, | ||
43 | width: context.bounds.width, | ||
44 | }, | ||
45 | fill: context.fill.clone(), | ||
46 | stroke: context.stroke.clone(), | ||
47 | }; | ||
48 | |||
49 | result.push_boxed_shape(self.content.dyn_clone(), content_context); | ||
50 | |||
51 | result | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl DynClone for Labeled { | ||
56 | fn dyn_clone(&self) -> Box<dyn ComplexShape> { | ||
57 | Box::new(Labeled { | ||
58 | label: self.label.clone(), | ||
59 | label_font: self.label_font.clone(), | ||
60 | content: self.content.dyn_clone(), | ||
61 | content_left: self.content_left.clone(), | ||
62 | }) | ||
63 | } | ||
64 | } | ||
diff --git a/examples/lib-dfscq-log/src/labeled_delimiter.rs b/examples/lib-dfscq-log/src/labeled_delimiter.rs new file mode 100644 index 0000000..5a1c610 --- /dev/null +++ b/examples/lib-dfscq-log/src/labeled_delimiter.rs | |||
@@ -0,0 +1,121 @@ | |||
1 | use diaphragm_core::{ | ||
2 | core_shapes::{StraightPath, Text}, | ||
3 | types::{Bounds, Float, Point2D, ShapeContext}, | ||
4 | ComplexShape, DrawResult, Drawable, SolverContext, | ||
5 | }; | ||
6 | |||
7 | #[derive(Debug, Clone)] | ||
8 | pub struct Delimiter { | ||
9 | pub width: Float, | ||
10 | pub label: Drawable<Text>, | ||
11 | } | ||
12 | |||
13 | #[derive(Debug, Clone)] | ||
14 | pub struct LabeledDelimiter { | ||
15 | pub delimiters: Vec<Delimiter>, | ||
16 | pub tick_height: Float, | ||
17 | } | ||
18 | |||
19 | impl ComplexShape for LabeledDelimiter { | ||
20 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
21 | let mut result = DrawResult::new(); | ||
22 | |||
23 | let bounds_left = context.bounds().left(solver); | ||
24 | let bounds_right = context.bounds().right(solver); | ||
25 | let bounds_bottom = context.bounds().bottom(solver); | ||
26 | let bounds_width = context.bounds().width(solver); | ||
27 | |||
28 | let tick_top = context.bounds().top(solver); | ||
29 | let tick_bottom = solver.float_add(&[tick_top, self.tick_height]); | ||
30 | |||
31 | let first_tick = Drawable::builder(StraightPath::new(vec![ | ||
32 | context.bounds().top_left(solver), | ||
33 | Point2D::new(bounds_left, tick_bottom), | ||
34 | ])) | ||
35 | .bounds( | ||
36 | Bounds::builder() | ||
37 | .top(tick_top) | ||
38 | .left(bounds_left) | ||
39 | .height(self.tick_height) | ||
40 | .width(Float::Fixed(0.)) | ||
41 | .build(solver), | ||
42 | ) | ||
43 | .stroke(context.stroke().clone()) | ||
44 | .build(solver); | ||
45 | |||
46 | let baseline_y = first_tick.bounds().vert_center(solver); | ||
47 | |||
48 | result.push(first_tick); | ||
49 | |||
50 | // TODO: split everything into functions | ||
51 | |||
52 | let baseline = Drawable::builder(StraightPath::new(vec![ | ||
53 | Point2D::new(bounds_left, baseline_y), | ||
54 | Point2D::new(bounds_right, baseline_y), | ||
55 | ])) | ||
56 | .bounds( | ||
57 | Bounds::builder() | ||
58 | .top(baseline_y) | ||
59 | .left(bounds_left) | ||
60 | .width(bounds_width) | ||
61 | .height(Float::Fixed(0.)) | ||
62 | .build(solver), | ||
63 | ) | ||
64 | .stroke(context.stroke().clone()) | ||
65 | .build(solver); | ||
66 | |||
67 | result.push(baseline); | ||
68 | |||
69 | let mut section_end = bounds_left; | ||
70 | let mut all_label_bottoms = vec![]; | ||
71 | |||
72 | for &Delimiter { | ||
73 | width: section_width, | ||
74 | ref label, | ||
75 | } in &self.delimiters | ||
76 | { | ||
77 | let section_begin = section_end; | ||
78 | section_end = solver.float_add(&[section_end, section_width]); | ||
79 | |||
80 | let section_half_width = solver.float_div(section_width, Float::Fixed(2.)); | ||
81 | let section_middle = solver.float_add(&[section_begin, section_half_width]); | ||
82 | |||
83 | let tick = Drawable::builder(StraightPath::new(vec![ | ||
84 | Point2D::new(section_end, tick_top), | ||
85 | Point2D::new(section_end, tick_bottom), | ||
86 | ])) | ||
87 | .bounds( | ||
88 | Bounds::builder() | ||
89 | .top(tick_top) | ||
90 | .left(section_end) | ||
91 | .height(self.tick_height) | ||
92 | .width(Float::Fixed(0.)) | ||
93 | .build(solver), | ||
94 | ) | ||
95 | .stroke(context.stroke().clone()) | ||
96 | .build(solver); | ||
97 | |||
98 | result.push(tick); | ||
99 | |||
100 | let label_top = label.bounds().top(solver); | ||
101 | let label_bottom = label.bounds().bottom(solver); | ||
102 | let label_horiz_center = label.bounds().horiz_center(solver); | ||
103 | |||
104 | let label_top_constraint = solver.float_eq(label_top, tick_bottom); | ||
105 | solver.constrain(label_top_constraint); | ||
106 | |||
107 | let label_middle_constraint = solver.float_eq(label_horiz_center, section_middle); | ||
108 | solver.constrain(label_middle_constraint); | ||
109 | |||
110 | result.push(label.clone()); | ||
111 | |||
112 | all_label_bottoms.push(label_bottom); | ||
113 | } | ||
114 | |||
115 | let wanted_bounds_bottom = solver.float_max(&all_label_bottoms); | ||
116 | let bounds_bottom_constraint = solver.float_eq(bounds_bottom, wanted_bounds_bottom); | ||
117 | solver.constrain(bounds_bottom_constraint); | ||
118 | |||
119 | result | ||
120 | } | ||
121 | } | ||
diff --git a/examples/lib-dfscq-log/src/layer.rs b/examples/lib-dfscq-log/src/layer.rs new file mode 100644 index 0000000..45edb56 --- /dev/null +++ b/examples/lib-dfscq-log/src/layer.rs | |||
@@ -0,0 +1,169 @@ | |||
1 | use diaphragm_core::{ | ||
2 | core_shapes::Rectangle, | ||
3 | core_shapes::Text, | ||
4 | text::FontDescription, | ||
5 | types::{Bounds, Float, ShapeContext}, | ||
6 | ComplexShape, DrawResult, Drawable, DynDrawable, SolverContext, | ||
7 | }; | ||
8 | |||
9 | #[derive(Clone)] | ||
10 | pub struct Entry { | ||
11 | // TODO: transform this to just Text | ||
12 | pub label: Option<String>, | ||
13 | pub label_vert_center_offset: Option<Float>, | ||
14 | pub content: DynDrawable, | ||
15 | } | ||
16 | |||
17 | #[derive(Clone)] | ||
18 | pub struct Layer { | ||
19 | // TODO: transform this to just Text | ||
20 | pub name: String, | ||
21 | pub name_font: FontDescription, | ||
22 | pub label_font: FontDescription, | ||
23 | pub padding: Float, | ||
24 | pub entries: Vec<Entry>, | ||
25 | pub entries_width: Float, | ||
26 | } | ||
27 | |||
28 | impl ComplexShape for Layer { | ||
29 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
30 | let mut result = DrawResult::new(); | ||
31 | |||
32 | let bounds_top = context.bounds().top(solver); | ||
33 | let bounds_left = context.bounds().left(solver); | ||
34 | let bounds_right = context.bounds().right(solver); | ||
35 | let bounds_height = context.bounds().height(solver); | ||
36 | |||
37 | let inner_top = solver.float_add(&[bounds_top, self.padding]); | ||
38 | let inner_right = solver.float_sub(&[bounds_right, self.padding]); | ||
39 | |||
40 | // Outer box | ||
41 | |||
42 | result.push(Drawable::new(Rectangle {}, context.clone())); | ||
43 | |||
44 | // Layer name | ||
45 | |||
46 | let layer_name = Drawable::builder(Text { | ||
47 | content: self.name.clone(), | ||
48 | font: self.name_font.clone(), | ||
49 | }) | ||
50 | .bounds( | ||
51 | Bounds::builder() | ||
52 | .top(inner_top) | ||
53 | .left(solver.float_add(&[bounds_left, self.padding])) | ||
54 | .build(solver), | ||
55 | ) | ||
56 | .stroke(context.stroke().clone()) | ||
57 | .fill(context.fill().clone()) | ||
58 | .build(solver); | ||
59 | |||
60 | let layer_name_bottom = layer_name.bounds().bottom(solver); | ||
61 | |||
62 | /* | ||
63 | let mut rect_context = layer_name_context.clone(); | ||
64 | rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.)); | ||
65 | result.push_shape(Rectangle {}, rect_context); | ||
66 | */ | ||
67 | |||
68 | result.push(layer_name); | ||
69 | |||
70 | // Entries | ||
71 | |||
72 | let mut entry_y_acc = inner_top; | ||
73 | |||
74 | for entry in &self.entries { | ||
75 | // Entry content | ||
76 | |||
77 | /* | ||
78 | let content_context = ShapeContext { | ||
79 | bounds: Bounds { | ||
80 | top: solver.new_free_float(), | ||
81 | left: content_left, | ||
82 | width: entry.width, | ||
83 | height: entry.height, | ||
84 | }, | ||
85 | fill: Default::default(), | ||
86 | stroke: Default::default(), | ||
87 | }; | ||
88 | */ | ||
89 | |||
90 | let content_vert_center = entry.content.bounds().vert_center(solver); | ||
91 | let content_top = entry.content.bounds().top(solver); | ||
92 | let content_left = entry.content.bounds().left(solver); | ||
93 | let content_bottom = entry.content.bounds().bottom(solver); | ||
94 | |||
95 | // TODO: to replace with label offset | ||
96 | let content_half_height = solver.float_sub(&[content_vert_center, content_top]); | ||
97 | |||
98 | result.push_dyn(entry.content.clone()); | ||
99 | |||
100 | // Entry label | ||
101 | |||
102 | if let Some(label_content) = entry.label.clone() { | ||
103 | let label_top = solver.new_free_float(); | ||
104 | let label_width = solver.new_free_float(); | ||
105 | let label_left = solver.float_sub(&[inner_right, self.entries_width, label_width]); | ||
106 | |||
107 | let label = Drawable::builder(Text { | ||
108 | content: label_content, | ||
109 | font: self.label_font.clone(), | ||
110 | }) | ||
111 | .bounds( | ||
112 | Bounds::builder() | ||
113 | .top(label_top) | ||
114 | .left(label_left) | ||
115 | .width(label_width) | ||
116 | .build(solver), | ||
117 | ) | ||
118 | .build(solver); | ||
119 | |||
120 | /* | ||
121 | let mut rect_context = label_context.clone(); | ||
122 | rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.)); | ||
123 | result.push_shape(Rectangle {}, rect_context); | ||
124 | */ | ||
125 | |||
126 | // TODO | ||
127 | let label_vert_center = label.bounds().vert_center(solver); | ||
128 | let label_top = label.bounds().top(solver); | ||
129 | let label_right = label.bounds().right(solver); | ||
130 | |||
131 | let label_vert_center_constraint = | ||
132 | solver.float_eq(label_vert_center, content_vert_center); | ||
133 | solver.constrain(label_vert_center_constraint); | ||
134 | |||
135 | let label_half_height = solver.float_sub(&[label_vert_center, label_top]); | ||
136 | |||
137 | let dumb_label_mid_placement = | ||
138 | solver.float_add(&[entry_y_acc, content_half_height]); | ||
139 | let safe_label_mid_placement = | ||
140 | solver.float_add(&[layer_name_bottom, label_half_height]); | ||
141 | let label_mid_placement = | ||
142 | solver.float_max(&[safe_label_mid_placement, dumb_label_mid_placement]); | ||
143 | let label_mid_placement_constraint = | ||
144 | solver.float_eq(label_vert_center, label_mid_placement); | ||
145 | solver.constrain(label_mid_placement_constraint); | ||
146 | |||
147 | let label_right_constraint = solver.float_eq(label_right, content_left); | ||
148 | solver.constrain(label_right_constraint); | ||
149 | |||
150 | result.push(label); | ||
151 | } else { | ||
152 | let content_top_constraint = solver.float_eq(content_top, entry_y_acc); | ||
153 | solver.constrain(content_top_constraint); | ||
154 | |||
155 | let wanted_content_left = solver.float_sub(&[inner_right, self.entries_width]); | ||
156 | let content_left_constraint = solver.float_eq(content_left, wanted_content_left); | ||
157 | solver.constrain(content_left_constraint); | ||
158 | } | ||
159 | |||
160 | entry_y_acc = solver.float_add(&[content_bottom, self.padding]); | ||
161 | } | ||
162 | |||
163 | let wanted_bounds_height = solver.float_sub(&[entry_y_acc, bounds_top]); | ||
164 | let height_constraint = solver.float_eq(bounds_height, wanted_bounds_height); | ||
165 | solver.constrain(height_constraint); | ||
166 | |||
167 | result | ||
168 | } | ||
169 | } | ||
diff --git a/examples/lib-dfscq-log/src/main.rs b/examples/lib-dfscq-log/src/main.rs new file mode 100644 index 0000000..fe5db9a --- /dev/null +++ b/examples/lib-dfscq-log/src/main.rs | |||
@@ -0,0 +1,642 @@ | |||
1 | mod block_list; | ||
2 | mod blocks; | ||
3 | mod bracket; | ||
4 | mod explode; | ||
5 | mod labeled_delimiter; | ||
6 | mod layer; | ||
7 | mod spacer; | ||
8 | |||
9 | //mod labeled; | ||
10 | //use labeled::Labeled; | ||
11 | |||
12 | use block_list::BlockList; | ||
13 | use blocks::*; | ||
14 | use explode::*; | ||
15 | use labeled_delimiter::*; | ||
16 | use layer::*; | ||
17 | use spacer::*; | ||
18 | |||
19 | use diaphragm_cairo_renderer::CairoRenderer; | ||
20 | use diaphragm_core::{ | ||
21 | colors::Color, | ||
22 | core_shapes::{Text}, | ||
23 | styles::*, | ||
24 | text::FontDescription, | ||
25 | types::*, | ||
26 | *, | ||
27 | }; | ||
28 | use diaphragm_z3_solver::{z3, Z3Context}; | ||
29 | |||
30 | fn main() { | ||
31 | let z3_cfg = z3::Config::new(); | ||
32 | let z3_ctx = z3::Context::new(&z3_cfg); | ||
33 | let ctx = Z3Context::new(&z3_ctx); | ||
34 | |||
35 | let cairo_renderer = CairoRenderer::new(); | ||
36 | |||
37 | let mut runtime = Runtime::new(Box::new(ctx), Box::new(cairo_renderer)); | ||
38 | |||
39 | let solver = runtime.solver_ctx(); | ||
40 | |||
41 | let blue = Color::from_rgb(0.35, 0.35, 1.); | ||
42 | let light_grey = Color::from_rgb(0.8, 0.8, 0.8); | ||
43 | let dark_grey = Color::from_rgb(0.5, 0.5, 0.5); | ||
44 | |||
45 | // ----------------8<---------------- | ||
46 | |||
47 | /* | ||
48 | let mut make_blocks = |grows: &[u8]| { | ||
49 | grows | ||
50 | .iter() | ||
51 | .map(|&grow| { | ||
52 | Drawable::builder(Block { grow }) | ||
53 | .fill(FillStyle::solid(blue)) | ||
54 | .build(solver) | ||
55 | }) | ||
56 | .collect() | ||
57 | }; | ||
58 | |||
59 | let blocks = Drawable::builder(Blocks { | ||
60 | blocks: make_blocks(&[1, 2, 1, 1, 4, 1, 1]), | ||
61 | unit_width: solver.new_free_float(), | ||
62 | }) | ||
63 | .bounds( | ||
64 | Bounds::builder() | ||
65 | .top(Float::Fixed(20.)) | ||
66 | .left(Float::Fixed(20.)) | ||
67 | .width(Float::Fixed(150.)) | ||
68 | .height(Float::Fixed(50.)) | ||
69 | .build(solver), | ||
70 | ) | ||
71 | .build(solver); | ||
72 | |||
73 | runtime.add_drawable(blocks); | ||
74 | */ | ||
75 | |||
76 | // ----------------8<---------------- | ||
77 | |||
78 | /* | ||
79 | let block_unit_width = solver.new_fixed_float(10.); | ||
80 | |||
81 | fn color_block(grow: u8, color: Color, solver: &mut dyn SolverContext) -> Drawable<Block> { | ||
82 | Drawable::builder(Block { grow }) | ||
83 | .fill(FillStyle::solid(color)) | ||
84 | .build(solver) | ||
85 | }; | ||
86 | |||
87 | fn blocks(block_descs: &[(u8, Color)], solver: &mut dyn SolverContext) -> Drawable<Blocks> { | ||
88 | let mut blocks = Vec::new(); | ||
89 | |||
90 | for &(grow, color) in block_descs { | ||
91 | blocks.push(color_block(grow, color, solver)); | ||
92 | } | ||
93 | |||
94 | Drawable::builder(Blocks { | ||
95 | blocks, | ||
96 | unit_width: solver.new_free_float(), | ||
97 | }) | ||
98 | .build(solver) | ||
99 | } | ||
100 | |||
101 | let block_list = Drawable::builder(BlockList { | ||
102 | block_list: vec![ | ||
103 | blocks(&[(1, light_grey), (1, light_grey), (1, light_grey)], solver), | ||
104 | blocks( | ||
105 | &[ | ||
106 | (1, light_grey), | ||
107 | (2, blue), | ||
108 | (1, light_grey), | ||
109 | (1, light_grey), | ||
110 | (1, light_grey), | ||
111 | ], | ||
112 | solver, | ||
113 | ), | ||
114 | blocks(&[(3, light_grey), (2, blue)], solver), | ||
115 | ], | ||
116 | block_unit_width, | ||
117 | bracket_width: block_unit_width, | ||
118 | blocks_vert_padding: block_unit_width, | ||
119 | }) | ||
120 | .bounds( | ||
121 | Bounds::builder() | ||
122 | .top(Float::Fixed(10.)) | ||
123 | .left(Float::Fixed(10.)) | ||
124 | .height(Float::Fixed(40.)) | ||
125 | .build(solver), | ||
126 | ) | ||
127 | .build(solver); | ||
128 | |||
129 | runtime.add_drawable(block_list); | ||
130 | */ | ||
131 | |||
132 | // ----------------8<---------------- | ||
133 | |||
134 | /* | ||
135 | let label_font = FontDescription { | ||
136 | family: String::from("mono"), | ||
137 | style: Default::default(), | ||
138 | weight: Default::default(), | ||
139 | size: Float::Fixed(15.), | ||
140 | }; | ||
141 | |||
142 | let layer = Drawable::builder(Layer { | ||
143 | name: String::from("Hello"), | ||
144 | name_font: FontDescription { | ||
145 | family: Default::default(), | ||
146 | style: Default::default(), | ||
147 | weight: Default::default(), | ||
148 | size: Float::Fixed(10.), | ||
149 | }, | ||
150 | entries: vec![], | ||
151 | padding: Float::Fixed(5.), | ||
152 | entries_width: Float::Fixed(50.), | ||
153 | label_font, | ||
154 | }) | ||
155 | .bounds(Bounds::builder() | ||
156 | .top(Float::Fixed(10.)) | ||
157 | .left(Float::Fixed(10.)) | ||
158 | .width(Float::Fixed(100.)) | ||
159 | .height(Float::Fixed(40.)) | ||
160 | .build(solver)) | ||
161 | .build(solver); | ||
162 | |||
163 | runtime.add_drawable(layer); | ||
164 | */ | ||
165 | |||
166 | // ----------------8<---------------- | ||
167 | |||
168 | let title_font = FontDescription { | ||
169 | family: String::from("Fanwood"), | ||
170 | style: Default::default(), | ||
171 | weight: Default::default(), | ||
172 | size: Float::Fixed(30.), | ||
173 | }; | ||
174 | |||
175 | let label_font = FontDescription { | ||
176 | family: String::from("mono"), | ||
177 | style: Default::default(), | ||
178 | weight: Default::default(), | ||
179 | size: Float::Fixed(15.), | ||
180 | }; | ||
181 | |||
182 | let layer_padding = Float::Fixed(15.); | ||
183 | let layer_margin = Float::Fixed(15.); | ||
184 | //let layer_height = Float::Fixed(40.); | ||
185 | let layer_left_content_padding = Float::Fixed(240.); | ||
186 | //let layer_width = solver.new_free_float(); | ||
187 | //let layer_width_constraint = solver.float_eq(layer_width, Float::Fixed(100.)); | ||
188 | //solver.constrain(layer_width_constraint); | ||
189 | |||
190 | let mut layer_top = Float::Fixed(15.); | ||
191 | |||
192 | let entries_width = solver.new_free_float(); | ||
193 | let mut all_entry_content_widths = vec![]; | ||
194 | |||
195 | let layer_width = solver.float_add(&[ | ||
196 | layer_left_content_padding, | ||
197 | entries_width, | ||
198 | layer_padding, | ||
199 | layer_padding, | ||
200 | ]); | ||
201 | |||
202 | let blocks_vert_padding = Float::Fixed(10.); | ||
203 | |||
204 | let block_unit_width = Float::Fixed(20.); | ||
205 | |||
206 | let blocks_height = Float::Fixed(26.); | ||
207 | let block_list_height = | ||
208 | solver.float_add(&[blocks_height, blocks_vert_padding, blocks_vert_padding]); | ||
209 | |||
210 | let blue_transaction_len = 5; | ||
211 | |||
212 | let blocks = |grows: &[u8], color, solver: &mut dyn SolverContext| { | ||
213 | let mut blocks = Vec::new(); | ||
214 | |||
215 | for &grow in grows { | ||
216 | blocks.push( | ||
217 | Drawable::builder(Block { grow }) | ||
218 | .fill(FillStyle::solid(color)) | ||
219 | .build(solver), | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | Drawable::builder(Blocks { | ||
224 | blocks, | ||
225 | unit_width: block_unit_width, | ||
226 | }) | ||
227 | .bounds(Bounds::builder().height(blocks_height).build(solver)) | ||
228 | .build(solver) | ||
229 | }; | ||
230 | |||
231 | let blocks_by_len = | ||
232 | |len, color, solver: &mut dyn SolverContext| blocks(&vec![1; len], color, solver); | ||
233 | |||
234 | // Log API | ||
235 | { | ||
236 | let blocks = blocks_by_len(blue_transaction_len, blue, solver); | ||
237 | let blocks_width = blocks.bounds().width(solver); | ||
238 | |||
239 | let layer = Drawable::builder(Layer { | ||
240 | name: String::from("LogAPI"), | ||
241 | name_font: title_font.clone(), | ||
242 | label_font: label_font.clone(), | ||
243 | padding: layer_padding, | ||
244 | entries: vec![Entry { | ||
245 | label: Some(String::from("activeTxn: ")), | ||
246 | label_vert_center_offset: None, | ||
247 | content: blocks.into(), | ||
248 | }], | ||
249 | entries_width, | ||
250 | }) | ||
251 | .bounds( | ||
252 | Bounds::builder() | ||
253 | // TODO: Replace that with a "distributeHorizontally" that applies to all layer | ||
254 | .top(layer_top) | ||
255 | .left(Float::Fixed(10.)) | ||
256 | .width(layer_width) | ||
257 | .build(solver), | ||
258 | ) | ||
259 | .build(solver); | ||
260 | |||
261 | all_entry_content_widths.push(blocks_width); | ||
262 | |||
263 | let layer_height = layer.bounds().height(solver); | ||
264 | layer_top = solver.float_add(&[layer_top, layer_height, layer_margin]); | ||
265 | |||
266 | runtime.add_drawable(layer); | ||
267 | } | ||
268 | |||
269 | let solver = runtime.solver_ctx(); | ||
270 | |||
271 | let other_transactions = [2, 7, 4]; | ||
272 | |||
273 | let group_commit_left; | ||
274 | let group_commit_right; | ||
275 | let group_commit_bottom; | ||
276 | |||
277 | // Group Commit | ||
278 | { | ||
279 | let mut block_list = Vec::new(); | ||
280 | for &blocks_count in other_transactions.iter() { | ||
281 | block_list.push(blocks_by_len(blocks_count, dark_grey, solver)); | ||
282 | } | ||
283 | |||
284 | block_list.push(blocks_by_len(blue_transaction_len, blue, solver)); | ||
285 | |||
286 | let block_list = Drawable::builder(BlockList { | ||
287 | block_list, | ||
288 | block_unit_width, | ||
289 | blocks_vert_padding: Float::Fixed(10.), | ||
290 | bracket_width: Float::Fixed(10.), | ||
291 | }) | ||
292 | .bounds(Bounds::builder().height(block_list_height).build(solver)) | ||
293 | .build(solver); | ||
294 | |||
295 | let content_width = block_list.bounds().width(solver); | ||
296 | |||
297 | group_commit_left = block_list.bounds().left(solver); | ||
298 | group_commit_right = block_list.bounds().right(solver); | ||
299 | group_commit_bottom = block_list.bounds().bottom(solver); | ||
300 | |||
301 | let layer = Drawable::builder(Layer { | ||
302 | name: String::from("GroupCommit"), | ||
303 | name_font: title_font.clone(), | ||
304 | label_font: label_font.clone(), | ||
305 | padding: layer_padding, | ||
306 | entries: vec![Entry { | ||
307 | label: Some(String::from("commitedTxns: ")), | ||
308 | label_vert_center_offset: None, | ||
309 | content: block_list.into(), | ||
310 | }], | ||
311 | entries_width, | ||
312 | }) | ||
313 | .bounds( | ||
314 | Bounds::builder() | ||
315 | .top(layer_top) | ||
316 | .left(Float::Fixed(10.)) | ||
317 | .width(layer_width) | ||
318 | .build(solver), | ||
319 | ) | ||
320 | .build(solver); | ||
321 | |||
322 | all_entry_content_widths.push(content_width); | ||
323 | |||
324 | let layer_height = layer.bounds().height(solver); | ||
325 | layer_top = solver.float_add(&[layer_top, layer_height, layer_margin]); | ||
326 | |||
327 | runtime.add_drawable(layer); | ||
328 | } | ||
329 | |||
330 | let solver = runtime.solver_ctx(); | ||
331 | |||
332 | let commit_in_log_left; | ||
333 | let commit_in_log_right; | ||
334 | let commit_in_log_top; | ||
335 | let big_block_grow; | ||
336 | let small_block_unit_width; | ||
337 | let data_in_log_left; | ||
338 | let data_in_log_right; | ||
339 | let data_in_log_bottom; | ||
340 | |||
341 | // Disk log | ||
342 | { | ||
343 | big_block_grow = (blue_transaction_len + other_transactions.iter().sum::<usize>()) as u8; | ||
344 | |||
345 | let make_block = |grow, color, solver: &mut dyn SolverContext| { | ||
346 | Drawable::builder(Block { grow }) | ||
347 | .bounds(Bounds::builder().height(blocks_height).build(solver)) | ||
348 | .fill(FillStyle::solid(color)) | ||
349 | .build(solver) | ||
350 | }; | ||
351 | |||
352 | let make_blocks = |block_descs: &[_], solver: &mut dyn SolverContext| { | ||
353 | let mut blocks = Vec::new(); | ||
354 | |||
355 | for &(grow, color) in block_descs { | ||
356 | blocks.push(make_block(grow, color, solver)); | ||
357 | } | ||
358 | |||
359 | blocks | ||
360 | }; | ||
361 | |||
362 | let header_block = make_block(big_block_grow, Color::black(), solver); | ||
363 | let header_block_width = header_block.bounds().width(solver); | ||
364 | |||
365 | let mut blocks = vec![header_block]; | ||
366 | |||
367 | blocks.append(&mut make_blocks( | ||
368 | &[(big_block_grow, light_grey), (big_block_grow, light_grey)], | ||
369 | solver, | ||
370 | )); | ||
371 | |||
372 | let sample_commit_start_id = blocks.len(); | ||
373 | |||
374 | for &txn_block_count in other_transactions.iter() { | ||
375 | for _i in 0..txn_block_count { | ||
376 | blocks.push(make_block(1, dark_grey, solver)); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | for _ in 0..blue_transaction_len { | ||
381 | blocks.push(make_block(1, blue, solver)); | ||
382 | } | ||
383 | |||
384 | let sample_commit_end_id = blocks.len() - 1; | ||
385 | |||
386 | commit_in_log_left = blocks[sample_commit_start_id].bounds().left(solver); | ||
387 | commit_in_log_right = blocks[sample_commit_end_id].bounds().right(solver); | ||
388 | commit_in_log_top = blocks[sample_commit_end_id].bounds().top(solver); | ||
389 | |||
390 | let log_data_blocks_widths: Vec<_> = blocks[1..] | ||
391 | .iter() | ||
392 | .map(|block| block.bounds().width(solver)) | ||
393 | .collect(); | ||
394 | let log_data_blocks_width = solver.float_add(&log_data_blocks_widths); | ||
395 | |||
396 | let log_space_block = make_block(big_block_grow, Color::white(), solver); | ||
397 | let log_space_width = log_space_block.bounds().width(solver); | ||
398 | blocks.push(log_space_block); | ||
399 | |||
400 | // Make it so that it takes as much space as the bigger one | ||
401 | small_block_unit_width = solver.new_free_float(); | ||
402 | |||
403 | let disk_log_layout = Drawable::builder(Blocks { | ||
404 | blocks, | ||
405 | unit_width: small_block_unit_width, | ||
406 | }) | ||
407 | .bounds(Bounds::builder().width(entries_width).build(solver)) | ||
408 | .build(solver); | ||
409 | |||
410 | let mut make_delimiter_label = |content| { | ||
411 | Drawable::builder(Text { | ||
412 | content: String::from(content), | ||
413 | font: FontDescription { | ||
414 | family: String::from("Fanwood"), | ||
415 | size: Float::Fixed(15.), | ||
416 | style: Default::default(), | ||
417 | weight: Default::default(), | ||
418 | }, | ||
419 | }) | ||
420 | .build(solver) | ||
421 | }; | ||
422 | |||
423 | let delimiters = vec![ | ||
424 | Delimiter { | ||
425 | label: make_delimiter_label("header"), | ||
426 | width: header_block_width, | ||
427 | }, | ||
428 | Delimiter { | ||
429 | label: make_delimiter_label("data"), | ||
430 | width: log_data_blocks_width, | ||
431 | }, | ||
432 | Delimiter { | ||
433 | label: make_delimiter_label("available"), | ||
434 | width: log_space_width, | ||
435 | }, | ||
436 | ]; | ||
437 | |||
438 | let disk_log_label = Drawable::builder(LabeledDelimiter { | ||
439 | delimiters, | ||
440 | tick_height: Float::Fixed(10.), | ||
441 | }) | ||
442 | .bounds(Bounds::builder().width(entries_width).build(solver)) | ||
443 | .build(solver); | ||
444 | |||
445 | let label_left = disk_log_label.bounds().left(solver); | ||
446 | data_in_log_left = solver.float_add(&[label_left, header_block_width]); | ||
447 | data_in_log_right = solver.float_add(&[data_in_log_left, log_data_blocks_width]); | ||
448 | data_in_log_bottom = disk_log_label.bounds().bottom(solver); | ||
449 | |||
450 | let layer = Drawable::builder(Layer { | ||
451 | name: String::from("DiskLog"), | ||
452 | name_font: title_font.clone(), | ||
453 | label_font: label_font.clone(), | ||
454 | padding: layer_padding, | ||
455 | entries: vec![ | ||
456 | Entry { | ||
457 | label: Some(String::from("disk log: ")), | ||
458 | label_vert_center_offset: None, | ||
459 | content: disk_log_layout.into(), | ||
460 | }, | ||
461 | Entry { | ||
462 | label: None, | ||
463 | label_vert_center_offset: None, | ||
464 | content: disk_log_label.into(), | ||
465 | }, | ||
466 | ], | ||
467 | entries_width, | ||
468 | }) | ||
469 | .bounds( | ||
470 | Bounds::builder() | ||
471 | .top(layer_top) | ||
472 | .left(Float::Fixed(10.)) | ||
473 | .width(layer_width) | ||
474 | .build(solver), | ||
475 | ) | ||
476 | .build(solver); | ||
477 | |||
478 | let layer_height = layer.bounds().height(solver); | ||
479 | layer_top = solver.float_add(&[layer_top, layer_height, layer_margin]); | ||
480 | |||
481 | runtime.add_drawable(layer); | ||
482 | } | ||
483 | |||
484 | let solver = runtime.solver_ctx(); | ||
485 | |||
486 | // Explode GroupLog -> DiskLog | ||
487 | { | ||
488 | let margin = Float::Fixed(6.); | ||
489 | let explode_top = solver.float_add(&[group_commit_bottom, margin]); | ||
490 | let explode_bottom = solver.float_sub(&[commit_in_log_top, margin]); | ||
491 | |||
492 | let explode = Drawable::builder(Explode { | ||
493 | top_left: Point2D::new(group_commit_left, explode_top), | ||
494 | top_right: Point2D::new(group_commit_right, explode_top), | ||
495 | bottom_left: Point2D::new(commit_in_log_left, explode_bottom), | ||
496 | bottom_right: Point2D::new(commit_in_log_right, explode_bottom), | ||
497 | |||
498 | arm_length: Float::Fixed(12.), | ||
499 | }) | ||
500 | .stroke( | ||
501 | StrokeStyle::builder() | ||
502 | .dash(DashStyle::new(vec![Float::Fixed(2.)], Float::Fixed(0.))) | ||
503 | .build(), | ||
504 | ) | ||
505 | .build(solver); | ||
506 | |||
507 | runtime.add_drawable(explode); | ||
508 | } | ||
509 | |||
510 | let solver = runtime.solver_ctx(); | ||
511 | |||
512 | let data_in_applier_top; | ||
513 | let data_in_applier_left; | ||
514 | let data_in_applier_right; | ||
515 | |||
516 | // Applier | ||
517 | { | ||
518 | // TODO: this is exactly the same as before... | ||
519 | let make_block = |grow, color, solver: &mut dyn SolverContext| { | ||
520 | Drawable::builder(Block { grow }) | ||
521 | .bounds(Bounds::builder().height(blocks_height).build(solver)) | ||
522 | .fill(FillStyle::solid(color)) | ||
523 | .build(solver) | ||
524 | }; | ||
525 | |||
526 | let _make_blocks = |block_descs: &[_], solver: &mut dyn SolverContext| { | ||
527 | let mut blocks = Vec::new(); | ||
528 | |||
529 | for &(grow, color) in block_descs { | ||
530 | blocks.push(make_block(grow, color, solver)); | ||
531 | } | ||
532 | |||
533 | blocks | ||
534 | }; | ||
535 | |||
536 | let mut blocks = vec![]; | ||
537 | |||
538 | blocks.push(make_block(big_block_grow, light_grey, solver)); | ||
539 | for &txn_block_count in other_transactions.iter() { | ||
540 | for _i in 0..txn_block_count { | ||
541 | blocks.push(make_block(1, dark_grey, solver)); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | for _ in 0..blue_transaction_len { | ||
546 | blocks.push(make_block(1, blue, solver)); | ||
547 | } | ||
548 | |||
549 | let blocks = Drawable::builder(Blocks { | ||
550 | blocks, | ||
551 | unit_width: small_block_unit_width, | ||
552 | }) | ||
553 | .build(solver); | ||
554 | |||
555 | data_in_applier_top = blocks.bounds().top(solver); | ||
556 | data_in_applier_left = blocks.bounds().left(solver); | ||
557 | data_in_applier_right = blocks.bounds().right(solver); | ||
558 | |||
559 | let spaced_data = Spacer::builder(blocks) | ||
560 | .horizontal_align_center(solver) | ||
561 | .vertical_align_center_with(Float::Fixed(10.)) | ||
562 | .build(solver); | ||
563 | |||
564 | let spaced_data = Drawable::builder(spaced_data) | ||
565 | .bounds(Bounds::builder().width(entries_width).build(solver)) | ||
566 | .build(solver); | ||
567 | |||
568 | let disk_data = Drawable::builder(Block { grow: 1 }) | ||
569 | .bounds( | ||
570 | Bounds::builder() | ||
571 | .height(blocks_height) | ||
572 | .width(entries_width) | ||
573 | .build(solver), | ||
574 | ) | ||
575 | .fill(FillStyle::solid(Color::white())) | ||
576 | .build(solver); | ||
577 | |||
578 | let layer = Drawable::builder(Layer { | ||
579 | name: String::from("Applier"), | ||
580 | name_font: title_font.clone(), | ||
581 | label_font: label_font.clone(), | ||
582 | padding: layer_padding, | ||
583 | entries: vec![ | ||
584 | Entry { | ||
585 | label: None, | ||
586 | label_vert_center_offset: None, | ||
587 | content: spaced_data.into(), | ||
588 | }, | ||
589 | Entry { | ||
590 | label: Some(String::from("disk data:")), | ||
591 | label_vert_center_offset: None, | ||
592 | content: disk_data.into(), | ||
593 | }, | ||
594 | ], | ||
595 | entries_width, | ||
596 | }) | ||
597 | .bounds( | ||
598 | Bounds::builder() | ||
599 | .top(layer_top) | ||
600 | .left(Float::Fixed(10.)) | ||
601 | .width(layer_width) | ||
602 | .build(solver), | ||
603 | ) | ||
604 | .build(solver); | ||
605 | |||
606 | runtime.add_drawable(layer); | ||
607 | } | ||
608 | |||
609 | let solver = runtime.solver_ctx(); | ||
610 | |||
611 | // Explode DiskLog -> Applier | ||
612 | { | ||
613 | let margin = Float::Fixed(6.); | ||
614 | let explode_top = solver.float_add(&[data_in_log_bottom, margin]); | ||
615 | let explode_bottom = solver.float_sub(&[data_in_applier_top, margin]); | ||
616 | |||
617 | let explode = Drawable::builder(Explode { | ||
618 | top_left: Point2D::new(data_in_log_left, explode_top), | ||
619 | top_right: Point2D::new(data_in_log_right, explode_top), | ||
620 | bottom_left: Point2D::new(data_in_applier_left, explode_bottom), | ||
621 | bottom_right: Point2D::new(data_in_applier_right, explode_bottom), | ||
622 | |||
623 | arm_length: Float::Fixed(12.), | ||
624 | }) | ||
625 | .stroke( | ||
626 | StrokeStyle::builder() | ||
627 | .dash(DashStyle::new(vec![Float::Fixed(2.)], Float::Fixed(0.))) | ||
628 | .build(), | ||
629 | ) | ||
630 | .build(solver); | ||
631 | |||
632 | runtime.add_drawable(explode); | ||
633 | } | ||
634 | |||
635 | let solver = runtime.solver_ctx(); | ||
636 | |||
637 | let max_entry_content_width = solver.float_max(&all_entry_content_widths); | ||
638 | let entries_width_constraint = solver.float_eq(entries_width, max_entry_content_width); | ||
639 | solver.constrain(entries_width_constraint); | ||
640 | |||
641 | runtime.render(); | ||
642 | } | ||
diff --git a/examples/lib-dfscq-log/src/main2.rs b/examples/lib-dfscq-log/src/main2.rs new file mode 100644 index 0000000..9db235d --- /dev/null +++ b/examples/lib-dfscq-log/src/main2.rs | |||
@@ -0,0 +1,61 @@ | |||
1 | fn main() { | ||
2 | let solver = Solver::new(); | ||
3 | let output = Output::new(); | ||
4 | |||
5 | let blue_transaction_len = 5; | ||
6 | |||
7 | let blue_block = Block::builder().color(blue); | ||
8 | let dark_gray_block = Block::builder().color(dark_gray); | ||
9 | |||
10 | let log_layer = Layer::builder() | ||
11 | .name("LogAPI") | ||
12 | .push_entry( | ||
13 | Entry::builder() | ||
14 | .label("activeTxn: ") | ||
15 | .content( | ||
16 | Blocks::builder() | ||
17 | .push(blue_transaction_len, blue_block.build()) | ||
18 | .build(), | ||
19 | ) | ||
20 | .build(), | ||
21 | ) | ||
22 | .build(); | ||
23 | |||
24 | let other_transactions = [2, 7, 4]; | ||
25 | |||
26 | let group_commit_layer = Layer::builder() | ||
27 | .name("GroupCommit") | ||
28 | .push_entry( | ||
29 | Entry::builder() | ||
30 | .label("commitedTxn: ") | ||
31 | .content( | ||
32 | BlockList::builder() | ||
33 | .append( | ||
34 | other_transactions | ||
35 | .iter() | ||
36 | // TODO: need collect? | ||
37 | .map(|len| Blocks::builder().push(len, dark_gray_block.build())), | ||
38 | ) | ||
39 | .push(Blocks::builder().push(blue_transaction_len, blue_block.build())) | ||
40 | .build(), | ||
41 | ) | ||
42 | .build(), | ||
43 | ) | ||
44 | .build(); | ||
45 | |||
46 | let disk_log_layer = todo!(); | ||
47 | |||
48 | let applier_layer = todo!(); | ||
49 | |||
50 | let layers = &[ | ||
51 | &log_layer, | ||
52 | &group_commit_layer, | ||
53 | &disk_log_layer, | ||
54 | &applier_layer, | ||
55 | ]; | ||
56 | constraints::distribute_vertically(solver, layers); | ||
57 | constraints::align_left(solver, layers); | ||
58 | |||
59 | solver.solve(); | ||
60 | output.write_to_stdout(Output::Format::SVG); | ||
61 | } | ||
diff --git a/examples/lib-dfscq-log/src/spacer.rs b/examples/lib-dfscq-log/src/spacer.rs new file mode 100644 index 0000000..6878183 --- /dev/null +++ b/examples/lib-dfscq-log/src/spacer.rs | |||
@@ -0,0 +1,133 @@ | |||
1 | use diaphragm_core::{ | ||
2 | types::{Float, ShapeContext}, | ||
3 | ComplexShape, DrawResult, DynDrawable, SolverContext, | ||
4 | }; | ||
5 | |||
6 | #[derive(Clone)] | ||
7 | pub struct Spacer { | ||
8 | pub margin_left: Float, | ||
9 | pub margin_right: Float, | ||
10 | pub margin_top: Float, | ||
11 | pub margin_bottom: Float, | ||
12 | pub content: DynDrawable, | ||
13 | } | ||
14 | |||
15 | impl Spacer { | ||
16 | pub fn builder<T: Into<DynDrawable>>(drawable: T) -> SpacerBuilder { | ||
17 | SpacerBuilder::new(drawable) | ||
18 | } | ||
19 | } | ||
20 | |||
21 | impl ComplexShape for Spacer { | ||
22 | fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult { | ||
23 | let mut result = DrawResult::new(); | ||
24 | |||
25 | let bounds_left = context.bounds().left(solver); | ||
26 | let bounds_right = context.bounds().right(solver); | ||
27 | let bounds_top = context.bounds().top(solver); | ||
28 | let bounds_bottom = context.bounds().bottom(solver); | ||
29 | |||
30 | let wanted_content_left = solver.float_add(&[bounds_left, self.margin_left]); | ||
31 | let content_left = self.content.bounds().left(solver); | ||
32 | let content_left_constraint = solver.float_eq(content_left, wanted_content_left); | ||
33 | solver.constrain(content_left_constraint); | ||
34 | |||
35 | let wanted_content_right = solver.float_sub(&[bounds_right, self.margin_right]); | ||
36 | let content_right = self.content.bounds().right(solver); | ||
37 | let content_right_constraint = solver.float_eq(content_right, wanted_content_right); | ||
38 | solver.constrain(content_right_constraint); | ||
39 | |||
40 | let wanted_content_top = solver.float_add(&[bounds_top, self.margin_top]); | ||
41 | let content_top = self.content.bounds().top(solver); | ||
42 | let content_top_constraint = solver.float_eq(content_top, wanted_content_top); | ||
43 | solver.constrain(content_top_constraint); | ||
44 | |||
45 | let wanted_content_bottom = solver.float_sub(&[bounds_bottom, self.margin_bottom]); | ||
46 | let content_bottom = self.content.bounds().bottom(solver); | ||
47 | let content_bottom_constraint = solver.float_eq(content_bottom, wanted_content_bottom); | ||
48 | solver.constrain(content_bottom_constraint); | ||
49 | |||
50 | result.push_dyn(self.content.clone()); | ||
51 | |||
52 | result | ||
53 | } | ||
54 | } | ||
55 | |||
56 | #[derive(Clone)] | ||
57 | pub struct SpacerBuilder { | ||
58 | pub margin_left: Option<Float>, | ||
59 | pub margin_right: Option<Float>, | ||
60 | pub margin_top: Option<Float>, | ||
61 | pub margin_bottom: Option<Float>, | ||
62 | pub content: DynDrawable, | ||
63 | } | ||
64 | |||
65 | impl SpacerBuilder { | ||
66 | pub fn new<T: Into<DynDrawable>>(drawable: T) -> Self { | ||
67 | SpacerBuilder { | ||
68 | margin_left: None, | ||
69 | margin_right: None, | ||
70 | margin_top: None, | ||
71 | margin_bottom: None, | ||
72 | content: drawable.into(), | ||
73 | } | ||
74 | } | ||
75 | |||
76 | pub fn margin_left(&mut self, margin_left: Float) -> &mut Self { | ||
77 | self.margin_left = Some(margin_left); | ||
78 | self | ||
79 | } | ||
80 | |||
81 | pub fn margin_right(&mut self, margin_right: Float) -> &mut Self { | ||
82 | self.margin_right = Some(margin_right); | ||
83 | self | ||
84 | } | ||
85 | |||
86 | pub fn margin_top(&mut self, margin_top: Float) -> &mut Self { | ||
87 | self.margin_top = Some(margin_top); | ||
88 | self | ||
89 | } | ||
90 | |||
91 | pub fn margin_bottom(&mut self, margin_bottom: Float) -> &mut Self { | ||
92 | self.margin_bottom = Some(margin_bottom); | ||
93 | self | ||
94 | } | ||
95 | |||
96 | pub fn vertical_align_center(&mut self, solver: &mut dyn SolverContext) -> &mut Self { | ||
97 | let vertical_margin = solver.new_free_float(); | ||
98 | self.margin_top = Some(vertical_margin); | ||
99 | self.margin_bottom = Some(vertical_margin); | ||
100 | self | ||
101 | } | ||
102 | |||
103 | pub fn vertical_align_center_with(&mut self, margin: Float) -> &mut Self { | ||
104 | self.margin_top = Some(margin); | ||
105 | self.margin_bottom = Some(margin); | ||
106 | self | ||
107 | } | ||
108 | |||
109 | pub fn horizontal_align_center(&mut self, solver: &mut dyn SolverContext) -> &mut Self { | ||
110 | let horizontal_margin = solver.new_free_float(); | ||
111 | self.margin_left = Some(horizontal_margin); | ||
112 | self.margin_right = Some(horizontal_margin); | ||
113 | self | ||
114 | } | ||
115 | |||
116 | pub fn horizontal_align_center_with(&mut self, margin: Float) -> &mut Self { | ||
117 | self.margin_left = Some(margin); | ||
118 | self.margin_right = Some(margin); | ||
119 | self | ||
120 | } | ||
121 | |||
122 | pub fn build(&self, solver: &mut dyn SolverContext) -> Spacer { | ||
123 | Spacer { | ||
124 | margin_left: self.margin_left.unwrap_or_else(|| solver.new_free_float()), | ||
125 | margin_right: self.margin_right.unwrap_or_else(|| solver.new_free_float()), | ||
126 | margin_top: self.margin_top.unwrap_or_else(|| solver.new_free_float()), | ||
127 | margin_bottom: self | ||
128 | .margin_bottom | ||
129 | .unwrap_or_else(|| solver.new_free_float()), | ||
130 | content: self.content.clone(), | ||
131 | } | ||
132 | } | ||
133 | } | ||
diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bcd2dca --- /dev/null +++ b/flake.lock | |||
@@ -0,0 +1,27 @@ | |||
1 | { | ||
2 | "nodes": { | ||
3 | "nixpkgs": { | ||
4 | "locked": { | ||
5 | "lastModified": 1670461440, | ||
6 | "narHash": "sha256-jy1LB8HOMKGJEGXgzFRLDU1CBGL0/LlkolgnqIsF0D8=", | ||
7 | "owner": "NixOS", | ||
8 | "repo": "nixpkgs", | ||
9 | "rev": "04a75b2eecc0acf6239acf9dd04485ff8d14f425", | ||
10 | "type": "github" | ||
11 | }, | ||
12 | "original": { | ||
13 | "owner": "NixOS", | ||
14 | "ref": "nixos-22.11", | ||
15 | "repo": "nixpkgs", | ||
16 | "type": "github" | ||
17 | } | ||
18 | }, | ||
19 | "root": { | ||
20 | "inputs": { | ||
21 | "nixpkgs": "nixpkgs" | ||
22 | } | ||
23 | } | ||
24 | }, | ||
25 | "root": "root", | ||
26 | "version": 7 | ||
27 | } | ||
diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..bbe2ab1 --- /dev/null +++ b/flake.nix | |||
@@ -0,0 +1,22 @@ | |||
1 | { | ||
2 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11"; | ||
3 | |||
4 | outputs = { | ||
5 | self, | ||
6 | nixpkgs, | ||
7 | }: let | ||
8 | pkgs = nixpkgs.legacyPackages.x86_64-linux; | ||
9 | in { | ||
10 | devShell.x86_64-linux = pkgs.mkShell { | ||
11 | buildInputs = with pkgs; [ | ||
12 | pkgconfig | ||
13 | cairo | ||
14 | pango | ||
15 | z3 | ||
16 | |||
17 | lua5_4 | ||
18 | stylua | ||
19 | ]; | ||
20 | }; | ||
21 | }; | ||
22 | } | ||
diff --git a/lua-bindings/Cargo.toml b/lua-bindings/Cargo.toml new file mode 100644 index 0000000..3859c4e --- /dev/null +++ b/lua-bindings/Cargo.toml | |||
@@ -0,0 +1,15 @@ | |||
1 | [package] | ||
2 | name = "diaphragm-lua-bindings" | ||
3 | version = "0.1.0" | ||
4 | edition = "2021" | ||
5 | |||
6 | [lib] | ||
7 | crate-type = ["cdylib"] | ||
8 | name = "diaphragm" | ||
9 | |||
10 | [dependencies] | ||
11 | diaphragm-core = { path = "../core" } | ||
12 | diaphragm-z3-solver = { path = "../z3-solver" } | ||
13 | diaphragm-cairo-renderer = { path = "../cairo-renderer" } | ||
14 | |||
15 | mlua = { version = "0.8", features = ["lua54", "module"] } | ||
diff --git a/lua-bindings/src/lib.rs b/lua-bindings/src/lib.rs new file mode 100644 index 0000000..6628ee2 --- /dev/null +++ b/lua-bindings/src/lib.rs | |||
@@ -0,0 +1,116 @@ | |||
1 | use std::sync::atomic::{AtomicUsize, Ordering}; | ||
2 | |||
3 | use diaphragm_core::{ | ||
4 | solving::VariableHandle, | ||
5 | text::{FontDescription as CoreFontDescription, FontStyle, FontWeight, Text as CoreText}, | ||
6 | types::Float as CoreFloat, | ||
7 | }; | ||
8 | // use diaphragm_cairo_renderer::CairoRenderer; | ||
9 | // use diaphragm_core::Runtime; | ||
10 | // use diaphragm_z3_solver::{z3, Z3Context}; | ||
11 | use mlua::prelude::*; | ||
12 | |||
13 | static MAX_ID: AtomicUsize = AtomicUsize::new(0); | ||
14 | |||
15 | #[derive(Clone, Copy, Debug)] | ||
16 | struct Float(CoreFloat); | ||
17 | |||
18 | impl Float { | ||
19 | fn new() -> Float { | ||
20 | Float(CoreFloat::Variable(VariableHandle::new( | ||
21 | MAX_ID.fetch_add(1, Ordering::SeqCst), | ||
22 | ))) | ||
23 | } | ||
24 | } | ||
25 | impl LuaUserData for Float {} | ||
26 | |||
27 | fn float(_: &Lua, _: ()) -> LuaResult<Float> { | ||
28 | Ok(Float::new()) | ||
29 | } | ||
30 | |||
31 | #[derive(Clone, Debug)] | ||
32 | struct FontDescription(CoreFontDescription); | ||
33 | impl LuaUserData for FontDescription {} | ||
34 | |||
35 | const DEFAULT_FONT_FAMILY: &str = "serif"; | ||
36 | |||
37 | impl Default for FontDescription { | ||
38 | fn default() -> Self { | ||
39 | Self(CoreFontDescription { | ||
40 | family: DEFAULT_FONT_FAMILY.to_string(), | ||
41 | style: FontStyle::Normal, | ||
42 | weight: FontWeight::Normal, | ||
43 | size: Float::new().0, | ||
44 | }) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | fn font(_: &Lua, params: LuaTable) -> LuaResult<FontDescription> { | ||
49 | // TODO: better validation of the table | ||
50 | // What happens when I mistype a param? | ||
51 | // TODO: better error handling | ||
52 | |||
53 | let family = params | ||
54 | .get::<_, Option<_>>("family")? | ||
55 | .unwrap_or_else(|| DEFAULT_FONT_FAMILY.to_string()); | ||
56 | |||
57 | let style = match params.get::<_, Option<String>>("style")?.as_deref() { | ||
58 | Some("normal") | None => FontStyle::Normal, | ||
59 | Some(_) => return Err(LuaError::RuntimeError("Unknown style".to_string())), | ||
60 | }; | ||
61 | |||
62 | let weight = match params.get::<_, Option<String>>("weight")?.as_deref() { | ||
63 | Some("normal") | None => FontWeight::Normal, | ||
64 | Some(_) => return Err(LuaError::RuntimeError("Unknown weight".to_string())), | ||
65 | }; | ||
66 | |||
67 | let size = params | ||
68 | .get::<_, Option<_>>("size")? | ||
69 | .unwrap_or_else(Float::new); | ||
70 | |||
71 | Ok(FontDescription(CoreFontDescription { | ||
72 | family, | ||
73 | style, | ||
74 | weight, | ||
75 | size: size.0, | ||
76 | })) | ||
77 | } | ||
78 | |||
79 | #[derive(Clone, Debug)] | ||
80 | struct Text(CoreText); | ||
81 | impl LuaUserData for Text {} | ||
82 | |||
83 | fn text(_: &Lua, params: LuaTable) -> LuaResult<Text> { | ||
84 | let content = params.get("content")?; | ||
85 | |||
86 | let font = params | ||
87 | .get::<_, Option<FontDescription>>("font")? | ||
88 | .unwrap_or_default(); | ||
89 | |||
90 | Ok(Text(CoreText { | ||
91 | content, | ||
92 | font: font.0, | ||
93 | })) | ||
94 | } | ||
95 | |||
96 | fn draw(_: &Lua, params: LuaTable) -> LuaResult<()> { | ||
97 | let content: LuaTable = params.get("content")?; | ||
98 | let output: LuaTable = params.get("output")?; | ||
99 | |||
100 | dbg!(content, output); | ||
101 | |||
102 | Ok(()) | ||
103 | } | ||
104 | |||
105 | #[mlua::lua_module] | ||
106 | fn libdiaphragm(lua: &Lua) -> LuaResult<LuaTable> { | ||
107 | // TODO: the solver as a mutable global solves so much problem (pun not intended) | ||
108 | let exports = lua.create_table()?; | ||
109 | exports.set("text", lua.create_function(text)?)?; | ||
110 | exports.set("font", lua.create_function(font)?)?; | ||
111 | exports.set("float", lua.create_function(float)?)?; | ||
112 | |||
113 | exports.set("draw", lua.create_function(draw)?)?; | ||
114 | |||
115 | Ok(exports) | ||
116 | } | ||
@@ -0,0 +1 @@ | |||
/nix/store/wzmhg661jib969sj02hbf5991mq4had4-lua-5.4.4 \ No newline at end of file | |||
diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..2d25ec7 --- /dev/null +++ b/shell.nix | |||
@@ -0,0 +1,10 @@ | |||
1 | { pkgs ? import <nixpkgs> {} }: | ||
2 | |||
3 | pkgs.mkShell { | ||
4 | buildInputs = with pkgs; [ | ||
5 | pkgconfig cairo pango z3 | ||
6 | |||
7 | # keep this line if you use bash | ||
8 | pkgs.bashInteractive | ||
9 | ]; | ||
10 | } | ||
diff --git a/test.svg b/test.svg new file mode 100644 index 0000000..bfef495 --- /dev/null +++ b/test.svg | |||
@@ -0,0 +1,377 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920pt" height="1080pt" viewBox="0 0 1920 1080" version="1.1"> | ||
3 | <defs> | ||
4 | <g> | ||
5 | <symbol overflow="visible" id="glyph0-0"> | ||
6 | <path style="stroke:none;" d="M 1.171875 0 L 10.546875 0 L 10.546875 -10.78125 L 1.171875 -10.78125 Z M 2.34375 -1.171875 L 2.34375 -9.609375 L 9.375 -9.609375 L 9.375 -1.171875 Z M 2.34375 -1.171875 "/> | ||
7 | </symbol> | ||
8 | <symbol overflow="visible" id="glyph0-1"> | ||
9 | <path style="stroke:none;" d="M 0.9375 -0.359375 C 0.9375 0.046875 0.9375 0.078125 1.25 0.078125 C 1.78125 0.078125 3.40625 0 4.109375 0 C 4.8125 0 12.09375 0.078125 12.640625 0.078125 C 12.875 0.078125 13.125 0.03125 13.15625 -0.1875 C 13.25 -0.875 13.640625 -3.140625 13.640625 -3.328125 C 13.640625 -3.46875 13.40625 -3.5625 13.171875 -3.5625 C 13.03125 -3.5625 12.9375 -3.5 12.921875 -3.375 L 12.640625 -1.40625 C 12.5625 -0.890625 12.46875 -0.890625 12.09375 -0.875 C 11.84375 -0.84375 7.625 -0.734375 5.234375 -0.734375 C 5.09375 -0.734375 5.046875 -1.875 5.046875 -3.453125 L 5.046875 -9.9375 C 5.046875 -12.21875 5.0625 -14.984375 5.25 -14.984375 L 6.890625 -14.984375 C 7.265625 -14.984375 7.3125 -15.046875 7.3125 -15.328125 C 7.3125 -15.65625 7.296875 -15.6875 6.921875 -15.6875 C 6.375 -15.6875 4.859375 -15.609375 4.15625 -15.609375 C 3.453125 -15.609375 1.953125 -15.6875 1.578125 -15.6875 C 1.203125 -15.6875 1.109375 -15.65625 1.109375 -15.328125 C 1.109375 -15 1.171875 -14.984375 1.484375 -14.984375 L 2.84375 -14.984375 C 2.984375 -14.984375 3 -14.15625 3 -12.890625 L 3 -7.484375 C 3 -4.015625 2.984375 -0.640625 2.796875 -0.640625 L 1.34375 -0.640625 C 0.96875 -0.640625 0.9375 -0.640625 0.9375 -0.359375 Z M 0.9375 -0.359375 "/> | ||
10 | </symbol> | ||
11 | <symbol overflow="visible" id="glyph0-2"> | ||
12 | <path style="stroke:none;" d="M 0.703125 -4.296875 C 0.703125 -1.734375 2.625 0.359375 5.140625 0.359375 C 8.046875 0.359375 9.75 -1.734375 9.75 -4.625 C 9.75 -7.203125 8.0625 -9.28125 5.515625 -9.28125 C 2.625 -9.28125 0.703125 -7.0625 0.703125 -4.296875 Z M 2.375 -3.96875 C 2.375 -6.546875 3.03125 -8.671875 5.234375 -8.671875 C 7.203125 -8.671875 8.046875 -6.609375 8.046875 -4.78125 C 8.046875 -2.671875 7.484375 -0.265625 5.140625 -0.265625 C 3.3125 -0.265625 2.375 -2.203125 2.375 -3.96875 Z M 2.375 -3.96875 "/> | ||
13 | </symbol> | ||
14 | <symbol overflow="visible" id="glyph0-3"> | ||
15 | <path style="stroke:none;" d="M 0.359375 4.0625 C 0.359375 5.9375 2.75 6.796875 4.6875 6.796875 C 7.71875 6.796875 9.84375 5.296875 9.84375 2.90625 C 9.84375 -0.125 5.0625 0.1875 2.09375 0 C 2 -0.03125 1.765625 -0.421875 1.765625 -0.703125 C 1.765625 -0.796875 1.78125 -0.890625 1.859375 -0.921875 C 3.421875 -1.359375 4.828125 -1.71875 5.90625 -2.140625 C 7.578125 -2.765625 8.609375 -3.703125 8.609375 -5.703125 C 8.609375 -6.734375 8.296875 -7.25 8.296875 -7.390625 C 8.296875 -7.484375 9.40625 -7.6875 9.6875 -7.71875 C 9.734375 -7.71875 9.75 -7.765625 9.75 -7.859375 C 9.75 -8.140625 9.609375 -8.515625 9.546875 -8.515625 C 8.8125 -8.46875 7.921875 -8.0625 7.78125 -8.0625 C 7.71875 -8.0625 6.734375 -9.265625 4.921875 -9.265625 C 2.84375 -9.265625 0.796875 -7.828125 0.796875 -5.765625 C 0.796875 -3.546875 2.109375 -2.484375 3.78125 -2 C 4.015625 -1.921875 4.21875 -1.90625 4.21875 -1.875 C 4.21875 -1.828125 3.5625 -1.671875 3.328125 -1.59375 C 2.578125 -1.390625 2.140625 -1.265625 1.546875 -1.125 C 1.25 -1.0625 1.125 -0.796875 1.125 -0.375 C 1.125 -0.125 1.15625 0.3125 1.34375 0.75 C 1.484375 1.0625 1.875 1.203125 2.28125 1.203125 L 3.609375 1.203125 C 3.96875 1.203125 4.109375 1.203125 4.109375 1.21875 C 4.109375 1.25 3.796875 1.3125 3.5625 1.359375 C 2.4375 1.59375 0.359375 2.4375 0.359375 4.0625 Z M 1.40625 3.890625 C 1.40625 2.34375 3.3125 1.59375 4.4375 1.59375 C 6.140625 1.59375 8.515625 2.109375 8.515625 3.46875 C 8.515625 5.53125 6.421875 6.1875 4.671875 6.1875 C 3.265625 6.1875 1.40625 5.4375 1.40625 3.890625 Z M 2.296875 -5.859375 C 2.296875 -7.40625 3.46875 -8.671875 4.8125 -8.671875 C 6.234375 -8.671875 7.15625 -7.578125 7.15625 -5.71875 C 7.15625 -3.609375 5.796875 -2.234375 4.859375 -2.234375 C 4.265625 -2.234375 2.296875 -3.5625 2.296875 -5.859375 Z M 2.296875 -5.859375 "/> | ||
16 | </symbol> | ||
17 | <symbol overflow="visible" id="glyph0-4"> | ||
18 | <path style="stroke:none;" d="M 0.703125 -0.359375 C 0.703125 0.046875 0.734375 0.078125 1.03125 0.078125 C 1.578125 0.078125 2.046875 0 2.75 0 C 3.453125 0 4.359375 0.078125 4.90625 0.078125 C 5.140625 0.078125 5.15625 0.03125 5.15625 -0.328125 C 5.15625 -0.609375 5.15625 -0.640625 4.90625 -0.640625 L 3.078125 -0.640625 C 3.046875 -0.640625 3.046875 -0.65625 3.046875 -0.703125 C 3.046875 -1.21875 4.34375 -4.484375 4.953125 -6.03125 C 5.0625 -6.328125 5.046875 -6.453125 5.484375 -6.453125 L 10.203125 -6.453125 C 10.546875 -6.453125 10.53125 -6.421875 10.671875 -6 C 11.140625 -4.6875 12.3125 -1.265625 12.3125 -0.703125 C 12.3125 -0.65625 12.3125 -0.640625 12.28125 -0.640625 L 11.015625 -0.640625 C 10.640625 -0.640625 10.59375 -0.640625 10.59375 -0.359375 C 10.59375 0.046875 10.625 0.078125 10.921875 0.078125 C 11.46875 0.078125 12.828125 0 13.53125 0 C 14.234375 0 15.28125 0.078125 15.640625 0.078125 C 15.875 0.078125 15.890625 0.03125 15.890625 -0.328125 C 15.890625 -0.609375 15.890625 -0.640625 15.640625 -0.640625 L 14.890625 -0.640625 C 14.609375 -0.640625 12.96875 -5.375 12 -8.046875 L 9.1875 -15.9375 C 9.171875 -16.03125 9.09375 -16.109375 8.984375 -16.109375 C 8.84375 -16.109375 8.671875 -15.796875 8.53125 -15.46875 C 8.28125 -14.84375 7.875 -14.625 7.6875 -14.15625 L 5.203125 -8.390625 C 4.875 -7.640625 2.046875 -0.640625 1.78125 -0.640625 L 1.125 -0.640625 C 0.75 -0.640625 0.703125 -0.640625 0.703125 -0.359375 Z M 5.421875 -7.15625 C 5.421875 -7.21875 5.46875 -7.34375 5.53125 -7.5 L 7.828125 -13.125 C 7.953125 -13.40625 8.015625 -13.578125 8.0625 -13.578125 C 8.109375 -13.578125 8.15625 -13.4375 8.25 -13.125 L 10.203125 -7.4375 C 10.25 -7.296875 10.296875 -7.203125 10.296875 -7.125 C 10.296875 -7.0625 10.21875 -7.015625 9.984375 -7.015625 L 5.796875 -7.015625 C 5.515625 -7.015625 5.421875 -7.0625 5.421875 -7.15625 Z M 5.421875 -7.15625 "/> | ||
19 | </symbol> | ||
20 | <symbol overflow="visible" id="glyph0-5"> | ||
21 | <path style="stroke:none;" d="M 0.9375 -15.21875 C 0.9375 -14.859375 1.125 -14.8125 1.40625 -14.8125 L 2.890625 -14.859375 C 2.984375 -14.859375 3 -13.8125 3 -12.328125 L 3 -11.109375 C 3 -8.046875 2.984375 -0.640625 2.796875 -0.640625 L 1.59375 -0.640625 C 1.21875 -0.640625 1.171875 -0.640625 1.171875 -0.359375 C 1.171875 0.046875 1.203125 0.078125 1.5 0.078125 C 1.71875 0.078125 3.3125 0 4.015625 0 C 4.71875 0 6.171875 0.078125 6.703125 0.078125 C 6.9375 0.078125 6.96875 0.03125 6.96875 -0.328125 C 6.96875 -0.609375 6.96875 -0.640625 6.703125 -0.640625 L 5 -0.640625 C 4.90625 -0.640625 4.875 -3.1875 4.875 -5.0625 L 4.875 -6.609375 C 4.875 -6.75 4.875 -6.875 5.109375 -6.875 C 5.765625 -6.875 6.3125 -6.796875 7.15625 -6.796875 C 10.453125 -6.796875 12.75 -8.046875 12.75 -11.046875 C 12.75 -14.203125 10.3125 -15.640625 7.125 -15.640625 C 6.59375 -15.640625 4.765625 -15.515625 4.0625 -15.515625 C 3.359375 -15.515625 1.78125 -15.5625 1.40625 -15.5625 C 1.109375 -15.5625 0.9375 -15.5625 0.9375 -15.21875 Z M 4.90625 -7.625 L 4.90625 -13.734375 C 4.90625 -14.4375 4.921875 -15 5.015625 -15 C 5.28125 -15.03125 5.53125 -15.03125 5.796875 -15.03125 C 8.578125 -15.03125 10.734375 -13.671875 10.734375 -11.390625 C 10.734375 -8.375 8.46875 -7.3125 5.796875 -7.3125 C 5.421875 -7.3125 4.90625 -7.34375 4.90625 -7.625 Z M 4.90625 -7.625 "/> | ||
22 | </symbol> | ||
23 | <symbol overflow="visible" id="glyph0-6"> | ||
24 | <path style="stroke:none;" d="M 0.703125 -0.359375 C 0.703125 0.046875 0.734375 0.078125 1.03125 0.078125 C 1.578125 0.078125 3.328125 0 4.03125 0 C 4.734375 0 6.3125 0.078125 6.84375 0.078125 C 7.078125 0.078125 7.109375 0.03125 7.109375 -0.328125 C 7.109375 -0.609375 7.109375 -0.640625 6.84375 -0.640625 L 5.1875 -0.640625 C 4.96875 -0.640625 4.953125 -4.921875 4.953125 -8.109375 L 4.953125 -11.28125 C 4.953125 -12.59375 4.96875 -14.984375 5.203125 -14.984375 L 6.6875 -14.984375 C 7.0625 -14.984375 7.109375 -14.984375 7.109375 -15.265625 C 7.109375 -15.65625 7.078125 -15.6875 6.78125 -15.6875 C 6.234375 -15.6875 4.78125 -15.609375 4.078125 -15.609375 C 3.375 -15.609375 1.640625 -15.6875 1.265625 -15.6875 C 0.96875 -15.6875 0.796875 -15.6875 0.796875 -15.328125 C 0.796875 -14.984375 0.984375 -14.984375 1.265625 -14.984375 L 2.71875 -14.984375 C 2.890625 -14.984375 2.953125 -13.21875 2.953125 -11.53125 L 2.953125 -9.234375 C 2.953125 -5.984375 2.9375 -0.640625 2.71875 -0.640625 L 1.125 -0.640625 C 0.75 -0.640625 0.703125 -0.640625 0.703125 -0.359375 Z M 0.703125 -0.359375 "/> | ||
25 | </symbol> | ||
26 | <symbol overflow="visible" id="glyph0-7"> | ||
27 | <path style="stroke:none;" d="M 1.0625 -7.859375 C 1.0625 -2.0625 4.96875 0.421875 9.28125 0.421875 C 12.46875 0.421875 15.734375 -1.296875 15.734375 -1.71875 C 15.734375 -2.484375 15.75 -3.21875 15.75 -3.796875 C 15.75 -4.625 15.75 -5.15625 16.0625 -5.15625 L 16.78125 -5.15625 C 16.953125 -5.15625 16.96875 -5.34375 16.96875 -5.53125 C 16.96875 -5.71875 16.953125 -5.859375 16.78125 -5.859375 C 15.6875 -5.84375 15.421875 -5.796875 14.671875 -5.796875 C 13.921875 -5.796875 12.734375 -5.84375 11.578125 -5.859375 C 11.421875 -5.859375 11.375 -5.65625 11.375 -5.4375 C 11.375 -5.28125 11.421875 -5.15625 11.5625 -5.15625 L 13.59375 -5.15625 C 13.78125 -5.15625 13.828125 -4.53125 13.828125 -3.796875 C 13.828125 -2.984375 13.8125 -2 13.765625 -1.59375 C 13.734375 -1.34375 12.59375 -0.28125 9.9375 -0.28125 C 6.140625 -0.28125 3.453125 -3.84375 3.453125 -7.8125 C 3.453125 -12.046875 6.078125 -15.234375 9.46875 -15.234375 C 12.65625 -15.234375 14.671875 -13.015625 14.671875 -12.6875 C 14.671875 -12.46875 14.578125 -10.90625 14.578125 -10.8125 C 14.578125 -10.59375 14.609375 -10.53125 15.03125 -10.53125 C 15.328125 -10.53125 15.40625 -10.625 15.40625 -10.90625 C 15.40625 -12.09375 15.46875 -14.8125 15.46875 -15.140625 C 15.46875 -15.421875 15.375 -15.453125 15.03125 -15.453125 C 14.671875 -15.453125 14.671875 -15.40625 14.671875 -15.140625 L 14.671875 -14.5625 C 14.671875 -14.15625 14.484375 -14.328125 14.28125 -14.484375 C 13.8125 -14.8125 12.171875 -15.875 9.5625 -15.875 C 4.828125 -15.875 1.0625 -13.03125 1.0625 -7.859375 Z M 1.0625 -7.859375 "/> | ||
28 | </symbol> | ||
29 | <symbol overflow="visible" id="glyph0-8"> | ||
30 | <path style="stroke:none;" d="M 0.59375 -8.28125 C 0.59375 -8.203125 0.59375 -8.1875 0.65625 -8.1875 C 0.75 -8.1875 2.09375 -8.234375 2.15625 -8.234375 C 2.234375 -8.234375 2.328125 -5.859375 2.328125 -3.796875 C 2.328125 -2.109375 2.296875 -0.59375 2.109375 -0.59375 L 1.109375 -0.59375 C 0.875 -0.59375 0.828125 -0.5 0.828125 -0.28125 C 0.828125 -0.03125 0.828125 0.046875 1.125 0.046875 C 1.828125 0.046875 2.5625 0 3.140625 0 C 3.828125 0 5.1875 0.046875 5.625 0.046875 C 5.9375 0.046875 5.9375 -0.078125 5.9375 -0.28125 C 5.9375 -0.5 5.90625 -0.59375 5.625 -0.59375 L 4.15625 -0.59375 C 3.875 -0.59375 3.875 -1.96875 3.875 -3.21875 C 3.875 -5.203125 4.03125 -8 5.203125 -8 C 5.671875 -8 6.078125 -7.265625 6.609375 -7.265625 C 6.984375 -7.265625 7.484375 -7.96875 7.484375 -8.234375 C 7.484375 -8.515625 6.84375 -9.234375 6.140625 -9.234375 C 5.4375 -9.234375 4.5 -8.515625 3.96875 -7.25 C 3.875 -7.03125 3.796875 -6.65625 3.75 -6.65625 C 3.734375 -6.65625 3.734375 -6.78125 3.734375 -7.078125 C 3.734375 -7.53125 3.75 -8.140625 3.75 -8.578125 C 3.75 -8.8125 3.84375 -8.8125 3.46875 -8.8125 C 3.3125 -8.8125 1.34375 -8.765625 1.015625 -8.75 C 0.6875 -8.71875 0.734375 -8.75 0.65625 -8.5625 C 0.609375 -8.4375 0.59375 -8.34375 0.59375 -8.28125 Z M 0.59375 -8.28125 "/> | ||
31 | </symbol> | ||
32 | <symbol overflow="visible" id="glyph0-9"> | ||
33 | <path style="stroke:none;" d="M 0.359375 -8.4375 C 0.359375 -8.375 0.375 -8.328125 0.453125 -8.328125 C 0.546875 -8.328125 1.53125 -8.34375 1.59375 -8.34375 C 1.875 -8.34375 1.875 -7.578125 1.875 -6.546875 L 1.875 -2.859375 C 1.875 -1.296875 2.203125 0.265625 4.4375 0.265625 C 6.1875 0.265625 8.140625 -0.84375 8.25 -0.84375 C 8.328125 -0.84375 8.328125 -0.3125 8.34375 0.046875 C 8.375 0.3125 8.46875 0.359375 8.609375 0.359375 C 8.765625 0.359375 10.25 0.125 11.046875 0 C 11.34375 -0.046875 11.375 -0.046875 11.375 -0.375 C 11.375 -0.515625 11.34375 -0.609375 11.25 -0.609375 C 11.203125 -0.609375 10.359375 -0.46875 10.296875 -0.46875 C 9.921875 -0.46875 9.84375 -0.703125 9.84375 -1.859375 C 9.84375 -3.3125 9.875 -8.90625 9.875 -8.90625 C 9.875 -9.03125 9.84375 -9.046875 9.703125 -9.046875 C 9.59375 -9.046875 7.5 -8.953125 7.0625 -8.9375 C 6.75 -8.90625 6.796875 -8.8125 6.75 -8.46875 C 6.75 -8.390625 6.78125 -8.375 6.84375 -8.375 C 6.9375 -8.375 8 -8.421875 8.0625 -8.421875 C 8.203125 -8.421875 8.25 -4.765625 8.25 -4.0625 L 8.25 -1.296875 C 8.25 -1.015625 6.875 -0.921875 6.125 -0.921875 C 4.734375 -0.921875 3.515625 -1.171875 3.515625 -2.484375 L 3.515625 -8.859375 C 3.515625 -8.984375 3.5 -9 3.359375 -9 C 3.234375 -9 1.296875 -8.9375 0.78125 -8.90625 C 0.5 -8.890625 0.5 -8.890625 0.421875 -8.703125 C 0.375 -8.578125 0.359375 -8.515625 0.359375 -8.4375 Z M 0.359375 -8.4375 "/> | ||
34 | </symbol> | ||
35 | <symbol overflow="visible" id="glyph0-10"> | ||
36 | <path style="stroke:none;" d="M 0.59375 -8.25 C 0.59375 -8.109375 0.65625 -8.140625 0.890625 -8.140625 C 1.015625 -8.140625 1.921875 -8.1875 2.0625 -8.1875 C 2.390625 -8.1875 2.421875 -8.1875 2.4375 -7.859375 C 2.515625 -6.890625 2.609375 -6.171875 2.609375 -1.125 L 2.609375 2.203125 C 2.609375 4.0625 2.609375 5.953125 2.53125 5.953125 L 1.25 5.953125 C 1.015625 5.953125 0.96875 6.046875 0.96875 6.265625 C 0.96875 6.515625 0.96875 6.59375 1.265625 6.59375 C 1.96875 6.59375 2.953125 6.546875 3.546875 6.546875 C 4.21875 6.546875 5.578125 6.59375 6.03125 6.59375 C 6.328125 6.59375 6.328125 6.46875 6.328125 6.265625 C 6.328125 6.046875 6.3125 5.953125 6.03125 5.953125 L 4.390625 5.953125 C 4.25 5.953125 4.265625 5.28125 4.25 4.390625 L 4.171875 -0.046875 C 4.171875 -0.3125 4.4375 -0.140625 4.734375 -0.046875 C 5.1875 0.09375 5.796875 0.21875 6.28125 0.21875 C 9.359375 0.21875 11.1875 -2.1875 11.1875 -4.546875 C 11.1875 -7.03125 9.875 -8.984375 7.171875 -8.984375 C 6.1875 -8.984375 5.1875 -8.515625 4.640625 -8.109375 C 4.4375 -7.953125 4.265625 -7.78125 4.203125 -7.78125 C 4.15625 -7.78125 4.15625 -7.859375 4.15625 -8.015625 L 4.15625 -8.578125 C 4.15625 -8.90625 4.078125 -8.90625 3.890625 -8.90625 C 3.796875 -8.90625 2.375 -8.8125 0.796875 -8.765625 C 0.734375 -8.765625 0.59375 -8.34375 0.59375 -8.25 Z M 4.171875 -1.21875 L 4.171875 -7.078125 C 4.171875 -7.171875 4.203125 -7.484375 4.953125 -7.859375 C 5.296875 -8.015625 5.796875 -8.15625 6.453125 -8.15625 C 8.1875 -8.15625 9.5 -6.6875 9.5 -4.390625 C 9.5 -2.515625 8.421875 -0.234375 6.21875 -0.234375 C 5.484375 -0.234375 4.171875 -0.65625 4.171875 -1.21875 Z M 4.171875 -1.21875 "/> | ||
37 | </symbol> | ||
38 | <symbol overflow="visible" id="glyph0-11"> | ||
39 | <path style="stroke:none;" d="M 1.0625 -7.859375 C 1.0625 -2.203125 4.96875 0.375 9.28125 0.375 C 12.265625 0.375 15.1875 -1.265625 15.234375 -1.6875 C 15.515625 -3.796875 15.609375 -4.578125 15.609375 -4.8125 C 15.609375 -4.96875 15.5625 -5.09375 15.328125 -5.109375 C 14.953125 -5.15625 14.859375 -5.109375 14.8125 -4.78125 L 14.515625 -2.140625 C 14.484375 -1.875 12.59375 -0.546875 9.9375 -0.546875 C 6.328125 -0.546875 3.453125 -3.84375 3.453125 -7.8125 C 3.453125 -12.046875 5.859375 -15.234375 9.265625 -15.234375 C 12.375 -15.234375 14.671875 -12.78125 14.671875 -12.453125 C 14.671875 -12.234375 14.578125 -10.4375 14.578125 -10.34375 C 14.578125 -10.125 14.609375 -10.0625 15.03125 -10.0625 C 15.328125 -10.0625 15.40625 -10.15625 15.40625 -10.4375 C 15.40625 -11.625 15.5 -14.53125 15.5 -14.953125 C 15.5 -15.234375 15.375 -15.265625 15.03125 -15.265625 C 14.671875 -15.265625 14.671875 -15.21875 14.671875 -14.953125 L 14.671875 -14.328125 C 14.671875 -13.921875 14.484375 -14.09375 14.28125 -14.25 C 13.8125 -14.578125 12.1875 -15.9375 9.421875 -15.9375 C 4.6875 -15.9375 1.0625 -12.75 1.0625 -7.859375 Z M 1.0625 -7.859375 "/> | ||
40 | </symbol> | ||
41 | <symbol overflow="visible" id="glyph0-12"> | ||
42 | <path style="stroke:none;" d="M 0.59375 -8.203125 C 0.59375 -8.15625 0.609375 -8.140625 0.703125 -8.140625 C 0.828125 -8.140625 2.015625 -8.203125 2.09375 -8.203125 C 2.140625 -8.203125 2.1875 -7.34375 2.1875 -6.375 L 2.1875 -3.828125 C 2.1875 -2.765625 2.1875 -1.8125 2.140625 -1.34375 C 2.09375 -0.890625 2.046875 -0.59375 1.828125 -0.59375 L 0.921875 -0.59375 C 0.6875 -0.59375 0.65625 -0.46875 0.65625 -0.265625 C 0.65625 0 0.75 0.046875 0.9375 0.046875 C 1.3125 0.046875 2.328125 0 2.90625 0 C 3.5 0 4.25 0.046875 4.6875 0.046875 C 5 0.046875 5.015625 -0.078125 5.015625 -0.28125 C 5.015625 -0.5 4.96875 -0.59375 4.6875 -0.59375 L 4.203125 -0.59375 C 3.75 -0.59375 3.75 -0.6875 3.75 -1.59375 L 3.75 -6.9375 C 3.75 -7.078125 3.78125 -7.171875 4.015625 -7.359375 C 4.390625 -7.640625 5.1875 -8.0625 6.359375 -8.0625 C 7.96875 -8.0625 8.046875 -6.65625 8.046875 -5.0625 C 8.046875 -4.90625 8.0625 -3.890625 8.0625 -2.859375 C 8.0625 -1.734375 8.046875 -0.59375 7.90625 -0.59375 L 6.984375 -0.59375 C 6.75 -0.59375 6.703125 -0.5 6.703125 -0.28125 C 6.703125 -0.03125 6.75 0.046875 7.0625 0.046875 C 7.765625 0.046875 8.1875 0 8.765625 0 C 9.453125 0 10.03125 0.046875 10.484375 0.046875 C 10.78125 0.046875 10.8125 -0.078125 10.8125 -0.28125 C 10.8125 -0.5 10.765625 -0.59375 10.484375 -0.59375 L 9.6875 -0.59375 C 9.609375 -0.59375 9.609375 -0.984375 9.609375 -1.546875 L 9.609375 -5.53125 C 9.609375 -6.9375 9.46875 -7.171875 9.46875 -7.359375 C 9.46875 -7.4375 10.546875 -8.0625 11.75 -8.0625 C 13.453125 -8.0625 13.828125 -6.640625 13.828125 -5.0625 C 13.828125 -3.96875 13.828125 -0.59375 13.625 -0.59375 L 12.6875 -0.59375 C 12.453125 -0.59375 12.328125 -0.5 12.328125 -0.28125 C 12.328125 -0.03125 12.328125 0.046875 12.640625 0.046875 C 13.34375 0.046875 14.046875 0 14.625 0 C 15.3125 0 15.96875 0.046875 16.40625 0.046875 C 16.71875 0.046875 16.734375 -0.078125 16.734375 -0.28125 C 16.734375 -0.5 16.6875 -0.59375 16.40625 -0.59375 L 15.65625 -0.59375 C 15.46875 -0.59375 15.421875 -0.65625 15.421875 -0.828125 C 15.421875 -1.953125 15.46875 -3.65625 15.46875 -5.625 C 15.46875 -7.640625 14.84375 -9.046875 12.5625 -9.046875 C 11.671875 -9.046875 10.359375 -8.53125 9.640625 -8.0625 C 9.46875 -7.953125 9.375 -7.90625 9.328125 -7.90625 C 9.265625 -7.90625 9.046875 -9.09375 7.265625 -9.09375 C 5.9375 -9.09375 4.671875 -8.296875 3.96875 -7.8125 C 3.75 -7.640625 3.734375 -7.546875 3.734375 -8.015625 L 3.734375 -8.671875 C 3.734375 -8.90625 3.734375 -8.9375 3.375 -8.9375 C 3.265625 -8.9375 2 -8.859375 1.03125 -8.8125 C 0.703125 -8.796875 0.75 -8.8125 0.6875 -8.625 C 0.640625 -8.484375 0.59375 -8.25 0.59375 -8.203125 Z M 0.59375 -8.203125 "/> | ||
43 | </symbol> | ||
44 | <symbol overflow="visible" id="glyph0-13"> | ||
45 | <path style="stroke:none;" d="M 0.59375 -8.375 C 0.59375 -8.296875 0.609375 -8.28125 0.6875 -8.28125 C 0.78125 -8.28125 1.78125 -8.328125 1.859375 -8.328125 C 2.09375 -8.328125 2.140625 -8.296875 2.15625 -7.953125 C 2.234375 -6.234375 2.25 -4.578125 2.25 -2.9375 C 2.25 -2.234375 2.25 -1.546875 2.234375 -0.875 C 2.234375 -0.640625 2.234375 -0.59375 1.96875 -0.59375 L 1.015625 -0.59375 C 0.703125 -0.59375 0.6875 -0.5 0.6875 -0.28125 C 0.6875 -0.03125 0.6875 0.046875 0.9375 0.046875 C 1.390625 0.046875 2.4375 0 3.03125 0 C 3.609375 0 4.546875 0.046875 5 0.046875 C 5.25 0.046875 5.25 -0.078125 5.25 -0.28125 C 5.25 -0.5 5.234375 -0.59375 5 -0.59375 L 4.15625 -0.59375 C 3.921875 -0.59375 3.921875 -0.65625 3.921875 -0.875 C 3.84375 -2.203125 3.84375 -3.515625 3.84375 -4.859375 L 3.84375 -8.84375 C 3.84375 -8.953125 3.828125 -8.984375 3.6875 -8.984375 C 3.5625 -8.984375 1.484375 -8.890625 1.03125 -8.859375 C 0.75 -8.84375 0.78125 -8.859375 0.6875 -8.671875 C 0.59375 -8.484375 0.59375 -8.4375 0.59375 -8.375 Z M 1.8125 -12.96875 C 1.8125 -12.3125 2.28125 -12 2.765625 -12 C 3.421875 -12 4.203125 -12.515625 4.203125 -13.3125 C 4.203125 -14 3.703125 -14.25 3.21875 -14.25 C 2.65625 -14.25 1.8125 -13.8125 1.8125 -12.96875 Z M 1.8125 -12.96875 "/> | ||
46 | </symbol> | ||
47 | <symbol overflow="visible" id="glyph0-14"> | ||
48 | <path style="stroke:none;" d="M 0.828125 -8.0625 C 0.828125 -7.96875 0.875 -7.90625 0.96875 -7.90625 L 1.546875 -7.90625 C 1.8125 -7.90625 1.828125 -7.34375 1.828125 -6.46875 C 1.828125 -5.796875 1.8125 -3.09375 1.78125 -1.40625 C 1.78125 -0.703125 2.140625 0.21875 3.46875 0.21875 C 4.4375 0.21875 6.421875 -0.78125 6.421875 -0.890625 C 6.421875 -1.0625 6.40625 -1.265625 6.328125 -1.265625 C 6.140625 -1.265625 5.375 -0.890625 4.453125 -0.890625 C 3.375 -0.890625 3.328125 -1.625 3.328125 -2.34375 L 3.328125 -6.84375 C 3.328125 -7.5 3.328125 -7.921875 3.40625 -7.921875 L 5.71875 -7.921875 C 5.890625 -7.921875 5.953125 -8 6.03125 -8.296875 C 6.125 -8.71875 6.09375 -8.71875 5.8125 -8.71875 L 3.59375 -8.71875 C 3.375 -8.71875 3.328125 -8.75 3.328125 -8.953125 C 3.328125 -9.328125 3.46875 -11.046875 3.46875 -11.109375 C 3.46875 -11.28125 3.359375 -11.34375 3.234375 -11.34375 C 3.140625 -11.34375 3.078125 -11.296875 3.03125 -11.234375 L 0.890625 -8.25 C 0.84375 -8.203125 0.828125 -8.140625 0.828125 -8.0625 Z M 0.828125 -8.0625 "/> | ||
49 | </symbol> | ||
50 | <symbol overflow="visible" id="glyph0-15"> | ||
51 | <path style="stroke:none;" d="M 0.828125 -0.234375 C 0.828125 0.046875 0.828125 0.09375 1.078125 0.09375 C 1.34375 0.09375 3.40625 0 4.0625 0 C 5.578125 0 7.109375 0.09375 8.625 0.09375 C 12.828125 0.046875 16.71875 -2.71875 16.71875 -7.859375 C 16.71875 -12.875 12.84375 -15.890625 7.78125 -15.890625 C 6.84375 -15.890625 4.734375 -15.609375 3 -15.609375 C 2.203125 -15.609375 1.484375 -15.640625 1.390625 -15.640625 C 1.078125 -15.640625 1.078125 -15.546875 1.078125 -15.265625 C 1.078125 -14.984375 1.171875 -14.984375 1.390625 -14.984375 L 3.03125 -15.03125 C 3.046875 -15.03125 3.078125 -14.296875 3.078125 -13.203125 C 3.078125 -9.3125 2.90625 -0.59375 2.765625 -0.59375 L 1.21875 -0.59375 C 0.921875 -0.59375 0.828125 -0.59375 0.828125 -0.234375 Z M 5 -2.015625 C 5 -5.28125 5 -8.484375 5.015625 -11.71875 C 5.015625 -12.78125 5.09375 -15.125 5.1875 -15.140625 C 5.71875 -15.28125 6.6875 -15.28125 7.296875 -15.28125 C 11.625 -15.28125 14.34375 -11.484375 14.34375 -8.15625 C 14.34375 -6.125 14.25 -0.515625 6.375 -0.515625 C 5.90625 -0.515625 5.1875 -0.515625 5.046875 -0.609375 C 5 -0.640625 5 -1.265625 5 -2.015625 Z M 5 -2.015625 "/> | ||
52 | </symbol> | ||
53 | <symbol overflow="visible" id="glyph0-16"> | ||
54 | <path style="stroke:none;" d="M 0.828125 -1.171875 C 0.828125 -0.453125 2.34375 0.28125 3.78125 0.28125 C 5.515625 0.28125 7.078125 -0.78125 7.078125 -2.484375 C 7.078125 -3.875 5.53125 -4.546875 4.171875 -5.203125 C 3.1875 -5.671875 2.25 -6.078125 2.25 -7.078125 C 2.25 -8.296875 3.1875 -8.71875 3.96875 -8.71875 C 5.484375 -8.71875 5.234375 -7.203125 5.765625 -7.203125 C 6.03125 -7.203125 6.703125 -7.390625 6.703125 -7.640625 C 6.703125 -8.1875 6.046875 -9.21875 4.265625 -9.21875 C 2.609375 -9.21875 0.890625 -8.140625 0.890625 -6.5625 C 0.890625 -4.90625 2.328125 -4.4375 3.609375 -3.875 C 4.71875 -3.40625 5.703125 -2.890625 5.703125 -1.78125 C 5.703125 -0.734375 4.953125 -0.265625 4.15625 -0.265625 C 3.03125 -0.265625 2.4375 -0.875 1.96875 -1.4375 C 1.6875 -1.765625 1.671875 -2.0625 1.53125 -2.0625 C 1.34375 -2.0625 0.828125 -1.546875 0.828125 -1.171875 Z M 0.828125 -1.171875 "/> | ||
55 | </symbol> | ||
56 | <symbol overflow="visible" id="glyph0-17"> | ||
57 | <path style="stroke:none;" d="M 0.234375 -15.21875 C 0.234375 -15.046875 0.265625 -15.03125 0.46875 -15.03125 C 0.703125 -15.03125 1.640625 -15.09375 1.78125 -15.09375 C 2 -15.09375 2 -10.203125 2 -5.53125 L 2 -1.015625 C 2 -0.65625 2 -0.59375 1.765625 -0.59375 L 0.796875 -0.59375 C 0.5625 -0.59375 0.515625 -0.5 0.515625 -0.28125 C 0.515625 -0.03125 0.515625 0.046875 0.828125 0.046875 C 1.078125 0.046875 1.921875 0 2.703125 0 C 3.375 0 3.84375 0.046875 4.296875 0.046875 C 4.59375 0.046875 4.59375 -0.078125 4.59375 -0.28125 C 4.59375 -0.5 4.578125 -0.59375 4.296875 -0.59375 L 3.75 -0.59375 C 3.515625 -0.59375 3.5 -0.59375 3.5 -1.015625 L 3.5 -4.15625 C 3.5 -4.4375 3.5 -4.53125 3.75 -4.53125 L 4.078125 -4.53125 C 4.3125 -4.53125 4.3125 -4.484375 4.59375 -4.125 L 7.171875 -0.9375 C 7.296875 -0.796875 7.40625 -0.59375 7.0625 -0.59375 L 6.796875 -0.59375 C 6.5625 -0.59375 6.515625 -0.5 6.515625 -0.28125 C 6.515625 -0.03125 6.515625 0.046875 6.828125 0.046875 C 7.15625 0.046875 7.828125 0 8.421875 0 C 9 0 9.65625 0.046875 9.984375 0.046875 C 10.296875 0.046875 10.296875 -0.078125 10.296875 -0.28125 C 10.296875 -0.5 10.265625 -0.59375 9.984375 -0.59375 L 9.75 -0.59375 C 9.546875 -0.59375 9.46875 -0.609375 9.234375 -0.890625 L 5.703125 -5 C 5.421875 -5.328125 5.421875 -5.203125 5.703125 -5.5625 C 6.125 -6.09375 8.015625 -8.4375 8.203125 -8.4375 L 8.953125 -8.4375 C 9.1875 -8.4375 9.234375 -8.53125 9.234375 -8.75 C 9.234375 -9 9.171875 -9.078125 8.9375 -9.078125 C 8.578125 -9.078125 8.046875 -9.03125 7.59375 -9.03125 C 7.109375 -9.03125 6.46875 -9.078125 6.234375 -9.078125 C 5.9375 -9.078125 5.90625 -8.953125 5.90625 -8.75 C 5.90625 -8.53125 5.9375 -8.4375 6.21875 -8.4375 L 6.6875 -8.4375 C 7.15625 -8.4375 7.078125 -8.34375 6.921875 -8.0625 C 6.375 -7.171875 5.71875 -6.28125 5.0625 -5.421875 C 4.90625 -5.203125 4.734375 -4.90625 4.390625 -4.90625 L 3.875 -4.90625 C 3.515625 -4.90625 3.5 -4.921875 3.5 -5.15625 L 3.75 -15.65625 C 3.75 -15.9375 3.75 -15.96875 3.59375 -15.96875 C 3.453125 -15.96875 1.40625 -15.828125 0.515625 -15.75 C 0.265625 -15.734375 0.234375 -15.609375 0.234375 -15.421875 Z M 0.234375 -15.21875 "/> | ||
58 | </symbol> | ||
59 | <symbol overflow="visible" id="glyph0-18"> | ||
60 | <path style="stroke:none;" d="M 0.46875 -15.125 C 0.46875 -15.046875 0.5 -15.046875 0.65625 -15.046875 C 0.75 -15.046875 1.671875 -15.140625 1.78125 -15.140625 C 2.015625 -15.140625 2 -15.09375 2.046875 -14.703125 C 2.234375 -12.609375 2.296875 -3.734375 2.296875 -2.578125 C 2.296875 -2 2.296875 -0.59375 2.203125 -0.59375 L 0.984375 -0.59375 C 0.75 -0.59375 0.703125 -0.5 0.703125 -0.28125 C 0.703125 -0.03125 0.703125 0.046875 1.015625 0.046875 C 1.71875 0.046875 2.609375 0 3.1875 0 C 3.875 0 4.59375 0.046875 5.046875 0.046875 C 5.34375 0.046875 5.34375 -0.078125 5.34375 -0.28125 C 5.34375 -0.5 5.328125 -0.59375 5.046875 -0.59375 L 4.125 -0.59375 C 3.9375 -0.59375 3.9375 -0.96875 3.9375 -1.5 C 3.9375 -6.21875 3.828125 -8.34375 3.796875 -15.546875 C 3.796875 -15.828125 3.796875 -15.890625 3.640625 -15.890625 C 3.5 -15.890625 1.6875 -15.75 0.75 -15.6875 C 0.546875 -15.65625 0.5625 -15.6875 0.515625 -15.5 C 0.5 -15.328125 0.46875 -15.1875 0.46875 -15.125 Z M 0.46875 -15.125 "/> | ||
61 | </symbol> | ||
62 | <symbol overflow="visible" id="glyph0-19"> | ||
63 | <path style="stroke:none;" d="M 0.703125 -4.265625 C 0.703125 -1.53125 2.296875 0.359375 5.1875 0.359375 C 7.546875 0.359375 9.234375 -1.71875 9.234375 -1.859375 C 9.234375 -1.921875 8.9375 -2.203125 8.859375 -2.203125 C 8.796875 -2.203125 7.71875 -0.6875 5.84375 -0.6875 C 4.078125 -0.6875 2.34375 -2.046875 2.34375 -4.546875 C 2.34375 -4.875 2.34375 -5.390625 2.46875 -5.390625 C 2.65625 -5.390625 7.453125 -5.28125 7.71875 -5.28125 C 8 -5.28125 8.984375 -5.375 8.984375 -5.5625 C 8.984375 -7.53125 7.8125 -9.28125 5.484375 -9.28125 C 2.65625 -9.28125 0.703125 -7.078125 0.703125 -4.265625 Z M 2.46875 -5.984375 C 2.5625 -7.15625 3.65625 -8.765625 5.203125 -8.765625 C 5.953125 -8.765625 7.359375 -8.28125 7.359375 -5.984375 C 7.359375 -5.9375 7.296875 -5.90625 6.421875 -5.890625 C 5.25 -5.84375 2.859375 -5.796875 2.75 -5.796875 C 2.5625 -5.796875 2.46875 -5.84375 2.46875 -5.984375 Z M 2.46875 -5.984375 "/> | ||
64 | </symbol> | ||
65 | <symbol overflow="visible" id="glyph1-0"> | ||
66 | <path style="stroke:none;" d="M 1.0625 -12.3125 L 1.0625 4.109375 L 5.984375 4.109375 L 5.984375 -12.3125 Z M 5.34375 3.5 L 1.703125 3.5 L 1.703125 -11.703125 L 5.34375 -11.703125 Z M 3.59375 -2.03125 L 3.59375 -2.5625 C 4.390625 -2.671875 4.71875 -3.125 4.71875 -3.9375 C 4.71875 -4.640625 4.421875 -5.28125 3.40625 -5.28125 C 2.953125 -5.28125 2.328125 -5.140625 2.328125 -4.828125 C 2.328125 -4.671875 2.421875 -4.5625 2.609375 -4.5625 C 2.65625 -4.5625 2.703125 -4.578125 2.75 -4.59375 C 2.953125 -4.6875 3.125 -4.71875 3.359375 -4.71875 C 3.953125 -4.71875 4.078125 -4.375 4.078125 -3.921875 C 4.078125 -3.296875 3.859375 -3.0625 3.015625 -3.015625 L 3.015625 -2.03125 C 3.015625 -1.859375 3.15625 -1.75 3.3125 -1.75 C 3.453125 -1.75 3.59375 -1.859375 3.59375 -2.03125 Z M 2.890625 -1 C 2.890625 -0.75 3.078125 -0.5625 3.3125 -0.5625 C 3.546875 -0.5625 3.71875 -0.75 3.71875 -1 C 3.71875 -1.234375 3.546875 -1.40625 3.3125 -1.40625 C 3.078125 -1.40625 2.890625 -1.234375 2.890625 -1 Z M 2.890625 -1 "/> | ||
67 | </symbol> | ||
68 | <symbol overflow="visible" id="glyph1-1"> | ||
69 | <path style="stroke:none;" d="M 5.609375 -1.34375 L 5.609375 -4.3125 C 5.609375 -5.53125 4.828125 -6.3125 3.296875 -6.3125 C 2.6875 -6.3125 2.03125 -6.1875 1.265625 -5.921875 L 1.53125 -5.171875 C 2.171875 -5.390625 2.734375 -5.484375 3.140625 -5.484375 C 4.0625 -5.484375 4.609375 -5.15625 4.609375 -4.25 L 4.609375 -3.75 L 3.6875 -3.75 C 1.828125 -3.75 0.8125 -3.03125 0.8125 -1.765625 C 0.8125 -0.625 1.5625 0.125 2.796875 0.125 C 3.59375 0.125 4.296875 -0.171875 4.734375 -0.734375 C 4.90625 -0.171875 5.328125 0.078125 5.859375 0.140625 L 6.109375 -0.5625 C 5.75 -0.671875 5.609375 -0.859375 5.609375 -1.34375 Z M 3.046875 -0.609375 C 2.234375 -0.609375 1.859375 -1.015625 1.859375 -1.78125 C 1.859375 -2.578125 2.359375 -3.078125 3.71875 -3.078125 L 4.609375 -3.078125 L 4.609375 -1.484375 C 4.25 -0.9375 3.65625 -0.609375 3.046875 -0.609375 Z M 3.046875 -0.609375 "/> | ||
70 | </symbol> | ||
71 | <symbol overflow="visible" id="glyph1-2"> | ||
72 | <path style="stroke:none;" d="M 3.96875 -0.71875 C 2.90625 -0.71875 2.140625 -1.40625 2.140625 -3.0625 C 2.140625 -4.6875 2.890625 -5.46875 3.96875 -5.46875 C 4.515625 -5.46875 5.03125 -5.28125 5.5625 -4.9375 L 6.03125 -5.578125 C 5.46875 -6.0625 4.765625 -6.3125 3.96875 -6.3125 C 2.140625 -6.3125 1.0625 -4.90625 1.0625 -3.0625 C 1.0625 -1.125 2.125 0.125 3.96875 0.125 C 4.6875 0.125 5.515625 -0.15625 6.046875 -0.609375 L 5.578125 -1.25 C 5.109375 -0.9375 4.59375 -0.71875 3.96875 -0.71875 Z M 3.96875 -0.71875 "/> | ||
73 | </symbol> | ||
74 | <symbol overflow="visible" id="glyph1-3"> | ||
75 | <path style="stroke:none;" d="M 6.078125 -0.3125 L 5.703125 -0.984375 C 5.375 -0.8125 4.96875 -0.6875 4.515625 -0.6875 C 3.671875 -0.6875 3.328125 -1.0625 3.328125 -1.734375 L 3.328125 -5.40625 L 5.34375 -5.40625 L 5.46875 -6.171875 L 3.328125 -6.171875 L 3.328125 -7.6875 L 2.34375 -7.578125 L 2.34375 -6.171875 L 0.921875 -6.171875 L 0.921875 -5.40625 L 2.34375 -5.40625 L 2.34375 -1.71875 C 2.34375 -0.640625 3.09375 0.125 4.421875 0.125 C 5 0.125 5.65625 -0.03125 6.078125 -0.3125 Z M 6.078125 -0.3125 "/> | ||
76 | </symbol> | ||
77 | <symbol overflow="visible" id="glyph1-4"> | ||
78 | <path style="stroke:none;" d="M 3.515625 -9.0625 C 3.09375 -9.0625 2.8125 -8.765625 2.8125 -8.375 C 2.8125 -7.96875 3.09375 -7.671875 3.515625 -7.671875 C 3.953125 -7.671875 4.25 -7.96875 4.25 -8.375 C 4.25 -8.765625 3.953125 -9.0625 3.515625 -9.0625 Z M 4.296875 -6.171875 L 1.484375 -6.171875 L 1.484375 -5.390625 L 3.3125 -5.390625 L 3.3125 -0.78125 L 1.421875 -0.78125 L 1.421875 0 L 6.03125 0 L 6.03125 -0.78125 L 4.296875 -0.78125 Z M 4.296875 -6.171875 "/> | ||
79 | </symbol> | ||
80 | <symbol overflow="visible" id="glyph1-5"> | ||
81 | <path style="stroke:none;" d="M 6.328125 -6.171875 L 5.296875 -6.171875 L 3.546875 -0.890625 L 1.765625 -6.171875 L 0.703125 -6.171875 L 2.9375 0 L 4.078125 0 Z M 6.328125 -6.171875 "/> | ||
82 | </symbol> | ||
83 | <symbol overflow="visible" id="glyph1-6"> | ||
84 | <path style="stroke:none;" d="M 1.953125 -2.75 L 6.109375 -2.75 C 6.125 -2.875 6.125 -3.0625 6.125 -3.265625 C 6.125 -5.140625 5.171875 -6.3125 3.609375 -6.3125 C 1.96875 -6.3125 0.921875 -4.953125 0.921875 -3.078125 C 0.921875 -1.15625 1.953125 0.125 3.75 0.125 C 4.515625 0.125 5.28125 -0.140625 5.859375 -0.59375 L 5.40625 -1.25 C 4.859375 -0.875 4.390625 -0.6875 3.75 -0.6875 C 2.796875 -0.6875 2 -1.3125 1.953125 -2.75 Z M 3.625 -5.5 C 4.5625 -5.5 5.140625 -4.8125 5.171875 -3.5 L 1.953125 -3.5 C 2.046875 -4.859375 2.703125 -5.5 3.625 -5.5 Z M 3.625 -5.5 "/> | ||
85 | </symbol> | ||
86 | <symbol overflow="visible" id="glyph1-7"> | ||
87 | <path style="stroke:none;" d="M 4.015625 -7.203125 L 6.453125 -7.203125 L 6.546875 -8.078125 L 0.46875 -8.078125 L 0.46875 -7.203125 L 2.984375 -7.203125 L 2.984375 0 L 4.015625 0 Z M 4.015625 -7.203125 "/> | ||
88 | </symbol> | ||
89 | <symbol overflow="visible" id="glyph1-8"> | ||
90 | <path style="stroke:none;" d="M 1.78125 0 L 3.484375 -2.65625 L 5.1875 0 L 6.375 0 L 4.109375 -3.3125 L 6.109375 -6.171875 L 4.96875 -6.171875 L 3.53125 -3.875 L 2.09375 -6.171875 L 0.921875 -6.171875 L 2.9375 -3.265625 L 0.65625 0 Z M 1.78125 0 "/> | ||
91 | </symbol> | ||
92 | <symbol overflow="visible" id="glyph1-9"> | ||
93 | <path style="stroke:none;" d="M 1.171875 0 L 2.15625 0 L 2.15625 -4.484375 C 2.484375 -4.984375 3.109375 -5.515625 3.828125 -5.515625 C 4.765625 -5.515625 4.890625 -5.015625 4.890625 -3.75 L 4.890625 0 L 5.875 0 L 5.875 -4.484375 C 5.875 -5.625 5.34375 -6.3125 4.140625 -6.3125 C 3.40625 -6.3125 2.59375 -5.9375 2.09375 -5.3125 L 2.015625 -6.171875 L 1.171875 -6.171875 Z M 1.171875 0 "/> | ||
94 | </symbol> | ||
95 | <symbol overflow="visible" id="glyph1-10"> | ||
96 | <path style="stroke:none;" d="M 2.5625 -5.046875 C 2.5625 -4.53125 2.96875 -4.09375 3.5 -4.09375 C 4.0625 -4.09375 4.453125 -4.53125 4.453125 -5.046875 C 4.453125 -5.5625 4.0625 -5.984375 3.5 -5.984375 C 2.96875 -5.984375 2.5625 -5.5625 2.5625 -5.046875 Z M 2.5625 -0.828125 C 2.5625 -0.28125 2.96875 0.125 3.5 0.125 C 4.0625 0.125 4.453125 -0.28125 4.453125 -0.828125 C 4.453125 -1.34375 4.0625 -1.765625 3.5 -1.765625 C 2.96875 -1.765625 2.5625 -1.34375 2.5625 -0.828125 Z M 2.5625 -0.828125 "/> | ||
97 | </symbol> | ||
98 | <symbol overflow="visible" id="glyph1-11"> | ||
99 | <path style="stroke:none;" d=""/> | ||
100 | </symbol> | ||
101 | <symbol overflow="visible" id="glyph1-12"> | ||
102 | <path style="stroke:none;" d="M 3.53125 -6.3125 C 1.796875 -6.3125 0.859375 -4.984375 0.859375 -3.078125 C 0.859375 -1.140625 1.78125 0.125 3.515625 0.125 C 5.234375 0.125 6.171875 -1.203125 6.171875 -3.09375 C 6.171875 -5.046875 5.265625 -6.3125 3.53125 -6.3125 Z M 3.53125 -5.5 C 4.578125 -5.5 5.109375 -4.71875 5.109375 -3.09375 C 5.109375 -1.4375 4.578125 -0.6875 3.515625 -0.6875 C 2.453125 -0.6875 1.921875 -1.4375 1.921875 -3.078125 C 1.921875 -4.71875 2.46875 -5.5 3.53125 -5.5 Z M 3.53125 -5.5 "/> | ||
103 | </symbol> | ||
104 | <symbol overflow="visible" id="glyph1-13"> | ||
105 | <path style="stroke:none;" d="M 5.234375 -6.3125 C 4.625 -6.3125 4.21875 -5.984375 3.875 -5.484375 C 3.6875 -6.125 3.234375 -6.3125 2.765625 -6.3125 C 2.140625 -6.3125 1.765625 -5.9375 1.4375 -5.453125 L 1.359375 -6.171875 L 0.59375 -6.171875 L 0.59375 0 L 1.5 0 L 1.5 -4.796875 C 1.84375 -5.328125 2.1875 -5.53125 2.578125 -5.53125 C 3.03125 -5.53125 3.0625 -5.21875 3.0625 -4.4375 L 3.0625 0 L 3.96875 0 L 3.96875 -4.796875 C 4.3125 -5.328125 4.671875 -5.53125 5.046875 -5.53125 C 5.5 -5.53125 5.53125 -5.21875 5.53125 -4.4375 L 5.53125 0 L 6.4375 0 L 6.4375 -4.59375 C 6.4375 -6.015625 5.84375 -6.3125 5.234375 -6.3125 Z M 5.234375 -6.3125 "/> | ||
106 | </symbol> | ||
107 | <symbol overflow="visible" id="glyph1-14"> | ||
108 | <path style="stroke:none;" d="M 4.875 -8.78125 L 4.875 -5.5625 C 4.453125 -6.046875 3.921875 -6.3125 3.21875 -6.3125 C 1.703125 -6.3125 0.796875 -4.9375 0.796875 -3.078125 C 0.796875 -1.15625 1.53125 0.125 3.15625 0.125 C 3.828125 0.125 4.4375 -0.171875 4.90625 -0.8125 L 5 0 L 5.859375 0 L 5.859375 -8.65625 Z M 3.46875 -5.515625 C 4.046875 -5.515625 4.53125 -5.21875 4.875 -4.71875 L 4.875 -1.640625 C 4.53125 -1.125 4.0625 -0.65625 3.359375 -0.65625 C 2.375 -0.65625 1.859375 -1.484375 1.859375 -3.078125 C 1.859375 -4.71875 2.453125 -5.515625 3.46875 -5.515625 Z M 3.46875 -5.515625 "/> | ||
109 | </symbol> | ||
110 | <symbol overflow="visible" id="glyph1-15"> | ||
111 | <path style="stroke:none;" d="M 3.28125 -0.6875 C 2.5625 -0.6875 1.90625 -0.953125 1.421875 -1.34375 L 0.875 -0.703125 C 1.390625 -0.25 2.15625 0.125 3.28125 0.125 C 4.59375 0.125 5.875 -0.390625 5.875 -1.71875 C 5.875 -2.859375 5.078125 -3.28125 3.875 -3.609375 C 2.625 -3.953125 2.234375 -4.140625 2.234375 -4.703125 C 2.234375 -5.171875 2.59375 -5.515625 3.578125 -5.515625 C 4.375 -5.515625 4.90625 -5.265625 5.359375 -4.953125 L 5.796875 -5.625 C 5.28125 -6 4.546875 -6.3125 3.546875 -6.3125 C 2.15625 -6.3125 1.203125 -5.65625 1.203125 -4.625 C 1.203125 -3.546875 2.046875 -3.15625 3.3125 -2.84375 C 4.625 -2.515625 4.8125 -2.21875 4.8125 -1.671875 C 4.8125 -1.0625 4.234375 -0.6875 3.28125 -0.6875 Z M 3.28125 -0.6875 "/> | ||
112 | </symbol> | ||
113 | <symbol overflow="visible" id="glyph1-16"> | ||
114 | <path style="stroke:none;" d="M 2.234375 -8.78125 L 1.25 -8.65625 L 1.25 0 L 2.234375 0 Z M 6.34375 -6.171875 L 5.078125 -6.171875 L 2.328125 -3.375 L 5.375 0 L 6.671875 0 L 3.578125 -3.390625 Z M 6.34375 -6.171875 "/> | ||
115 | </symbol> | ||
116 | <symbol overflow="visible" id="glyph1-17"> | ||
117 | <path style="stroke:none;" d="M 3.59375 -8.65625 L 0.703125 -8.65625 L 0.703125 -7.875 L 2.609375 -7.875 L 2.609375 -1.578125 C 2.609375 -0.5 3.34375 0.125 4.4375 0.125 C 5.0625 0.125 5.5625 -0.015625 5.890625 -0.1875 L 5.640625 -0.90625 C 5.296875 -0.78125 4.96875 -0.6875 4.609375 -0.6875 C 4.015625 -0.6875 3.59375 -0.921875 3.59375 -1.53125 Z M 3.59375 -8.65625 "/> | ||
118 | </symbol> | ||
119 | <symbol overflow="visible" id="glyph1-18"> | ||
120 | <path style="stroke:none;" d="M 6.203125 -6.828125 C 5.46875 -6.515625 4.9375 -6.3125 3.390625 -6.3125 C 1.921875 -6.3125 0.921875 -5.421875 0.921875 -4.15625 C 0.921875 -3.359375 1.25 -2.828125 1.953125 -2.46875 C 1.515625 -2.171875 1.28125 -1.765625 1.28125 -1.390625 C 1.28125 -0.765625 1.765625 -0.21875 2.84375 -0.21875 L 3.9375 -0.21875 C 4.71875 -0.21875 5.328125 0.078125 5.328125 0.671875 C 5.328125 1.34375 4.71875 1.6875 3.375 1.6875 C 2 1.6875 1.671875 1.34375 1.671875 0.625 L 0.78125 0.625 C 0.78125 1.875 1.40625 2.484375 3.375 2.484375 C 5.25 2.484375 6.3125 1.8125 6.3125 0.609375 C 6.3125 -0.359375 5.375 -1.0625 4.140625 -1.0625 L 3.03125 -1.0625 C 2.390625 -1.0625 2.203125 -1.296875 2.203125 -1.59375 C 2.203125 -1.8125 2.34375 -2.046875 2.515625 -2.1875 C 2.796875 -2.09375 3.03125 -2.0625 3.453125 -2.0625 C 4.90625 -2.0625 5.765625 -2.9375 5.765625 -4.15625 C 5.765625 -4.859375 5.421875 -5.390625 4.6875 -5.71875 C 5.375 -5.71875 5.984375 -5.734375 6.5 -5.890625 Z M 3.375 -5.578125 C 4.296875 -5.578125 4.75 -5.09375 4.75 -4.171875 C 4.75 -3.265625 4.28125 -2.71875 3.40625 -2.71875 C 2.390625 -2.71875 1.9375 -3.3125 1.9375 -4.15625 C 1.9375 -5 2.375 -5.578125 3.375 -5.578125 Z M 3.375 -5.578125 "/> | ||
121 | </symbol> | ||
122 | <symbol overflow="visible" id="glyph2-0"> | ||
123 | <path style="stroke:none;" d="M 1.828125 -21.328125 L 1.828125 7.109375 L 10.359375 7.109375 L 10.359375 -21.328125 Z M 9.265625 6.046875 L 2.953125 6.046875 L 2.953125 -20.265625 L 9.265625 -20.265625 Z M 6.234375 -3.515625 L 6.234375 -4.421875 C 7.59375 -4.625 8.171875 -5.40625 8.171875 -6.828125 C 8.171875 -8.046875 7.65625 -9.15625 5.90625 -9.15625 C 5.125 -9.15625 4.015625 -8.921875 4.015625 -8.375 C 4.015625 -8.109375 4.203125 -7.90625 4.515625 -7.90625 C 4.59375 -7.90625 4.671875 -7.921875 4.78125 -7.96875 C 5.125 -8.125 5.40625 -8.1875 5.828125 -8.1875 C 6.84375 -8.1875 7.0625 -7.578125 7.0625 -6.78125 C 7.0625 -5.703125 6.6875 -5.296875 5.21875 -5.21875 L 5.21875 -3.515625 C 5.21875 -3.203125 5.46875 -3.03125 5.734375 -3.03125 C 5.96875 -3.03125 6.234375 -3.203125 6.234375 -3.515625 Z M 5.015625 -1.734375 C 5.015625 -1.296875 5.328125 -0.96875 5.734375 -0.96875 C 6.140625 -0.96875 6.4375 -1.296875 6.4375 -1.734375 C 6.4375 -2.140625 6.140625 -2.4375 5.734375 -2.4375 C 5.328125 -2.4375 5.015625 -2.140625 5.015625 -1.734375 Z M 5.015625 -1.734375 "/> | ||
124 | </symbol> | ||
125 | <symbol overflow="visible" id="glyph2-1"> | ||
126 | <path style="stroke:none;" d="M 6.09375 -3.359375 C 5.1875 -3.359375 4.46875 -2.625 4.46875 -1.703125 C 4.46875 -1.171875 4.734375 -0.65625 5.125 -0.359375 L 4.171875 3.640625 L 5.703125 3.640625 L 7.359375 -0.125 C 7.640625 -0.75 7.734375 -1.21875 7.734375 -1.734375 C 7.734375 -2.625 7.03125 -3.359375 6.09375 -3.359375 Z M 6.09375 -3.359375 "/> | ||
127 | </symbol> | ||
128 | <symbol overflow="visible" id="glyph2-2"> | ||
129 | <path style="stroke:none;" d=""/> | ||
130 | </symbol> | ||
131 | <symbol overflow="visible" id="glyph3-0"> | ||
132 | <path style="stroke:none;" d="M 0.59375 0 L 5.28125 0 L 5.28125 -5.390625 L 0.59375 -5.390625 Z M 1.171875 -0.59375 L 1.171875 -4.8125 L 4.6875 -4.8125 L 4.6875 -0.59375 Z M 1.171875 -0.59375 "/> | ||
133 | </symbol> | ||
134 | <symbol overflow="visible" id="glyph3-1"> | ||
135 | <path style="stroke:none;" d="M 0.125 -7.5 C 0.125 -7.4375 0.125 -7.375 0.171875 -7.375 C 0.21875 -7.375 0.84375 -7.453125 0.875 -7.453125 C 0.953125 -7.453125 0.9375 -7.40625 0.953125 -7.25 C 1 -6.359375 1.046875 -4.46875 1.046875 -3.078125 C 1.046875 -2.234375 1.046875 -1.609375 1.03125 -0.5 C 1.03125 -0.328125 1.03125 -0.296875 0.921875 -0.296875 L 0.453125 -0.296875 C 0.34375 -0.296875 0.3125 -0.25 0.3125 -0.140625 C 0.3125 -0.015625 0.3125 0.03125 0.46875 0.03125 C 0.828125 0.03125 1.1875 0 1.484375 0 C 1.8125 0 2.234375 0.03125 2.453125 0.03125 C 2.609375 0.03125 2.609375 -0.03125 2.609375 -0.140625 C 2.609375 -0.25 2.59375 -0.296875 2.453125 -0.296875 L 2 -0.296875 C 1.890625 -0.296875 1.890625 -0.296875 1.875 -0.5 C 1.859375 -0.8125 1.859375 -1.375 1.859375 -1.859375 L 1.859375 -3.609375 C 1.859375 -3.65625 1.875 -3.703125 2.046875 -3.78125 C 2.28125 -3.90625 2.609375 -4.03125 3.078125 -4.03125 C 3.875 -4.03125 4.203125 -3.328125 4.203125 -2.484375 C 4.203125 -1.25 4.203125 -0.65625 4.1875 -0.421875 C 4.171875 -0.296875 4.171875 -0.296875 4.0625 -0.296875 L 3.59375 -0.296875 C 3.484375 -0.296875 3.453125 -0.25 3.453125 -0.140625 C 3.453125 -0.015625 3.453125 0.03125 3.59375 0.03125 C 3.953125 0.03125 4.3125 0 4.609375 0 C 4.953125 0 5.21875 0.03125 5.4375 0.03125 C 5.59375 0.03125 5.609375 -0.03125 5.609375 -0.140625 C 5.609375 -0.25 5.578125 -0.296875 5.4375 -0.296875 L 5.140625 -0.296875 C 5.015625 -0.296875 5 -0.3125 5 -0.4375 L 5 -2.109375 C 5 -3.375 4.859375 -4.515625 3.546875 -4.515625 C 3.046875 -4.515625 2.34375 -4.25 1.984375 -4.046875 C 1.859375 -3.96875 1.859375 -3.953125 1.859375 -4.15625 C 1.859375 -5.1875 1.90625 -6.703125 1.953125 -7.671875 C 1.953125 -7.796875 1.953125 -7.90625 1.890625 -7.90625 C 1.8125 -7.90625 0.71875 -7.765625 0.171875 -7.703125 C 0.125 -7.6875 0.125 -7.59375 0.125 -7.5 Z M 0.125 -7.5 "/> | ||
136 | </symbol> | ||
137 | <symbol overflow="visible" id="glyph3-2"> | ||
138 | <path style="stroke:none;" d="M 0.359375 -2.140625 C 0.359375 -0.765625 1.15625 0.171875 2.59375 0.171875 C 3.78125 0.171875 4.625 -0.859375 4.625 -0.921875 C 4.625 -0.96875 4.46875 -1.109375 4.4375 -1.109375 C 4.390625 -1.109375 3.859375 -0.34375 2.921875 -0.34375 C 2.046875 -0.34375 1.171875 -1.015625 1.171875 -2.28125 C 1.171875 -2.4375 1.171875 -2.703125 1.234375 -2.703125 C 1.328125 -2.703125 3.734375 -2.640625 3.859375 -2.640625 C 4 -2.640625 4.484375 -2.6875 4.484375 -2.78125 C 4.484375 -3.765625 3.90625 -4.640625 2.75 -4.640625 C 1.328125 -4.640625 0.359375 -3.546875 0.359375 -2.140625 Z M 1.234375 -2.984375 C 1.28125 -3.578125 1.828125 -4.390625 2.609375 -4.390625 C 2.984375 -4.390625 3.6875 -4.140625 3.6875 -2.984375 C 3.6875 -2.96875 3.640625 -2.953125 3.21875 -2.9375 C 2.625 -2.921875 1.4375 -2.890625 1.375 -2.890625 C 1.28125 -2.890625 1.234375 -2.921875 1.234375 -2.984375 Z M 1.234375 -2.984375 "/> | ||
139 | </symbol> | ||
140 | <symbol overflow="visible" id="glyph3-3"> | ||
141 | <path style="stroke:none;" d="M 0.40625 -0.828125 C 0.40625 -0.234375 0.828125 0.171875 1.5625 0.171875 C 2.046875 0.171875 2.671875 -0.171875 2.90625 -0.3125 C 3 -0.359375 3.125 -0.453125 3.140625 -0.453125 C 3.171875 -0.453125 3.1875 0.203125 3.609375 0.203125 C 3.734375 0.203125 3.828125 0.125 3.921875 0.078125 C 4.171875 -0.109375 4.671875 -0.453125 4.671875 -0.5 C 4.671875 -0.578125 4.578125 -0.6875 4.53125 -0.6875 C 4.484375 -0.6875 4.125 -0.40625 4.078125 -0.40625 C 3.875 -0.40625 3.828125 -0.640625 3.828125 -0.75 C 3.828125 -1.015625 3.890625 -2.546875 3.890625 -3.140625 C 3.890625 -4.0625 3.546875 -4.671875 2.359375 -4.671875 C 1.59375 -4.671875 0.578125 -4.109375 0.578125 -3.140625 C 0.578125 -3.015625 0.609375 -2.96875 0.671875 -2.96875 C 0.71875 -2.96875 1.109375 -3.15625 1.296875 -3.296875 C 1.359375 -3.34375 1.375 -3.46875 1.375 -3.546875 C 1.390625 -4.015625 1.421875 -4.1875 1.75 -4.328125 C 1.859375 -4.375 2 -4.390625 2.109375 -4.390625 C 3.125 -4.390625 3.125 -3.578125 3.125 -2.75 C 3.125 -2.65625 3.125 -2.578125 3.03125 -2.5625 C 1.875 -2.375 0.40625 -1.875 0.40625 -0.828125 Z M 1.234375 -1.15625 C 1.234375 -1.71875 1.78125 -2.03125 2.328125 -2.203125 C 2.671875 -2.3125 3.03125 -2.375 3.0625 -2.375 C 3.125 -2.375 3.125 -2.328125 3.125 -2.25 L 3.125 -0.6875 C 3.125 -0.625 2.515625 -0.359375 2 -0.359375 C 1.5 -0.359375 1.234375 -0.78125 1.234375 -1.15625 Z M 1.234375 -1.15625 "/> | ||
142 | </symbol> | ||
143 | <symbol overflow="visible" id="glyph3-4"> | ||
144 | <path style="stroke:none;" d="M 0.359375 -2.125 C 0.359375 -0.4375 1.375 0.15625 2.421875 0.15625 C 2.921875 0.15625 3.421875 -0.0625 3.828125 -0.3125 C 3.984375 -0.40625 4 -0.375 4 -0.265625 C 4 -0.21875 3.984375 0.140625 3.984375 0.171875 C 3.984375 0.21875 4.015625 0.265625 4.0625 0.265625 L 5.40625 0.09375 C 5.5625 0.078125 5.5625 0.03125 5.5625 -0.125 C 5.5625 -0.25 5.515625 -0.234375 5.421875 -0.21875 C 5.25 -0.203125 5.125 -0.171875 5.03125 -0.171875 C 4.84375 -0.171875 4.765625 -0.28125 4.765625 -0.75 C 4.75 -1.171875 4.734375 -1.78125 4.734375 -2.15625 C 4.734375 -5.796875 4.8125 -7.296875 4.8125 -7.703125 C 4.8125 -7.953125 4.796875 -7.96875 4.6875 -7.96875 C 4.625 -7.96875 3.828125 -7.84375 3.15625 -7.765625 C 3.078125 -7.75 3.078125 -7.6875 3.0625 -7.609375 C 3.03125 -7.4375 3.03125 -7.4375 3.109375 -7.4375 C 3.1875 -7.4375 3.859375 -7.53125 3.890625 -7.53125 C 3.921875 -7.53125 4.015625 -5.53125 4.015625 -4.34375 C 4.015625 -4.25 4.015625 -4.140625 3.9375 -4.140625 C 3.921875 -4.140625 3.4375 -4.4375 2.734375 -4.4375 C 1.390625 -4.4375 0.359375 -3.453125 0.359375 -2.125 Z M 1.203125 -2.203125 C 1.203125 -3.25 1.84375 -4.203125 2.875 -4.203125 C 3.484375 -4.203125 4.015625 -3.75 4.015625 -3.59375 L 4.015625 -0.671875 C 4.015625 -0.453125 3.296875 -0.28125 2.984375 -0.28125 C 1.71875 -0.28125 1.203125 -1.109375 1.203125 -2.203125 Z M 1.203125 -2.203125 "/> | ||
145 | </symbol> | ||
146 | <symbol overflow="visible" id="glyph3-5"> | ||
147 | <path style="stroke:none;" d="M 0.296875 -4.140625 C 0.296875 -4.109375 0.296875 -4.09375 0.328125 -4.09375 C 0.375 -4.09375 1.046875 -4.109375 1.078125 -4.109375 C 1.109375 -4.109375 1.15625 -2.9375 1.15625 -1.90625 C 1.15625 -1.0625 1.15625 -0.296875 1.0625 -0.296875 L 0.546875 -0.296875 C 0.4375 -0.296875 0.40625 -0.25 0.40625 -0.140625 C 0.40625 -0.015625 0.40625 0.03125 0.5625 0.03125 C 0.921875 0.03125 1.28125 0 1.578125 0 C 1.90625 0 2.59375 0.03125 2.8125 0.03125 C 2.96875 0.03125 2.96875 -0.03125 2.96875 -0.140625 C 2.96875 -0.25 2.953125 -0.296875 2.8125 -0.296875 L 2.078125 -0.296875 C 1.9375 -0.296875 1.9375 -0.984375 1.9375 -1.609375 C 1.9375 -2.609375 2.015625 -4 2.609375 -4 C 2.84375 -4 3.03125 -3.640625 3.3125 -3.640625 C 3.5 -3.640625 3.734375 -3.984375 3.734375 -4.109375 C 3.734375 -4.25 3.421875 -4.625 3.078125 -4.625 C 2.71875 -4.625 2.25 -4.25 1.984375 -3.625 C 1.9375 -3.515625 1.90625 -3.328125 1.875 -3.328125 C 1.859375 -3.328125 1.859375 -3.390625 1.859375 -3.546875 C 1.859375 -3.765625 1.875 -4.0625 1.875 -4.296875 C 1.875 -4.40625 1.921875 -4.40625 1.734375 -4.40625 C 1.65625 -4.40625 0.671875 -4.390625 0.5 -4.375 C 0.34375 -4.359375 0.359375 -4.375 0.328125 -4.28125 C 0.3125 -4.21875 0.296875 -4.171875 0.296875 -4.140625 Z M 0.296875 -4.140625 "/> | ||
148 | </symbol> | ||
149 | <symbol overflow="visible" id="glyph3-6"> | ||
150 | <path style="stroke:none;" d="M 0.40625 -4.03125 C 0.40625 -3.984375 0.4375 -3.953125 0.484375 -3.953125 L 0.78125 -3.953125 C 0.90625 -3.953125 0.921875 -3.671875 0.921875 -3.234375 C 0.921875 -2.890625 0.90625 -1.546875 0.890625 -0.703125 C 0.890625 -0.359375 1.0625 0.109375 1.734375 0.109375 C 2.21875 0.109375 3.21875 -0.390625 3.21875 -0.453125 C 3.21875 -0.53125 3.203125 -0.640625 3.171875 -0.640625 C 3.078125 -0.640625 2.6875 -0.453125 2.234375 -0.453125 C 1.6875 -0.453125 1.671875 -0.8125 1.671875 -1.171875 L 1.671875 -3.421875 C 1.671875 -3.75 1.671875 -3.96875 1.703125 -3.96875 L 2.859375 -3.96875 C 2.9375 -3.96875 2.984375 -4 3.015625 -4.15625 C 3.0625 -4.359375 3.046875 -4.359375 2.90625 -4.359375 L 1.796875 -4.359375 C 1.6875 -4.359375 1.671875 -4.375 1.671875 -4.484375 C 1.671875 -4.671875 1.734375 -5.515625 1.734375 -5.5625 C 1.734375 -5.640625 1.671875 -5.671875 1.625 -5.671875 C 1.578125 -5.671875 1.53125 -5.65625 1.515625 -5.609375 L 0.453125 -4.125 C 0.421875 -4.109375 0.40625 -4.0625 0.40625 -4.03125 Z M 0.40625 -4.03125 "/> | ||
151 | </symbol> | ||
152 | <symbol overflow="visible" id="glyph3-7"> | ||
153 | <path style="stroke:none;" d="M 0.296875 -4.3125 C 0.296875 -4.203125 0.3125 -4.15625 0.453125 -4.15625 L 0.546875 -4.15625 C 0.734375 -4.15625 0.734375 -4.15625 0.8125 -3.984375 C 1.28125 -2.765625 1.953125 -0.875 2.09375 -0.484375 C 2.171875 -0.234375 2.28125 0.296875 2.4375 0.296875 C 2.46875 0.296875 2.515625 0.265625 2.5625 0.21875 C 2.875 -0.25 2.953125 -0.21875 3.140625 -0.609375 C 3.671875 -1.71875 4.375 -3.578125 4.625 -4.046875 C 4.6875 -4.140625 4.6875 -4.15625 4.78125 -4.15625 L 4.96875 -4.15625 C 5.09375 -4.15625 5.109375 -4.203125 5.109375 -4.3125 C 5.109375 -4.4375 5.09375 -4.484375 4.984375 -4.484375 C 4.8125 -4.484375 4.640625 -4.453125 4.390625 -4.453125 C 4.15625 -4.453125 3.8125 -4.484375 3.71875 -4.484375 C 3.5625 -4.484375 3.546875 -4.421875 3.546875 -4.3125 C 3.546875 -4.203125 3.5625 -4.15625 3.703125 -4.15625 L 4.015625 -4.15625 C 4.09375 -4.15625 4.125 -4.09375 4.125 -3.96875 C 4.125 -3.59375 3.3125 -1.625 3.03125 -0.96875 C 2.984375 -0.84375 2.953125 -0.78125 2.921875 -0.78125 C 2.890625 -0.78125 2.84375 -0.828125 2.78125 -0.984375 C 2.4375 -1.78125 1.671875 -4.015625 1.671875 -4.0625 C 1.671875 -4.15625 1.765625 -4.15625 1.890625 -4.15625 L 2.234375 -4.15625 C 2.359375 -4.15625 2.375 -4.203125 2.375 -4.3125 C 2.375 -4.4375 2.375 -4.484375 2.234375 -4.484375 C 2.015625 -4.484375 1.53125 -4.453125 1.234375 -4.453125 C 0.890625 -4.453125 0.671875 -4.484375 0.453125 -4.484375 C 0.296875 -4.484375 0.296875 -4.421875 0.296875 -4.3125 Z M 0.296875 -4.3125 "/> | ||
154 | </symbol> | ||
155 | <symbol overflow="visible" id="glyph3-8"> | ||
156 | <path style="stroke:none;" d="M 0.296875 -4.1875 C 0.296875 -4.15625 0.3125 -4.140625 0.34375 -4.140625 C 0.390625 -4.140625 0.890625 -4.15625 0.921875 -4.15625 C 1.046875 -4.15625 1.0625 -4.15625 1.078125 -3.96875 C 1.109375 -3.125 1.125 -2.28125 1.125 -1.46875 C 1.125 -1.109375 1.125 -0.78125 1.109375 -0.4375 C 1.109375 -0.3125 1.109375 -0.296875 0.984375 -0.296875 L 0.5 -0.296875 C 0.359375 -0.296875 0.34375 -0.25 0.34375 -0.140625 C 0.34375 -0.015625 0.34375 0.03125 0.46875 0.03125 C 0.6875 0.03125 1.21875 0 1.515625 0 C 1.8125 0 2.28125 0.03125 2.5 0.03125 C 2.625 0.03125 2.625 -0.03125 2.625 -0.140625 C 2.625 -0.25 2.609375 -0.296875 2.5 -0.296875 L 2.078125 -0.296875 C 1.953125 -0.296875 1.953125 -0.328125 1.953125 -0.4375 C 1.921875 -1.109375 1.921875 -1.765625 1.921875 -2.421875 L 1.921875 -4.421875 C 1.921875 -4.484375 1.90625 -4.484375 1.84375 -4.484375 C 1.78125 -4.484375 0.734375 -4.4375 0.515625 -4.4375 C 0.375 -4.421875 0.390625 -4.4375 0.34375 -4.34375 C 0.296875 -4.25 0.296875 -4.21875 0.296875 -4.1875 Z M 0.90625 -6.484375 C 0.90625 -6.15625 1.140625 -6 1.390625 -6 C 1.71875 -6 2.09375 -6.265625 2.09375 -6.65625 C 2.09375 -7 1.859375 -7.125 1.609375 -7.125 C 1.328125 -7.125 0.90625 -6.90625 0.90625 -6.484375 Z M 0.90625 -6.484375 "/> | ||
157 | </symbol> | ||
158 | <symbol overflow="visible" id="glyph3-9"> | ||
159 | <path style="stroke:none;" d="M 0.234375 -7.5625 C 0.234375 -7.53125 0.25 -7.53125 0.328125 -7.53125 C 0.375 -7.53125 0.828125 -7.578125 0.890625 -7.578125 C 1.015625 -7.578125 1 -7.546875 1.015625 -7.34375 C 1.109375 -6.3125 1.15625 -1.859375 1.15625 -1.296875 C 1.15625 -1 1.15625 -0.296875 1.109375 -0.296875 L 0.5 -0.296875 C 0.375 -0.296875 0.359375 -0.25 0.359375 -0.140625 C 0.359375 -0.015625 0.359375 0.03125 0.5 0.03125 C 0.859375 0.03125 1.296875 0 1.59375 0 C 1.9375 0 2.296875 0.03125 2.515625 0.03125 C 2.671875 0.03125 2.671875 -0.03125 2.671875 -0.140625 C 2.671875 -0.25 2.65625 -0.296875 2.515625 -0.296875 L 2.0625 -0.296875 C 1.96875 -0.296875 1.96875 -0.484375 1.96875 -0.75 C 1.96875 -3.109375 1.90625 -4.171875 1.90625 -7.765625 C 1.90625 -7.90625 1.90625 -7.953125 1.8125 -7.953125 C 1.75 -7.953125 0.84375 -7.875 0.375 -7.84375 C 0.265625 -7.828125 0.28125 -7.84375 0.265625 -7.75 C 0.25 -7.671875 0.234375 -7.59375 0.234375 -7.5625 Z M 0.234375 -7.5625 "/> | ||
160 | </symbol> | ||
161 | <symbol overflow="visible" id="glyph3-10"> | ||
162 | <path style="stroke:none;" d="M 0.0625 -7.484375 C 0.0625 -7.4375 0.078125 -7.421875 0.125 -7.421875 C 0.171875 -7.421875 0.796875 -7.484375 0.84375 -7.484375 C 1 -7.484375 1.046875 -2.703125 1.046875 -2.3125 C 1.046875 -1.53125 0.984375 -0.078125 0.984375 -0.015625 C 0.984375 0.09375 1.03125 0.140625 1.125 0.140625 C 1.25 0.140625 1.46875 -0.078125 1.703125 -0.078125 C 2.03125 -0.078125 2.328125 0.15625 2.75 0.15625 C 4.078125 0.15625 5.328125 -0.6875 5.328125 -2.203125 C 5.328125 -3.484375 4.40625 -4.53125 3.078125 -4.53125 C 2.5 -4.53125 1.859375 -4.171875 1.828125 -4.171875 C 1.8125 -4.171875 1.8125 -4.34375 1.8125 -4.625 C 1.8125 -5.578125 1.859375 -7.75 1.859375 -7.75 C 1.859375 -7.8125 1.859375 -7.921875 1.78125 -7.921875 C 1.71875 -7.921875 0.6875 -7.796875 0.125 -7.734375 C 0.078125 -7.734375 0.0625 -7.5625 0.0625 -7.484375 Z M 1.796875 -0.75 C 1.796875 -1.140625 1.8125 -2.703125 1.8125 -3.890625 C 1.8125 -3.953125 2.21875 -4.1875 2.609375 -4.1875 C 3.640625 -4.1875 4.484375 -3.234375 4.484375 -2.1875 C 4.484375 -1.15625 3.875 -0.171875 2.78125 -0.171875 C 2.453125 -0.171875 1.796875 -0.171875 1.796875 -0.75 Z M 1.796875 -0.75 "/> | ||
163 | </symbol> | ||
164 | </g> | ||
165 | </defs> | ||
166 | <g id="surface1"> | ||
167 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10 15 L 738 15 L 738 95.5 L 10 95.5 Z M 10 15 "/> | ||
168 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
169 | <use xlink:href="#glyph0-1" x="25" y="46.171875"/> | ||
170 | <use xlink:href="#glyph0-2" x="39" y="46.171875"/> | ||
171 | <use xlink:href="#glyph0-3" x="49" y="46.171875"/> | ||
172 | <use xlink:href="#glyph0-4" x="59" y="46.171875"/> | ||
173 | <use xlink:href="#glyph0-5" x="75" y="46.171875"/> | ||
174 | <use xlink:href="#glyph0-6" x="88" y="46.171875"/> | ||
175 | </g> | ||
176 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
177 | <use xlink:href="#glyph1-1" x="182.5" y="70.957031"/> | ||
178 | <use xlink:href="#glyph1-2" x="189.5" y="70.957031"/> | ||
179 | <use xlink:href="#glyph1-3" x="196.5" y="70.957031"/> | ||
180 | <use xlink:href="#glyph1-4" x="203.5" y="70.957031"/> | ||
181 | <use xlink:href="#glyph1-5" x="210.5" y="70.957031"/> | ||
182 | <use xlink:href="#glyph1-6" x="217.5" y="70.957031"/> | ||
183 | <use xlink:href="#glyph1-7" x="224.5" y="70.957031"/> | ||
184 | <use xlink:href="#glyph1-8" x="231.5" y="70.957031"/> | ||
185 | <use xlink:href="#glyph1-9" x="238.5" y="70.957031"/> | ||
186 | <use xlink:href="#glyph1-10" x="245.5" y="70.957031"/> | ||
187 | <use xlink:href="#glyph1-11" x="252.5" y="70.957031"/> | ||
188 | </g> | ||
189 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10 110.5 L 738 110.5 L 738 201 L 10 201 Z M 10 110.5 "/> | ||
190 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
191 | <use xlink:href="#glyph0-7" x="25" y="141.671875"/> | ||
192 | <use xlink:href="#glyph0-8" x="43" y="141.671875"/> | ||
193 | <use xlink:href="#glyph0-2" x="51" y="141.671875"/> | ||
194 | <use xlink:href="#glyph0-9" x="61" y="141.671875"/> | ||
195 | <use xlink:href="#glyph0-10" x="73" y="141.671875"/> | ||
196 | <use xlink:href="#glyph0-11" x="85" y="141.671875"/> | ||
197 | <use xlink:href="#glyph0-2" x="102" y="141.671875"/> | ||
198 | <use xlink:href="#glyph0-12" x="112" y="141.671875"/> | ||
199 | <use xlink:href="#glyph0-12" x="129" y="141.671875"/> | ||
200 | <use xlink:href="#glyph0-13" x="146" y="141.671875"/> | ||
201 | <use xlink:href="#glyph0-14" x="152" y="141.671875"/> | ||
202 | </g> | ||
203 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
204 | <use xlink:href="#glyph1-2" x="160" y="166.457031"/> | ||
205 | <use xlink:href="#glyph1-12" x="167" y="166.457031"/> | ||
206 | <use xlink:href="#glyph1-13" x="174" y="166.457031"/> | ||
207 | <use xlink:href="#glyph1-13" x="181" y="166.457031"/> | ||
208 | <use xlink:href="#glyph1-4" x="188" y="166.457031"/> | ||
209 | <use xlink:href="#glyph1-3" x="195" y="166.457031"/> | ||
210 | <use xlink:href="#glyph1-6" x="202" y="166.457031"/> | ||
211 | <use xlink:href="#glyph1-14" x="209" y="166.457031"/> | ||
212 | <use xlink:href="#glyph1-7" x="216" y="166.457031"/> | ||
213 | <use xlink:href="#glyph1-8" x="223" y="166.457031"/> | ||
214 | <use xlink:href="#glyph1-9" x="230" y="166.457031"/> | ||
215 | <use xlink:href="#glyph1-15" x="237" y="166.457031"/> | ||
216 | <use xlink:href="#glyph1-10" x="244" y="166.457031"/> | ||
217 | <use xlink:href="#glyph1-11" x="251" y="166.457031"/> | ||
218 | </g> | ||
219 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10 216 L 738 216 L 738 336.5 L 10 336.5 Z M 10 216 "/> | ||
220 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
221 | <use xlink:href="#glyph0-15" x="25" y="247.171875"/> | ||
222 | <use xlink:href="#glyph0-13" x="43" y="247.171875"/> | ||
223 | <use xlink:href="#glyph0-16" x="49" y="247.171875"/> | ||
224 | <use xlink:href="#glyph0-17" x="57" y="247.171875"/> | ||
225 | <use xlink:href="#glyph0-1" x="68" y="247.171875"/> | ||
226 | <use xlink:href="#glyph0-2" x="82" y="247.171875"/> | ||
227 | <use xlink:href="#glyph0-3" x="92" y="247.171875"/> | ||
228 | </g> | ||
229 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
230 | <use xlink:href="#glyph1-14" x="190" y="271.957031"/> | ||
231 | <use xlink:href="#glyph1-4" x="197" y="271.957031"/> | ||
232 | <use xlink:href="#glyph1-15" x="204" y="271.957031"/> | ||
233 | <use xlink:href="#glyph1-16" x="211" y="271.957031"/> | ||
234 | <use xlink:href="#glyph1-11" x="218" y="271.957031"/> | ||
235 | <use xlink:href="#glyph1-17" x="225" y="271.957031"/> | ||
236 | <use xlink:href="#glyph1-12" x="232" y="271.957031"/> | ||
237 | <use xlink:href="#glyph1-18" x="239" y="271.957031"/> | ||
238 | <use xlink:href="#glyph1-10" x="246" y="271.957031"/> | ||
239 | <use xlink:href="#glyph1-11" x="253" y="271.957031"/> | ||
240 | </g> | ||
241 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:2;stroke-miterlimit:10;" d="M 265 192 L 265 204 L 539.800781 237.5 L 539.800781 249.5 "/> | ||
242 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:2;stroke-miterlimit:10;" d="M 723 192 L 723 204 L 631.398438 237.5 L 631.398438 249.5 "/> | ||
243 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10 351.5 L 738 351.5 L 738 468.5 L 10 468.5 Z M 10 351.5 "/> | ||
244 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
245 | <use xlink:href="#glyph0-4" x="25" y="382.671875"/> | ||
246 | <use xlink:href="#glyph0-10" x="41" y="382.671875"/> | ||
247 | <use xlink:href="#glyph0-10" x="53" y="382.671875"/> | ||
248 | <use xlink:href="#glyph0-18" x="65" y="382.671875"/> | ||
249 | <use xlink:href="#glyph0-13" x="71" y="382.671875"/> | ||
250 | <use xlink:href="#glyph0-19" x="77" y="382.671875"/> | ||
251 | <use xlink:href="#glyph0-8" x="87" y="382.671875"/> | ||
252 | </g> | ||
253 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
254 | <use xlink:href="#glyph1-14" x="190" y="443.957031"/> | ||
255 | <use xlink:href="#glyph1-4" x="197" y="443.957031"/> | ||
256 | <use xlink:href="#glyph1-15" x="204" y="443.957031"/> | ||
257 | <use xlink:href="#glyph1-16" x="211" y="443.957031"/> | ||
258 | <use xlink:href="#glyph1-11" x="218" y="443.957031"/> | ||
259 | <use xlink:href="#glyph1-14" x="225" y="443.957031"/> | ||
260 | <use xlink:href="#glyph1-1" x="232" y="443.957031"/> | ||
261 | <use xlink:href="#glyph1-3" x="239" y="443.957031"/> | ||
262 | <use xlink:href="#glyph1-1" x="246" y="443.957031"/> | ||
263 | <use xlink:href="#glyph1-10" x="253" y="443.957031"/> | ||
264 | </g> | ||
265 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:2;stroke-miterlimit:10;" d="M 356.601562 327.5 L 356.601562 339.5 L 402.398438 358.5 L 402.398438 370.5 "/> | ||
266 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:2;stroke-miterlimit:10;" d="M 631.398438 327.5 L 631.398438 339.5 L 585.601562 358.5 L 585.601562 370.5 "/> | ||
267 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
268 | <use xlink:href="#glyph2-1" x="315" y="168.992188"/> | ||
269 | <use xlink:href="#glyph2-2" x="327" y="168.992188"/> | ||
270 | </g> | ||
271 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
272 | <use xlink:href="#glyph2-1" x="481" y="168.992188"/> | ||
273 | <use xlink:href="#glyph2-2" x="493" y="168.992188"/> | ||
274 | </g> | ||
275 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
276 | <use xlink:href="#glyph2-1" x="587" y="168.992188"/> | ||
277 | <use xlink:href="#glyph2-2" x="599" y="168.992188"/> | ||
278 | </g> | ||
279 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 265 296.5 L 265 306.5 "/> | ||
280 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 265 301.5 L 723 301.5 "/> | ||
281 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.601562 296.5 L 356.601562 306.5 "/> | ||
282 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
283 | <use xlink:href="#glyph3-1" x="291.113281" y="314.585938"/> | ||
284 | <use xlink:href="#glyph3-2" x="297.113281" y="314.585938"/> | ||
285 | <use xlink:href="#glyph3-3" x="302.113281" y="314.585938"/> | ||
286 | <use xlink:href="#glyph3-4" x="307.113281" y="314.585938"/> | ||
287 | <use xlink:href="#glyph3-2" x="313.113281" y="314.585938"/> | ||
288 | <use xlink:href="#glyph3-5" x="318.113281" y="314.585938"/> | ||
289 | </g> | ||
290 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 631.398438 296.5 L 631.398438 306.5 "/> | ||
291 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
292 | <use xlink:href="#glyph3-4" x="481.34375" y="314.585938"/> | ||
293 | <use xlink:href="#glyph3-3" x="487.34375" y="314.585938"/> | ||
294 | <use xlink:href="#glyph3-6" x="492.34375" y="314.585938"/> | ||
295 | <use xlink:href="#glyph3-3" x="495.34375" y="314.585938"/> | ||
296 | </g> | ||
297 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 723 296.5 L 723 306.5 "/> | ||
298 | <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> | ||
299 | <use xlink:href="#glyph3-3" x="652.355469" y="314.585938"/> | ||
300 | <use xlink:href="#glyph3-7" x="657.355469" y="314.585938"/> | ||
301 | <use xlink:href="#glyph3-3" x="662.355469" y="314.585938"/> | ||
302 | <use xlink:href="#glyph3-8" x="667.355469" y="314.585938"/> | ||
303 | <use xlink:href="#glyph3-9" x="670.355469" y="314.585938"/> | ||
304 | <use xlink:href="#glyph3-3" x="673.355469" y="314.585938"/> | ||
305 | <use xlink:href="#glyph3-10" x="678.355469" y="314.585938"/> | ||
306 | <use xlink:href="#glyph3-9" x="684.355469" y="314.585938"/> | ||
307 | <use xlink:href="#glyph3-2" x="687.355469" y="314.585938"/> | ||
308 | </g> | ||
309 | <path style="fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 265 427.5 L 723 427.5 L 723 453.5 L 265 453.5 Z M 265 427.5 "/> | ||
310 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 265 54.5 L 285 54.5 L 285 80.5 L 265 80.5 Z M 265 54.5 "/> | ||
311 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 285 54.5 L 305 54.5 L 305 80.5 L 285 80.5 Z M 285 54.5 "/> | ||
312 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 305 54.5 L 325 54.5 L 325 80.5 L 305 80.5 Z M 305 54.5 "/> | ||
313 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 325 54.5 L 345 54.5 L 345 80.5 L 325 80.5 Z M 325 54.5 "/> | ||
314 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 345 54.5 L 365 54.5 L 365 80.5 L 345 80.5 Z M 345 54.5 "/> | ||
315 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 275 140 L 265 140 L 265 186 L 275 186 "/> | ||
316 | <path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 713 140 L 723 140 L 723 186 L 713 186 "/> | ||
317 | <path style="fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 265 255.5 L 356.601562 255.5 L 356.601562 281.5 L 265 281.5 Z M 265 255.5 "/> | ||
318 | <path style="fill-rule:nonzero;fill:rgb(80%,80%,80%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.601562 255.5 L 448.203125 255.5 L 448.203125 281.5 L 356.601562 281.5 Z M 356.601562 255.5 "/> | ||
319 | <path style="fill-rule:nonzero;fill:rgb(80%,80%,80%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 448.199219 255.5 L 539.800781 255.5 L 539.800781 281.5 L 448.199219 281.5 Z M 448.199219 255.5 "/> | ||
320 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 539.800781 255.5 L 544.890625 255.5 L 544.890625 281.5 L 539.800781 281.5 Z M 539.800781 255.5 "/> | ||
321 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 544.890625 255.5 L 549.980469 255.5 L 549.980469 281.5 L 544.890625 281.5 Z M 544.890625 255.5 "/> | ||
322 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 549.976562 255.5 L 555.066406 255.5 L 555.066406 281.5 L 549.976562 281.5 Z M 549.976562 255.5 "/> | ||
323 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.066406 255.5 L 560.15625 255.5 L 560.15625 281.5 L 555.066406 281.5 Z M 555.066406 255.5 "/> | ||
324 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 560.15625 255.5 L 565.246094 255.5 L 565.246094 281.5 L 560.15625 281.5 Z M 560.15625 255.5 "/> | ||
325 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 565.246094 255.5 L 570.335938 255.5 L 570.335938 281.5 L 565.246094 281.5 Z M 565.246094 255.5 "/> | ||
326 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 570.332031 255.5 L 575.421875 255.5 L 575.421875 281.5 L 570.332031 281.5 Z M 570.332031 255.5 "/> | ||
327 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 575.421875 255.5 L 580.511719 255.5 L 580.511719 281.5 L 575.421875 281.5 Z M 575.421875 255.5 "/> | ||
328 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 580.511719 255.5 L 585.601562 255.5 L 585.601562 281.5 L 580.511719 281.5 Z M 580.511719 255.5 "/> | ||
329 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 585.601562 255.5 L 590.691406 255.5 L 590.691406 281.5 L 585.601562 281.5 Z M 585.601562 255.5 "/> | ||
330 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 590.6875 255.5 L 595.777344 255.5 L 595.777344 281.5 L 590.6875 281.5 Z M 590.6875 255.5 "/> | ||
331 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 595.777344 255.5 L 600.867188 255.5 L 600.867188 281.5 L 595.777344 281.5 Z M 595.777344 255.5 "/> | ||
332 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 600.867188 255.5 L 605.957031 255.5 L 605.957031 281.5 L 600.867188 281.5 Z M 600.867188 255.5 "/> | ||
333 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 605.957031 255.5 L 611.046875 255.5 L 611.046875 281.5 L 605.957031 281.5 Z M 605.957031 255.5 "/> | ||
334 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 611.042969 255.5 L 616.132812 255.5 L 616.132812 281.5 L 611.042969 281.5 Z M 611.042969 255.5 "/> | ||
335 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 616.132812 255.5 L 621.222656 255.5 L 621.222656 281.5 L 616.132812 281.5 Z M 616.132812 255.5 "/> | ||
336 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 621.222656 255.5 L 626.3125 255.5 L 626.3125 281.5 L 621.222656 281.5 Z M 621.222656 255.5 "/> | ||
337 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 626.3125 255.5 L 631.402344 255.5 L 631.402344 281.5 L 626.3125 281.5 Z M 626.3125 255.5 "/> | ||
338 | <path style="fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 631.398438 255.5 L 723 255.5 L 723 281.5 L 631.398438 281.5 Z M 631.398438 255.5 "/> | ||
339 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 275 150 L 295 150 L 295 176 L 275 176 Z M 275 150 "/> | ||
340 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 295 150 L 315 150 L 315 176 L 295 176 Z M 295 150 "/> | ||
341 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 341 150 L 361 150 L 361 176 L 341 176 Z M 341 150 "/> | ||
342 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 361 150 L 381 150 L 381 176 L 361 176 Z M 361 150 "/> | ||
343 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 381 150 L 401 150 L 401 176 L 381 176 Z M 381 150 "/> | ||
344 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 401 150 L 421 150 L 421 176 L 401 176 Z M 401 150 "/> | ||
345 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 421 150 L 441 150 L 441 176 L 421 176 Z M 421 150 "/> | ||
346 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 441 150 L 461 150 L 461 176 L 441 176 Z M 441 150 "/> | ||
347 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 461 150 L 481 150 L 481 176 L 461 176 Z M 461 150 "/> | ||
348 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 507 150 L 527 150 L 527 176 L 507 176 Z M 507 150 "/> | ||
349 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 527 150 L 547 150 L 547 176 L 527 176 Z M 527 150 "/> | ||
350 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 547 150 L 567 150 L 567 176 L 547 176 Z M 547 150 "/> | ||
351 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 567 150 L 587 150 L 587 176 L 567 176 Z M 567 150 "/> | ||
352 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613 150 L 633 150 L 633 176 L 613 176 Z M 613 150 "/> | ||
353 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 633 150 L 653 150 L 653 176 L 633 176 Z M 633 150 "/> | ||
354 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 653 150 L 673 150 L 673 176 L 653 176 Z M 653 150 "/> | ||
355 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 673 150 L 693 150 L 693 176 L 673 176 Z M 673 150 "/> | ||
356 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 693 150 L 713 150 L 713 176 L 693 176 Z M 693 150 "/> | ||
357 | <path style="fill-rule:nonzero;fill:rgb(80%,80%,80%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 402.398438 376.5 L 494 376.5 L 494 402.5 L 402.398438 402.5 Z M 402.398438 376.5 "/> | ||
358 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 494 376.5 L 499.089844 376.5 L 499.089844 402.5 L 494 402.5 Z M 494 376.5 "/> | ||
359 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 499.089844 376.5 L 504.179688 376.5 L 504.179688 402.5 L 499.089844 402.5 Z M 499.089844 376.5 "/> | ||
360 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 504.179688 376.5 L 509.269531 376.5 L 509.269531 402.5 L 504.179688 402.5 Z M 504.179688 376.5 "/> | ||
361 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 509.265625 376.5 L 514.355469 376.5 L 514.355469 402.5 L 509.265625 402.5 Z M 509.265625 376.5 "/> | ||
362 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 514.355469 376.5 L 519.445312 376.5 L 519.445312 402.5 L 514.355469 402.5 Z M 514.355469 376.5 "/> | ||
363 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 519.445312 376.5 L 524.535156 376.5 L 524.535156 402.5 L 519.445312 402.5 Z M 519.445312 376.5 "/> | ||
364 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.535156 376.5 L 529.625 376.5 L 529.625 402.5 L 524.535156 402.5 Z M 524.535156 376.5 "/> | ||
365 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 529.621094 376.5 L 534.710938 376.5 L 534.710938 402.5 L 529.621094 402.5 Z M 529.621094 376.5 "/> | ||
366 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 534.710938 376.5 L 539.800781 376.5 L 539.800781 402.5 L 534.710938 402.5 Z M 534.710938 376.5 "/> | ||
367 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 539.800781 376.5 L 544.890625 376.5 L 544.890625 402.5 L 539.800781 402.5 Z M 539.800781 376.5 "/> | ||
368 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 544.890625 376.5 L 549.980469 376.5 L 549.980469 402.5 L 544.890625 402.5 Z M 544.890625 376.5 "/> | ||
369 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 549.976562 376.5 L 555.066406 376.5 L 555.066406 402.5 L 549.976562 402.5 Z M 549.976562 376.5 "/> | ||
370 | <path style="fill-rule:nonzero;fill:rgb(50%,50%,50%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.066406 376.5 L 560.15625 376.5 L 560.15625 402.5 L 555.066406 402.5 Z M 555.066406 376.5 "/> | ||
371 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 560.15625 376.5 L 565.246094 376.5 L 565.246094 402.5 L 560.15625 402.5 Z M 560.15625 376.5 "/> | ||
372 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 565.246094 376.5 L 570.335938 376.5 L 570.335938 402.5 L 565.246094 402.5 Z M 565.246094 376.5 "/> | ||
373 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 570.332031 376.5 L 575.421875 376.5 L 575.421875 402.5 L 570.332031 402.5 Z M 570.332031 376.5 "/> | ||
374 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 575.421875 376.5 L 580.511719 376.5 L 580.511719 402.5 L 575.421875 402.5 Z M 575.421875 376.5 "/> | ||
375 | <path style="fill-rule:nonzero;fill:rgb(35%,35%,100%);fill-opacity:1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 580.511719 376.5 L 585.601562 376.5 L 585.601562 402.5 L 580.511719 402.5 Z M 580.511719 376.5 "/> | ||
376 | </g> | ||
377 | </svg> | ||
diff --git a/z3-solver/Cargo.toml b/z3-solver/Cargo.toml new file mode 100644 index 0000000..6f63e1c --- /dev/null +++ b/z3-solver/Cargo.toml | |||
@@ -0,0 +1,12 @@ | |||
1 | [package] | ||
2 | name = "diaphragm-z3-solver" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Minijackson <minijackson@riseup.net>"] | ||
5 | edition = "2021" | ||
6 | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
8 | |||
9 | [dependencies] | ||
10 | diaphragm-core = { path = "../core" } | ||
11 | |||
12 | z3 = "0.9" | ||
diff --git a/z3-solver/src/lib.rs b/z3-solver/src/lib.rs new file mode 100644 index 0000000..04d77eb --- /dev/null +++ b/z3-solver/src/lib.rs | |||
@@ -0,0 +1,691 @@ | |||
1 | pub use z3; | ||
2 | |||
3 | use diaphragm_core::{ | ||
4 | solving::VariableHandle, | ||
5 | types::{Bool, Float}, | ||
6 | SolverContext, SolverModel, | ||
7 | }; | ||
8 | |||
9 | use z3::ast::Ast; | ||
10 | |||
11 | use std::collections::HashMap; | ||
12 | |||
13 | #[derive(Debug)] | ||
14 | pub struct Z3Context<'z3> { | ||
15 | ctx: &'z3 z3::Context, | ||
16 | solver: z3::Solver<'z3>, | ||
17 | |||
18 | floats: HashMap<VariableHandle, z3::ast::Real<'z3>>, | ||
19 | max_float_id: u32, | ||
20 | |||
21 | bools: HashMap<VariableHandle, z3::ast::Bool<'z3>>, | ||
22 | pub max_bool_id: u32, | ||
23 | } | ||
24 | |||
25 | impl Drop for Z3Context<'_> { | ||
26 | fn drop(&mut self) { | ||
27 | eprintln!("bool: {}", self.max_bool_id); | ||
28 | eprintln!("float: {}", self.max_float_id); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | fn value_to_num_den(value: f64) -> (i32, i32) { | ||
33 | let fract = value.fract(); | ||
34 | let number_of_fract_digits = -fract.log10().floor(); | ||
35 | |||
36 | if number_of_fract_digits >= 1. && !number_of_fract_digits.is_infinite() { | ||
37 | let den = 10f64.powf(number_of_fract_digits); | ||
38 | ((value * den) as i32, den as i32) | ||
39 | } else { | ||
40 | (value as i32, 1) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | impl<'z3> Z3Context<'z3> { | ||
45 | pub fn new(ctx: &'z3 z3::Context) -> Self { | ||
46 | Self { | ||
47 | ctx, | ||
48 | solver: z3::Solver::new(&ctx), | ||
49 | floats: HashMap::new(), | ||
50 | max_float_id: 0, | ||
51 | bools: HashMap::new(), | ||
52 | max_bool_id: 0, | ||
53 | } | ||
54 | } | ||
55 | |||
56 | fn anon_float(&mut self, f: z3::ast::Real<'z3>) -> Float { | ||
57 | self.max_float_id += 1; | ||
58 | let id = self.max_float_id; | ||
59 | let handle = VariableHandle::new(id as usize); | ||
60 | self.floats.insert(handle, f); | ||
61 | Float::from_handle(handle) | ||
62 | } | ||
63 | |||
64 | fn anon_bool(&mut self, f: z3::ast::Bool<'z3>) -> Bool { | ||
65 | self.max_bool_id += 1; | ||
66 | let id = self.max_bool_id; | ||
67 | let handle = VariableHandle::new(id as usize); | ||
68 | self.bools.insert(handle, dbg!(f)); | ||
69 | Bool::new(handle) | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | fn float_handle(&mut self, f: Float) -> VariableHandle { | ||
74 | match f { | ||
75 | Float::Fixed(value) => { | ||
76 | let new_float = self.new_fixed_float(value); | ||
77 | self.float_handle(new_float) | ||
78 | } | ||
79 | Float::Variable(handle) => handle, | ||
80 | } | ||
81 | } | ||
82 | */ | ||
83 | |||
84 | fn float(&self, f: Float) -> z3::ast::Real<'z3> { | ||
85 | let handle = match f { | ||
86 | Float::Fixed(value) => { | ||
87 | let (num, den) = value_to_num_den(value); | ||
88 | return z3::ast::Real::from_real(&self.ctx, num, den); | ||
89 | } | ||
90 | Float::Variable(handle) => handle, | ||
91 | }; | ||
92 | |||
93 | self.floats | ||
94 | .get(&handle) | ||
95 | .expect("Couldn't get float") | ||
96 | .clone() | ||
97 | } | ||
98 | |||
99 | fn bool(&self, f: Bool) -> &z3::ast::Bool<'z3> { | ||
100 | self.bools.get(&f.handle()).expect("Couldn't get float") | ||
101 | } | ||
102 | } | ||
103 | |||
104 | impl<'z3> SolverContext for Z3Context<'z3> { | ||
105 | fn solve<'a>(&'a self) -> Box<dyn SolverModel + 'a> { | ||
106 | match self.solver.check() { | ||
107 | z3::SatResult::Unsat | z3::SatResult::Unknown => panic!("Failed solving"), | ||
108 | z3::SatResult::Sat => {} | ||
109 | } | ||
110 | Box::new(Z3Model { | ||
111 | ctx: self, | ||
112 | model: self.solver.get_model().unwrap(), | ||
113 | }) | ||
114 | } | ||
115 | |||
116 | fn constrain(&mut self, assertion: Bool) { | ||
117 | self.solver.assert( | ||
118 | self.bools | ||
119 | .get(&assertion.handle()) | ||
120 | .expect("Couldn't get bool"), | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | // Floats | ||
125 | |||
126 | fn new_free_float(&mut self) -> Float { | ||
127 | self.max_float_id += 1; | ||
128 | let id = self.max_float_id; | ||
129 | let handle = VariableHandle::new(id as usize); | ||
130 | self.floats | ||
131 | .insert(handle, z3::ast::Real::new_const(&self.ctx, id)); | ||
132 | Float::from_handle(handle) | ||
133 | } | ||
134 | |||
135 | fn new_fixed_float(&mut self, value: f64) -> Float { | ||
136 | self.max_float_id += 1; | ||
137 | let id = self.max_float_id; | ||
138 | let handle = VariableHandle::new(id as usize); | ||
139 | |||
140 | let (num, den) = value_to_num_den(value); | ||
141 | |||
142 | self.floats | ||
143 | .insert(handle, z3::ast::Real::from_real(&self.ctx, num, den)); | ||
144 | Float::from_handle(handle) | ||
145 | } | ||
146 | |||
147 | // TODO: that's a lot of copying things | ||
148 | |||
149 | fn float_add(&mut self, values: &[Float]) -> Float { | ||
150 | let values = values.iter().map(|f| self.float(*f)).collect::<Vec<_>>(); | ||
151 | let result = z3::ast::Real::add( | ||
152 | self.ctx, | ||
153 | &values.iter().collect::<Vec<_>>() | ||
154 | ); | ||
155 | |||
156 | self.anon_float(result) | ||
157 | } | ||
158 | |||
159 | fn float_sub(&mut self, values: &[Float]) -> Float { | ||
160 | let values = values.iter().map(|f| self.float(*f)).collect::<Vec<_>>(); | ||
161 | let result = z3::ast::Real::sub( | ||
162 | self.ctx, | ||
163 | &values.iter().collect::<Vec<_>>() | ||
164 | ); | ||
165 | |||
166 | self.anon_float(result) | ||
167 | } | ||
168 | |||
169 | fn float_mul(&mut self, values: &[Float]) -> Float { | ||
170 | let values = values.iter().map(|f| self.float(*f)).collect::<Vec<_>>(); | ||
171 | let result = z3::ast::Real::mul( | ||
172 | self.ctx, | ||
173 | &values.iter().collect::<Vec<_>>() | ||
174 | ); | ||
175 | |||
176 | self.anon_float(result) | ||
177 | } | ||
178 | |||
179 | fn float_div(&mut self, lhs: Float, rhs: Float) -> Float { | ||
180 | let lhs = self.float(lhs); | ||
181 | let rhs = self.float(rhs); | ||
182 | let result = lhs.div(&rhs); | ||
183 | self.anon_float(result) | ||
184 | } | ||
185 | |||
186 | fn float_neg(&mut self, value: Float) -> Float { | ||
187 | self.anon_float(self.float(value).unary_minus()) | ||
188 | } | ||
189 | |||
190 | fn float_eq(&mut self, lhs: Float, rhs: Float) -> Bool { | ||
191 | let lhs = self.float(lhs); | ||
192 | let rhs = self.float(rhs); | ||
193 | let result = lhs._eq(&rhs); | ||
194 | self.anon_bool(result) | ||
195 | } | ||
196 | |||
197 | fn float_ne(&mut self, lhs: Float, rhs: Float) -> Bool { | ||
198 | let lhs = self.float(lhs); | ||
199 | let rhs = self.float(rhs); | ||
200 | let result = lhs._eq(&rhs).not(); | ||
201 | self.anon_bool(result) | ||
202 | } | ||
203 | |||
204 | fn float_gt(&mut self, lhs: Float, rhs: Float) -> Bool { | ||
205 | let lhs = self.float(lhs); | ||
206 | let rhs = self.float(rhs); | ||
207 | let result = lhs.gt(&rhs); | ||
208 | self.anon_bool(result) | ||
209 | } | ||
210 | |||
211 | fn float_ge(&mut self, lhs: Float, rhs: Float) -> Bool { | ||
212 | let lhs = self.float(lhs); | ||
213 | let rhs = self.float(rhs); | ||
214 | let result = lhs.ge(&rhs); | ||
215 | self.anon_bool(result) | ||
216 | } | ||
217 | |||
218 | fn float_lt(&mut self, lhs: Float, rhs: Float) -> Bool { | ||
219 | let lhs = self.float(lhs); | ||
220 | let rhs = self.float(rhs); | ||
221 | let result = lhs.lt(&rhs); | ||
222 | self.anon_bool(result) | ||
223 | } | ||
224 | |||
225 | fn float_le(&mut self, lhs: Float, rhs: Float) -> Bool { | ||
226 | let lhs = self.float(lhs); | ||
227 | let rhs = self.float(rhs); | ||
228 | let result = lhs.le(&rhs); | ||
229 | self.anon_bool(result) | ||
230 | } | ||
231 | |||
232 | // Bools | ||
233 | |||
234 | fn new_free_bool(&mut self) -> Bool { | ||
235 | self.max_bool_id += 1; | ||
236 | let id = self.max_bool_id; | ||
237 | let handle = VariableHandle::new(id as usize); | ||
238 | self.bools | ||
239 | .insert(handle, z3::ast::Bool::new_const(&self.ctx, id)); | ||
240 | Bool::new(handle) | ||
241 | } | ||
242 | |||
243 | fn new_fixed_bool(&mut self, value: bool) -> Bool { | ||
244 | self.max_bool_id += 1; | ||
245 | let id = self.max_bool_id; | ||
246 | let handle = VariableHandle::new(id as usize); | ||
247 | |||
248 | self.bools | ||
249 | .insert(handle, z3::ast::Bool::from_bool(&self.ctx, value)); | ||
250 | Bool::new(handle) | ||
251 | } | ||
252 | |||
253 | fn bool_eq(&mut self, lhs: Bool, rhs: Bool) -> Bool { | ||
254 | let lhs = self.bool(lhs); | ||
255 | let rhs = self.bool(rhs); | ||
256 | let result = lhs._eq(&rhs); | ||
257 | self.anon_bool(result) | ||
258 | } | ||
259 | |||
260 | fn bool_ne(&mut self, lhs: Bool, rhs: Bool) -> Bool { | ||
261 | let lhs = self.bool(lhs); | ||
262 | let rhs = self.bool(rhs); | ||
263 | let result = lhs._eq(&rhs).not(); | ||
264 | self.anon_bool(result) | ||
265 | } | ||
266 | |||
267 | fn bool_and(&mut self, values: &[Bool]) -> Bool { | ||
268 | let result = z3::ast::Bool::and( | ||
269 | self.ctx, | ||
270 | &values.iter().map(|b| self.bool(*b)).collect::<Vec<_>>(), | ||
271 | ); | ||
272 | |||
273 | self.anon_bool(result) | ||
274 | } | ||
275 | |||
276 | fn bool_or(&mut self, values: &[Bool]) -> Bool { | ||
277 | let result = z3::ast::Bool::or( | ||
278 | self.ctx, | ||
279 | &values.iter().map(|b| self.bool(*b)).collect::<Vec<_>>(), | ||
280 | ); | ||
281 | |||
282 | self.anon_bool(result) | ||
283 | } | ||
284 | |||
285 | fn bool_not(&mut self, value: Bool) -> Bool { | ||
286 | self.anon_bool(self.bool(value).not()) | ||
287 | } | ||
288 | |||
289 | fn bool_implies(&mut self, lhs: Bool, rhs: Bool) -> Bool { | ||
290 | let lhs = self.bool(lhs); | ||
291 | let rhs = self.bool(rhs); | ||
292 | let result = lhs.implies(rhs); | ||
293 | self.anon_bool(result) | ||
294 | } | ||
295 | } | ||
296 | |||
297 | pub struct Z3Model<'z3> { | ||
298 | ctx: &'z3 Z3Context<'z3>, | ||
299 | model: z3::Model<'z3>, | ||
300 | } | ||
301 | |||
302 | impl SolverModel for Z3Model<'_> { | ||
303 | fn eval_float(&self, f: Float) -> Option<f64> { | ||
304 | let handle = match f { | ||
305 | Float::Fixed(value) => return Some(value), | ||
306 | Float::Variable(handle) => handle, | ||
307 | }; | ||
308 | |||
309 | let (num, den) = self | ||
310 | .model | ||
311 | .eval::<z3::ast::Real>(self.ctx.floats.get(&handle).expect("Couldn't find float")) | ||
312 | .unwrap() | ||
313 | .as_real() | ||
314 | .unwrap(); | ||
315 | // TODO: handle errors | ||
316 | Some(num as f64 / den as f64) | ||
317 | } | ||
318 | |||
319 | fn eval_bool(&self, f: Bool) -> Option<bool> { | ||
320 | Some( | ||
321 | self.model | ||
322 | .eval::<z3::ast::Bool>(&self.ctx.bool(f)) | ||
323 | .unwrap() | ||
324 | .as_bool() | ||
325 | .unwrap(), | ||
326 | ) | ||
327 | // TODO: handle errors | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | use std::cell::RefCell; | ||
333 | use std::collections::HashMap; | ||
334 | use std::rc::Rc; | ||
335 | |||
336 | #[derive(Clone, Eq, PartialEq, Debug)] | ||
337 | pub struct Z3Float<'z3> { | ||
338 | id: u32, | ||
339 | real: z3::ast::Real<'z3>, | ||
340 | ctx: Z3Context<'z3>, | ||
341 | } | ||
342 | |||
343 | // TODO: try to remove this clone? | ||
344 | fn get_real<'z3>(f: &dyn VariableFloat, ctx: &Z3Context<'z3>) -> z3::ast::Real<'z3> { | ||
345 | let id = f.id() as u32; | ||
346 | ctx.0 | ||
347 | .borrow() | ||
348 | .floats | ||
349 | .get(&id) | ||
350 | .expect("Couldn't find float") | ||
351 | .clone() | ||
352 | } | ||
353 | |||
354 | impl<'z3> VariableFloat<'z3> for Z3Float<'z3> { | ||
355 | fn id(&self) -> usize { | ||
356 | self.id as usize | ||
357 | } | ||
358 | |||
359 | fn dyn_clone(&self) -> Box<dyn VariableFloat<'z3> + 'z3> { | ||
360 | Box::new(Z3Float { | ||
361 | id: self.id, | ||
362 | real: self.real.clone(), | ||
363 | ctx: self.ctx.clone(), | ||
364 | }) | ||
365 | } | ||
366 | |||
367 | fn eq(&self, other: &dyn VariableFloat) -> Bool<'z3> { | ||
368 | let other = get_real(other, &self.ctx); | ||
369 | let result = self.real._eq(&other); | ||
370 | let id = self.ctx.anon_bool(&result); | ||
371 | |||
372 | Bool::new(Box::new(Z3Bool { | ||
373 | id, | ||
374 | real: result, | ||
375 | ctx: self.ctx.clone(), | ||
376 | })) | ||
377 | } | ||
378 | |||
379 | fn neq(&self, other: &dyn VariableFloat) -> Bool<'z3> { | ||
380 | let other = get_real(other, &self.ctx); | ||
381 | let result = self.real._eq(&other).not(); | ||
382 | let id = self.ctx.anon_bool(&result); | ||
383 | |||
384 | Bool::new(Box::new(Z3Bool { | ||
385 | id, | ||
386 | real: result, | ||
387 | ctx: self.ctx.clone(), | ||
388 | })) | ||
389 | } | ||
390 | |||
391 | fn gt(&self, other: &dyn VariableFloat) -> Bool<'z3> { | ||
392 | let other = get_real(other, &self.ctx); | ||
393 | let result = self.real.gt(&other); | ||
394 | let id = self.ctx.anon_bool(&result); | ||
395 | |||
396 | Bool::new(Box::new(Z3Bool { | ||
397 | id, | ||
398 | real: result, | ||
399 | ctx: self.ctx.clone(), | ||
400 | })) | ||
401 | } | ||
402 | |||
403 | fn ge(&self, other: &dyn VariableFloat) -> Bool<'z3> { | ||
404 | let other = get_real(other, &self.ctx); | ||
405 | let result = self.real.ge(&other); | ||
406 | let id = self.ctx.anon_bool(&result); | ||
407 | |||
408 | Bool::new(Box::new(Z3Bool { | ||
409 | id, | ||
410 | real: result, | ||
411 | ctx: self.ctx.clone(), | ||
412 | })) | ||
413 | } | ||
414 | |||
415 | fn lt(&self, other: &dyn VariableFloat) -> Bool<'z3> { | ||
416 | let other = get_real(other, &self.ctx); | ||
417 | let result = self.real.lt(&other); | ||
418 | let id = self.ctx.anon_bool(&result); | ||
419 | |||
420 | Bool::new(Box::new(Z3Bool { | ||
421 | id, | ||
422 | real: result, | ||
423 | ctx: self.ctx.clone(), | ||
424 | })) | ||
425 | } | ||
426 | |||
427 | fn le(&self, other: &dyn VariableFloat) -> Bool<'z3> { | ||
428 | let other = get_real(other, &self.ctx); | ||
429 | let result = self.real.le(&other); | ||
430 | let id = self.ctx.anon_bool(&result); | ||
431 | |||
432 | Bool::new(Box::new(Z3Bool { | ||
433 | id, | ||
434 | real: result, | ||
435 | ctx: self.ctx.clone(), | ||
436 | })) | ||
437 | } | ||
438 | |||
439 | fn add(&self, other: &dyn VariableFloat) -> Float<'z3> { | ||
440 | let other = get_real(other, &self.ctx); | ||
441 | let result = &self.real + &other; | ||
442 | let id = self.ctx.anon_float(&result); | ||
443 | |||
444 | Float::new(Box::new(Z3Float { | ||
445 | id, | ||
446 | real: result, | ||
447 | ctx: self.ctx.clone(), | ||
448 | })) | ||
449 | } | ||
450 | |||
451 | fn sub(&self, other: &dyn VariableFloat) -> Float<'z3> { | ||
452 | let other = get_real(other, &self.ctx); | ||
453 | let result = &self.real - &other; | ||
454 | let id = self.ctx.anon_float(&result); | ||
455 | |||
456 | Float::new(Box::new(Z3Float { | ||
457 | id, | ||
458 | real: result, | ||
459 | ctx: self.ctx.clone(), | ||
460 | })) | ||
461 | } | ||
462 | |||
463 | fn mul(&self, other: &dyn VariableFloat) -> Float<'z3> { | ||
464 | let other = get_real(other, &self.ctx); | ||
465 | let result = &self.real * &other; | ||
466 | let id = self.ctx.anon_float(&result); | ||
467 | |||
468 | Float::new(Box::new(Z3Float { | ||
469 | id, | ||
470 | real: result, | ||
471 | ctx: self.ctx.clone(), | ||
472 | })) | ||
473 | } | ||
474 | |||
475 | fn div(&self, other: &dyn VariableFloat) -> Float<'z3> { | ||
476 | let other = get_real(other, &self.ctx); | ||
477 | let result = &self.real / &other; | ||
478 | let id = self.ctx.anon_float(&result); | ||
479 | |||
480 | Float::new(Box::new(Z3Float { | ||
481 | id, | ||
482 | real: result, | ||
483 | ctx: self.ctx.clone(), | ||
484 | })) | ||
485 | } | ||
486 | |||
487 | fn neg(&self) -> Float<'z3> { | ||
488 | let result = self.real.unary_minus(); | ||
489 | let id = self.ctx.anon_float(&result); | ||
490 | |||
491 | Float::new(Box::new(Z3Float { | ||
492 | id, | ||
493 | real: result, | ||
494 | ctx: self.ctx.clone(), | ||
495 | })) | ||
496 | } | ||
497 | } | ||
498 | |||
499 | #[derive(Clone, Eq, PartialEq, Debug)] | ||
500 | pub struct Z3Bool<'z3> { | ||
501 | id: u32, | ||
502 | real: z3::ast::Bool<'z3>, | ||
503 | ctx: Z3Context<'z3>, | ||
504 | } | ||
505 | |||
506 | // TODO: try to remove this clone? | ||
507 | fn get_bool<'z3>(f: &dyn VariableBool, ctx: &Z3Context<'z3>) -> z3::ast::Bool<'z3> { | ||
508 | let id = f.id() as u32; | ||
509 | ctx.0 | ||
510 | .borrow() | ||
511 | .bools | ||
512 | .get(&id) | ||
513 | .expect("Couldn't find bool") | ||
514 | .clone() | ||
515 | } | ||
516 | |||
517 | impl<'z3> VariableBool<'z3> for Z3Bool<'z3> { | ||
518 | fn id(&self) -> usize { | ||
519 | self.id as usize | ||
520 | } | ||
521 | |||
522 | fn dyn_clone(&self) -> Box<dyn VariableBool<'z3> + 'z3> { | ||
523 | Box::new(Z3Bool { | ||
524 | id: self.id, | ||
525 | real: self.real.clone(), | ||
526 | ctx: self.ctx.clone(), | ||
527 | }) | ||
528 | } | ||
529 | |||
530 | fn eq(&self, other: &dyn VariableBool) -> Bool<'z3> { | ||
531 | let other = get_bool(other, &self.ctx); | ||
532 | let result = self.real._eq(&other); | ||
533 | let id = self.ctx.anon_bool(&result); | ||
534 | |||
535 | Bool::new(Box::new(Z3Bool { | ||
536 | id, | ||
537 | real: result, | ||
538 | ctx: self.ctx.clone(), | ||
539 | })) | ||
540 | } | ||
541 | |||
542 | fn neq(&self, other: &dyn VariableBool) -> Bool<'z3> { | ||
543 | let other = get_bool(other, &self.ctx); | ||
544 | let result = self.real._eq(&other).not(); | ||
545 | let id = self.ctx.anon_bool(&result); | ||
546 | |||
547 | Bool::new(Box::new(Z3Bool { | ||
548 | id, | ||
549 | real: result, | ||
550 | ctx: self.ctx.clone(), | ||
551 | })) | ||
552 | } | ||
553 | |||
554 | fn and(&self, other: &dyn VariableBool) -> Bool<'z3> { | ||
555 | let other = get_bool(other, &self.ctx); | ||
556 | let result = &self.real & &other; | ||
557 | let id = self.ctx.anon_bool(&result); | ||
558 | |||
559 | Bool::new(Box::new(Z3Bool { | ||
560 | id, | ||
561 | real: result, | ||
562 | ctx: self.ctx.clone(), | ||
563 | })) | ||
564 | } | ||
565 | |||
566 | fn or(&self, other: &dyn VariableBool) -> Bool<'z3> { | ||
567 | let other = get_bool(other, &self.ctx); | ||
568 | let result = &self.real | &other; | ||
569 | let id = self.ctx.anon_bool(&result); | ||
570 | |||
571 | Bool::new(Box::new(Z3Bool { | ||
572 | id, | ||
573 | real: result, | ||
574 | ctx: self.ctx.clone(), | ||
575 | })) | ||
576 | } | ||
577 | |||
578 | fn not(&self) -> Bool<'z3> { | ||
579 | let result = self.real.not(); | ||
580 | let id = self.ctx.anon_bool(&result); | ||
581 | |||
582 | Bool::new(Box::new(Z3Bool { | ||
583 | id, | ||
584 | real: result, | ||
585 | ctx: self.ctx.clone(), | ||
586 | })) | ||
587 | } | ||
588 | } | ||
589 | |||
590 | #[derive(Clone, Eq, PartialEq, Debug)] | ||
591 | pub struct Z3Context<'z3>(Rc<RefCell<Z3ContextImpl<'z3>>>); | ||
592 | |||
593 | #[derive(Eq, PartialEq, Debug)] | ||
594 | pub struct Z3ContextImpl<'z3> { | ||
595 | ctx: z3::Context, | ||
596 | floats: HashMap<u32, z3::ast::Real<'z3>>, | ||
597 | max_float_id: u32, | ||
598 | bools: HashMap<u32, z3::ast::Bool<'z3>>, | ||
599 | max_bool_id: u32, | ||
600 | } | ||
601 | |||
602 | impl<'z3> Z3Context<'z3> { | ||
603 | pub fn new() -> Self { | ||
604 | let conf = z3::Config::new(); | ||
605 | let ctx = z3::Context::new(&conf); | ||
606 | Z3Context(Rc::new(RefCell::new(Z3ContextImpl { | ||
607 | ctx, | ||
608 | floats: HashMap::new(), | ||
609 | max_float_id: 0, | ||
610 | bools: HashMap::new(), | ||
611 | max_bool_id: 0, | ||
612 | }))) | ||
613 | } | ||
614 | |||
615 | fn anon_float(&self, f: &z3::ast::Real<'z3>) -> u32 { | ||
616 | let mut ctx = self.0.borrow_mut(); | ||
617 | |||
618 | ctx.max_float_id += 1; | ||
619 | let id = ctx.max_float_id; | ||
620 | ctx.floats.insert(id, f.clone()); | ||
621 | id | ||
622 | } | ||
623 | |||
624 | fn anon_bool(&self, f: &z3::ast::Bool<'z3>) -> u32 { | ||
625 | let mut ctx = self.0.borrow_mut(); | ||
626 | |||
627 | ctx.max_float_id += 1; | ||
628 | let id = ctx.max_float_id; | ||
629 | ctx.bools.insert(id, f.clone()); | ||
630 | id | ||
631 | } | ||
632 | } | ||
633 | |||
634 | impl<'z3> SolverContext<'z3> for Z3Context<'z3> { | ||
635 | fn new_float(&'z3 mut self) -> Box<dyn VariableFloat<'z3> + 'z3> { | ||
636 | let mut ctx: std::cell::RefMut<'z3, _> = self.0.borrow_mut(); | ||
637 | |||
638 | ctx.max_float_id += 1; | ||
639 | let id = ctx.max_float_id; | ||
640 | // :( | ||
641 | // Should be safe since the z3 context inside the RefCell of self cannot be dropped while | ||
642 | // the Box is still alive | ||
643 | let f = z3::ast::Real::new_const(unsafe { std::mem::transmute(&ctx.ctx) }, id); | ||
644 | ctx.floats.insert(id, f.clone()); | ||
645 | Box::new(Z3Float { | ||
646 | id, | ||
647 | real: f, | ||
648 | ctx: self.clone(), | ||
649 | }) | ||
650 | } | ||
651 | |||
652 | fn new_bool(&'z3 mut self) -> Box<dyn VariableBool<'z3> + 'z3> { | ||
653 | let mut ctx = self.0.borrow_mut(); | ||
654 | |||
655 | ctx.max_bool_id += 1; | ||
656 | let id = ctx.max_float_id; | ||
657 | // :( | ||
658 | // Should be safe since the z3 context inside the RefCell of self cannot be dropped while | ||
659 | // the Box is still alive | ||
660 | let b = z3::ast::Bool::new_const(unsafe { std::mem::transmute(&ctx.ctx) }, id); | ||
661 | ctx.bools.insert(id, b.clone()); | ||
662 | Box::new(Z3Bool { | ||
663 | id: id, | ||
664 | real: b, | ||
665 | ctx: self.clone(), | ||
666 | }) | ||
667 | } | ||
668 | } | ||
669 | |||
670 | pub struct Z3Solver<'z3>(z3::Solver<'z3>); | ||
671 | |||
672 | impl<'z3> Z3Solver<'z3> { | ||
673 | pub fn new(ctx: &'z3 Z3Context) -> Self { | ||
674 | Self(z3::Solver::new(unsafe { | ||
675 | // :( | ||
676 | // again | ||
677 | std::mem::transmute(&ctx.0.borrow().ctx) | ||
678 | })) | ||
679 | } | ||
680 | } | ||
681 | |||
682 | impl<'z3> Solver for Z3Solver<'z3> { | ||
683 | fn constrain(&mut self, assertion: &Bool) { | ||
684 | todo!() | ||
685 | } | ||
686 | |||
687 | fn solve(&self) -> Box<dyn SolverModel> { | ||
688 | todo!() | ||
689 | } | ||
690 | } | ||
691 | */ | ||
diff --git a/z3-solver/src/solving/mod.rs b/z3-solver/src/solving/mod.rs new file mode 100644 index 0000000..f3f6673 --- /dev/null +++ b/z3-solver/src/solving/mod.rs | |||
@@ -0,0 +1,9 @@ | |||
1 | pub mod z3; | ||
2 | |||
3 | #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] | ||
4 | pub struct FloatHandle(u32); | ||
5 | |||
6 | pub trait Solver { | ||
7 | // TODO: make handles generic? | ||
8 | fn new_float<'a>(&'a mut self, handles: &mut z3::Handles<'a>) -> FloatHandle; | ||
9 | } | ||
diff --git a/z3-solver/src/solving/z3/mod.rs b/z3-solver/src/solving/z3/mod.rs new file mode 100644 index 0000000..2f29073 --- /dev/null +++ b/z3-solver/src/solving/z3/mod.rs | |||
@@ -0,0 +1,44 @@ | |||
1 | use super::{Solver, FloatHandle}; | ||
2 | |||
3 | use std::collections::HashMap; | ||
4 | |||
5 | pub struct Z3Solver { | ||
6 | ctx: z3::Context, | ||
7 | } | ||
8 | |||
9 | pub struct Handles<'a> { | ||
10 | float: HashMap<u32, z3::ast::Real<'a>>, | ||
11 | float_max_id: u32, | ||
12 | } | ||
13 | |||
14 | impl<'a> Handles<'a> { | ||
15 | pub fn new() -> Self { | ||
16 | Self { | ||
17 | float: HashMap::new(), | ||
18 | float_max_id: 0, | ||
19 | } | ||
20 | } | ||
21 | } | ||
22 | |||
23 | impl Z3Solver { | ||
24 | pub fn new<'a>() -> (Self, Handles<'a>) { | ||
25 | let config = z3::Config::new(); | ||
26 | |||
27 | ( | ||
28 | Self { | ||
29 | ctx: z3::Context::new(&config), | ||
30 | }, | ||
31 | Handles::new(), | ||
32 | ) | ||
33 | } | ||
34 | } | ||
35 | |||
36 | impl Solver for Z3Solver { | ||
37 | fn new_float<'a>(&'a mut self, handles: &mut Handles<'a>) -> FloatHandle { | ||
38 | let id = handles.float_max_id; | ||
39 | let float = z3::ast::Real::new_const(&self.ctx, id); | ||
40 | handles.float_max_id += 1; | ||
41 | handles.float.insert(id, float); | ||
42 | FloatHandle(id) | ||
43 | } | ||
44 | } | ||