diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..60492e63 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +!public/svgnest/** diff --git a/public/svgnest b/public/svgnest deleted file mode 160000 index 1248dc21..00000000 --- a/public/svgnest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1248dc21efd3f90d1aa52ba5785e27e5217ed2c9 diff --git a/public/svgnest/LICENSE.txt b/public/svgnest/LICENSE.txt new file mode 100644 index 00000000..885e0602 --- /dev/null +++ b/public/svgnest/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Jack Qiao + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/public/svgnest/favicon16.gif b/public/svgnest/favicon16.gif new file mode 100644 index 00000000..cfe824bb Binary files /dev/null and b/public/svgnest/favicon16.gif differ diff --git a/public/svgnest/favicon32.gif b/public/svgnest/favicon32.gif new file mode 100644 index 00000000..b4144128 Binary files /dev/null and b/public/svgnest/favicon32.gif differ diff --git a/public/svgnest/font/fonts/LatoLatin-Bold.eot b/public/svgnest/font/fonts/LatoLatin-Bold.eot new file mode 100644 index 00000000..d90b47b8 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Bold.eot differ diff --git a/public/svgnest/font/fonts/LatoLatin-Bold.ttf b/public/svgnest/font/fonts/LatoLatin-Bold.ttf new file mode 100644 index 00000000..c598c24a Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Bold.ttf differ diff --git a/public/svgnest/font/fonts/LatoLatin-Bold.woff b/public/svgnest/font/fonts/LatoLatin-Bold.woff new file mode 100644 index 00000000..cdfcbe0f Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Bold.woff differ diff --git a/public/svgnest/font/fonts/LatoLatin-Bold.woff2 b/public/svgnest/font/fonts/LatoLatin-Bold.woff2 new file mode 100644 index 00000000..2615c853 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Bold.woff2 differ diff --git a/public/svgnest/font/fonts/LatoLatin-BoldItalic.eot b/public/svgnest/font/fonts/LatoLatin-BoldItalic.eot new file mode 100644 index 00000000..17216efe Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-BoldItalic.eot differ diff --git a/public/svgnest/font/fonts/LatoLatin-BoldItalic.ttf b/public/svgnest/font/fonts/LatoLatin-BoldItalic.ttf new file mode 100644 index 00000000..c1f225af Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-BoldItalic.ttf differ diff --git a/public/svgnest/font/fonts/LatoLatin-BoldItalic.woff b/public/svgnest/font/fonts/LatoLatin-BoldItalic.woff new file mode 100644 index 00000000..3e683fea Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-BoldItalic.woff differ diff --git a/public/svgnest/font/fonts/LatoLatin-BoldItalic.woff2 b/public/svgnest/font/fonts/LatoLatin-BoldItalic.woff2 new file mode 100644 index 00000000..f7bace13 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-BoldItalic.woff2 differ diff --git a/public/svgnest/font/fonts/LatoLatin-Light.eot b/public/svgnest/font/fonts/LatoLatin-Light.eot new file mode 100644 index 00000000..865537d9 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Light.eot differ diff --git a/public/svgnest/font/fonts/LatoLatin-Light.ttf b/public/svgnest/font/fonts/LatoLatin-Light.ttf new file mode 100644 index 00000000..6af1b85d Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Light.ttf differ diff --git a/public/svgnest/font/fonts/LatoLatin-Light.woff b/public/svgnest/font/fonts/LatoLatin-Light.woff new file mode 100644 index 00000000..e7d4278c Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Light.woff differ diff --git a/public/svgnest/font/fonts/LatoLatin-Light.woff2 b/public/svgnest/font/fonts/LatoLatin-Light.woff2 new file mode 100644 index 00000000..b6d02883 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Light.woff2 differ diff --git a/public/svgnest/font/fonts/LatoLatin-Regular.eot b/public/svgnest/font/fonts/LatoLatin-Regular.eot new file mode 100644 index 00000000..96a90359 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Regular.eot differ diff --git a/public/svgnest/font/fonts/LatoLatin-Regular.ttf b/public/svgnest/font/fonts/LatoLatin-Regular.ttf new file mode 100644 index 00000000..bcc57780 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Regular.ttf differ diff --git a/public/svgnest/font/fonts/LatoLatin-Regular.woff b/public/svgnest/font/fonts/LatoLatin-Regular.woff new file mode 100644 index 00000000..bf73a6d9 Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Regular.woff differ diff --git a/public/svgnest/font/fonts/LatoLatin-Regular.woff2 b/public/svgnest/font/fonts/LatoLatin-Regular.woff2 new file mode 100644 index 00000000..a4d084bf Binary files /dev/null and b/public/svgnest/font/fonts/LatoLatin-Regular.woff2 differ diff --git a/public/svgnest/font/generator_config.txt b/public/svgnest/font/generator_config.txt new file mode 100644 index 00000000..01937678 --- /dev/null +++ b/public/svgnest/font/generator_config.txt @@ -0,0 +1,5 @@ +# Font Squirrel Font-face Generator Configuration File +# Upload this file to the generator to recreate the settings +# you used to create these fonts. + +{"mode":"optimal","formats":["ttf","woff","eotz"],"tt_instructor":"default","fix_vertical_metrics":"Y","fix_gasp":"xy","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","subset_ot_features_list":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"} \ No newline at end of file diff --git a/public/svgnest/font/lato-hai-demo.html b/public/svgnest/font/lato-hai-demo.html new file mode 100644 index 00000000..d7cd23f1 --- /dev/null +++ b/public/svgnest/font/lato-hai-demo.html @@ -0,0 +1,612 @@ + + + + + + + + + + + + + Lato Hairline Regular Specimen + + + + + + +
+ + + +
+ + +
+ +
+
+
AaBb
+
+
+ +
+
A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;
+
+
+
+ + + + + + + + + + + + + + + + +
10abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
11abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
12abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
13abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
14abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
16abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
18abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
20abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
24abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
30abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
36abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
48abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
60abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
72abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
90abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ +
+ +
+ + + +
+ + +
+
◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body
body
body
body
+
+ bodyLato Hairline Regular +
+
+ bodyArial +
+
+ bodyVerdana +
+
+ bodyGeorgia +
+ + + +
+ + +
+ +
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+ +
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + +
+
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + + +
+ +
+ +
+ +
+

Lorem Ipsum Dolor

+

Etiam porta sem malesuada magna mollis euismod

+ + +
+
+
+
+

Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

+ + +

Pellentesque ornare sem

+ +

Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

+ +

Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur.

+ +

Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla.

+ +

Cras mattis consectetur

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum.

+ +

Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.

+
+ + +
+ +
+ + + + + + +
+
+
+ +

Language Support

+

The subset of Lato Hairline Regular in this kit supports the following languages:
+ + Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Swedish

+

Glyph Chart

+

The subset of Lato Hairline Regular in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.

+
+ +



+

 

+

!

!
+

"

"
+

#

#
+

$

$
+

%

%
+

&

&
+

'

'
+

(

(
+

)

)
+

*

*
+

+

+
+

,

,
+

-

-
+

.

.
+

/

/
+

0

0
+

1

1
+

2

2
+

3

3
+

4

4
+

5

5
+

6

6
+

7

7
+

8

8
+

9

9
+

:

:
+

&#59;

;
+

<

<
+

&#61;

=
+

&#62;

>
+

&#63;

?
+

&#64;

@
+

&#65;

A
+

&#66;

B
+

&#67;

C
+

&#68;

D
+

&#69;

E
+

&#70;

F
+

&#71;

G
+

&#72;

H
+

&#73;

I
+

&#74;

J
+

&#75;

K
+

&#76;

L
+

&#77;

M
+

&#78;

N
+

&#79;

O
+

&#80;

P
+

&#81;

Q
+

&#82;

R
+

&#83;

S
+

&#84;

T
+

&#85;

U
+

&#86;

V
+

&#87;

W
+

&#88;

X
+

&#89;

Y
+

&#90;

Z
+

&#91;

[
+

&#92;

\
+

&#93;

]
+

&#94;

^
+

&#95;

_
+

&#96;

`
+

&#97;

a
+

&#98;

b
+

&#99;

c
+

&#100;

d
+

&#101;

e
+

&#102;

f
+

&#103;

g
+

&#104;

h
+

&#105;

i
+

&#106;

j
+

&#107;

k
+

&#108;

l
+

&#109;

m
+

&#110;

n
+

&#111;

o
+

&#112;

p
+

&#113;

q
+

&#114;

r
+

&#115;

s
+

&#116;

t
+

&#117;

u
+

&#118;

v
+

&#119;

w
+

&#120;

x
+

&#121;

y
+

&#122;

z
+

&#123;

{
+

&#124;

|
+

&#125;

}
+

&#126;

~
+

&#160;

 
+

&#161;

¡
+

&#162;

¢
+

&#163;

£
+

&#164;

¤
+

&#165;

¥
+

&#166;

¦
+

&#167;

§
+

&#168;

¨
+

&#169;

©
+

&#170;

ª
+

&#171;

«
+

&#172;

¬
+

&#173;

­
+

&#174;

®
+

&#175;

¯
+

&#176;

°
+

&#177;

±
+

&#178;

²
+

&#179;

³
+

&#180;

´
+

&#181;

µ
+

&#182;

+

&#183;

·
+

&#184;

¸
+

&#185;

¹
+

&#186;

º
+

&#187;

»
+

&#188;

¼
+

&#189;

½
+

&#190;

¾
+

&#191;

¿
+

&#192;

À
+

&#193;

Á
+

&#194;

Â
+

&#195;

Ã
+

&#196;

Ä
+

&#197;

Å
+

&#198;

Æ
+

&#199;

Ç
+

&#200;

È
+

&#201;

É
+

&#202;

Ê
+

&#203;

Ë
+

&#204;

Ì
+

&#205;

Í
+

&#206;

Î
+

&#207;

Ï
+

&#208;

Ð
+

&#209;

Ñ
+

&#210;

Ò
+

&#211;

Ó
+

&#212;

Ô
+

&#213;

Õ
+

&#214;

Ö
+

&#215;

×
+

&#216;

Ø
+

&#217;

Ù
+

&#218;

Ú
+

&#219;

Û
+

&#220;

Ü
+

&#221;

Ý
+

&#222;

Þ
+

&#223;

ß
+

&#224;

à
+

&#225;

á
+

&#226;

â
+

&#227;

ã
+

&#228;

ä
+

&#229;

å
+

&#230;

æ
+

&#231;

ç
+

&#232;

è
+

&#233;

é
+

&#234;

ê
+

&#235;

ë
+

&#236;

ì
+

&#237;

í
+

&#238;

î
+

&#239;

ï
+

&#240;

ð
+

&#241;

ñ
+

&#242;

ò
+

&#243;

ó
+

&#244;

ô
+

&#245;

õ
+

&#246;

ö
+

&#247;

÷
+

&#248;

ø
+

&#249;

ù
+

&#250;

ú
+

&#251;

û
+

&#252;

ü
+

&#253;

ý
+

&#254;

þ
+

&#255;

ÿ
+

&#338;

Œ
+

&#339;

œ
+

&#376;

Ÿ
+

&#710;

ˆ
+

&#732;

˜
+

&#8192;

 
+

&#8193;

+

&#8194;

+

&#8195;

+

&#8196;

+

&#8197;

+

&#8198;

+

&#8199;

+

&#8200;

+

&#8201;

+

&#8202;

+

&#8208;

+

&#8209;

+

&#8210;

+

&#8211;

+

&#8212;

+

&#8216;

+

&#8217;

+

&#8218;

+

&#8220;

+

&#8221;

+

&#8222;

+

&#8226;

+

&#8230;

+

&#8239;

+

&#8249;

+

&#8250;

+

&#8287;

+

&#8364;

+

&#8482;

+

&#9724;

+

&#64257;

+

&#64258;

+
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Installing Webfonts

+ +

Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.

+ +

1. Upload your webfonts

+

You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.

+ +

2. Include the webfont stylesheet

+

A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the Fontspring blog post about it. The code for it is as follows:

+ + + +@font-face{ + font-family: 'MyWebFont'; + src: url('WebFont.eot'); + src: url('WebFont.eot?#iefix') format('embedded-opentype'), + url('WebFont.woff') format('woff'), + url('WebFont.ttf') format('truetype'), + url('WebFont.svg#webfont') format('svg'); +} + + +

We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:

+ <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /> + +

3. Modify your own stylesheet

+

To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:

+p { font-family: 'WebFont', Arial, sans-serif; } + +

4. Test

+

Getting webfonts to work cross-browser can be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.

+
+ + +
+ +
+ +
+ +
+ + diff --git a/public/svgnest/font/lato-hai-webfont.eot b/public/svgnest/font/lato-hai-webfont.eot new file mode 100644 index 00000000..bf259266 Binary files /dev/null and b/public/svgnest/font/lato-hai-webfont.eot differ diff --git a/public/svgnest/font/lato-hai-webfont.svg b/public/svgnest/font/lato-hai-webfont.svg new file mode 100644 index 00000000..4fb4b778 --- /dev/null +++ b/public/svgnest/font/lato-hai-webfont.svg @@ -0,0 +1,4241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/svgnest/font/lato-hai-webfont.ttf b/public/svgnest/font/lato-hai-webfont.ttf new file mode 100644 index 00000000..b420b858 Binary files /dev/null and b/public/svgnest/font/lato-hai-webfont.ttf differ diff --git a/public/svgnest/font/lato-hai-webfont.woff b/public/svgnest/font/lato-hai-webfont.woff new file mode 100644 index 00000000..02328f3a Binary files /dev/null and b/public/svgnest/font/lato-hai-webfont.woff differ diff --git a/public/svgnest/font/lato-lig-demo.html b/public/svgnest/font/lato-lig-demo.html new file mode 100644 index 00000000..f6c074b8 --- /dev/null +++ b/public/svgnest/font/lato-lig-demo.html @@ -0,0 +1,612 @@ + + + + + + + + + + + + + Lato Light Regular Specimen + + + + + + +
+ + + +
+ + +
+ +
+
+
AaBb
+
+
+ +
+
A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;
+
+
+
+ + + + + + + + + + + + + + + + +
10abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
11abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
12abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
13abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
14abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
16abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
18abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
20abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
24abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
30abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
36abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
48abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
60abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
72abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
90abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ +
+ +
+ + + +
+ + +
+
◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body
body
body
body
+
+ bodyLato Light Regular +
+
+ bodyArial +
+
+ bodyVerdana +
+
+ bodyGeorgia +
+ + + +
+ + +
+ +
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+ +
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + +
+
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + + +
+ +
+ +
+ +
+

Lorem Ipsum Dolor

+

Etiam porta sem malesuada magna mollis euismod

+ + +
+
+
+
+

Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

+ + +

Pellentesque ornare sem

+ +

Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

+ +

Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur.

+ +

Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla.

+ +

Cras mattis consectetur

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum.

+ +

Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.

+
+ + +
+ +
+ + + + + + +
+
+
+ +

Language Support

+

The subset of Lato Light Regular in this kit supports the following languages:
+ + Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Swedish

+

Glyph Chart

+

The subset of Lato Light Regular in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.

+
+ +

&#13;

+

&#32;

+

&#33;

!
+

&#34;

"
+

&#35;

#
+

&#36;

$
+

&#37;

%
+

&#38;

&
+

&#39;

'
+

&#40;

(
+

&#41;

)
+

&#42;

*
+

&#43;

+
+

&#44;

,
+

&#45;

-
+

&#46;

.
+

&#47;

/
+

&#48;

0
+

&#49;

1
+

&#50;

2
+

&#51;

3
+

&#52;

4
+

&#53;

5
+

&#54;

6
+

&#55;

7
+

&#56;

8
+

&#57;

9
+

&#58;

:
+

&#59;

;
+

&#60;

<
+

&#61;

=
+

&#62;

>
+

&#63;

?
+

&#64;

@
+

&#65;

A
+

&#66;

B
+

&#67;

C
+

&#68;

D
+

&#69;

E
+

&#70;

F
+

&#71;

G
+

&#72;

H
+

&#73;

I
+

&#74;

J
+

&#75;

K
+

&#76;

L
+

&#77;

M
+

&#78;

N
+

&#79;

O
+

&#80;

P
+

&#81;

Q
+

&#82;

R
+

&#83;

S
+

&#84;

T
+

&#85;

U
+

&#86;

V
+

&#87;

W
+

&#88;

X
+

&#89;

Y
+

&#90;

Z
+

&#91;

[
+

&#92;

\
+

&#93;

]
+

&#94;

^
+

&#95;

_
+

&#96;

`
+

&#97;

a
+

&#98;

b
+

&#99;

c
+

&#100;

d
+

&#101;

e
+

&#102;

f
+

&#103;

g
+

&#104;

h
+

&#105;

i
+

&#106;

j
+

&#107;

k
+

&#108;

l
+

&#109;

m
+

&#110;

n
+

&#111;

o
+

&#112;

p
+

&#113;

q
+

&#114;

r
+

&#115;

s
+

&#116;

t
+

&#117;

u
+

&#118;

v
+

&#119;

w
+

&#120;

x
+

&#121;

y
+

&#122;

z
+

&#123;

{
+

&#124;

|
+

&#125;

}
+

&#126;

~
+

&#160;

 
+

&#161;

¡
+

&#162;

¢
+

&#163;

£
+

&#164;

¤
+

&#165;

¥
+

&#166;

¦
+

&#167;

§
+

&#168;

¨
+

&#169;

©
+

&#170;

ª
+

&#171;

«
+

&#172;

¬
+

&#173;

­
+

&#174;

®
+

&#175;

¯
+

&#176;

°
+

&#177;

±
+

&#178;

²
+

&#179;

³
+

&#180;

´
+

&#181;

µ
+

&#182;

+

&#183;

·
+

&#184;

¸
+

&#185;

¹
+

&#186;

º
+

&#187;

»
+

&#188;

¼
+

&#189;

½
+

&#190;

¾
+

&#191;

¿
+

&#192;

À
+

&#193;

Á
+

&#194;

Â
+

&#195;

Ã
+

&#196;

Ä
+

&#197;

Å
+

&#198;

Æ
+

&#199;

Ç
+

&#200;

È
+

&#201;

É
+

&#202;

Ê
+

&#203;

Ë
+

&#204;

Ì
+

&#205;

Í
+

&#206;

Î
+

&#207;

Ï
+

&#208;

Ð
+

&#209;

Ñ
+

&#210;

Ò
+

&#211;

Ó
+

&#212;

Ô
+

&#213;

Õ
+

&#214;

Ö
+

&#215;

×
+

&#216;

Ø
+

&#217;

Ù
+

&#218;

Ú
+

&#219;

Û
+

&#220;

Ü
+

&#221;

Ý
+

&#222;

Þ
+

&#223;

ß
+

&#224;

à
+

&#225;

á
+

&#226;

â
+

&#227;

ã
+

&#228;

ä
+

&#229;

å
+

&#230;

æ
+

&#231;

ç
+

&#232;

è
+

&#233;

é
+

&#234;

ê
+

&#235;

ë
+

&#236;

ì
+

&#237;

í
+

&#238;

î
+

&#239;

ï
+

&#240;

ð
+

&#241;

ñ
+

&#242;

ò
+

&#243;

ó
+

&#244;

ô
+

&#245;

õ
+

&#246;

ö
+

&#247;

÷
+

&#248;

ø
+

&#249;

ù
+

&#250;

ú
+

&#251;

û
+

&#252;

ü
+

&#253;

ý
+

&#254;

þ
+

&#255;

ÿ
+

&#338;

Œ
+

&#339;

œ
+

&#376;

Ÿ
+

&#710;

ˆ
+

&#732;

˜
+

&#8192;

 
+

&#8193;

+

&#8194;

+

&#8195;

+

&#8196;

+

&#8197;

+

&#8198;

+

&#8199;

+

&#8200;

+

&#8201;

+

&#8202;

+

&#8208;

+

&#8209;

+

&#8210;

+

&#8211;

+

&#8212;

+

&#8216;

+

&#8217;

+

&#8218;

+

&#8220;

+

&#8221;

+

&#8222;

+

&#8226;

+

&#8230;

+

&#8239;

+

&#8249;

+

&#8250;

+

&#8287;

+

&#8364;

+

&#8482;

+

&#9724;

+

&#64257;

+

&#64258;

+
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Installing Webfonts

+ +

Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.

+ +

1. Upload your webfonts

+

You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.

+ +

2. Include the webfont stylesheet

+

A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the Fontspring blog post about it. The code for it is as follows:

+ + + +@font-face{ + font-family: 'MyWebFont'; + src: url('WebFont.eot'); + src: url('WebFont.eot?#iefix') format('embedded-opentype'), + url('WebFont.woff') format('woff'), + url('WebFont.ttf') format('truetype'), + url('WebFont.svg#webfont') format('svg'); +} + + +

We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:

+ <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /> + +

3. Modify your own stylesheet

+

To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:

+p { font-family: 'WebFont', Arial, sans-serif; } + +

4. Test

+

Getting webfonts to work cross-browser can be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.

+
+ + +
+ +
+ +
+ +
+ + diff --git a/public/svgnest/font/lato-lig-webfont.eot b/public/svgnest/font/lato-lig-webfont.eot new file mode 100644 index 00000000..896fe86b Binary files /dev/null and b/public/svgnest/font/lato-lig-webfont.eot differ diff --git a/public/svgnest/font/lato-lig-webfont.svg b/public/svgnest/font/lato-lig-webfont.svg new file mode 100644 index 00000000..7cf9c924 --- /dev/null +++ b/public/svgnest/font/lato-lig-webfont.svg @@ -0,0 +1,4241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/svgnest/font/lato-lig-webfont.ttf b/public/svgnest/font/lato-lig-webfont.ttf new file mode 100644 index 00000000..08bcb343 Binary files /dev/null and b/public/svgnest/font/lato-lig-webfont.ttf differ diff --git a/public/svgnest/font/lato-lig-webfont.woff b/public/svgnest/font/lato-lig-webfont.woff new file mode 100644 index 00000000..e94b97c8 Binary files /dev/null and b/public/svgnest/font/lato-lig-webfont.woff differ diff --git a/public/svgnest/font/latolatinfonts.css b/public/svgnest/font/latolatinfonts.css new file mode 100644 index 00000000..35ac106d --- /dev/null +++ b/public/svgnest/font/latolatinfonts.css @@ -0,0 +1,35 @@ +/* Webfont: LatoLatin-Bold */@font-face { + font-family: 'LatoLatinWeb'; + src: url('fonts/LatoLatin-Bold.eot'); /* IE9 Compat Modes */ + src: url('fonts/LatoLatin-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('fonts/LatoLatin-Bold.woff2') format('woff2'), /* Modern Browsers */ + url('fonts/LatoLatin-Bold.woff') format('woff'), /* Modern Browsers */ + url('fonts/LatoLatin-Bold.ttf') format('truetype'); + font-style: normal; + font-weight: bold; + text-rendering: optimizeLegibility; +} + +/* Webfont: LatoLatin-Regular */@font-face { + font-family: 'LatoLatinWeb'; + src: url('fonts/LatoLatin-Regular.eot'); /* IE9 Compat Modes */ + src: url('fonts/LatoLatin-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('fonts/LatoLatin-Regular.woff2') format('woff2'), /* Modern Browsers */ + url('fonts/LatoLatin-Regular.woff') format('woff'), /* Modern Browsers */ + url('fonts/LatoLatin-Regular.ttf') format('truetype'); + font-style: normal; + font-weight: normal; + text-rendering: optimizeLegibility; +} + +/* Webfont: LatoLatin-Light */@font-face { + font-family: 'LatoLatinWebLight'; + src: url('fonts/LatoLatin-Light.eot'); /* IE9 Compat Modes */ + src: url('fonts/LatoLatin-Light.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('fonts/LatoLatin-Light.woff2') format('woff2'), /* Modern Browsers */ + url('fonts/LatoLatin-Light.woff') format('woff'), /* Modern Browsers */ + url('fonts/LatoLatin-Light.ttf') format('truetype'); + font-style: normal; + font-weight: normal; + text-rendering: optimizeLegibility; +} \ No newline at end of file diff --git a/public/svgnest/font/specimen_files/easytabs.js b/public/svgnest/font/specimen_files/easytabs.js new file mode 100644 index 00000000..167f53b7 --- /dev/null +++ b/public/svgnest/font/specimen_files/easytabs.js @@ -0,0 +1,7 @@ +(function($){$.fn.easyTabs=function(option){var param=jQuery.extend({fadeSpeed:"fast",defaultContent:1,activeClass:'active'},option);$(this).each(function(){var thisId="#"+this.id;if(param.defaultContent==''){param.defaultContent=1;} +if(typeof param.defaultContent=="number") +{var defaultTab=$(thisId+" .tabs li:eq("+(param.defaultContent-1)+") a").attr('href').substr(1);}else{var defaultTab=param.defaultContent;} +$(thisId+" .tabs li a").each(function(){var tabToHide=$(this).attr('href').substr(1);$("#"+tabToHide).addClass('easytabs-tab-content');});hideAll();changeContent(defaultTab);function hideAll(){$(thisId+" .easytabs-tab-content").hide();} +function changeContent(tabId){hideAll();$(thisId+" .tabs li").removeClass(param.activeClass);$(thisId+" .tabs li a[href=#"+tabId+"]").closest('li').addClass(param.activeClass);if(param.fadeSpeed!="none") +{$(thisId+" #"+tabId).fadeIn(param.fadeSpeed);}else{$(thisId+" #"+tabId).show();}} +$(thisId+" .tabs li").click(function(){var tabId=$(this).find('a').attr('href').substr(1);changeContent(tabId);return false;});});}})(jQuery); \ No newline at end of file diff --git a/public/svgnest/font/specimen_files/grid_12-825-55-15.css b/public/svgnest/font/specimen_files/grid_12-825-55-15.css new file mode 100644 index 00000000..3d6aef78 --- /dev/null +++ b/public/svgnest/font/specimen_files/grid_12-825-55-15.css @@ -0,0 +1,129 @@ +/*Notes about grid: +Columns: 12 +Grid Width: 825px +Column Width: 55px +Gutter Width: 15px +-------------------------------*/ + + + +.section {margin-bottom: 18px; +} +.section:after {content: ".";display: block;height: 0;clear: both;visibility: hidden;} +.section {*zoom: 1;} + +.section .firstcolumn, +.section .firstcol {margin-left: 0;} + + +/* Border on left hand side of a column. */ +.border { + padding-left: 7px; + margin-left: 7px; + border-left: 1px solid #eee; +} + +/* Border with more whitespace, spans one column. */ +.colborder { + padding-left: 42px; + margin-left: 42px; + border-left: 1px solid #eee; +} + + + +/* The Grid Classes */ +.grid1, .grid1_2cols, .grid1_3cols, .grid1_4cols, .grid2, .grid2_3cols, .grid2_4cols, .grid3, .grid3_2cols, .grid3_4cols, .grid4, .grid4_3cols, .grid5, .grid5_2cols, .grid5_3cols, .grid5_4cols, .grid6, .grid6_4cols, .grid7, .grid7_2cols, .grid7_3cols, .grid7_4cols, .grid8, .grid8_3cols, .grid9, .grid9_2cols, .grid9_4cols, .grid10, .grid10_3cols, .grid10_4cols, .grid11, .grid11_2cols, .grid11_3cols, .grid11_4cols, .grid12 +{margin-left: 15px;float: left;display: inline; overflow: hidden;} + + +.width1, .grid1, .span-1 {width: 55px;} +.width1_2cols,.grid1_2cols {width: 20px;} +.width1_3cols,.grid1_3cols {width: 8px;} +.width1_4cols,.grid1_4cols {width: 2px;} +.input_width1 {width: 49px;} + +.width2, .grid2, .span-2 {width: 125px;} +.width2_3cols,.grid2_3cols {width: 31px;} +.width2_4cols,.grid2_4cols {width: 20px;} +.input_width2 {width: 119px;} + +.width3, .grid3, .span-3 {width: 195px;} +.width3_2cols,.grid3_2cols {width: 90px;} +.width3_4cols,.grid3_4cols {width: 37px;} +.input_width3 {width: 189px;} + +.width4, .grid4, .span-4 {width: 265px;} +.width4_3cols,.grid4_3cols {width: 78px;} +.input_width4 {width: 259px;} + +.width5, .grid5, .span-5 {width: 335px;} +.width5_2cols,.grid5_2cols {width: 160px;} +.width5_3cols,.grid5_3cols {width: 101px;} +.width5_4cols,.grid5_4cols {width: 72px;} +.input_width5 {width: 329px;} + +.width6, .grid6, .span-6 {width: 405px;} +.width6_4cols,.grid6_4cols {width: 90px;} +.input_width6 {width: 399px;} + +.width7, .grid7, .span-7 {width: 475px;} +.width7_2cols,.grid7_2cols {width: 230px;} +.width7_3cols,.grid7_3cols {width: 148px;} +.width7_4cols,.grid7_4cols {width: 107px;} +.input_width7 {width: 469px;} + +.width8, .grid8, .span-8 {width: 545px;} +.width8_3cols,.grid8_3cols {width: 171px;} +.input_width8 {width: 539px;} + +.width9, .grid9, .span-9 {width: 615px;} +.width9_2cols,.grid9_2cols {width: 300px;} +.width9_4cols,.grid9_4cols {width: 142px;} +.input_width9 {width: 609px;} + +.width10, .grid10, .span-10 {width: 685px;} +.width10_3cols,.grid10_3cols {width: 218px;} +.width10_4cols,.grid10_4cols {width: 160px;} +.input_width10 {width: 679px;} + +.width11, .grid11, .span-11 {width: 755px;} +.width11_2cols,.grid11_2cols {width: 370px;} +.width11_3cols,.grid11_3cols {width: 241px;} +.width11_4cols,.grid11_4cols {width: 177px;} +.input_width11 {width: 749px;} + +.width12, .grid12, .span-12 {width: 825px;} +.input_width12 {width: 819px;} + +/* Subdivided grid spaces */ +.emptycols_left1, .prepend-1 {padding-left: 70px;} +.emptycols_right1, .append-1 {padding-right: 70px;} +.emptycols_left2, .prepend-2 {padding-left: 140px;} +.emptycols_right2, .append-2 {padding-right: 140px;} +.emptycols_left3, .prepend-3 {padding-left: 210px;} +.emptycols_right3, .append-3 {padding-right: 210px;} +.emptycols_left4, .prepend-4 {padding-left: 280px;} +.emptycols_right4, .append-4 {padding-right: 280px;} +.emptycols_left5, .prepend-5 {padding-left: 350px;} +.emptycols_right5, .append-5 {padding-right: 350px;} +.emptycols_left6, .prepend-6 {padding-left: 420px;} +.emptycols_right6, .append-6 {padding-right: 420px;} +.emptycols_left7, .prepend-7 {padding-left: 490px;} +.emptycols_right7, .append-7 {padding-right: 490px;} +.emptycols_left8, .prepend-8 {padding-left: 560px;} +.emptycols_right8, .append-8 {padding-right: 560px;} +.emptycols_left9, .prepend-9 {padding-left: 630px;} +.emptycols_right9, .append-9 {padding-right: 630px;} +.emptycols_left10, .prepend-10 {padding-left: 700px;} +.emptycols_right10, .append-10 {padding-right: 700px;} +.emptycols_left11, .prepend-11 {padding-left: 770px;} +.emptycols_right11, .append-11 {padding-right: 770px;} +.pull-1 {margin-left: -70px;} +.push-1 {margin-right: -70px;margin-left: 18px;float: right;} +.pull-2 {margin-left: -140px;} +.push-2 {margin-right: -140px;margin-left: 18px;float: right;} +.pull-3 {margin-left: -210px;} +.push-3 {margin-right: -210px;margin-left: 18px;float: right;} +.pull-4 {margin-left: -280px;} +.push-4 {margin-right: -280px;margin-left: 18px;float: right;} \ No newline at end of file diff --git a/public/svgnest/font/specimen_files/specimen_stylesheet.css b/public/svgnest/font/specimen_files/specimen_stylesheet.css new file mode 100644 index 00000000..aecc43c3 --- /dev/null +++ b/public/svgnest/font/specimen_files/specimen_stylesheet.css @@ -0,0 +1,396 @@ +@import url('grid_12-825-55-15.css'); + +/* + CSS Reset by Eric Meyer - Released under Public Domain + http://meyerweb.com/eric/tools/css/reset/ +*/ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, table, +caption, tbody, tfoot, thead, tr, th, td + {margin: 0;padding: 0;border: 0;outline: 0; + font-size: 100%;vertical-align: baseline; + background: transparent;} +body {line-height: 1;} +ol, ul {list-style: none;} +blockquote, q {quotes: none;} +blockquote:before, blockquote:after, +q:before, q:after {content: ''; content: none;} +:focus {outline: 0;} +ins {text-decoration: none;} +del {text-decoration: line-through;} +table {border-collapse: collapse;border-spacing: 0;} + + + + +body { + color: #000; + background-color: #dcdcdc; +} + +a { + text-decoration: none; + color: #1883ba; +} + +h1{ + font-size: 32px; + font-weight: normal; + font-style: normal; + margin-bottom: 18px; +} + +h2{ + font-size: 18px; +} + +#container { + width: 865px; + margin: 0px auto; +} + + +#header { + padding: 20px; + font-size: 36px; + background-color: #000; + color: #fff; +} + +#header span { + color: #666; +} +#main_content { + background-color: #fff; + padding: 60px 20px 20px; +} + + +#footer p { + margin: 0; + padding-top: 10px; + padding-bottom: 50px; + color: #333; + font: 10px Arial, sans-serif; +} + +.tabs { + width: 100%; + height: 31px; + background-color: #444; +} +.tabs li { + float: left; + margin: 0; + overflow: hidden; + background-color: #444; +} +.tabs li a { + display: block; + color: #fff; + text-decoration: none; + font: bold 11px/11px 'Arial'; + text-transform: uppercase; + padding: 10px 15px; + border-right: 1px solid #fff; +} + +.tabs li a:hover { + background-color: #00b3ff; + +} + +.tabs li.active a { + color: #000; + background-color: #fff; +} + + + +div.huge { + + font-size: 300px; + line-height: 1em; + padding: 0; + letter-spacing: -.02em; + overflow: hidden; +} +div.glyph_range { + font-size: 72px; + line-height: 1.1em; +} + +.size10{ font-size: 10px; } +.size11{ font-size: 11px; } +.size12{ font-size: 12px; } +.size13{ font-size: 13px; } +.size14{ font-size: 14px; } +.size16{ font-size: 16px; } +.size18{ font-size: 18px; } +.size20{ font-size: 20px; } +.size24{ font-size: 24px; } +.size30{ font-size: 30px; } +.size36{ font-size: 36px; } +.size48{ font-size: 48px; } +.size60{ font-size: 60px; } +.size72{ font-size: 72px; } +.size90{ font-size: 90px; } + + +.psample_row1 { height: 120px;} +.psample_row1 { height: 120px;} +.psample_row2 { height: 160px;} +.psample_row3 { height: 160px;} +.psample_row4 { height: 160px;} + +.psample { + overflow: hidden; + position: relative; +} +.psample p { + line-height: 1.3em; + display: block; + overflow: hidden; + margin: 0; +} + +.psample span { + margin-right: .5em; +} + +.white_blend { + width: 100%; + height: 61px; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNrs3TsKgFAMRUE/eer+NxztxMYuEWQG3ECKwwUF58ycAKixOAGAyAKILAAiCyCyACILgMgCiCyAyAIgsgAiCyCyAIgsgMgCiCwAIgsgsgAiC4DIAogsACIL0CWuZ3UGgLrIhjMA1EV2OAOAJQtgyQLwjOzmDAAiCyCyAIgsQFtkd2cAEFkAkQVAZAHaIns4A4AlC2DJAiCyACILILIAiCzAV5H1dQGAJQsgsgCILIDIAvwisl58AViyAJYsACILILIAIgvAe2T9EhxAZAFEFgCRBeiL7HAGgLrIhjMAWLIAliwAt1OAAQDwygTBulLIlQAAAABJRU5ErkJggg==); + position: absolute; + bottom: 0; +} +.black_blend { + width: 100%; + height: 61px; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNrs3TEKhTAQRVGjibr/9QoxhY2N3Ywo50A28IrLwP9g6b1PAMSYTQAgsgAiC4DIAogsgMgCILIAIgsgsgCILIDIAogsACILILIAIguAyAKILIDIAiCyACILgMgCZCnjLWYAiFGvB0BQZJsZAFyyAC5ZAO6RXc0AILIAIguAyAKkRXYzA4DIAogsACILkBbZ3QwALlkAlywAIgsgsgAiC4DIArwVWf8uAHDJAogsACILILIAv4isH74AXLIALlkARBZAZAFEFoDnyPokOIDIAogsACILkBfZZgaAuMhWMwC4ZAE+p4x3mAEgxinAAJ+XBbPWGkwAAAAAAElFTkSuQmCC); + position: absolute; + bottom: 0; +} +.fullreverse { + background: #000 !important; + color: #fff !important; + margin-left: -20px; + padding-left: 20px; + margin-right: -20px; + padding-right: 20px; + padding: 20px; + margin-bottom:0; +} + + +.sample_table td { + padding-top: 3px; + padding-bottom:5px; + padding-left: 5px; + vertical-align: middle; + line-height: 1.2em; +} + +.sample_table td:first-child { + background-color: #eee; + text-align: right; + padding-right: 5px; + padding-left: 0; + padding: 5px; + font: 11px/12px "Courier New", Courier, mono; +} + +code { + white-space: pre; + background-color: #eee; + display: block; + padding: 10px; + margin-bottom: 18px; + overflow: auto; +} + + +.bottom,.last {margin-bottom:0 !important; padding-bottom:0 !important;} + +.box { + padding: 18px; + margin-bottom: 18px; + background: #eee; +} + +.reverse,.reversed { background: #000 !important;color: #fff !important; border: none !important;} + +#bodycomparison { + position: relative; + overflow: hidden; + font-size: 72px; + height: 90px; + white-space: nowrap; +} + +#bodycomparison div{ + font-size: 72px; + line-height: 90px; + display: inline; + margin: 0 15px 0 0; + padding: 0; +} + +#bodycomparison div span{ + font: 10px Arial; + position: absolute; + left: 0; +} +#xheight { + float: none; + position: absolute; + color: #d9f3ff; + font-size: 72px; + line-height: 90px; +} + +.fontbody { + position: relative; +} +.arialbody{ + font-family: Arial; + position: relative; +} +.verdanabody{ + font-family: Verdana; + position: relative; +} +.georgiabody{ + font-family: Georgia; + position: relative; +} + +/* @group Layout page + */ + +#layout h1 { + font-size: 36px; + line-height: 42px; + font-weight: normal; + font-style: normal; +} + +#layout h2 { + font-size: 24px; + line-height: 23px; + font-weight: normal; + font-style: normal; +} + +#layout h3 { + font-size: 22px; + line-height: 1.4em; + margin-top: 1em; + font-weight: normal; + font-style: normal; +} + + +#layout p.byline { + font-size: 12px; + margin-top: 18px; + line-height: 12px; + margin-bottom: 0; +} +#layout p { + font-size: 14px; + line-height: 21px; + margin-bottom: .5em; +} + +#layout p.large{ + font-size: 18px; + line-height: 26px; +} + +#layout .sidebar p{ + font-size: 12px; + line-height: 1.4em; +} + +#layout p.caption { + font-size: 10px; + margin-top: -16px; + margin-bottom: 18px; +} + +/* @end */ + +/* @group Glyphs */ + +#glyph_chart div{ + background-color: #d9f3ff; + color: black; + float: left; + font-size: 36px; + height: 1.2em; + line-height: 1.2em; + margin-bottom: 1px; + margin-right: 1px; + text-align: center; + width: 1.2em; + position: relative; + padding: .6em .2em .2em; +} + +#glyph_chart div p { + position: absolute; + left: 0; + top: 0; + display: block; + text-align: center; + font: bold 9px Arial, sans-serif; + background-color: #3a768f; + width: 100%; + color: #fff; + padding: 2px 0; +} + + +#glyphs h1 { + font-family: Arial, sans-serif; +} +/* @end */ + +/* @group Installing */ + +#installing { + font: 13px Arial, sans-serif; +} + +#installing p, +#glyphs p{ + line-height: 1.2em; + margin-bottom: 18px; + font: 13px Arial, sans-serif; +} + + + +#installing h3{ + font-size: 15px; + margin-top: 18px; +} + +/* @end */ + +#rendering h1 { + font-family: Arial, sans-serif; +} +.render_table td { + font: 11px "Courier New", Courier, mono; + vertical-align: middle; +} + + diff --git a/public/svgnest/font/stylesheet.css b/public/svgnest/font/stylesheet.css new file mode 100644 index 00000000..b9371546 --- /dev/null +++ b/public/svgnest/font/stylesheet.css @@ -0,0 +1,30 @@ +/* Generated by Font Squirrel (http://www.fontsquirrel.com) on July 12, 2014 */ + + + +@font-face { + font-family: 'latohairline'; + src: url('lato-hai-webfont.eot'); + src: url('lato-hai-webfont.eot?#iefix') format('embedded-opentype'), + url('lato-hai-webfont.woff') format('woff'), + url('lato-hai-webfont.ttf') format('truetype'), + url('lato-hai-webfont.svg#latohairline') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'latolight'; + src: url('lato-lig-webfont.eot'); + src: url('lato-lig-webfont.eot?#iefix') format('embedded-opentype'), + url('lato-lig-webfont.woff') format('woff'), + url('lato-lig-webfont.ttf') format('truetype'), + url('lato-lig-webfont.svg#latolight') format('svg'); + font-weight: normal; + font-style: normal; + +} \ No newline at end of file diff --git a/public/svgnest/img/background.png b/public/svgnest/img/background.png new file mode 100644 index 00000000..ea7279ee Binary files /dev/null and b/public/svgnest/img/background.png differ diff --git a/public/svgnest/img/close.svg b/public/svgnest/img/close.svg new file mode 100644 index 00000000..21276a2e --- /dev/null +++ b/public/svgnest/img/close.svg @@ -0,0 +1,13 @@ + + + + + + + diff --git a/public/svgnest/img/code.svg b/public/svgnest/img/code.svg new file mode 100644 index 00000000..8cbc5cd8 --- /dev/null +++ b/public/svgnest/img/code.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/public/svgnest/img/download.svg b/public/svgnest/img/download.svg new file mode 100644 index 00000000..efe8e7f6 --- /dev/null +++ b/public/svgnest/img/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/svgnest/img/logo.svg b/public/svgnest/img/logo.svg new file mode 100644 index 00000000..b403b4f4 --- /dev/null +++ b/public/svgnest/img/logo.svg @@ -0,0 +1,46 @@ + + + + diff --git a/public/svgnest/img/settings.svg b/public/svgnest/img/settings.svg new file mode 100644 index 00000000..5cb0399b --- /dev/null +++ b/public/svgnest/img/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/svgnest/img/spin.svg b/public/svgnest/img/spin.svg new file mode 100644 index 00000000..119c929c --- /dev/null +++ b/public/svgnest/img/spin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/svgnest/img/start.svg b/public/svgnest/img/start.svg new file mode 100644 index 00000000..2dd7d0a4 --- /dev/null +++ b/public/svgnest/img/start.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/svgnest/img/upload.svg b/public/svgnest/img/upload.svg new file mode 100644 index 00000000..27b76e01 --- /dev/null +++ b/public/svgnest/img/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/svgnest/img/zoomin.svg b/public/svgnest/img/zoomin.svg new file mode 100644 index 00000000..82468877 --- /dev/null +++ b/public/svgnest/img/zoomin.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/svgnest/img/zoomout.svg b/public/svgnest/img/zoomout.svg new file mode 100644 index 00000000..6a84f7c6 --- /dev/null +++ b/public/svgnest/img/zoomout.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/public/svgnest/index.html b/public/svgnest/index.html new file mode 100644 index 00000000..ad1ccdde --- /dev/null +++ b/public/svgnest/index.html @@ -0,0 +1,912 @@ + + + + + + + + MAnest - MakeArmy hosted nesting app powered by SVGnest! + + + + + + + + + + + + + + + + + + + + + +
+ + +

MAnest

+ Fast Nesting for Makers + + + + + + +

+ Powered by SVGnest, a free open source project by Jack000 — + visit the github here. +

+
+

What exactly is "nesting"?

+

If you have some parts to cut out of a piece of metal/plastic/wood etc, you'd want to arrange the parts to use as little material as possible. This is a common problem if you use a laser cutter, plasma cutter, or CNC machine.

+

In computer terms this is called the irregular bin-packing problem

+ +

How much does it cost?

+

It's free and open source. The code and implementation details are on Github

+ +

Does it use inches? mm?

+

SVG has its internal units, the distance related fields in the settings use SVG units, ie. pixels. The conversion between a pixel and real units depend on the exporting software, but it's typically 72 pixels = 1 inch

+ +

My SVG text/image doesn't show up?

+

Nesting only works for closed shapes, so SVG elements that don't represent closed shapes are removed. Convert text and any other elements to outlines first. Ensure that outlines do not intersect or overlap eachother. Outlines that are inside other outlines are considered holes.

+ +

It doesn't ever stop?

+

The software will continuously look for better solutions until you press the stop button. You can stop at any time and download the SVG file.

+ +

Some parts seem to slightly overlap?

+

Curved shapes are approximated with line segments. For a more accurate nest with curved parts, decrease the curve tolerance parameter in the configuration.

+ +

I need help?

+

Add an issue on Github or contact me personally: jack.works +

+
+ +
+ +
+ + +
+
+ +

Space between parts

? + + +

Curve tolerance

? + + +

Part rotations

? + + +

GA population

? + + +

GA mutation rate

? + + +

Part in Part

? + + +

Explore concave areas

? + + Save Settings +
+
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+
+
+ + diff --git a/public/svgnest/index.html.bak b/public/svgnest/index.html.bak new file mode 100644 index 00000000..2edba475 --- /dev/null +++ b/public/svgnest/index.html.bak @@ -0,0 +1,914 @@ + + + + + + + + MAnest - MakeArmy hosted nesting app powered by SVGnest! + + + + + + + + + + + + + + + + + + + + + +
+ + +

MAnest

+ Fast Nesting for Makers + + + + + + +

+ Powered by SVGnest, a free open source project by Jack000 — + visit the github here. +

+
+

What exactly is "nesting"?

+

If you have some parts to cut out of a piece of metal/plastic/wood etc, you'd want to arrange the parts to use as little material as possible. This is a common problem if you use a laser cutter, plasma cutter, or CNC machine.

+

In computer terms this is called the irregular bin-packing problem

+ +

How much does it cost?

+

It's free and open source. The code and implementation details are on Github

+ +

Does it use inches? mm?

+

SVG has its internal units, the distance related fields in the settings use SVG units, ie. pixels. The conversion between a pixel and real units depend on the exporting software, but it's typically 72 pixels = 1 inch

+ +

My SVG text/image doesn't show up?

+

Nesting only works for closed shapes, so SVG elements that don't represent closed shapes are removed. Convert text and any other elements to outlines first. Ensure that outlines do not intersect or overlap eachother. Outlines that are inside other outlines are considered holes.

+ +

It doesn't ever stop?

+

The software will continuously look for better solutions until you press the stop button. You can stop at any time and download the SVG file.

+ +

Some parts seem to slightly overlap?

+

Curved shapes are approximated with line segments. For a more accurate nest with curved parts, decrease the curve tolerance parameter in the configuration.

+ +

I need help?

+

Add an issue on Github or contact me personally: jack.works +

+
+ +
+ +
+ + +
+
+ +

Space between parts

? + + +

Curve tolerance

? + + +

Part rotations

? + + +

GA population

? + + +

GA mutation rate

? + + +

Part in Part

? + + +

Explore concave areas

? + + Save Settings +
+
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+
+
+ + diff --git a/public/svgnest/readme.md b/public/svgnest/readme.md new file mode 100644 index 00000000..949c8791 --- /dev/null +++ b/public/svgnest/readme.md @@ -0,0 +1,114 @@ +# ![SVGNest](http://svgnest.com/github/logo2.png) + +**SVGNest**: A browser-based vector nesting tool. + +**Demo:** http://svgnest.com + +(requires SVG and webworker support). Mobile warning: running the demo is CPU intensive. + +references (PDF): +- [López-Camacho *et al.* 2013](http://www.cs.stir.ac.uk/~goc/papers/EffectiveHueristic2DAOR2013.pdf) +- [Kendall 2000](http://www.graham-kendall.com/papers/k2001.pdf) +- [E.K. Burke *et al.* 2006](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.440.379&rep=rep1&type=pdf) + +## What is "nesting"? + +Given a square piece of material and some letters to be laser-cut: + +![letter nesting](http://svgnest.com/github/letters.png) + +We want to pack all the letters into the square, using as little material as possible. If a single square is not enough, we also want to minimize the number of squares used. + +In the CNC world this is called "[nesting](http://sigmanest.com/)", and [software](http://www.mynesting.com/) that [does this](http://www.autodesk.com/products/trunest/overview) is typically targeted at [industrial customers](http://www.hypertherm.com/en/Products/Automated_cutting/Nesting_software/) and [very expensive](http://www.nestfab.com/pricing/). + +SVGnest is a free and open-source alternative that solves this problem with the orbital approach outlined in [E.K. Burke *et al.* 2006], using a genetic algorithm for global optimization. It works for arbitrary containers and concave edge cases, and performs on-par with existing commercial software. + +![non-rectangular shapes](http://svgnest.com/github/shapes.png) + +It also features part-in-part support, for placing parts in the holes of other parts. + +![non-rectangular shapes](http://svgnest.com/github/recursion.png) + +## Usage + +Make sure all parts have been converted to outlines, and that no outlines overlap. Upload the SVG file and select one of the outlines to be used as the bin. + +All other outlines are automatically processed as parts for nesting. + +## Outline of algorithm + +While [good heuristics](http://cgi.csc.liv.ac.uk/~epa/surveyhtml.html) exist for the rectangular bin packing problem, in the real world we are concerned with irregular shapes. + +The strategy is made of two parts: + +- the placement strategy (ie. how do I insert each part into a bin?) +- and the optimization strategy (ie. what's the best order of insertions?) + +### Placing the part + +The key concept here is the "No Fit Polygon". + +Given polygons A and B, we want to "orbit" B around A such that they always touch but do not intersect. + +![No Fit Polygon example](http://svgnest.com/github/nfp.png) + +The resulting orbit is the NFP. The NFP contains all possible placements of B that touches the previously placed parts. We can then choose a point on the NFP as the placement position using some heuristics. + +Similarly we can construct an "Inner Fit Polygon" for the part and the bin. This is the same as the NFP, except the orbiting polygon is inside the stationary one. + +When two or more parts have already been placed, we can take the union of the NFPs of the previously placed parts. + +![No Fit Polygon example](http://svgnest.com/github/nfp2.png) + +This means that we need to compute O(nlogn) NFPs to complete the first packing. While there are ways to mitigate this, we take the brute-force approach which has good properties for the optimization algo. + +### Optimization + +Now that we can place the parts, we need to optimize the insertion order. Here's an example of a bad insertion order: + +![Bad insertion order](http://svgnest.com/github/badnest.png) + +If the large "C" is placed last, the concave space inside it won't be utilized because all the parts that could have filled it have already been placed. + +To solve this, we use the "first-fit-decreasing" heuristic. Larger parts are placed first, and smaller parts last. This is quite intuitive, as the smaller parts tend to act as "sand" to fill the gaps left by the larger parts. + +![Good insertion order](http://svgnest.com/github/goodnest.png) + +While this strategy gives us a good start, we want to explore more of the solution space. We could simply randomize the insertion order, but we can probably do better with a genetic algorithm. (If you don't know what a GA is, [this article](http://www.ai-junkie.com/ga/intro/gat1.html) is a very approachable read) + +## Evaluating fitness + +In our GA the insertion order and the rotation of the parts form the gene. The fitness function follows these rules: + +1. Minimize the number of unplaceable parts (parts that cannot fit any bin due to its rotation) +2. Minimize the number of bins used +3. Minimize the *width* of all placed parts + +The third one is rather arbitrary, as we can also optimize for rectangular bounds or a minimal concave hull. In real-world use the material to be cut tends to be rectangular, and those options tend to result in long slivers of un-used material. + +Because small mutations in the gene cause potentially large changes in overall fitness, the individuals of the population can be very similar. By caching NFPs new individuals can be evaluated very quickly. + +## Performance + +![SVGnest comparison](http://svgnest.com/github/comparison1.png) + +Performs similarly to commercial software, after both have run for about 5 minutes. + +## Configuration parameters + +- **Space between parts:** Minimum space between parts (eg. for laser kerf, CNC offset etc.) +- **Curve tolerance:** The maximum error allowed for linear approximations of Bezier paths and arcs, in SVG units or "pixels". Decrease this value if curved parts appear to slightly overlap. +- **Part rotations:** The *possible* number of rotations to evaluate for each part. eg. 4 for only the cardinal directions. Larger values may improve results, but will be slower to converge. +- **GA population:** The population size for the Genetic Algorithm +- **GA mutation rate:** The probability of mutation for each gene or part placement. Values from 1-50 +- **Part in part:** When enabled, places parts in the holes of other parts. This is off by default as it can be resource intensive +- **Explore concave areas:** When enabled, solves the concave edge case at a cost of some performance and placement robustness: + +![Concave flag example](http://svgnest.com/github/concave.png) + +## To-do + +- ~~Recursive placement (putting parts in holes of other parts)~~ +- Customize fitness function (gravity direction, etc) +- kill worker threads when stop button is clicked +- fix certain edge cases in NFP generation \ No newline at end of file diff --git a/public/svgnest/style.css b/public/svgnest/style.css new file mode 100644 index 00000000..96dc53c3 --- /dev/null +++ b/public/svgnest/style.css @@ -0,0 +1,628 @@ +/* ========================================================= + SVGNest — MakeArmy True-Gray Theme (final teal version) + - Neutral gray UI with Teal accents (#20C5B5) + - Fixed #svgnest top spacing (removed giant gap) + - Restores !important on SVG stroke/fill so uploaded parts display correctly + - Accent is consistent across links, buttons, tooltips, selection, progress + ========================================================= */ + +:root{ + /* Neutral grayscale foundation */ + --bg: #0e0e0e; /* page background (near-black) */ + --bg-2: #1a1a1a; /* panels / cards / buttons */ + --bg-3: #121212; /* bins / work areas */ + --text: #e0e0e0; /* primary text */ + --muted: #a0a0a0; /* secondary text */ + --border: #2a2a2a; /* subtle borders */ + --shadow: rgba(0,0,0,0.40); + + /* Teal accent */ + --accent: #20C5B5; /* primary accent */ + --accent-2: #1aa397; /* darker hover/active */ + + /* True-grays (replace any previous blues) */ + --gray-1: #f0f0f0; /* headings, light text */ + --gray-2: #cccccc; /* subheadings */ + --gray-3: #888888; /* lines / subtle emphasis */ + --gray-4: #555555; /* secondary fills */ +} + +/* ===== Base ===== */ +html, body{ + margin: 0; + padding: 0; + border: 0; + font: normal 22px/1.4 'LatoLatinWeb', helvetica, arial, verdana, sans-serif; + background-color: var(--bg); + color: var(--muted); +} + +a{ + color: var(--accent); + text-decoration: none; + transition: color .15s ease; +} +a:hover{ + color: var(--accent-2); + text-decoration: underline; +} + +h1{ + font-size: 1.5em; + font-family: 'LatoLatinWebLight', helvetica, arial, verdana, sans-serif; + font-weight: normal; + margin: 1.5em 0 0.5em 0; + color: var(--gray-1); +} +h2{ + font-size: 1.1em; + font-weight: bold; + margin: 0 0 0.5em 0; + color: var(--gray-2); +} +h3{ + font-size: 1em; + font-weight: bold; + margin: 1em 0 0.2em 0; + color: var(--gray-2); +} + +/* ===== Splash ===== */ +#splash{ + width: 28em; + margin: 8% auto 0 auto; +} +#splash .logo{ + width: 50%; + margin: 0 0 0 25%; + height: auto; +} +#splash h1{ color: var(--accent); } +#splash h1.title{ + font-size: 3.5em; + margin: 0; + padding: 0; + text-align: center; +} +.subscript{ font-size: 0.75em; } +#splash .subscript{ + display: block; + color: var(--accent); + font-size: 1.45em; + text-align: center; + font-style: normal; +} + +/* ===== Nav + Buttons ===== */ +.nav{ margin: 0; padding: 0; } +li{ list-style: none; float: left; margin: 0; padding: 0; } + +.button{ + display: block; + margin: 0 0.5em; + padding: 0.6em 2.4em; + background-color: var(--bg-2); + border-radius: 5em; + border: 1px solid var(--border); + cursor: pointer; + color: var(--accent); + box-shadow: 0 1px 0 rgba(0,0,0,0.25); + transition: color .15s ease, box-shadow .15s ease, border-color .15s ease, background-color .15s ease; +} +.button a:hover{ text-decoration: none; } + +.button.start{ + background: var(--bg-2) url(img/start.svg) no-repeat 1.8em 50% / 1.4em 1.4em; + padding-left: 3.7em; +} +.button.spinner{ + background: var(--bg-2) url(img/spin.svg) no-repeat 1.8em 50% / 1.4em 1.4em; + padding-left: 3.7em; +} +.button.upload{ + background: var(--bg-2) url(img/upload.svg) no-repeat 2.2em 50% / 1em 1em; + padding-left: 4em; +} +.button.download{ + background: var(--bg-2) url(img/download.svg) no-repeat 2.2em 50% / 1em 1em; + padding-left: 4em; +} +.button.code{ + background: var(--bg-2) url(img/code.svg) no-repeat 2em 50% / 1.2em 1.2em; + padding-left: 3.9em; +} +.button.config{ + background: var(--bg-2) url(img/settings.svg) no-repeat 2em 50% / 1.2em 1.2em; + padding-left: 3.9em; +} +.button.close{ + background: var(--bg-2) url(img/close.svg) no-repeat 1.8em 50% / 2em 2em; + padding-left: 3.9em; +} +.button.zoomin{ background: var(--bg-2) url(img/zoomin.svg) no-repeat 50% 50% / 1.5em 1.5em; } +.button.zoomout{ background: var(--bg-2) url(img/zoomout.svg) no-repeat 50% 50% / 1.5em 1.5em; } +.button.exit{ background: var(--bg-2) url(img/close.svg) no-repeat 50% 50% / 1.5em 1.5em; } + +.button:hover{ + color: var(--accent-2); + border-color: var(--accent); + box-shadow: 0 2px 8px rgba(0,0,0,0.25); + text-decoration: none; +} +.button:active{ + background-color: #1f1f1f; + border-color: var(--accent-2); + box-shadow: inset 0 2px 2px rgba(0,0,0,0.35); +} +.button.disabled{ + cursor: default; opacity: 0.5; color: #999; + -webkit-filter: saturate(0); filter: saturate(0); +} +.button.disabled:hover{ box-shadow: none; border-color: var(--border); } +.button.disabled:active{ background-color: var(--bg-2); box-shadow: none; } + +#splash .nav{ float: left; width: 150%; margin: 4em 0 0 -20%; } +#faq{ display: none; float: left; margin-top: 2em; padding-bottom: 5em; } + +/* ===== SVGNest layout ===== */ +#svgnest, #messagewrapper{ width: 72em; } + +/* FIXED: smaller, responsive top spacing (replaces 9em) */ +#svgnest{ + display: none; + margin: clamp(1rem, 3vh, 2.5rem) auto 0 auto; +} + +#svgnest .logo, #svgnest .sidebar{ float: left; width: 22%; margin-right: 8%; } +#svgnest .sidebar h1{ font-size: 3em; color: var(--text); } +#svgnest .sidebar{ clear: both; width: 100%; margin-top: 3em; } + +#svgnest .nav{ float: left; margin: 0 0 0 -0.5em; padding: 0; } +#controls{ margin-top: 0.5em; float: left; position: relative; } + +/* ===== Info sidebar ===== */ +#info, #info_placement{ display: none; } +h1.label{ + font-size: 4em; margin: 0.2em 0 0 0; padding: 0; + line-height: 1; font-weight: normal; color: var(--text); +} +h1.label sup{ font-size: 0.5em; } +.column{ margin: 0.5em 4em 2em 0; float: left; } + +/* ===== Progress ===== */ +.progress{ + width: 51%; + clear: both; + height: 1.2em; + background-color: var(--bg-2); + border: 1px solid var(--accent); /* accent border */ + border-radius: 1em; + margin-bottom: 0.4em; +} +.progress_inner{ + height: 100%; + background-color: var(--accent); /* accent fill */ + border-radius: 1em; +} + +/* ===== Config panel ===== */ +#config{ + max-height: 0; + overflow: hidden; + width: 20em; + position: absolute; + top: 0; + left: 24.5em; + background-color: var(--bg-2); + border-radius: 0.5em; + transition: max-height 0.5s; + box-shadow: 0 2px 8px var(--shadow); +} +#configwrapper{ float: left; padding: 3em 0 1em 2em; } +#config.active{ display: block; max-height: 50em; } +#configbutton{ position: relative; z-index: 2; width: 3em; padding: 0; height: 2.5em; background-position: 50%; } +#zoominbutton, #zoomoutbutton, #exitbutton{ width: 3em; padding: 0; height: 2.5em; background-position: 50%; } +#configbutton.close:hover{ box-shadow: none; } +#configsave{ margin-left: 7%; } + +#config input, #config h3, #config .tooltip{ margin: 1em 0 0 0; height: 2em; padding: 0; } +#config input{ + float: left; width: 13%; font-size: 1em; + border: 1px solid var(--accent); + color: var(--text); + background: #141414; + text-align: center; clear: left; border-radius: 0.4em; + transition: border-color .15s ease, background-color .15s ease; +} +#config input:hover{ background-color: #181818; border-color: var(--accent-2); } +#config input.checkbox{ width: 7%; margin-left: 4%; margin-right: 4%; border: 1px solid var(--border); } +#config h3{ float: left; width: 65%; margin-left: 5%; padding: 0; font-size: 0.8em; line-height: 3em; color: var(--muted); } +#config .tooltip{ + float: left; max-width: 15%; width: 1.5em; height: 1.5em; + font-size: 0.8em; font-weight: bold; background-color: var(--accent); + color: #fff; text-align: center; line-height: 1.5; margin-top: 1.8em; + cursor: default; border-radius: 3em; +} +#config .button{ float: left; clear: both; margin-top: 2em; } + +/* ===== SVG areas ===== */ +#select{ margin-top: 2em; } +#select, #bins{ float: left; width: 69%; position: relative; } + +#select svg, #bins svg{ + width: 100%; height: auto; position: absolute; top: 0; + margin: 0; display: block; overflow: visible; pointer-events: none; +} + +/* Selection strokes (use accent; override uploaded inline styles) */ +#select svg *{ + fill: #fff !important; + fill-opacity: 0 !important; + stroke: var(--accent) !important; + stroke-width: 2px !important; + vector-effect: non-scaling-stroke !important; + stroke-linejoin: round !important; + pointer-events: fill !important; +} +#select svg *.fullRect{ + fill: #1b1b1b !important; + fill-opacity: 1 !important; + stroke: #1b1b1b !important; + stroke-width: 2px !important; + vector-effect: non-scaling-stroke !important; + stroke-linejoin: round !important; +} +#select svg *:hover{ stroke: var(--accent-2) !important; cursor: pointer !important; } +#select svg *.active{ stroke: var(--accent-2) !important; stroke-width: 3px !important; } +#select.disabled svg *, #select.disabled svg *:hover, #select.disabled svg *.active{ + stroke: #6b6b6b !important; stroke-width: 2px !important; cursor: default !important; +} + +/* Bins (neutral grays) */ +#bins svg{ margin-bottom: 2em; } +#bins svg.grid{ float: left; width: 45%; margin-right: 5%; min-width: 20em; } +#bins svg *{ + fill: var(--gray-4) !important; + stroke: var(--gray-3) !important; + stroke-width: 2px !important; + vector-effect: non-scaling-stroke !important; + stroke-linejoin: round !important; +} +#bins svg .bin{ fill: var(--bg-3) !important; stroke: var(--gray-4) !important; } +#bins svg .hole{ fill: var(--bg) !important; stroke: var(--gray-3) !important; } + +/* ===== Messages ===== */ +#messagewrapper{ + width: 50em; overflow: hidden; + background: var(--gray-4) url(img/close.svg) no-repeat 99% 0.5em / 3em 3em; + line-height: 4em; + position: fixed; left: 50%; margin-left: -25em; bottom: 1em; + text-align: center; border-radius: 0.5em; color: #fff; + box-shadow: 0 6px 24px var(--shadow); + border-left: 4px solid var(--accent); /* subtle accent marker */ +} +#messagewrapper:hover{ background-color: #666; border-left-color: var(--accent-2); } +#message{ overflow: hidden; height: 0; } +#message.active, #message.error{ height: 4em; cursor: pointer; } +#message.error{ color: #ff314e; font-weight: bold; } + +/* ===== Animations (kept intact) ===== */ +.animated{ + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} +@-webkit-keyframes bounce{ + from,20%,53%,80%,to{ + -webkit-animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000); + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } + 40%,43%{ + -webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-30px,0); + transform: translate3d(0,-30px,0); + } + 70%{ + -webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-15px,0); + transform: translate3d(0,-15px,0); + } + 90%{ + -webkit-transform: translate3d(0,-4px,0); + transform: translate3d(0,-4px,0); + } +} +@keyframes bounce{ + from,20%,53%,80%,to{ + animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000); + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } + 40%,43%{ + animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-30px,0); + transform: translate3d(0,-30px,0); + } + 70%{ + animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-15px,0); + transform: translate3d(0,-15px,0); + } + 90%{ + -webkit-transform: translate3d(0,-4px,0); + transform: translate3d(0,-4px,0); + } +} +.bounce{ + -webkit-animation-name: bounce; + animation-name: bounce; + -webkit-transform-origin: center bottom; + transform-origin: center bottom; +} +@-webkit-keyframes slideInUp{ + from{ + -webkit-transform: translate3d(0,100%,0); + transform: translate3d(0,100%,0); + visibility: visible; + } + to{ + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } +} +@keyframes slideInUp{ + from{ + -webkit-transform: translate3d(0,100%,0); + transform: translate3d(0,100%,0); + visibility: visible; + } + to{ + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } +} +.slideInUp{ + -webkit-animation-name: slideInUp; + animation-name: slideInUp; +} + +/* ===== Responsive ===== */ +@media only screen and (max-width: 1800px){ + body { font-size: 20px; } + #svgnest, #messagewrapper{ width: 60em; } + .progress{ width: 61%; } +} + +@media only screen and (max-width: 1500px){ + body { font-size: 16px; } + + #svgnest, #messagewrapper{ width: 50em; } + /* replaces old 5em top margin */ + #svgnest{ margin-top: clamp(0.75rem, 2vh, 1.5rem); } + + #svgnest .logo{ width: 25%; } + #controls{ margin-top: 0.75em; } + + #splash .logo{ width: 60%; margin: 0 20%; } + #splash h1.title{ margin: 0; font-size: 2em; } + #splash .subscript{ font-size: 1em; } + + h1.label{ font-size: 3em; } + .progress{ width: 75%; } +} + +@media only screen and (max-width: 1300px){ + body { font-size: 14px; } +} + +@media only screen and (max-width: 790px){ + #splash{ width: 100%; } + #splash .logo{ width: 40%; margin-left: 30%; float: left; } + #splash h1.title{ margin: 0; font-size: 2em; } + #splash .subscript{ font-size: 1em; } + body { font-size: 18px; } + + #splash .nav{ width: 60%; margin-left: 20%; margin-top: 2em; } + #splash .nav li{ float: none; display: block; margin-top: 1em; } + + #faq{ padding: 3em; } +} + +/* ===== MakeArmy splash nav & buttons — one-row, mono font, less rounded ===== */ + +/* use Hack sitewide */ +html, body { + font-family: "Hack", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; +} + +/* kill the old float hack and center as a single flex row */ +#splash .nav { + /* override old: float:left; width:150%; margin: 4em 0 0 -20%; */ + float: none; + width: auto; + margin: 3rem auto 0 auto; + padding: 0; + + display: flex; + align-items: center; + justify-content: center; + + /* keep them on one line on wide screens */ + flex-wrap: nowrap; + gap: 18px; +} + +/* list items no longer float */ +#splash .nav li { + list-style: none; + float: none; +} + +/* button shape: slimmer, less rounded, mono font keeps line-height crisp */ +#splash .nav .button { + border-radius: 12px; /* was pill; now closer to your other UI */ + padding: 0.55em 1.2em; /* a bit tighter so all fit in one row */ + font-size: 0.95em; + line-height: 1.2; + white-space: nowrap; /* prevent label wrapping */ +} + +/* keep left padding for icon-capable buttons (no icon on Back is fine) */ +#splash .nav .button.start { padding-left: 3.7em; } +#splash .nav .button.spinner { padding-left: 3.7em; } +#splash .nav .button.upload { padding-left: 4em; } +#splash .nav .button.download { padding-left: 4em; } +#splash .nav .button.code { padding-left: 3.9em; } +#splash .nav .button.config { padding-left: 3.9em; } +#splash .nav .button.close { padding-left: 3.9em; } + +/* ensure the standalone Back button visually matches height/shape */ +#splash .nav .button.back { + /* no extra left padding (no icon), but same height/roundedness */ +} + +/* responsive fallback: allow wrapping only on truly narrow screens */ +@media (max-width: 860px) { + #splash .nav { + flex-wrap: wrap; + row-gap: 12px; + } +} + + +/* ===== Splash buttons: sharp corners, no icons, one row ===== */ + +/* one-line row stays the same */ +#splash .nav{ + display:flex; align-items:center; justify-content:center; + flex-wrap:nowrap; gap:14px; /* you can nudge this if you need space */ + margin:3rem auto 0; padding:0; width:auto; float:none; +} + +/* kill legacy floats */ +#splash .nav li{ list-style:none; float:none; } + +/* sharper buttons + uniform padding */ +#splash .nav .button{ + border-radius:6px; /* sharper (not quite square) */ + padding:0.55em 1.2em; /* same for all buttons */ + font-size:0.95em; + line-height:1.2; + white-space:nowrap; +} + +/* nuke all icon pseudo-elements from the splash row */ +#splash .nav .button::before{ display:none !important; } + +/* remove the old “extra left padding for icons” */ +#splash .nav .button.start, +#splash .nav .button.spinner, +#splash .nav .button.upload, +#splash .nav .button.download, +#splash .nav .button.code, +#splash .nav .button.config, +#splash .nav .button.close{ + padding:0.55em 1.2em; +} + +/* responsive: only wrap on narrow screens */ +@media (max-width: 860px){ + #splash .nav{ flex-wrap:wrap; row-gap:12px; } +} + +/* ===== Powered-by footer on splash ===== */ +#poweredby{ + margin: 1.25rem auto 0; + text-align: center; + font-size: 0.95rem; + color: var(--muted); + max-width: 72ch; +} +#poweredby a{ + color: var(--accent); + text-decoration: underline; +} +#poweredby a:hover{ color: var(--accent-2); } + + + +/* Restore icon backgrounds for app controls (non-splash) */ +.button.start{ background: #1a1a1a url(img/start.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; } +.button.spinner{ background: #1a1a1a url(img/spin.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; } +.button.upload{ background: #1a1a1a url(img/upload.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; } +.button.download{ background: #1a1a1a url(img/download.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; } +.button.code{ background: #1a1a1a url(img/code.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; } +.button.config{ background: #1a1a1a url(img/settings.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; } +.button.close{ background: #1a1a1a url(img/close.svg) no-repeat 1.8em 50%; background-size: 2em 2em; padding-left: 3.9em; } +.button.zoomin{ background: #1a1a1a url(img/zoomin.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; } +.button.zoomout{ background: #1a1a1a url(img/zoomout.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; } +.button.exit{ background: #1a1a1a url(img/close.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; } + + + +/* Keep splash narrow; stretch only its nav/footer for centering */ +#splash{ width:28em; margin:8% auto 0 auto; } +#splash .logo{ max-width: 220px; width: 50%; margin: 0 0 0 25%; height:auto; display:block; } +#splash .nav, #poweredby{ width:100%; text-align:center; } + + + +/* --- Splash page buttons override: text-only, no icons --- */ +#splash .nav .button { + border-radius: 6px; + padding: 0.55em 1.2em; + font-size: 0.95em; + line-height: 1.2; + white-space: nowrap; + + background-image: none !important; + padding-left: 1.2em !important; /* uniform spacing */ +} + +/* --- FINAL stacking: toolbar above panel; both above SVGs --- */ +#svgnest { position: relative; } + +/* SVG layers lowest */ +#select, #bins { position: relative; z-index: 0; } +#select svg, #bins svg { position: absolute; z-index: 0; } + +/* Toolbar must beat the panel so the gear/X is clickable */ +#controls { position: relative; z-index: 1000 !important; } + +/* Panel above drawings but below toolbar */ +#config { position: absolute; z-index: 900 !important; pointer-events: auto; } + +/* Toast always on top */ +#messagewrapper { position: fixed; z-index: 99999 !important; } + + +/* === FINAL STACKING ORDER (toolbar above panel; both above SVGs) === */ +#svgnest { position: relative; } + +/* SVG canvases lowest */ +#select, #bins { position: relative; z-index: 0; } +#select svg, #bins svg { position: absolute; z-index: 0; } + +/* Toolbar wins over panel so the gear/X can always be clicked */ +#controls { position: relative; z-index: 1000 !important; } + +/* Panel overlays drawings but stays below toolbar */ +#config { position: absolute; z-index: 900 !important; pointer-events: auto; } + +/* Toast message on top of everything */ +#messagewrapper { position: fixed; z-index: 99999 !important; } + +/* Panel should NOT intercept clicks when closed */ +#config:not(.active) { +pointer-events: none; /* let clicks pass through */ +} + +/* Keep toolbar reliably above the panel when open */ +#controls { position: relative; z-index: 1000 !important; } +#controls .button { position: relative; z-index: 1001; } + +/* Panel above drawings but below toolbar */ +#config { position: absolute; z-index: 900 !important; } diff --git a/public/svgnest/style.css.bak b/public/svgnest/style.css.bak new file mode 100644 index 00000000..6cd2e932 --- /dev/null +++ b/public/svgnest/style.css.bak @@ -0,0 +1,584 @@ +/* ========================================================= + SVGNest — MakeArmy True-Gray Theme (final teal version) + - Neutral gray UI with Teal accents (#20C5B5) + - Fixed #svgnest top spacing (removed giant gap) + - Restores !important on SVG stroke/fill so uploaded parts display correctly + - Accent is consistent across links, buttons, tooltips, selection, progress + ========================================================= */ + +:root{ + /* Neutral grayscale foundation */ + --bg: #0e0e0e; /* page background (near-black) */ + --bg-2: #1a1a1a; /* panels / cards / buttons */ + --bg-3: #121212; /* bins / work areas */ + --text: #e0e0e0; /* primary text */ + --muted: #a0a0a0; /* secondary text */ + --border: #2a2a2a; /* subtle borders */ + --shadow: rgba(0,0,0,0.40); + + /* Teal accent */ + --accent: #20C5B5; /* primary accent */ + --accent-2: #1aa397; /* darker hover/active */ + + /* True-grays (replace any previous blues) */ + --gray-1: #f0f0f0; /* headings, light text */ + --gray-2: #cccccc; /* subheadings */ + --gray-3: #888888; /* lines / subtle emphasis */ + --gray-4: #555555; /* secondary fills */ +} + +/* ===== Base ===== */ +html, body{ + margin: 0; + padding: 0; + border: 0; + font: normal 22px/1.4 'LatoLatinWeb', helvetica, arial, verdana, sans-serif; + background-color: var(--bg); + color: var(--muted); +} + +a{ + color: var(--accent); + text-decoration: none; + transition: color .15s ease; +} +a:hover{ + color: var(--accent-2); + text-decoration: underline; +} + +h1{ + font-size: 1.5em; + font-family: 'LatoLatinWebLight', helvetica, arial, verdana, sans-serif; + font-weight: normal; + margin: 1.5em 0 0.5em 0; + color: var(--gray-1); +} +h2{ + font-size: 1.1em; + font-weight: bold; + margin: 0 0 0.5em 0; + color: var(--gray-2); +} +h3{ + font-size: 1em; + font-weight: bold; + margin: 1em 0 0.2em 0; + color: var(--gray-2); +} + +/* ===== Splash ===== */ +#splash{ + width: 28em; + margin: 8% auto 0 auto; +} +#splash .logo{ + width: 50%; + margin: 0 0 0 25%; + height: auto; +} +#splash h1{ color: var(--accent); } +#splash h1.title{ + font-size: 3.5em; + margin: 0; + padding: 0; + text-align: center; +} +.subscript{ font-size: 0.75em; } +#splash .subscript{ + display: block; + color: var(--accent); + font-size: 1.45em; + text-align: center; + font-style: normal; +} + +/* ===== Nav + Buttons ===== */ +.nav{ margin: 0; padding: 0; } +li{ list-style: none; float: left; margin: 0; padding: 0; } + +.button{ + display: block; + margin: 0 0.5em; + padding: 0.6em 2.4em; + background-color: var(--bg-2); + border-radius: 5em; + border: 1px solid var(--border); + cursor: pointer; + color: var(--accent); + box-shadow: 0 1px 0 rgba(0,0,0,0.25); + transition: color .15s ease, box-shadow .15s ease, border-color .15s ease, background-color .15s ease; +} +.button a:hover{ text-decoration: none; } + +.button.start{ + background: var(--bg-2) url(img/start.svg) no-repeat 1.8em 50% / 1.4em 1.4em; + padding-left: 3.7em; +} +.button.spinner{ + background: var(--bg-2) url(img/spin.svg) no-repeat 1.8em 50% / 1.4em 1.4em; + padding-left: 3.7em; +} +.button.upload{ + background: var(--bg-2) url(img/upload.svg) no-repeat 2.2em 50% / 1em 1em; + padding-left: 4em; +} +.button.download{ + background: var(--bg-2) url(img/download.svg) no-repeat 2.2em 50% / 1em 1em; + padding-left: 4em; +} +.button.code{ + background: var(--bg-2) url(img/code.svg) no-repeat 2em 50% / 1.2em 1.2em; + padding-left: 3.9em; +} +.button.config{ + background: var(--bg-2) url(img/settings.svg) no-repeat 2em 50% / 1.2em 1.2em; + padding-left: 3.9em; +} +.button.close{ + background: var(--bg-2) url(img/close.svg) no-repeat 1.8em 50% / 2em 2em; + padding-left: 3.9em; +} +.button.zoomin{ background: var(--bg-2) url(img/zoomin.svg) no-repeat 50% 50% / 1.5em 1.5em; } +.button.zoomout{ background: var(--bg-2) url(img/zoomout.svg) no-repeat 50% 50% / 1.5em 1.5em; } +.button.exit{ background: var(--bg-2) url(img/close.svg) no-repeat 50% 50% / 1.5em 1.5em; } + +.button:hover{ + color: var(--accent-2); + border-color: var(--accent); + box-shadow: 0 2px 8px rgba(0,0,0,0.25); + text-decoration: none; +} +.button:active{ + background-color: #1f1f1f; + border-color: var(--accent-2); + box-shadow: inset 0 2px 2px rgba(0,0,0,0.35); +} +.button.disabled{ + cursor: default; opacity: 0.5; color: #999; + -webkit-filter: saturate(0); filter: saturate(0); +} +.button.disabled:hover{ box-shadow: none; border-color: var(--border); } +.button.disabled:active{ background-color: var(--bg-2); box-shadow: none; } + +#splash .nav{ float: left; width: 150%; margin: 4em 0 0 -20%; } +#faq{ display: none; float: left; margin-top: 2em; padding-bottom: 5em; } + +/* ===== SVGNest layout ===== */ +#svgnest, #messagewrapper{ width: 72em; } + +/* FIXED: smaller, responsive top spacing (replaces 9em) */ +#svgnest{ + display: none; + margin: clamp(1rem, 3vh, 2.5rem) auto 0 auto; +} + +#svgnest .logo, #svgnest .sidebar{ float: left; width: 22%; margin-right: 8%; } +#svgnest .sidebar h1{ font-size: 3em; color: var(--text); } +#svgnest .sidebar{ clear: both; width: 100%; margin-top: 3em; } + +#svgnest .nav{ float: left; margin: 0 0 0 -0.5em; padding: 0; } +#controls{ margin-top: 0.5em; float: left; position: relative; } + +/* ===== Info sidebar ===== */ +#info, #info_placement{ display: none; } +h1.label{ + font-size: 4em; margin: 0.2em 0 0 0; padding: 0; + line-height: 1; font-weight: normal; color: var(--text); +} +h1.label sup{ font-size: 0.5em; } +.column{ margin: 0.5em 4em 2em 0; float: left; } + +/* ===== Progress ===== */ +.progress{ + width: 51%; + clear: both; + height: 1.2em; + background-color: var(--bg-2); + border: 1px solid var(--accent); /* accent border */ + border-radius: 1em; + margin-bottom: 0.4em; +} +.progress_inner{ + height: 100%; + background-color: var(--accent); /* accent fill */ + border-radius: 1em; +} + +/* ===== Config panel ===== */ +#config{ + max-height: 0; + overflow: hidden; + width: 20em; + position: absolute; + top: 0; + left: 24.5em; + background-color: var(--bg-2); + border-radius: 0.5em; + transition: max-height 0.5s; + box-shadow: 0 2px 8px var(--shadow); +} +#configwrapper{ float: left; padding: 3em 0 1em 2em; } +#config.active{ display: block; max-height: 50em; } +#configbutton{ position: relative; z-index: 2; width: 3em; padding: 0; height: 2.5em; background-position: 50%; } +#zoominbutton, #zoomoutbutton, #exitbutton{ width: 3em; padding: 0; height: 2.5em; background-position: 50%; } +#configbutton.close:hover{ box-shadow: none; } +#configsave{ margin-left: 7%; } + +#config input, #config h3, #config .tooltip{ margin: 1em 0 0 0; height: 2em; padding: 0; } +#config input{ + float: left; width: 13%; font-size: 1em; + border: 1px solid var(--accent); + color: var(--text); + background: #141414; + text-align: center; clear: left; border-radius: 0.4em; + transition: border-color .15s ease, background-color .15s ease; +} +#config input:hover{ background-color: #181818; border-color: var(--accent-2); } +#config input.checkbox{ width: 7%; margin-left: 4%; margin-right: 4%; border: 1px solid var(--border); } +#config h3{ float: left; width: 65%; margin-left: 5%; padding: 0; font-size: 0.8em; line-height: 3em; color: var(--muted); } +#config .tooltip{ + float: left; max-width: 15%; width: 1.5em; height: 1.5em; + font-size: 0.8em; font-weight: bold; background-color: var(--accent); + color: #fff; text-align: center; line-height: 1.5; margin-top: 1.8em; + cursor: default; border-radius: 3em; +} +#config .button{ float: left; clear: both; margin-top: 2em; } + +/* ===== SVG areas ===== */ +#select{ margin-top: 2em; } +#select, #bins{ float: left; width: 69%; position: relative; } + +#select svg, #bins svg{ + width: 100%; height: auto; position: absolute; top: 0; + margin: 0; display: block; overflow: visible; pointer-events: none; +} + +/* Selection strokes (use accent; override uploaded inline styles) */ +#select svg *{ + fill: #fff !important; + fill-opacity: 0 !important; + stroke: var(--accent) !important; + stroke-width: 2px !important; + vector-effect: non-scaling-stroke !important; + stroke-linejoin: round !important; + pointer-events: fill !important; +} +#select svg *.fullRect{ + fill: #1b1b1b !important; + fill-opacity: 1 !important; + stroke: #1b1b1b !important; + stroke-width: 2px !important; + vector-effect: non-scaling-stroke !important; + stroke-linejoin: round !important; +} +#select svg *:hover{ stroke: var(--accent-2) !important; cursor: pointer !important; } +#select svg *.active{ stroke: var(--accent-2) !important; stroke-width: 3px !important; } +#select.disabled svg *, #select.disabled svg *:hover, #select.disabled svg *.active{ + stroke: #6b6b6b !important; stroke-width: 2px !important; cursor: default !important; +} + +/* Bins (neutral grays) */ +#bins svg{ margin-bottom: 2em; } +#bins svg.grid{ float: left; width: 45%; margin-right: 5%; min-width: 20em; } +#bins svg *{ + fill: var(--gray-4) !important; + stroke: var(--gray-3) !important; + stroke-width: 2px !important; + vector-effect: non-scaling-stroke !important; + stroke-linejoin: round !important; +} +#bins svg .bin{ fill: var(--bg-3) !important; stroke: var(--gray-4) !important; } +#bins svg .hole{ fill: var(--bg) !important; stroke: var(--gray-3) !important; } + +/* ===== Messages ===== */ +#messagewrapper{ + width: 50em; overflow: hidden; + background: var(--gray-4) url(img/close.svg) no-repeat 99% 0.5em / 3em 3em; + line-height: 4em; + position: fixed; left: 50%; margin-left: -25em; bottom: 1em; + text-align: center; border-radius: 0.5em; color: #fff; + box-shadow: 0 6px 24px var(--shadow); + border-left: 4px solid var(--accent); /* subtle accent marker */ +} +#messagewrapper:hover{ background-color: #666; border-left-color: var(--accent-2); } +#message{ overflow: hidden; height: 0; } +#message.active, #message.error{ height: 4em; cursor: pointer; } +#message.error{ color: #ff314e; font-weight: bold; } + +/* ===== Animations (kept intact) ===== */ +.animated{ + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} +@-webkit-keyframes bounce{ + from,20%,53%,80%,to{ + -webkit-animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000); + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } + 40%,43%{ + -webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-30px,0); + transform: translate3d(0,-30px,0); + } + 70%{ + -webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-15px,0); + transform: translate3d(0,-15px,0); + } + 90%{ + -webkit-transform: translate3d(0,-4px,0); + transform: translate3d(0,-4px,0); + } +} +@keyframes bounce{ + from,20%,53%,80%,to{ + animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000); + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } + 40%,43%{ + animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-30px,0); + transform: translate3d(0,-30px,0); + } + 70%{ + animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060); + -webkit-transform: translate3d(0,-15px,0); + transform: translate3d(0,-15px,0); + } + 90%{ + -webkit-transform: translate3d(0,-4px,0); + transform: translate3d(0,-4px,0); + } +} +.bounce{ + -webkit-animation-name: bounce; + animation-name: bounce; + -webkit-transform-origin: center bottom; + transform-origin: center bottom; +} +@-webkit-keyframes slideInUp{ + from{ + -webkit-transform: translate3d(0,100%,0); + transform: translate3d(0,100%,0); + visibility: visible; + } + to{ + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } +} +@keyframes slideInUp{ + from{ + -webkit-transform: translate3d(0,100%,0); + transform: translate3d(0,100%,0); + visibility: visible; + } + to{ + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + } +} +.slideInUp{ + -webkit-animation-name: slideInUp; + animation-name: slideInUp; +} + +/* ===== Responsive ===== */ +@media only screen and (max-width: 1800px){ + body { font-size: 20px; } + #svgnest, #messagewrapper{ width: 60em; } + .progress{ width: 61%; } +} + +@media only screen and (max-width: 1500px){ + body { font-size: 16px; } + + #svgnest, #messagewrapper{ width: 50em; } + /* replaces old 5em top margin */ + #svgnest{ margin-top: clamp(0.75rem, 2vh, 1.5rem); } + + #svgnest .logo{ width: 25%; } + #controls{ margin-top: 0.75em; } + + #splash .logo{ width: 60%; margin: 0 20%; } + #splash h1.title{ margin: 0; font-size: 2em; } + #splash .subscript{ font-size: 1em; } + + h1.label{ font-size: 3em; } + .progress{ width: 75%; } +} + +@media only screen and (max-width: 1300px){ + body { font-size: 14px; } +} + +@media only screen and (max-width: 790px){ + #splash{ width: 100%; } + #splash .logo{ width: 40%; margin-left: 30%; float: left; } + #splash h1.title{ margin: 0; font-size: 2em; } + #splash .subscript{ font-size: 1em; } + body { font-size: 18px; } + + #splash .nav{ width: 60%; margin-left: 20%; margin-top: 2em; } + #splash .nav li{ float: none; display: block; margin-top: 1em; } + + #faq{ padding: 3em; } +} + +/* ===== MakeArmy splash nav & buttons — one-row, mono font, less rounded ===== */ + +/* use Hack sitewide */ +html, body { + font-family: "Hack", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; +} + +/* kill the old float hack and center as a single flex row */ +#splash .nav { + /* override old: float:left; width:150%; margin: 4em 0 0 -20%; */ + float: none; + width: auto; + margin: 3rem auto 0 auto; + padding: 0; + + display: flex; + align-items: center; + justify-content: center; + + /* keep them on one line on wide screens */ + flex-wrap: nowrap; + gap: 18px; +} + +/* list items no longer float */ +#splash .nav li { + list-style: none; + float: none; +} + +/* button shape: slimmer, less rounded, mono font keeps line-height crisp */ +#splash .nav .button { + border-radius: 12px; /* was pill; now closer to your other UI */ + padding: 0.55em 1.2em; /* a bit tighter so all fit in one row */ + font-size: 0.95em; + line-height: 1.2; + white-space: nowrap; /* prevent label wrapping */ +} + +/* keep left padding for icon-capable buttons (no icon on Back is fine) */ +#splash .nav .button.start { padding-left: 3.7em; } +#splash .nav .button.spinner { padding-left: 3.7em; } +#splash .nav .button.upload { padding-left: 4em; } +#splash .nav .button.download { padding-left: 4em; } +#splash .nav .button.code { padding-left: 3.9em; } +#splash .nav .button.config { padding-left: 3.9em; } +#splash .nav .button.close { padding-left: 3.9em; } + +/* ensure the standalone Back button visually matches height/shape */ +#splash .nav .button.back { + /* no extra left padding (no icon), but same height/roundedness */ +} + +/* responsive fallback: allow wrapping only on truly narrow screens */ +@media (max-width: 860px) { + #splash .nav { + flex-wrap: wrap; + row-gap: 12px; + } +} + + +/* ===== Splash buttons: sharp corners, no icons, one row ===== */ + +/* one-line row stays the same */ +#splash .nav{ + display:flex; align-items:center; justify-content:center; + flex-wrap:nowrap; gap:14px; /* you can nudge this if you need space */ + margin:3rem auto 0; padding:0; width:auto; float:none; +} + +/* kill legacy floats */ +#splash .nav li{ list-style:none; float:none; } + +/* sharper buttons + uniform padding */ +#splash .nav .button{ + border-radius:6px; /* sharper (not quite square) */ + padding:0.55em 1.2em; /* same for all buttons */ + font-size:0.95em; + line-height:1.2; + white-space:nowrap; +} + +/* nuke all icon pseudo-elements from the splash row */ +#splash .nav .button::before{ display:none !important; } + +/* remove the old “extra left padding for icons” */ +#splash .nav .button.start, +#splash .nav .button.spinner, +#splash .nav .button.upload, +#splash .nav .button.download, +#splash .nav .button.code, +#splash .nav .button.config, +#splash .nav .button.close{ + padding:0.55em 1.2em; +} + +/* responsive: only wrap on narrow screens */ +@media (max-width: 860px){ + #splash .nav{ flex-wrap:wrap; row-gap:12px; } +} + +/* ===== Powered-by footer on splash ===== */ +#poweredby{ + margin: 1.25rem auto 0; + text-align: center; + font-size: 0.95rem; + color: var(--muted); + max-width: 72ch; +} +#poweredby a{ + color: var(--accent); + text-decoration: underline; +} +#poweredby a:hover{ color: var(--accent-2); } + + + +/* Restore icon backgrounds for app controls (non-splash) */ +.button.start{ background: #1a1a1a url(img/start.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; } +.button.spinner{ background: #1a1a1a url(img/spin.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; } +.button.upload{ background: #1a1a1a url(img/upload.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; } +.button.download{ background: #1a1a1a url(img/download.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; } +.button.code{ background: #1a1a1a url(img/code.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; } +.button.config{ background: #1a1a1a url(img/settings.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; } +.button.close{ background: #1a1a1a url(img/close.svg) no-repeat 1.8em 50%; background-size: 2em 2em; padding-left: 3.9em; } +.button.zoomin{ background: #1a1a1a url(img/zoomin.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; } +.button.zoomout{ background: #1a1a1a url(img/zoomout.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; } +.button.exit{ background: #1a1a1a url(img/close.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; } + + + +/* Keep splash narrow; stretch only its nav/footer for centering */ +#splash{ width:28em; margin:8% auto 0 auto; } +#splash .logo{ max-width: 220px; width: 50%; margin: 0 0 0 25%; height:auto; display:block; } +#splash .nav, #poweredby{ width:100%; text-align:center; } + + + +/* --- Splash page buttons override: text-only, no icons --- */ +#splash .nav .button { + border-radius: 6px; + padding: 0.55em 1.2em; + font-size: 0.95em; + line-height: 1.2; + white-space: nowrap; + + background-image: none !important; + padding-left: 1.2em !important; /* uniform spacing */ +} + diff --git a/public/svgnest/svgnest.js b/public/svgnest/svgnest.js new file mode 100644 index 00000000..187356ad --- /dev/null +++ b/public/svgnest/svgnest.js @@ -0,0 +1,988 @@ +/*! + * SvgNest + * Licensed under the MIT license + */ + +(function(root){ + 'use strict'; + + root.SvgNest = new SvgNest(); + + function SvgNest(){ + var self = this; + + var svg = null; + + // keep a reference to any style nodes, to maintain color/fill info + this.style = null; + + var parts = null; + + var tree = null; + + + var bin = null; + var binPolygon = null; + var binBounds = null; + var nfpCache = {}; + var config = { + clipperScale: 10000000, + curveTolerance: 0.3, + spacing: 0, + rotations: 4, + populationSize: 10, + mutationRate: 10, + useHoles: false, + exploreConcave: false + }; + + this.working = false; + + var GA = null; + var best = null; + var workerTimer = null; + var progress = 0; + + this.parsesvg = function(svgstring){ + // reset if in progress + this.stop(); + + bin = null; + binPolygon = null; + tree = null; + + // parse svg + svg = SvgParser.load(svgstring); + + this.style = SvgParser.getStyle(); + + svg = SvgParser.clean(); + + tree = this.getParts(svg.childNodes); + + //re-order elements such that deeper elements are on top, so they can be moused over + function zorder(paths){ + // depth-first + var length = paths.length; + for(var i=0; i 0){ + zorder(paths[i].children); + } + } + } + + return svg; + } + + this.setbin = function(element){ + if(!svg){ + return; + } + bin = element; + } + + this.config = function(c){ + // clean up inputs + + if(!c){ + return config; + } + + if(c.curveTolerance && !GeometryUtil.almostEqual(parseFloat(c.curveTolerance), 0)){ + config.curveTolerance = parseFloat(c.curveTolerance); + } + + if('spacing' in c){ + config.spacing = parseFloat(c.spacing); + } + + if(c.rotations && parseInt(c.rotations) > 0){ + config.rotations = parseInt(c.rotations); + } + + if(c.populationSize && parseInt(c.populationSize) > 2){ + config.populationSize = parseInt(c.populationSize); + } + + if(c.mutationRate && parseInt(c.mutationRate) > 0){ + config.mutationRate = parseInt(c.mutationRate); + } + + if('useHoles' in c){ + config.useHoles = !!c.useHoles; + } + + if('exploreConcave' in c){ + config.exploreConcave = !!c.exploreConcave; + } + + SvgParser.config({ tolerance: config.curveTolerance}); + + best = null; + nfpCache = {}; + binPolygon = null; + GA = null; + + return config; + } + + // progressCallback is called when progress is made + // displayCallback is called when a new placement has been made + this.start = function(progressCallback, displayCallback){ + if(!svg || !bin){ + return false; + } + + parts = Array.prototype.slice.call(svg.childNodes); + var binindex = parts.indexOf(bin); + + if(binindex >= 0){ + // don't process bin as a part of the tree + parts.splice(binindex, 1); + } + + // build tree without bin + tree = this.getParts(parts.slice(0)); + + offsetTree(tree, 0.5*config.spacing, this.polygonOffset.bind(this)); + + // offset tree recursively + function offsetTree(t, offset, offsetFunction){ + for(var i=0; i 0){ + offsetTree(t[i].childNodes, -offset, offsetFunction); + } + } + } + + binPolygon = SvgParser.polygonify(bin); + binPolygon = this.cleanPolygon(binPolygon); + + if(!binPolygon || binPolygon.length < 3){ + return false; + } + + binBounds = GeometryUtil.getPolygonBounds(binPolygon); + + if(config.spacing > 0){ + var offsetBin = this.polygonOffset(binPolygon, -0.5*config.spacing); + if(offsetBin.length == 1){ + // if the offset contains 0 or more than 1 path, something went wrong. + binPolygon = offsetBin.pop(); + } + } + + binPolygon.id = -1; + + // put bin on origin + var xbinmax = binPolygon[0].x; + var xbinmin = binPolygon[0].x; + var ybinmax = binPolygon[0].y; + var ybinmin = binPolygon[0].y; + + for(var i=1; i xbinmax){ + xbinmax = binPolygon[i].x; + } + else if(binPolygon[i].x < xbinmin){ + xbinmin = binPolygon[i].x; + } + if(binPolygon[i].y > ybinmax){ + ybinmax = binPolygon[i].y; + } + else if(binPolygon[i].y < ybinmin){ + ybinmin = binPolygon[i].y; + } + } + + for(i=0; i 0){ + binPolygon.reverse(); + } + + // remove duplicate endpoints, ensure counterclockwise winding direction + for(i=0; i 0){ + tree[i].reverse(); + } + } + + var self = this; + this.working = false; + + workerTimer = setInterval(function(){ + if(!self.working){ + self.launchWorkers.call(self, tree, binPolygon, config, progressCallback, displayCallback); + self.working = true; + } + + progressCallback(progress); + }, 100); + } + + this.launchWorkers = function(tree, binPolygon, config, progressCallback, displayCallback){ + function shuffle(array) { + var currentIndex = array.length, temporaryValue, randomIndex ; + + // While there remain elements to shuffle... + while (0 !== currentIndex) { + + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; + } + + var i,j; + + if(GA === null){ + // initiate new GA + var adam = tree.slice(0); + + // seed with decreasing area + adam.sort(function(a, b){ + return Math.abs(GeometryUtil.polygonArea(b)) - Math.abs(GeometryUtil.polygonArea(a)); + }); + + GA = new GeneticAlgorithm(adam, binPolygon, config); + } + + var individual = null; + + // evaluate all members of the population + for(i=0; i 0){ + for(var i=0; i 0){ + nfp[i].reverse(); + } + } + } + else{ + // warning on null inner NFP + // this is not an error, as the part may simply be larger than the bin or otherwise unplaceable due to geometry + log('NFP Warning: ', pair.key); + } + } + else{ + if(searchEdges){ + nfp = GeometryUtil.noFitPolygon(A,B,false,searchEdges); + } + else{ + nfp = minkowskiDifference(A,B); + } + // sanity check + if(!nfp || nfp.length == 0){ + log('NFP Error: ', pair.key); + log('A: ',JSON.stringify(A)); + log('B: ',JSON.stringify(B)); + return null; + } + + for(var i=0; i 0){ + nfp[i].reverse(); + } + + if(i > 0){ + if(GeometryUtil.pointInPolygon(nfp[i][0], nfp[0])){ + if(GeometryUtil.polygonArea(nfp[i]) < 0){ + nfp[i].reverse(); + } + } + } + } + + // generate nfps for children (holes of parts) if any exist + if(useHoles && A.childNodes && A.childNodes.length > 0){ + var Bbounds = GeometryUtil.getPolygonBounds(B); + + for(var i=0; i Bbounds.width && Abounds.height > Bbounds.height){ + + var cnfp = GeometryUtil.noFitPolygon(A.childNodes[i],B,true,searchEdges); + // ensure all interior NFPs have the same winding direction + if(cnfp && cnfp.length > 0){ + for(var j=0; j sarea){ + clipperNfp = n; + largestArea = sarea; + } + } + + for(var i=0; i 2 && Math.abs(GeometryUtil.polygonArea(poly)) > config.curveTolerance*config.curveTolerance){ + poly.source = i; + polygons.push(poly); + } + } + + // turn the list into a tree + toTree(polygons); + + function toTree(list, idstart){ + var parents = []; + var i,j; + + // assign a unique id to each leaf + var id = idstart || 0; + + for(i=0; i biggestarea){ + biggest = simple[i]; + biggestarea = area; + } + } + + // clean up singularities, coincident points and edges + var clean = ClipperLib.Clipper.CleanPolygon(biggest, config.curveTolerance*config.clipperScale); + + if(!clean || clean.length == 0){ + return null; + } + + return this.clipperToSvg(clean); + } + + // converts a polygon from normal float coordinates to integer coordinates used by clipper, as well as x/y -> X/Y + this.svgToClipper = function(polygon){ + var clip = []; + for(var i=0; i 0){ + var flattened = _flattenTree(part.children, true); + for(k=0; k 0){ + flat = flat.concat(_flattenTree(t[i].children, !hole)); + } + } + + return flat; + } + + return svglist; + } + + this.stop = function(){ + this.working = false; + if(workerTimer){ + clearInterval(workerTimer); + } + }; + } + + function GeneticAlgorithm(adam, bin, config){ + + this.config = config || { populationSize: 10, mutationRate: 10, rotations: 4 }; + this.binBounds = GeometryUtil.getPolygonBounds(bin); + + // population is an array of individuals. Each individual is a object representing the order of insertion and the angle each part is rotated + var angles = []; + for(var i=0; i 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + return array; + } + + angleList = shuffleArray(angleList); + + for(i=0; i= 0){ + pop.splice(pop.indexOf(exclude),1); + } + + var rand = Math.random(); + + var lower = 0; + var weight = 1/pop.length; + var upper = weight; + + for(var i=0; i lower && rand < upper){ + return pop[i]; + } + lower = upper; + upper += 2*weight * ((pop.length-i)/pop.length); + } + + return pop[0]; + } + +})(window); diff --git a/public/svgnest/svgparser.js b/public/svgnest/svgparser.js new file mode 100644 index 00000000..f7f96be1 --- /dev/null +++ b/public/svgnest/svgparser.js @@ -0,0 +1,793 @@ +/*! + * SvgParser + * A library to convert an SVG string to parse-able segments for CAD/CAM use + * Licensed under the MIT license + */ + + (function(root){ + 'use strict'; + + function SvgParser(){ + // the SVG document + this.svg; + + // the top level SVG element of the SVG document + this.svgRoot; + + this.allowedElements = ['svg','circle','ellipse','path','polygon','polyline','rect', 'line']; + + this.conf = { + tolerance: 2, // max bound for bezier->line segment conversion, in native SVG units + toleranceSvg: 0.005 // fudge factor for browser inaccuracy in SVG unit handling + }; + } + + SvgParser.prototype.config = function(config){ + this.conf.tolerance = config.tolerance; + } + + SvgParser.prototype.load = function(svgString){ + + if(!svgString || typeof svgString !== 'string'){ + throw Error('invalid SVG string'); + } + + var parser = new DOMParser(); + var svg = parser.parseFromString(svgString, "image/svg+xml"); + + this.svgRoot = false; + + if(svg){ + this.svg = svg; + + for(var i=0; i 0){ + var transform = this.transformParse(transformString); + } + + if(!transform){ + transform = new Matrix(); + } + + var tarray = transform.toArray(); + + // decompose affine matrix to rotate, scale components (translate is just the 3rd column) + var rotate = Math.atan2(tarray[1], tarray[3])*180/Math.PI; + var scale = Math.sqrt(tarray[0]*tarray[0]+tarray[2]*tarray[2]); + + if(element.tagName == 'g' || element.tagName == 'svg' || element.tagName == 'defs' || element.tagName == 'clipPath'){ + element.removeAttribute('transform'); + var children = Array.prototype.slice.call(element.childNodes); + + for(var i=0; i 0){ + element.parentElement.appendChild(element.childNodes[0]); + } + } + } + + // remove all elements with tag name not in the whitelist + // use this to remove , etc that don't represent shapes + SvgParser.prototype.filter = function(whitelist, element){ + if(!whitelist || whitelist.length == 0){ + throw Error('invalid whitelist'); + } + + element = element || this.svgRoot; + + for(var i=0; i=0; i--){ + if(i > 0 && seglist[i].pathSegTypeAsLetter == 'M' || seglist[i].pathSegTypeAsLetter == 'm'){ + lastM = i; + break; + } + } + + if(lastM == 0){ + return false; // only 1 M command, no need to split + } + + for( i=0; i 1){ + path.parentElement.insertBefore(paths[i], path); + addedPaths.push(paths[i]); + } + } + + path.remove(); + + return addedPaths; + } + + // recursively run the given function on the given element + SvgParser.prototype.recurse = function(element, func){ + // only operate on original DOM tree, ignore any children that are added. Avoid infinite loops + var children = Array.prototype.slice.call(element.childNodes); + for(var i=0; i 0 && /[QqTt]/.test(seglist.getItem(i-1).pathSegTypeAsLetter)){ + x1 = prevx + (prevx-prevx1); + y1 = prevy + (prevy-prevy1); + } + else{ + x1 = prevx; + y1 = prevy; + } + case 'q': + case 'Q': + var pointlist = GeometryUtil.QuadraticBezier.linearize({x: prevx, y: prevy}, {x: x, y: y}, {x: x1, y: y1}, this.conf.tolerance); + pointlist.shift(); // firstpoint would already be in the poly + for(var j=0; j 0 && /[CcSs]/.test(seglist.getItem(i-1).pathSegTypeAsLetter)){ + x1 = prevx + (prevx-prevx2); + y1 = prevy + (prevy-prevy2); + } + else{ + x1 = prevx; + y1 = prevy; + } + case 'c': + case 'C': + var pointlist = GeometryUtil.CubicBezier.linearize({x: prevx, y: prevy}, {x: x, y: y}, {x: x1, y: y1}, {x: x2, y: y2}, this.conf.tolerance); + pointlist.shift(); // firstpoint would already be in the poly + for(var j=0; j 0 && GeometryUtil.almostEqual(poly[0].x,poly[poly.length-1].x, this.conf.toleranceSvg) && GeometryUtil.almostEqual(poly[0].y,poly[poly.length-1].y, this.conf.toleranceSvg)){ + poly.pop(); + } + + return poly; + }; + + // expose public methods + var parser = new SvgParser(); + + root.SvgParser = { + config: parser.config.bind(parser), + load: parser.load.bind(parser), + getStyle: parser.getStyle.bind(parser), + clean: parser.cleanInput.bind(parser), + polygonify: parser.polygonify.bind(parser) + }; + +}(window)); \ No newline at end of file diff --git a/public/svgnest/util/clipper.js b/public/svgnest/util/clipper.js new file mode 100644 index 00000000..39191292 --- /dev/null +++ b/public/svgnest/util/clipper.js @@ -0,0 +1,244 @@ +// rev 452 +/******************************************************************************** + * * + * Author : Angus Johnson * + * Version : 6.1.3a * + * Date : 22 January 2014 * + * Website : http://www.angusj.com * + * Copyright : Angus Johnson 2010-2014 * + * * + * License: * + * Use, modification & distribution is subject to Boost Software License Ver 1. * + * http://www.boost.org/LICENSE_1_0.txt * + * * + * Attributions: * + * The code in this library is an extension of Bala Vatti's clipping algorithm: * + * "A generic solution to polygon clipping" * + * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * + * http://portal.acm.org/citation.cfm?id=129906 * + * * + * Computer graphics and geometric modeling: implementation and algorithms * + * By Max K. Agoston * + * Springer; 1 edition (January 4, 2005) * + * http://books.google.com/books?q=vatti+clipping+agoston * + * * + * See also: * + * "Polygon Offsetting by Computing Winding Numbers" * + * Paper no. DETC2005-85513 pp. 565-575 * + * ASME 2005 International Design Engineering Technical Conferences * + * and Computers and Information in Engineering Conference (IDETC/CIE2005) * + * September 24-28, 2005 , Long Beach, California, USA * + * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * + * * + *******************************************************************************/ +/******************************************************************************* + * * + * Author : Timo * + * Version : 6.1.3.2 * + * Date : 1 February 2014 * + * * + * This is a translation of the C# Clipper library to Javascript. * + * Int128 struct of C# is implemented using JSBN of Tom Wu. * + * Because Javascript lacks support for 64-bit integers, the space * + * is a little more restricted than in C# version. * + * * + * C# version has support for coordinate space: * + * +-4611686018427387903 ( sqrt(2^127 -1)/2 ) * + * while Javascript version has support for space: * + * +-4503599627370495 ( sqrt(2^106 -1)/2 ) * + * * + * Tom Wu's JSBN proved to be the fastest big integer library: * + * http://jsperf.com/big-integer-library-test * + * * + * This class can be made simpler when (if ever) 64-bit integer support comes. * + * * + *******************************************************************************/ +/******************************************************************************* + * * + * Basic JavaScript BN library - subset useful for RSA encryption. * + * http://www-cs-students.stanford.edu/~tjw/jsbn/ * + * Copyright (c) 2005 Tom Wu * + * All Rights Reserved. * + * See "LICENSE" for details: * + * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE * + * * + *******************************************************************************/ +(function(){function k(a,b,c){d.biginteger_used=1;null!=a&&("number"==typeof a&&"undefined"==typeof b?this.fromInt(a):"number"==typeof a?this.fromNumber(a,b,c):null==b&&"string"!=typeof a?this.fromString(a,256):this.fromString(a,b))}function q(){return new k(null)}function Q(a,b,c,e,d,g){for(;0<=--g;){var h=b*this[a++]+c[e]+d;d=Math.floor(h/67108864);c[e++]=h&67108863}return d}function R(a,b,c,e,d,g){var h=b&32767;for(b>>=15;0<=--g;){var l=this[a]&32767,k=this[a++]>>15,n=b*l+k*h,l=h*l+((n&32767)<< +15)+c[e]+(d&1073741823);d=(l>>>30)+(n>>>15)+b*k+(d>>>30);c[e++]=l&1073741823}return d}function S(a,b,c,e,d,g){var h=b&16383;for(b>>=14;0<=--g;){var l=this[a]&16383,k=this[a++]>>14,n=b*l+k*h,l=h*l+((n&16383)<<14)+c[e]+d;d=(l>>28)+(n>>14)+b*k;c[e++]=l&268435455}return d}function L(a,b){var c=B[a.charCodeAt(b)];return null==c?-1:c}function v(a){var b=q();b.fromInt(a);return b}function C(a){var b=1,c;0!=(c=a>>>16)&&(a=c,b+=16);0!=(c=a>>8)&&(a=c,b+=8);0!=(c=a>>4)&&(a=c,b+=4);0!=(c=a>>2)&&(a=c,b+=2);0!= +a>>1&&(b+=1);return b}function x(a){this.m=a}function y(a){this.m=a;this.mp=a.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<=u;++u)B[r++]=u;r=97;for(u=10;36>u;++u)B[r++]=u;r=65;for(u=10;36>u;++u)B[r++]=u;x.prototype.convert= +function(a){return 0>a.s||0<=a.compareTo(this.m)?a.mod(this.m):a};x.prototype.revert=function(a){return a};x.prototype.reduce=function(a){a.divRemTo(this.m,null,a)};x.prototype.mulTo=function(a,b,c){a.multiplyTo(b,c);this.reduce(c)};x.prototype.sqrTo=function(a,b){a.squareTo(b);this.reduce(b)};y.prototype.convert=function(a){var b=q();a.abs().dlShiftTo(this.m.t,b);b.divRemTo(this.m,null,b);0>a.s&&0>15)*this.mpl&this.um)<<15)&a.DM,c=b+this.m.t;for(a[c]+=this.m.am(0,e,a,b,0,this.m.t);a[c]>=a.DV;)a[c]-=a.DV,a[++c]++}a.clamp();a.drShiftTo(this.m.t,a);0<=a.compareTo(this.m)&&a.subTo(this.m,a)};y.prototype.mulTo=function(a,b,c){a.multiplyTo(b,c);this.reduce(c)};y.prototype.sqrTo=function(a,b){a.squareTo(b);this.reduce(b)};k.prototype.copyTo= +function(a){for(var b=this.t-1;0<=b;--b)a[b]=this[b];a.t=this.t;a.s=this.s};k.prototype.fromInt=function(a){this.t=1;this.s=0>a?-1:0;0a?this[0]=a+this.DV:this.t=0};k.prototype.fromString=function(a,b){var c;if(16==b)c=4;else if(8==b)c=3;else if(256==b)c=8;else if(2==b)c=1;else if(32==b)c=5;else if(4==b)c=2;else{this.fromRadix(a,b);return}this.s=this.t=0;for(var e=a.length,d=!1,g=0;0<=--e;){var h=8==c?a[e]&255:L(a,e);0>h?"-"==a.charAt(e)&&(d=!0):(d=!1,0==g?this[this.t++]=h:g+c>this.DB? +(this[this.t-1]|=(h&(1<>this.DB-g):this[this.t-1]|=h<=this.DB&&(g-=this.DB))}8==c&&0!=(a[0]&128)&&(this.s=-1,0>e|h,h=(this[l]&d)<=this.t)b.t=0;else{var e=a%this.DB,d=this.DB-e,g=(1<>e;for(var h=c+1;h>e;0>=this.DB;if(a.t>=this.DB;e+=this.s}else{for(e+=this.s;c>=this.DB;e-=a.s}b.s=0>e?-1:0;-1>e?b[c++]=this.DV+e:0=b.DV&&(a[c+b.t]-=b.DV,a[c+b.t+1]=1)}0=e.t)){var d=this.abs();if(d.t< +e.t)null!=b&&b.fromInt(0),null!=c&&this.copyTo(c);else{null==c&&(c=q());var g=q(),h=this.s;a=a.s;var l=this.DB-C(e[e.t-1]);0>this.F2:0),n=this.FV/z,z=(1<h&&k.ZERO.subTo(c,c)}}}};k.prototype.invDigit=function(){if(1>this.t)return 0;var a=this[0];if(0==(a&1))return 0;var b=a&3,b=b*(2-(a&15)*b)&15,b=b*(2-(a&255)*b)&255,b=b*(2-((a&65535)*b&65535))&65535,b=b*(2-a*b%this.DV)%this.DV;return 0a)return k.ONE;var c=q(),e=q(),d=b.convert(this),g=C(a)-1;for(d.copyTo(c);0<=--g;)if(b.sqrTo(c,e),0<(a&1<this.s)return"-"+this.negate().toString(a);if(16==a)a=4;else if(8==a)a=3;else if(2==a)a=1;else if(32==a)a=5;else if(4==a)a=2;else return this.toRadix(a);var b=(1<> +h)&&(e=!0,d="0123456789abcdefghijklmnopqrstuvwxyz".charAt(c));0<=g;)h>(h+=this.DB-a)):(c=this[g]>>(h-=a)&b,0>=h&&(h+=this.DB,--g)),0this.s?this.negate():this};k.prototype.compareTo=function(a){var b=this.s-a.s;if(0!=b)return b;var c=this.t,b=c-a.t;if(0!=b)return 0>this.s? +-b:b;for(;0<=--c;)if(0!=(b=this[c]-a[c]))return b;return 0};k.prototype.bitLength=function(){return 0>=this.t?0:this.DB*(this.t-1)+C(this[this.t-1]^this.s&this.DM)};k.prototype.mod=function(a){var b=q();this.abs().divRemTo(a,null,b);0>this.s&&0a||b.isEven()?new x(b):new y(b);return this.exp(a,c)};k.ZERO=v(0);k.ONE=v(1);A.prototype.convert=O;A.prototype.revert=O;A.prototype.mulTo=function(a,b,c){a.multiplyTo(b, +c)};A.prototype.sqrTo=function(a,b){a.squareTo(b)};w.prototype.convert=function(a){if(0>a.s||a.t>2*this.m.t)return a.mod(this.m);if(0>a.compareTo(this.m))return a;var b=q();a.copyTo(b);this.reduce(b);return b};w.prototype.revert=function(a){return a};w.prototype.reduce=function(a){a.drShiftTo(this.m.t-1,this.r2);a.t>this.m.t+1&&(a.t=this.m.t+1,a.clamp());this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);for(this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);0>a.compareTo(this.r2);)a.dAddOffset(1, +this.m.t+1);for(a.subTo(this.r2,a);0<=a.compareTo(this.m);)a.subTo(this.m,a)};w.prototype.mulTo=function(a,b,c){a.multiplyTo(b,c);this.reduce(c)};w.prototype.sqrTo=function(a,b){a.squareTo(b);this.reduce(b)};var t=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401, +409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],V=67108864/t[t.length-1];k.prototype.chunkSize=function(a){return Math.floor(Math.LN2*this.DB/Math.log(a))};k.prototype.toRadix=function(a){null== +a&&(a=10);if(0==this.signum()||2>a||36z?"-"==a.charAt(l)&&0==this.signum()&&(d=!0):(h=b*h+z,++g>=c&&(this.dMultiply(e),this.dAddOffset(h, +0),h=g=0))}0a)this.fromInt(1);else for(this.fromNumber(a,c),this.testBit(a-1)||this.bitwiseTo(k.ONE.shiftLeft(a-1),I,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(b);)this.dAddOffset(2,0),this.bitLength()>a&&this.subTo(k.ONE.shiftLeft(a-1),this);else{c=[];var e=a&7;c.length=(a>>3)+1;b.nextBytes(c);c[0]=0>=this.DB;if(a.t< +this.t){for(e+=a.s;c>=this.DB;e+=this.s}else{for(e+=this.s;c>=this.DB;e+=a.s}b.s=0>e?-1:0;0e&&(b[c++]=this.DV+e);b.t=c;b.clamp()};k.prototype.dMultiply=function(a){this[this.t]=this.am(0,a-1,this,0,0,this.t);++this.t;this.clamp()};k.prototype.dAddOffset=function(a,b){if(0!=a){for(;this.t<=b;)this[this.t++]=0;for(this[b]+=a;this[b]>=this.DV;)this[b]-=this.DV,++b>=this.t&&(this[this.t++]=0),++this[b]}};k.prototype.multiplyLowerTo= +function(a,b,c){var e=Math.min(this.t+a.t,b);c.s=0;for(c.t=e;0=a)return 0;var b=this.DV%a,c=0>this.s?a- +1:0;if(0=c)return!1;var e=b.shiftRight(c);a=a+1>>1;a>t.length&&(a=t.length);for(var d=q(),g=0;gthis.s){if(1==this.t)return this[0]-this.DV;if(0==this.t)return-1}else{if(1==this.t)return this[0];if(0==this.t)return 0}return(this[1]&(1<<32-this.DB)-1)<>24};k.prototype.shortValue=function(){return 0==this.t?this.s:this[0]<<16>>16};k.prototype.signum=function(){return 0>this.s?-1:0>=this.t||1==this.t&&0>=this[0]? +0:1};k.prototype.toByteArray=function(){var a=this.t,b=[];b[0]=this.s;var c=this.DB-a*this.DB%8,e,d=0;if(0>c)!=(this.s&this.DM)>>c&&(b[d++]=e|this.s<c?(e=(this[a]&(1<>(c+=this.DB-8)):(e=this[a]>>(c-=8)&255,0>=c&&(c+=this.DB,--a)),0!=(e&128)&&(e|=-256),0==d&&(this.s&128)!=(e&128)&&++d,0this.compareTo(a)? +this:a};k.prototype.max=function(a){return 0a?this.rShiftTo(-a,b):this.lShiftTo(a,b);return b};k.prototype.shiftRight=function(a){var b=q();0>a?this.lShiftTo(-a,b):this.rShiftTo(a,b);return b};k.prototype.getLowestSetBit=function(){for(var a=0;a>=16,c+=16);0==(a&255)&&(a>>=8,c+=8);0==(a&15)&&(a>>=4,c+=4);0==(a&3)&&(a>>=2,c+=2);0==(a&1)&&++c;a=c}return b+a}return 0>this.s?this.t*this.DB:-1};k.prototype.bitCount=function(){for(var a=0,b=this.s& +this.DM,c=0;c=this.t?0!=this.s:0!=(this[b]&1<=c)return d;e=18>c?1:48>c?3:144>c?4:768>c?5:6;g=8>c?new x(b):b.isEven()?new w(b):new y(b);var h=[],l=3,k=e-1,n=(1<< +e)-1;h[1]=g.convert(this);if(1=k?p=a[m]>>c-k&n:(p=(a[m]&(1<>this.DB+c-k));for(l=e;0==(p&1);)p>>=1,--l;0>(c-=l)&&(c+=this.DB,--m);if(r)h[p].copyTo(d),r=!1;else{for(;1--c&&(c=this.DB-1,--m)}return g.revert(d)};k.prototype.modInverse= +function(a){var b=a.isEven();if(this.isEven()&&b||0==a.signum())return k.ZERO;for(var c=a.clone(),e=this.clone(),d=v(1),g=v(0),h=v(0),l=v(1);0!=c.signum();){for(;c.isEven();)c.rShiftTo(1,c),b?(d.isEven()&&g.isEven()||(d.addTo(this,d),g.subTo(a,g)),d.rShiftTo(1,d)):g.isEven()||g.subTo(a,g),g.rShiftTo(1,g);for(;e.isEven();)e.rShiftTo(1,e),b?(h.isEven()&&l.isEven()||(h.addTo(this,h),l.subTo(a,l)),h.rShiftTo(1,h)):l.isEven()||l.subTo(a,l),l.rShiftTo(1,l);0<=c.compareTo(e)?(c.subTo(e,c),b&&d.subTo(h,d), +g.subTo(l,g)):(e.subTo(c,e),b&&h.subTo(d,h),l.subTo(g,l))}if(0!=e.compareTo(k.ONE))return k.ZERO;if(0<=l.compareTo(a))return l.subtract(a);if(0>l.signum())l.addTo(a,l);else return l;return 0>l.signum()?l.add(a):l};k.prototype.pow=function(a){return this.exp(a,new A)};k.prototype.gcd=function(a){var b=0>this.s?this.negate():this.clone();a=0>a.s?a.negate():a.clone();if(0>b.compareTo(a)){var c=b,b=a;a=c}var c=b.getLowestSetBit(),e=a.getLowestSetBit();if(0>e)return b;ca.compareTo(b)?!0:!1};m.op_Addition=function(a,b){return(new m(a)).add(new m(b))};m.op_Subtraction= +function(a,b){return(new m(a)).subtract(new m(b))};m.Int128Mul=function(a,b){return(new m(a)).multiply(new m(b))};m.op_Division=function(a,b){return a.divide(b)};m.prototype.ToDouble=function(){return parseFloat(this.toString())};if("undefined"==typeof K)var K=function(a,b){var c;if("undefined"==typeof Object.getOwnPropertyNames)for(c in b.prototype){if("undefined"==typeof a.prototype[c]||a.prototype[c]==Object.prototype[c])a.prototype[c]=b.prototype[c]}else for(var e=Object.getOwnPropertyNames(b.prototype), +d=0;da||2147483647a?Math.ceil(a):Math.floor(a):~~a}:F&&"function"==typeof Number.toInteger?function(a){return Number.toInteger(a)}:P||H?function(a){return parseInt(a,10)}:p?function(a){return-2147483648>a||2147483647a?Math.ceil(a):Math.floor(a):a|0}:function(a){return 0>a?Math.ceil(a): +Math.floor(a)};d.Clear=function(a){a.length=0};d.PI=3.141592653589793;d.PI2=6.283185307179586;d.IntPoint=function(){var a;a=arguments;var b=a.length;this.Y=this.X=0;2==b?(this.X=a[0],this.Y=a[1]):1==b?a[0]instanceof d.DoublePoint?(a=a[0],this.X=d.Clipper.Round(a.X),this.Y=d.Clipper.Round(a.Y)):(a=a[0],this.X=a.X,this.Y=a.Y):this.Y=this.X=0};d.IntPoint.op_Equality=function(a,b){return a.X==b.X&&a.Y==b.Y};d.IntPoint.op_Inequality=function(a,b){return a.X!=b.X||a.Y!=b.Y};d.IntPoint0=function(){this.Y= +this.X=0};d.IntPoint1=function(a){this.X=a.X;this.Y=a.Y};d.IntPoint1dp=function(a){this.X=d.Clipper.Round(a.X);this.Y=d.Clipper.Round(a.Y)};d.IntPoint2=function(a,b){this.X=a;this.Y=b};d.IntRect=function(){var a=arguments,b=a.length;4==b?(this.left=a[0],this.top=a[1],this.right=a[2],this.bottom=a[3]):1==b?(this.left=ir.left,this.top=ir.top,this.right=ir.right,this.bottom=ir.bottom):this.bottom=this.right=this.top=this.left=0};d.IntRect0=function(){this.bottom=this.right=this.top=this.left=0};d.IntRect1= +function(a){this.left=a.left;this.top=a.top;this.right=a.right;this.bottom=a.bottom};d.IntRect4=function(a,b,c,e){this.left=a;this.top=b;this.right=c;this.bottom=e};d.ClipType={ctIntersection:0,ctUnion:1,ctDifference:2,ctXor:3};d.PolyType={ptSubject:0,ptClip:1};d.PolyFillType={pftEvenOdd:0,pftNonZero:1,pftPositive:2,pftNegative:3};d.JoinType={jtSquare:0,jtRound:1,jtMiter:2};d.EndType={etOpenSquare:0,etOpenRound:1,etOpenButt:2,etClosedLine:3,etClosedPolygon:4};d.EdgeSide={esLeft:0,esRight:1};d.Direction= +{dRightToLeft:0,dLeftToRight:1};d.TEdge=function(){this.Bot=new d.IntPoint;this.Curr=new d.IntPoint;this.Top=new d.IntPoint;this.Delta=new d.IntPoint;this.Dx=0;this.PolyTyp=d.PolyType.ptSubject;this.Side=d.EdgeSide.esLeft;this.OutIdx=this.WindCnt2=this.WindCnt=this.WindDelta=0;this.PrevInSEL=this.NextInSEL=this.PrevInAEL=this.NextInAEL=this.NextInLML=this.Prev=this.Next=null};d.IntersectNode=function(){this.Edge2=this.Edge1=null;this.Pt=new d.IntPoint};d.MyIntersectNodeSort=function(){};d.MyIntersectNodeSort.Compare= +function(a,b){return b.Pt.Y-a.Pt.Y};d.LocalMinima=function(){this.Y=0;this.Next=this.RightBound=this.LeftBound=null};d.Scanbeam=function(){this.Y=0;this.Next=null};d.OutRec=function(){this.Idx=0;this.IsOpen=this.IsHole=!1;this.PolyNode=this.BottomPt=this.Pts=this.FirstLeft=null};d.OutPt=function(){this.Idx=0;this.Pt=new d.IntPoint;this.Prev=this.Next=null};d.Join=function(){this.OutPt2=this.OutPt1=null;this.OffPt=new d.IntPoint};d.ClipperBase=function(){this.m_CurrentLM=this.m_MinimaList=null;this.m_edges= +[];this.PreserveCollinear=this.m_HasOpenPaths=this.m_UseFullRange=!1;this.m_CurrentLM=this.m_MinimaList=null;this.m_HasOpenPaths=this.m_UseFullRange=!1};d.ClipperBase.horizontal=-9007199254740992;d.ClipperBase.Skip=-2;d.ClipperBase.Unassigned=-1;d.ClipperBase.tolerance=1E-20;d.ClipperBase.loRange=47453132;d.ClipperBase.hiRange=0xfffffffffffff;d.ClipperBase.near_zero=function(a){return a>-d.ClipperBase.tolerance&&ab.X==a.Xb.Y==a.Yb.X==a.Xb.Y==a.Yd.ClipperBase.hiRange||a.Y>d.ClipperBase.hiRange||-a.X>d.ClipperBase.hiRange||-a.Y>d.ClipperBase.hiRange)&& +d.Error("Coordinate outside allowed range in RangeTest().");else if(a.X>d.ClipperBase.loRange||a.Y>d.ClipperBase.loRange||-a.X>d.ClipperBase.loRange||-a.Y>d.ClipperBase.loRange)b.Value=!0,this.RangeTest(a,b)};d.ClipperBase.prototype.InitEdge=function(a,b,c,e){a.Next=b;a.Prev=c;a.Curr.X=e.X;a.Curr.Y=e.Y;a.OutIdx=-1};d.ClipperBase.prototype.InitEdge2=function(a,b){a.Curr.Y>=a.Next.Curr.Y?(a.Bot.X=a.Curr.X,a.Bot.Y=a.Curr.Y,a.Top.X=a.Next.Curr.X,a.Top.Y=a.Next.Curr.Y):(a.Top.X=a.Curr.X,a.Top.Y=a.Curr.Y, +a.Bot.X=a.Next.Curr.X,a.Bot.Y=a.Next.Curr.Y);this.SetDx(a);a.PolyTyp=b};d.ClipperBase.prototype.FindNextLocMin=function(a){for(var b;;){for(;d.IntPoint.op_Inequality(a.Bot,a.Prev.Bot)||d.IntPoint.op_Equality(a.Curr,a.Top);)a=a.Next;if(a.Dx!=d.ClipperBase.horizontal&&a.Prev.Dx!=d.ClipperBase.horizontal)break;for(;a.Prev.Dx==d.ClipperBase.horizontal;)a=a.Prev;for(b=a;a.Dx==d.ClipperBase.horizontal;)a=a.Next;if(a.Top.Y!=a.Prev.Bot.Y){b.Prev.Bot.Xe.Next.Top.X&&(e=f.Prev)}for(;a!=e;)a.NextInLML=a.Next,a.Dx==d.ClipperBase.horizontal&& +a!=c&&a.Bot.X!=a.Prev.Top.X&&this.ReverseHorizontal(a),a=a.Next;a.Dx==d.ClipperBase.horizontal&&a!=c&&a.Bot.X!=a.Prev.Top.X&&this.ReverseHorizontal(a);e=e.Next}else{for(;e.Top.Y==e.Prev.Bot.Y&&e.Prev.OutIdx!=d.ClipperBase.Skip;)e=e.Prev;if(e.Dx==d.ClipperBase.horizontal&&e.Prev.OutIdx!=d.ClipperBase.Skip){for(f=e;f.Next.Dx==d.ClipperBase.horizontal;)f=f.Next;f.Next.Top.X==e.Prev.Top.X?b||(e=f.Next):f.Next.Top.X>e.Prev.Top.X&&(e=f.Next)}for(;a!=e;)a.NextInLML=a.Prev,a.Dx==d.ClipperBase.horizontal&& +a!=c&&a.Bot.X!=a.Next.Top.X&&this.ReverseHorizontal(a),a=a.Prev;a.Dx==d.ClipperBase.horizontal&&a!=c&&a.Bot.X!=a.Next.Top.X&&this.ReverseHorizontal(a);e=e.Prev}if(e.OutIdx==d.ClipperBase.Skip){a=e;if(b){for(;a.Top.Y==a.Next.Bot.Y;)a=a.Next;for(;a!=e&&a.Dx==d.ClipperBase.horizontal;)a=a.Prev}else{for(;a.Top.Y==a.Prev.Bot.Y;)a=a.Prev;for(;a!=e&&a.Dx==d.ClipperBase.horizontal;)a=a.Next}a==e?e=b?a.Next:a.Prev:(a=b?e.Next:e.Prev,c=new d.LocalMinima,c.Next=null,c.Y=a.Bot.Y,c.LeftBound=null,c.RightBound= +a,c.RightBound.WindDelta=0,e=this.ProcessBound(c.RightBound,b),this.InsertLocalMinima(c))}return e};d.ClipperBase.prototype.AddPath=function(a,b,c){c||b!=d.PolyType.ptClip||d.Error("AddPath: Open paths must be subject.");var e=a.length-1;if(c)for(;0e||!c&&1>e)return!1;for(var f=[],g=0;g<=e;g++)f.push(new d.TEdge);var h=!0;f[1].Curr.X=a[1].X;f[1].Curr.Y=a[1].Y;var l={Value:this.m_UseFullRange};this.RangeTest(a[0], +l);this.m_UseFullRange=l.Value;l.Value=this.m_UseFullRange;this.RangeTest(a[e],l);this.m_UseFullRange=l.Value;this.InitEdge(f[0],f[1],f[e],a[0]);this.InitEdge(f[e],f[0],f[e-1],a[e]);for(g=e-1;1<=g;--g)l.Value=this.m_UseFullRange,this.RangeTest(a[g],l),this.m_UseFullRange=l.Value,this.InitEdge(f[g],f[g+1],f[g-1],a[g]);for(g=a=e=f[0];;)if(d.IntPoint.op_Equality(a.Curr,a.Next.Curr)){if(a==a.Next)break;a==e&&(e=a.Next);g=a=this.RemoveEdge(a)}else{if(a.Prev==a.Next)break;else if(c&&d.ClipperBase.SlopesEqual(a.Prev.Curr, +a.Curr,a.Next.Curr,this.m_UseFullRange)&&(!this.PreserveCollinear||!this.Pt2IsBetweenPt1AndPt3(a.Prev.Curr,a.Curr,a.Next.Curr))){a==e&&(e=a.Next);a=this.RemoveEdge(a);g=a=a.Prev;continue}a=a.Next;if(a==g)break}if(!c&&a==a.Next||c&&a.Prev==a.Next)return!1;c||(this.m_HasOpenPaths=!0,e.Prev.OutIdx=d.ClipperBase.Skip);a=e;do this.InitEdge2(a,b),a=a.Next,h&&a.Curr.Y!=e.Curr.Y&&(h=!1);while(a!=e);if(h){if(c)return!1;a.Prev.OutIdx=d.ClipperBase.Skip;a.Prev.Bot.Xa.X==b.Xa.Y==b.Y=this.m_MinimaList.Y)a.Next=this.m_MinimaList,this.m_MinimaList=a;else{for(var b=this.m_MinimaList;null!==b.Next&&a.Ythis.m_Scanbeam.Y){var b=new d.Scanbeam;b.Y=a;b.Next=this.m_Scanbeam;this.m_Scanbeam=b}else{for(var c= +this.m_Scanbeam;null!==c.Next&&a<=c.Next.Y;)c=c.Next;a!=c.Y&&(b=new d.Scanbeam,b.Y=a,b.Next=c.Next,c.Next=b)}};d.Clipper.prototype.Execute=function(){var a=arguments,b=a.length,c=a[1]instanceof d.PolyTree;if(4!=b||c){if(4==b&&c){var b=a[0],e=a[1],c=a[2],a=a[3];if(this.m_ExecuteLocked)return!1;this.m_ExecuteLocked=!0;this.m_SubjFillType=c;this.m_ClipFillType=a;this.m_ClipType=b;this.m_UsingPolyTree=!0;try{(f=this.ExecuteInternal())&&this.BuildResult2(e)}finally{this.DisposeAllPolyPts(),this.m_ExecuteLocked= +!1}return f}if(2==b&&!c||2==b&&c)return b=a[0],e=a[1],this.Execute(b,e,d.PolyFillType.pftEvenOdd,d.PolyFillType.pftEvenOdd)}else{b=a[0];e=a[1];c=a[2];a=a[3];if(this.m_ExecuteLocked)return!1;this.m_HasOpenPaths&&d.Error("Error: PolyTree struct is need for open path clipping.");this.m_ExecuteLocked=!0;d.Clear(e);this.m_SubjFillType=c;this.m_ClipFillType=a;this.m_ClipType=b;this.m_UsingPolyTree=!1;try{var f=this.ExecuteInternal();f&&this.BuildResult(e)}finally{this.DisposeAllPolyPts(),this.m_ExecuteLocked= +!1}return f}};d.Clipper.prototype.FixHoleLinkage=function(a){if(null!==a.FirstLeft&&(a.IsHole==a.FirstLeft.IsHole||null===a.FirstLeft.Pts)){for(var b=a.FirstLeft;null!==b&&(b.IsHole==a.IsHole||null===b.Pts);)b=b.FirstLeft;a.FirstLeft=b}};d.Clipper.prototype.ExecuteInternal=function(){try{this.Reset();if(null===this.m_CurrentLM)return!1;var a=this.PopScanbeam();do{this.InsertLocalMinimaIntoAEL(a);d.Clear(this.m_GhostJoins);this.ProcessHorizontals(!1);if(null===this.m_Scanbeam)break;var b=this.PopScanbeam(); +if(!this.ProcessIntersections(a,b))return!1;this.ProcessEdgesAtTopOfScanbeam(b);a=b}while(null!==this.m_Scanbeam||null!==this.m_CurrentLM);for(var a=0,c=this.m_PolyOuts.length;aa.Top.Y?b.Top.Xd.Clipper.TopX(b,a.Top.Y):b.Curr.Xa.WindCnt2}case d.ClipType.ctUnion:switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0=== +a.WindCnt2;case d.PolyFillType.pftPositive:return 0>=a.WindCnt2;default:return 0<=a.WindCnt2}case d.ClipType.ctDifference:if(a.PolyTyp==d.PolyType.ptSubject)switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0===a.WindCnt2;case d.PolyFillType.pftPositive:return 0>=a.WindCnt2;default:return 0<=a.WindCnt2}else switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0!==a.WindCnt2;case d.PolyFillType.pftPositive:return 0 +a.WindCnt2}case d.ClipType.ctXor:if(0===a.WindDelta)switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0===a.WindCnt2;case d.PolyFillType.pftPositive:return 0>=a.WindCnt2;default:return 0<=a.WindCnt2}}return!0};d.Clipper.prototype.SetWindingCount=function(a){for(var b=a.PrevInAEL;null!==b&&(b.PolyTyp!=a.PolyTyp||0===b.WindDelta);)b=b.PrevInAEL;if(null===b)a.WindCnt=0===a.WindDelta?1:a.WindDelta,a.WindCnt2=0,b=this.m_ActiveEdges;else{if(0===a.WindDelta&&this.m_ClipType!= +d.ClipType.ctUnion)a.WindCnt=1;else if(this.IsEvenOddFillType(a))if(0===a.WindDelta){for(var c=!0,e=b.PrevInAEL;null!==e;)e.PolyTyp==b.PolyTyp&&0!==e.WindDelta&&(c=!c),e=e.PrevInAEL;a.WindCnt=c?0:1}else a.WindCnt=a.WindDelta;else 0>b.WindCnt*b.WindDelta?1b.WindDelta*a.WindDelta?b.WindCnt:b.WindCnt+a.WindDelta:a.WindCnt=0===a.WindDelta?1:a.WindDelta:a.WindCnt=0===a.WindDelta?0>b.WindCnt?b.WindCnt-1:b.WindCnt+1:0>b.WindDelta*a.WindDelta?b.WindCnt:b.WindCnt+a.WindDelta; +a.WindCnt2=b.WindCnt2;b=b.NextInAEL}if(this.IsEvenOddAltFillType(a))for(;b!=a;)0!==b.WindDelta&&(a.WindCnt2=0===a.WindCnt2?1:0),b=b.NextInAEL;else for(;b!=a;)a.WindCnt2+=b.WindDelta,b=b.NextInAEL};d.Clipper.prototype.AddEdgeToSEL=function(a){null===this.m_SortedEdges?(this.m_SortedEdges=a,a.PrevInSEL=null,a.NextInSEL=null):(a.NextInSEL=this.m_SortedEdges,a.PrevInSEL=null,this.m_SortedEdges=this.m_SortedEdges.PrevInSEL=a)};d.Clipper.prototype.CopyAELToSEL=function(){var a=this.m_ActiveEdges;for(this.m_SortedEdges= +a;null!==a;)a.PrevInSEL=a.PrevInAEL,a=a.NextInSEL=a.NextInAEL};d.Clipper.prototype.SwapPositionsInAEL=function(a,b){if(a.NextInAEL!=a.PrevInAEL&&b.NextInAEL!=b.PrevInAEL){if(a.NextInAEL==b){var c=b.NextInAEL;null!==c&&(c.PrevInAEL=a);var e=a.PrevInAEL;null!==e&&(e.NextInAEL=b);b.PrevInAEL=e;b.NextInAEL=a;a.PrevInAEL=b;a.NextInAEL=c}else b.NextInAEL==a?(c=a.NextInAEL,null!==c&&(c.PrevInAEL=b),e=b.PrevInAEL,null!==e&&(e.NextInAEL=a),a.PrevInAEL=e,a.NextInAEL=b,b.PrevInAEL=a,b.NextInAEL=c):(c=a.NextInAEL, +e=a.PrevInAEL,a.NextInAEL=b.NextInAEL,null!==a.NextInAEL&&(a.NextInAEL.PrevInAEL=a),a.PrevInAEL=b.PrevInAEL,null!==a.PrevInAEL&&(a.PrevInAEL.NextInAEL=a),b.NextInAEL=c,null!==b.NextInAEL&&(b.NextInAEL.PrevInAEL=b),b.PrevInAEL=e,null!==b.PrevInAEL&&(b.PrevInAEL.NextInAEL=b));null===a.PrevInAEL?this.m_ActiveEdges=a:null===b.PrevInAEL&&(this.m_ActiveEdges=b)}};d.Clipper.prototype.SwapPositionsInSEL=function(a,b){if(null!==a.NextInSEL||null!==a.PrevInSEL)if(null!==b.NextInSEL||null!==b.PrevInSEL){if(a.NextInSEL== +b){var c=b.NextInSEL;null!==c&&(c.PrevInSEL=a);var e=a.PrevInSEL;null!==e&&(e.NextInSEL=b);b.PrevInSEL=e;b.NextInSEL=a;a.PrevInSEL=b;a.NextInSEL=c}else b.NextInSEL==a?(c=a.NextInSEL,null!==c&&(c.PrevInSEL=b),e=b.PrevInSEL,null!==e&&(e.NextInSEL=a),a.PrevInSEL=e,a.NextInSEL=b,b.PrevInSEL=a,b.NextInSEL=c):(c=a.NextInSEL,e=a.PrevInSEL,a.NextInSEL=b.NextInSEL,null!==a.NextInSEL&&(a.NextInSEL.PrevInSEL=a),a.PrevInSEL=b.PrevInSEL,null!==a.PrevInSEL&&(a.PrevInSEL.NextInSEL=a),b.NextInSEL=c,null!==b.NextInSEL&& +(b.NextInSEL.PrevInSEL=b),b.PrevInSEL=e,null!==b.PrevInSEL&&(b.PrevInSEL.NextInSEL=b));null===a.PrevInSEL?this.m_SortedEdges=a:null===b.PrevInSEL&&(this.m_SortedEdges=b)}};d.Clipper.prototype.AddLocalMaxPoly=function(a,b,c){this.AddOutPt(a,c);0==b.WindDelta&&this.AddOutPt(b,c);a.OutIdx==b.OutIdx?(a.OutIdx=-1,b.OutIdx=-1):a.OutIdxb.Dx?(e=this.AddOutPt(a, +c),b.OutIdx=a.OutIdx,a.Side=d.EdgeSide.esLeft,b.Side=d.EdgeSide.esRight,f=a,a=f.PrevInAEL==b?b.PrevInAEL:f.PrevInAEL):(e=this.AddOutPt(b,c),a.OutIdx=b.OutIdx,a.Side=d.EdgeSide.esRight,b.Side=d.EdgeSide.esLeft,f=b,a=f.PrevInAEL==a?a.PrevInAEL:f.PrevInAEL);null!==a&&0<=a.OutIdx&&d.Clipper.TopX(a,c.Y)==d.Clipper.TopX(f,c.Y)&&d.ClipperBase.SlopesEqual(f,a,this.m_UseFullRange)&&0!==f.WindDelta&&0!==a.WindDelta&&(c=this.AddOutPt(a,c),this.AddJoin(e,c,f.Top));return e};d.Clipper.prototype.CreateOutRec=function(){var a= +new d.OutRec;a.Idx=-1;a.IsHole=!1;a.IsOpen=!1;a.FirstLeft=null;a.Pts=null;a.BottomPt=null;a.PolyNode=null;this.m_PolyOuts.push(a);a.Idx=this.m_PolyOuts.length-1;return a};d.Clipper.prototype.AddOutPt=function(a,b){var c=a.Side==d.EdgeSide.esLeft;if(0>a.OutIdx){var e=this.CreateOutRec();e.IsOpen=0===a.WindDelta;var f=new d.OutPt;e.Pts=f;f.Idx=e.Idx;f.Pt.X=b.X;f.Pt.Y=b.Y;f.Next=f;f.Prev=f;e.IsOpen||this.SetHoleState(a,e);a.OutIdx=e.Idx}else{var e=this.m_PolyOuts[a.OutIdx],g=e.Pts;if(c&&d.IntPoint.op_Equality(b, +g.Pt))return g;if(!c&&d.IntPoint.op_Equality(b,g.Prev.Pt))return g.Prev;f=new d.OutPt;f.Idx=e.Idx;f.Pt.X=b.X;f.Pt.Y=b.Y;f.Next=g;f.Prev=g.Prev;f.Prev.Next=f;g.Prev=f;c&&(e.Pts=f)}return f};d.Clipper.prototype.SwapPoints=function(a,b){var c=new d.IntPoint(a.Value);a.Value.X=b.Value.X;a.Value.Y=b.Value.Y;b.Value.X=c.X;b.Value.Y=c.Y};d.Clipper.prototype.HorzSegmentsOverlap=function(a,b,c,e){return a.X>c.X==a.Xc.X==b.Xa.X==c.Xa.X==e.X=g&&e>=c||f>=g&&f>= +c};d.Clipper.prototype.GetBottomPt=function(a){for(var b=null,c=a.Next;c!=a;)c.Pt.Y>a.Pt.Y?(a=c,b=null):c.Pt.Y==a.Pt.Y&&c.Pt.X<=a.Pt.X&&(c.Pt.Xe.Pt.Y?a:c.Pt.Ye.Pt.X?b:c.Next==c?b:e.Next==e?a:this.FirstIsBottomPt(c,e)?a:b};d.Clipper.prototype.Param1RightOfParam2=function(a,b){do if(a=a.FirstLeft,a==b)return!0;while(null!==a);return!1};d.Clipper.prototype.GetOutRec=function(a){for(a=this.m_PolyOuts[a];a!=this.m_PolyOuts[a.Idx];)a=this.m_PolyOuts[a.Idx];return a};d.Clipper.prototype.AppendPolygon=function(a,b){var c=this.m_PolyOuts[a.OutIdx],e=this.m_PolyOuts[b.OutIdx],f;f=this.Param1RightOfParam2(c, +e)?e:this.Param1RightOfParam2(e,c)?c:this.GetLowermostRec(c,e);var g=c.Pts,h=g.Prev,l=e.Pts,k=l.Prev;a.Side==d.EdgeSide.esLeft?(b.Side==d.EdgeSide.esLeft?(this.ReversePolyPtLinks(l),l.Next=g,g.Prev=l,h.Next=k,k.Prev=h,c.Pts=k):(k.Next=g,g.Prev=k,l.Prev=h,h.Next=l,c.Pts=l),g=d.EdgeSide.esLeft):(b.Side==d.EdgeSide.esRight?(this.ReversePolyPtLinks(l),h.Next=k,k.Prev=h,l.Next=g,g.Prev=l):(h.Next=l,l.Prev=h,g.Prev=k,k.Next=g),g=d.EdgeSide.esRight);c.BottomPt=null;f==e&&(e.FirstLeft!=c&&(c.FirstLeft=e.FirstLeft), +c.IsHole=e.IsHole);e.Pts=null;e.BottomPt=null;e.FirstLeft=c;f=a.OutIdx;h=b.OutIdx;a.OutIdx=-1;b.OutIdx=-1;for(l=this.m_ActiveEdges;null!==l;){if(l.OutIdx==h){l.OutIdx=f;l.Side=g;break}l=l.NextInAEL}e.Idx=c.Idx};d.Clipper.prototype.ReversePolyPtLinks=function(a){if(null!==a){var b,c;b=a;do c=b.Next,b.Next=b.Prev,b=b.Prev=c;while(b!=a)}};d.Clipper.SwapSides=function(a,b){var c=a.Side;a.Side=b.Side;b.Side=c};d.Clipper.SwapPolyIndexes=function(a,b){var c=a.OutIdx;a.OutIdx=b.OutIdx;b.OutIdx=c};d.Clipper.prototype.IntersectEdges= +function(a,b,c,e){var f=!e&&null===a.NextInLML&&a.Top.X==c.X&&a.Top.Y==c.Y;e=!e&&null===b.NextInLML&&b.Top.X==c.X&&b.Top.Y==c.Y;var g=0<=a.OutIdx,h=0<=b.OutIdx;if(0===a.WindDelta||0===b.WindDelta)0===a.WindDelta&&0===b.WindDelta?(f||e)&&g&&h&&this.AddLocalMaxPoly(a,b,c):a.PolyTyp==b.PolyTyp&&a.WindDelta!=b.WindDelta&&this.m_ClipType==d.ClipType.ctUnion?0===a.WindDelta?h&&(this.AddOutPt(a,c),g&&(a.OutIdx=-1)):g&&(this.AddOutPt(b,c),h&&(b.OutIdx=-1)):a.PolyTyp!=b.PolyTyp&&(0!==a.WindDelta||1!=Math.abs(b.WindCnt)|| +this.m_ClipType==d.ClipType.ctUnion&&0!==b.WindCnt2?0!==b.WindDelta||1!=Math.abs(a.WindCnt)||this.m_ClipType==d.ClipType.ctUnion&&0!==a.WindCnt2||(this.AddOutPt(b,c),h&&(b.OutIdx=-1)):(this.AddOutPt(a,c),g&&(a.OutIdx=-1))),f&&(0>a.OutIdx?this.DeleteFromAEL(a):d.Error("Error intersecting polylines")),e&&(0>b.OutIdx?this.DeleteFromAEL(b):d.Error("Error intersecting polylines"));else{if(a.PolyTyp==b.PolyTyp)if(this.IsEvenOddFillType(a)){var l=a.WindCnt;a.WindCnt=b.WindCnt;b.WindCnt=l}else a.WindCnt= +0===a.WindCnt+b.WindDelta?-a.WindCnt:a.WindCnt+b.WindDelta,b.WindCnt=0===b.WindCnt-a.WindDelta?-b.WindCnt:b.WindCnt-a.WindDelta;else this.IsEvenOddFillType(b)?a.WindCnt2=0===a.WindCnt2?1:0:a.WindCnt2+=b.WindDelta,this.IsEvenOddFillType(a)?b.WindCnt2=0===b.WindCnt2?1:0:b.WindCnt2-=a.WindDelta;var k,n,m;a.PolyTyp==d.PolyType.ptSubject?(k=this.m_SubjFillType,m=this.m_ClipFillType):(k=this.m_ClipFillType,m=this.m_SubjFillType);b.PolyTyp==d.PolyType.ptSubject?(n=this.m_SubjFillType,l=this.m_ClipFillType): +(n=this.m_ClipFillType,l=this.m_SubjFillType);switch(k){case d.PolyFillType.pftPositive:k=a.WindCnt;break;case d.PolyFillType.pftNegative:k=-a.WindCnt;break;default:k=Math.abs(a.WindCnt)}switch(n){case d.PolyFillType.pftPositive:n=b.WindCnt;break;case d.PolyFillType.pftNegative:n=-b.WindCnt;break;default:n=Math.abs(b.WindCnt)}if(g&&h)f||e||0!==k&&1!=k||0!==n&&1!=n||a.PolyTyp!=b.PolyTyp&&this.m_ClipType!=d.ClipType.ctXor?this.AddLocalMaxPoly(a,b,c):(this.AddOutPt(a,c),this.AddOutPt(b,c),d.Clipper.SwapSides(a, +b),d.Clipper.SwapPolyIndexes(a,b));else if(g){if(0===n||1==n)this.AddOutPt(a,c),d.Clipper.SwapSides(a,b),d.Clipper.SwapPolyIndexes(a,b)}else if(h){if(0===k||1==k)this.AddOutPt(b,c),d.Clipper.SwapSides(a,b),d.Clipper.SwapPolyIndexes(a,b)}else if(!(0!==k&&1!=k||0!==n&&1!=n||f||e)){switch(m){case d.PolyFillType.pftPositive:g=a.WindCnt2;break;case d.PolyFillType.pftNegative:g=-a.WindCnt2;break;default:g=Math.abs(a.WindCnt2)}switch(l){case d.PolyFillType.pftPositive:h=b.WindCnt2;break;case d.PolyFillType.pftNegative:h= +-b.WindCnt2;break;default:h=Math.abs(b.WindCnt2)}if(a.PolyTyp!=b.PolyTyp)this.AddLocalMinPoly(a,b,c);else if(1==k&&1==n)switch(this.m_ClipType){case d.ClipType.ctIntersection:0=g&&0>=h&&this.AddLocalMinPoly(a,b,c);break;case d.ClipType.ctDifference:(a.PolyTyp==d.PolyType.ptClip&&0=g&&0>=h)&&this.AddLocalMinPoly(a,b,c);break;case d.ClipType.ctXor:this.AddLocalMinPoly(a,b,c)}else d.Clipper.SwapSides(a, +b)}f!=e&&(f&&0<=a.OutIdx||e&&0<=b.OutIdx)&&(d.Clipper.SwapSides(a,b),d.Clipper.SwapPolyIndexes(a,b));f&&this.DeleteFromAEL(a);e&&this.DeleteFromAEL(b)}};d.Clipper.prototype.DeleteFromAEL=function(a){var b=a.PrevInAEL,c=a.NextInAEL;if(null!==b||null!==c||a==this.m_ActiveEdges)null!==b?b.NextInAEL=c:this.m_ActiveEdges=c,null!==c&&(c.PrevInAEL=b),a.NextInAEL=null,a.PrevInAEL=null};d.Clipper.prototype.DeleteFromSEL=function(a){var b=a.PrevInSEL,c=a.NextInSEL;if(null!==b||null!==c||a==this.m_SortedEdges)null!== +b?b.NextInSEL=c:this.m_SortedEdges=c,null!==c&&(c.PrevInSEL=b),a.NextInSEL=null,a.PrevInSEL=null};d.Clipper.prototype.UpdateEdgeIntoAEL=function(a){null===a.NextInLML&&d.Error("UpdateEdgeIntoAEL: invalid call");var b=a.PrevInAEL,c=a.NextInAEL;a.NextInLML.OutIdx=a.OutIdx;null!==b?b.NextInAEL=a.NextInLML:this.m_ActiveEdges=a.NextInLML;null!==c&&(c.PrevInAEL=a.NextInLML);a.NextInLML.Side=a.Side;a.NextInLML.WindDelta=a.WindDelta;a.NextInLML.WindCnt=a.WindCnt;a.NextInLML.WindCnt2=a.WindCnt2;a=a.NextInLML; +a.Curr.X=a.Bot.X;a.Curr.Y=a.Bot.Y;a.PrevInAEL=b;a.NextInAEL=c;d.ClipperBase.IsHorizontal(a)||this.InsertScanbeam(a.Top.Y);return a};d.Clipper.prototype.ProcessHorizontals=function(a){for(var b=this.m_SortedEdges;null!==b;)this.DeleteFromSEL(b),this.ProcessHorizontal(b,a),b=this.m_SortedEdges};d.Clipper.prototype.GetHorzDirection=function(a,b){a.Bot.X=f){0<=a.OutIdx&&0!=a.WindDelta&&this.PrepareHorzJoins(a,b);if(n==l&&k){e==d.Direction.dLeftToRight?this.IntersectEdges(a,n,n.Top,!1):this.IntersectEdges(n,a,n.Top,!1);0<=l.OutIdx&&d.Error("ProcessHorizontal error");return}if(e==d.Direction.dLeftToRight){var m=new d.IntPoint(n.Curr.X,a.Curr.Y);this.IntersectEdges(a, +n,m,!0)}else m=new d.IntPoint(n.Curr.X,a.Curr.Y),this.IntersectEdges(n,a,m,!0);this.SwapPositionsInAEL(a,n)}else if(e==d.Direction.dLeftToRight&&n.Curr.X>=g||e==d.Direction.dRightToLeft&&n.Curr.X<=f)break;n=c}0<=a.OutIdx&&0!==a.WindDelta&&this.PrepareHorzJoins(a,b);if(null!==a.NextInLML&&d.ClipperBase.IsHorizontal(a.NextInLML))a=this.UpdateEdgeIntoAEL(a),0<=a.OutIdx&&this.AddOutPt(a,a.Bot),c={Dir:e,Left:f,Right:g},this.GetHorzDirection(a,c),e=c.Dir,f=c.Left,g=c.Right;else break}null!==a.NextInLML? +0<=a.OutIdx?(e=this.AddOutPt(a,a.Top),a=this.UpdateEdgeIntoAEL(a),0!==a.WindDelta&&(f=a.PrevInAEL,c=a.NextInAEL,null!==f&&f.Curr.X==a.Bot.X&&f.Curr.Y==a.Bot.Y&&0!==f.WindDelta&&0<=f.OutIdx&&f.Curr.Y>f.Top.Y&&d.ClipperBase.SlopesEqual(a,f,this.m_UseFullRange)?(c=this.AddOutPt(f,a.Bot),this.AddJoin(e,c,a.Top)):null!==c&&c.Curr.X==a.Bot.X&&c.Curr.Y==a.Bot.Y&&0!==c.WindDelta&&0<=c.OutIdx&&c.Curr.Y>c.Top.Y&&d.ClipperBase.SlopesEqual(a,c,this.m_UseFullRange)&&(c=this.AddOutPt(c,a.Bot),this.AddJoin(e,c, +a.Top)))):this.UpdateEdgeIntoAEL(a):null!==l?0<=l.OutIdx?(e==d.Direction.dLeftToRight?this.IntersectEdges(a,l,a.Top,!1):this.IntersectEdges(l,a,a.Top,!1),0<=l.OutIdx&&d.Error("ProcessHorizontal error")):(this.DeleteFromAEL(a),this.DeleteFromAEL(l)):(0<=a.OutIdx&&this.AddOutPt(a,a.Top),this.DeleteFromAEL(a))};d.Clipper.prototype.GetNextInAEL=function(a,b){return b==d.Direction.dLeftToRight?a.NextInAEL:a.PrevInAEL};d.Clipper.prototype.IsMinima=function(a){return null!==a&&a.Prev.NextInLML!=a&&a.Next.NextInLML!= +a};d.Clipper.prototype.IsMaxima=function(a,b){return null!==a&&a.Top.Y==b&&null===a.NextInLML};d.Clipper.prototype.IsIntermediate=function(a,b){return a.Top.Y==b&&null!==a.NextInLML};d.Clipper.prototype.GetMaximaPair=function(a){var b=null;d.IntPoint.op_Equality(a.Next.Top,a.Top)&&null===a.Next.NextInLML?b=a.Next:d.IntPoint.op_Equality(a.Prev.Top,a.Top)&&null===a.Prev.NextInLML&&(b=a.Prev);return null===b||-2!=b.OutIdx&&(b.NextInAEL!=b.PrevInAEL||d.ClipperBase.IsHorizontal(b))?b:null};d.Clipper.prototype.ProcessIntersections= +function(a,b){if(null==this.m_ActiveEdges)return!0;try{this.BuildIntersectList(a,b);if(0==this.m_IntersectList.length)return!0;if(1==this.m_IntersectList.length||this.FixupIntersectionOrder())this.ProcessIntersectList();else return!1}catch(c){this.m_SortedEdges=null,this.m_IntersectList.length=0,d.Error("ProcessIntersections error")}this.m_SortedEdges=null;return!0};d.Clipper.prototype.BuildIntersectList=function(a,b){if(null!==this.m_ActiveEdges){var c=this.m_ActiveEdges;for(this.m_SortedEdges=c;null!== +c;)c.PrevInSEL=c.PrevInAEL,c.NextInSEL=c.NextInAEL,c.Curr.X=d.Clipper.TopX(c,b),c=c.NextInAEL;for(var e=!0;e&&null!==this.m_SortedEdges;){e=!1;for(c=this.m_SortedEdges;null!==c.NextInSEL;){var f=c.NextInSEL,g=new d.IntPoint;c.Curr.X>f.Curr.X?(!this.IntersectPoint(c,f,g)&&c.Curr.X>f.Curr.X+1&&d.Error("Intersection error"),g.Y>a&&(g.Y=a,Math.abs(c.Dx)>Math.abs(f.Dx)?g.X=d.Clipper.TopX(f,a):g.X=d.Clipper.TopX(c,a)),e=new d.IntersectNode,e.Edge1=c,e.Edge2=f,e.Pt.X=g.X,e.Pt.Y=g.Y,this.m_IntersectList.push(e), +this.SwapPositionsInSEL(c,f),e=!0):c=f}if(null!==c.PrevInSEL)c.PrevInSEL.NextInSEL=null;else break}this.m_SortedEdges=null}};d.Clipper.prototype.EdgesAdjacent=function(a){return a.Edge1.NextInSEL==a.Edge2||a.Edge1.PrevInSEL==a.Edge2};d.Clipper.IntersectNodeSort=function(a,b){return b.Pt.Y-a.Pt.Y};d.Clipper.prototype.FixupIntersectionOrder=function(){this.m_IntersectList.sort(this.m_IntersectNodeComparer);this.CopyAELToSEL();for(var a=this.m_IntersectList.length,b=0;ba?Math.ceil(a-0.5):Math.round(a)};F=function(a){return 0>a?Math.ceil(a-0.5):Math.floor(a+0.5)};G=function(a){return 0>a?-Math.round(Math.abs(a)):Math.round(a)};H=function(a){if(0>a)return a-=0.5,-2147483648>a?Math.ceil(a):a|0;a+=0.5;return 2147483647a.Bot.Y?(c.X=b.Bot.X,c.Y=b.Bot.Y):(c.X=a.Bot.X,c.Y=a.Bot.Y),!1;if(0===a.Delta.X)c.X=a.Bot.X,d.ClipperBase.IsHorizontal(b)?c.Y=b.Bot.Y:(f=b.Bot.Y-b.Bot.X/b.Dx,c.Y=d.Clipper.Round(c.X/b.Dx+f));else if(0===b.Delta.X)c.X=b.Bot.X,d.ClipperBase.IsHorizontal(a)?c.Y=a.Bot.Y:(e=a.Bot.Y-a.Bot.X/a.Dx,c.Y=d.Clipper.Round(c.X/a.Dx+e));else{e=a.Bot.X-a.Bot.Y*a.Dx;f=b.Bot.X-b.Bot.Y*b.Dx;var g=(f-e)/(a.Dx-b.Dx);c.Y=d.Clipper.Round(g);Math.abs(a.Dx)b.Top.Y)return c.Y=a.Top.Y,c.X=d.Clipper.TopX(b,a.Top.Y),c.Xe.Top.Y&&d.ClipperBase.SlopesEqual(b,e,this.m_UseFullRange)&&0!==b.WindDelta&&0!==e.WindDelta?(e=this.AddOutPt(e,b.Bot),this.AddJoin(c,e,b.Top)):null!==f&&f.Curr.X==b.Bot.X&&f.Curr.Y==b.Bot.Y&&null!==c&&0<=f.OutIdx&&f.Curr.Y>f.Top.Y&&d.ClipperBase.SlopesEqual(b,f,this.m_UseFullRange)&& +0!==b.WindDelta&&0!==f.WindDelta&&(e=this.AddOutPt(f,b.Bot),this.AddJoin(c,e,b.Top))}b=b.NextInAEL}};d.Clipper.prototype.DoMaxima=function(a){var b=this.GetMaximaPair(a);if(null===b)0<=a.OutIdx&&this.AddOutPt(a,a.Top),this.DeleteFromAEL(a);else{for(var c=a.NextInAEL;null!==c&&c!=b;)this.IntersectEdges(a,c,a.Top,!0),this.SwapPositionsInAEL(a,c),c=a.NextInAEL;-1==a.OutIdx&&-1==b.OutIdx?(this.DeleteFromAEL(a),this.DeleteFromAEL(b)):0<=a.OutIdx&&0<=b.OutIdx?this.IntersectEdges(a,b,a.Top,!1):0===a.WindDelta? +(0<=a.OutIdx&&(this.AddOutPt(a,a.Top),a.OutIdx=-1),this.DeleteFromAEL(a),0<=b.OutIdx&&(this.AddOutPt(b,a.Top),b.OutIdx=-1),this.DeleteFromAEL(b)):d.Error("DoMaxima error")}};d.Clipper.ReversePaths=function(a){for(var b=0,c=a.length;bf)){for(var g=Array(f),h=0;hf||!e.IsOpen&&3>f)){this.FixHoleLinkage(e);var g=new d.PolyNode;a.m_AllPolys.push(g);e.PolyNode=g;g.m_polygon.length=f;for(var e=e.Pts.Prev,h=0;h< +f;h++)g.m_polygon[h]=e.Pt,e=e.Prev}}b=0;for(c=this.m_PolyOuts.length;bb.Pt.X?d.Direction.dRightToLeft:d.Direction.dLeftToRight;e=c.Pt.X>e.Pt.X?d.Direction.dRightToLeft:d.Direction.dLeftToRight;if(h==e)return!1;if(h==d.Direction.dLeftToRight){for(;a.Next.Pt.X<=f.X&&a.Next.Pt.X>= +a.Pt.X&&a.Next.Pt.Y==f.Y;)a=a.Next;g&&a.Pt.X!=f.X&&(a=a.Next);b=this.DupOutPt(a,!g);d.IntPoint.op_Inequality(b.Pt,f)&&(a=b,a.Pt.X=f.X,a.Pt.Y=f.Y,b=this.DupOutPt(a,!g))}else{for(;a.Next.Pt.X>=f.X&&a.Next.Pt.X<=a.Pt.X&&a.Next.Pt.Y==f.Y;)a=a.Next;g||a.Pt.X==f.X||(a=a.Next);b=this.DupOutPt(a,g);d.IntPoint.op_Inequality(b.Pt,f)&&(a=b,a.Pt.X=f.X,a.Pt.Y=f.Y,b=this.DupOutPt(a,g))}if(e==d.Direction.dLeftToRight){for(;c.Next.Pt.X<=f.X&&c.Next.Pt.X>=c.Pt.X&&c.Next.Pt.Y==f.Y;)c=c.Next;g&&c.Pt.X!=f.X&&(c=c.Next); +e=this.DupOutPt(c,!g);d.IntPoint.op_Inequality(e.Pt,f)&&(c=e,c.Pt.X=f.X,c.Pt.Y=f.Y,e=this.DupOutPt(c,!g))}else{for(;c.Next.Pt.X>=f.X&&c.Next.Pt.X<=c.Pt.X&&c.Next.Pt.Y==f.Y;)c=c.Next;g||c.Pt.X==f.X||(c=c.Next);e=this.DupOutPt(c,g);d.IntPoint.op_Inequality(e.Pt,f)&&(c=e,c.Pt.X=f.X,c.Pt.Y=f.Y,e=this.DupOutPt(c,g))}h==d.Direction.dLeftToRight==g?(a.Prev=c,c.Next=a,b.Next=e,e.Prev=b):(a.Next=c,c.Prev=a,b.Prev=e,e.Next=b);return!0};d.Clipper.prototype.JoinPoints=function(a,b,c){var e=a.OutPt1,f=new d.OutPt, +g=a.OutPt2,h=new d.OutPt;if((h=a.OutPt1.Pt.Y==a.OffPt.Y)&&d.IntPoint.op_Equality(a.OffPt,a.OutPt1.Pt)&&d.IntPoint.op_Equality(a.OffPt,a.OutPt2.Pt)){for(f=a.OutPt1.Next;f!=e&&d.IntPoint.op_Equality(f.Pt,a.OffPt);)f=f.Next;f=f.Pt.Y>a.OffPt.Y;for(h=a.OutPt2.Next;h!=g&&d.IntPoint.op_Equality(h.Pt,a.OffPt);)h=h.Next;if(f==h.Pt.Y>a.OffPt.Y)return!1;f?(f=this.DupOutPt(e,!1),h=this.DupOutPt(g,!0),e.Prev=g,g.Next=e,f.Next=h,h.Prev=f):(f=this.DupOutPt(e,!0),h=this.DupOutPt(g,!1),e.Next=g,g.Prev=e,f.Prev=h, +h.Next=f);a.OutPt1=e;a.OutPt2=f;return!0}if(h){for(f=e;e.Prev.Pt.Y==e.Pt.Y&&e.Prev!=f&&e.Prev!=g;)e=e.Prev;for(;f.Next.Pt.Y==f.Pt.Y&&f.Next!=e&&f.Next!=g;)f=f.Next;if(f.Next==e||f.Next==g)return!1;for(h=g;g.Prev.Pt.Y==g.Pt.Y&&g.Prev!=h&&g.Prev!=f;)g=g.Prev;for(;h.Next.Pt.Y==h.Pt.Y&&h.Next!=g&&h.Next!=e;)h=h.Next;if(h.Next==g||h.Next==e)return!1;c={Left:null,Right:null};if(!this.GetOverlap(e.Pt.X,f.Pt.X,g.Pt.X,h.Pt.X,c))return!1;b=c.Left;var l=c.Right;c=new d.IntPoint;e.Pt.X>=b&&e.Pt.X<=l?(c.X=e.Pt.X, +c.Y=e.Pt.Y,b=e.Pt.X>f.Pt.X):g.Pt.X>=b&&g.Pt.X<=l?(c.X=g.Pt.X,c.Y=g.Pt.Y,b=g.Pt.X>h.Pt.X):f.Pt.X>=b&&f.Pt.X<=l?(c.X=f.Pt.X,c.Y=f.Pt.Y,b=f.Pt.X>e.Pt.X):(c.X=h.Pt.X,c.Y=h.Pt.Y,b=h.Pt.X>g.Pt.X);a.OutPt1=e;a.OutPt2=g;return this.JoinHorz(e,f,g,h,c,b)}for(f=e.Next;d.IntPoint.op_Equality(f.Pt,e.Pt)&&f!=e;)f=f.Next;if(l=f.Pt.Y>e.Pt.Y||!d.ClipperBase.SlopesEqual(e.Pt,f.Pt,a.OffPt,this.m_UseFullRange)){for(f=e.Prev;d.IntPoint.op_Equality(f.Pt,e.Pt)&&f!=e;)f=f.Prev;if(f.Pt.Y>e.Pt.Y||!d.ClipperBase.SlopesEqual(e.Pt, +f.Pt,a.OffPt,this.m_UseFullRange))return!1}for(h=g.Next;d.IntPoint.op_Equality(h.Pt,g.Pt)&&h!=g;)h=h.Next;var k=h.Pt.Y>g.Pt.Y||!d.ClipperBase.SlopesEqual(g.Pt,h.Pt,a.OffPt,this.m_UseFullRange);if(k){for(h=g.Prev;d.IntPoint.op_Equality(h.Pt,g.Pt)&&h!=g;)h=h.Prev;if(h.Pt.Y>g.Pt.Y||!d.ClipperBase.SlopesEqual(g.Pt,h.Pt,a.OffPt,this.m_UseFullRange))return!1}if(f==e||h==g||f==h||b==c&&l==k)return!1;l?(f=this.DupOutPt(e,!1),h=this.DupOutPt(g,!0),e.Prev=g,g.Next=e,f.Next=h,h.Prev=f):(f=this.DupOutPt(e,!0), +h=this.DupOutPt(g,!1),e.Next=g,g.Prev=e,f.Prev=h,h.Next=f);a.OutPt1=e;a.OutPt2=f;return!0};d.Clipper.GetBounds=function(a){for(var b=0,c=a.length;be.right&&(e.right=a[b][f].X),a[b][f].Ye.bottom&&(e.bottom=a[b][f].Y);return e};d.Clipper.prototype.GetBounds2= +function(a){var b=a,c=new d.IntRect;c.left=a.Pt.X;c.right=a.Pt.X;c.top=a.Pt.Y;c.bottom=a.Pt.Y;for(a=a.Next;a!=b;)a.Pt.Xc.right&&(c.right=a.Pt.X),a.Pt.Yc.bottom&&(c.bottom=a.Pt.Y),a=a.Next;return c};d.Clipper.PointInPolygon=function(a,b){var c=0,e=b.length;if(3>e)return 0;for(var d=b[0],g=1;g<=e;++g){var h=g==e?b[0]:b[g];if(h.Y==a.Y&&(h.X==a.X||d.Y==a.Y&&h.X>a.X==d.X=a.X)if(h.X>a.X)c=1-c;else{var l= +(d.X-a.X)*(h.Y-a.Y)-(h.X-a.X)*(d.Y-a.Y);if(0==l)return-1;0d.Y&&(c=1-c)}else if(h.X>a.X){l=(d.X-a.X)*(h.Y-a.Y)-(h.X-a.X)*(d.Y-a.Y);if(0==l)return-1;0d.Y&&(c=1-c)}d=h}return c};d.Clipper.prototype.PointInPolygon=function(a,b){for(var c=0,e=b;;){var d=b.Pt.X,g=b.Pt.Y,h=b.Next.Pt.X,l=b.Next.Pt.Y;if(l==a.Y&&(h==a.X||g==a.Y&&h>a.X==d=a.X)if(h>a.X)c=1-c;else{d=(d-a.X)*(l-a.Y)-(h-a.X)*(g-a.Y);if(0==d)return-1;0g&&(c=1-c)}else if(h>a.X){d=(d-a.X)*(l- +a.Y)-(h-a.X)*(g-a.Y);if(0==d)return-1;0g&&(c=1-c)}b=b.Next;if(e==b)break}return c};d.Clipper.prototype.Poly2ContainsPoly1=function(a,b){var c=a;do{var e=this.PointInPolygon(c.Pt,b);if(0<=e)return 0!=e;c=c.Next}while(c!=a);return!0};d.Clipper.prototype.FixupFirstLefts1=function(a,b){for(var c=0,e=this.m_PolyOuts.length;cb)return 0;for(var c=0,e=0,d=b-1;ec&&(c=0);for(var g=Array(c),f=0;fe)){var f=new d.PolyNode;f.m_jointype=b;f.m_endtype=c;if(c==d.EndType.etClosedLine||c==d.EndType.etClosedPolygon)for(;0f.m_polygon[b].Y||a[h].Y==f.m_polygon[b].Y&&a[h].Xg||c!=d.EndType.etClosedPolygon&&0>g)&&(this.m_polyNodes.AddChild(f),c==d.EndType.etClosedPolygon))if(0>this.m_lowest.X)this.m_lowest=new d.IntPoint(0,b);else if(a=this.m_polyNodes.Childs()[this.m_lowest.X].m_polygon[this.m_lowest.Y],f.m_polygon[b].Y>a.Y||f.m_polygon[b].Y==a.Y&&f.m_polygon[b].X=this.ArcTolerance?d.ClipperOffset.def_arc_tolerance:this.ArcTolerance>Math.abs(a)*d.ClipperOffset.def_arc_tolerance?Math.abs(a)*d.ClipperOffset.def_arc_tolerance:this.ArcTolerance,e=3.14159265358979/Math.acos(1-b/Math.abs(a));this.m_sin=Math.sin(d.ClipperOffset.two_pi/e);this.m_cos=Math.cos(d.ClipperOffset.two_pi/e);this.m_StepsPerRad=e/d.ClipperOffset.two_pi;0>a&&(this.m_sin= +-this.m_sin);for(b=0;b=a&&(3>f||c.m_endtype!=d.EndType.etClosedPolygon))){this.m_destPoly=[];if(1==f)if(c.m_jointype==d.JoinType.jtRound)for(var c=1,f=0,g=1;g<=e;g++){this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[0].X+c*a),d.ClipperOffset.Round(this.m_srcPoly[0].Y+f*a)));var h=c,c=c*this.m_cos-this.m_sin*f,f=h*this.m_sin+f*this.m_cos}else for(f= +c=-1,g=0;4>g;++g)this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[0].X+c*a),d.ClipperOffset.Round(this.m_srcPoly[0].Y+f*a))),0>c?c=1:0>f?f=1:c=-1;else{for(g=this.m_normals.length=0;gthis.m_sinA&&-5E-5this.m_sinA&&(this.m_sinA=-1);if(0>this.m_sinA*this.m_delta)this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_normals[b].X*this.m_delta),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_normals[b].Y*this.m_delta))),this.m_destPoly.push(new d.IntPoint(this.m_srcPoly[a])),this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_normals[a].X*this.m_delta),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_normals[a].Y* +this.m_delta)));else switch(c){case d.JoinType.jtMiter:c=1+(this.m_normals[a].X*this.m_normals[b].X+this.m_normals[a].Y*this.m_normals[b].Y);c>=this.m_miterLim?this.DoMiter(a,b,c):this.DoSquare(a,b);break;case d.JoinType.jtSquare:this.DoSquare(a,b);break;case d.JoinType.jtRound:this.DoRound(a,b)}return a};d.ClipperOffset.prototype.DoSquare=function(a,b){var c=Math.tan(Math.atan2(this.m_sinA,this.m_normals[b].X*this.m_normals[a].X+this.m_normals[b].Y*this.m_normals[a].Y)/4);this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+ +this.m_delta*(this.m_normals[b].X-this.m_normals[b].Y*c)),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_delta*(this.m_normals[b].Y+this.m_normals[b].X*c))));this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_delta*(this.m_normals[a].X+this.m_normals[a].Y*c)),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_delta*(this.m_normals[a].Y-this.m_normals[a].X*c))))};d.ClipperOffset.prototype.DoMiter=function(a,b,c){c=this.m_delta/c;this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+ +(this.m_normals[b].X+this.m_normals[a].X)*c),d.ClipperOffset.Round(this.m_srcPoly[a].Y+(this.m_normals[b].Y+this.m_normals[a].Y)*c)))};d.ClipperOffset.prototype.DoRound=function(a,b){for(var c=Math.atan2(this.m_sinA,this.m_normals[b].X*this.m_normals[a].X+this.m_normals[b].Y*this.m_normals[a].Y),c=d.Cast_Int32(d.ClipperOffset.Round(this.m_StepsPerRad*Math.abs(c))),e=this.m_normals[b].X,f=this.m_normals[b].Y,g,h=0;hb)return a;c||(a=[a]);for(var e=a.length,f,g,h,l,k,n,m,p=[],q=0;qf)h=g,p.push(h);else{h=g;l=b*b;k=g[0];for(m=n=1;mb)return d.JS.Clone(a);a[0]instanceof Array||(a=[a]);var c,e, +f,g,h,l,k,m,p,q,r,s,t,u,v,x=a.length,y=b*b,w=[];for(c=0;cg;g++){h=[];l=f.length;f[l-1].X!=f[0].X||f[l-1].Y!=f[0].Y?(r=1,f.push({X:f[0].X,Y:f[0].Y}),l=f.length):r=0;q=[];for(e=0;en)return 0;b&&(a[n]=a[0],n++);for(;--n;)g=a[n],k=g.X,g=g.Y,h=a[n-1],m=h.X,h=h.Y,d+=e((k-m)*(k-m)+(g-h)*(g-h));b&&a.pop();return d/c};d.JS.PerimeterOfPaths= +function(a,b,c){c||(c=1);for(var e=0,f=0;f -1) { + doc.documentElement.innerHTML = markup; + } + else { + doc.body.innerHTML = markup; + } + return doc; + } else { + return nativeParse.apply(this, arguments); + } + }; +}(DOMParser)); \ No newline at end of file diff --git a/public/svgnest/util/eval.js b/public/svgnest/util/eval.js new file mode 100644 index 00000000..585850e1 --- /dev/null +++ b/public/svgnest/util/eval.js @@ -0,0 +1,11 @@ +var isNode = typeof module !== 'undefined' && module.exports; + +if (isNode) { + process.once('message', function (code) { + eval(JSON.parse(code).data); + }); +} else { + self.onmessage = function (code) { + eval(code.data); + }; +} \ No newline at end of file diff --git a/public/svgnest/util/filesaver.js b/public/svgnest/util/filesaver.js new file mode 100644 index 00000000..315dc02e --- /dev/null +++ b/public/svgnest/util/filesaver.js @@ -0,0 +1,188 @@ +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.3.2 + * 2016-06-16 18:25:19 + * + * By Eli Grey, http://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ + +var saveAs = saveAs || (function(view) { + "use strict"; + // IE <10 is explicitly unsupported + if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { + return; + } + var + doc = view.document + // only get URL when necessary in case Blob.js hasn't overridden it yet + , get_URL = function() { + return view.URL || view.webkitURL || view; + } + , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") + , can_use_save_link = "download" in save_link + , click = function(node) { + var event = new MouseEvent("click"); + node.dispatchEvent(event); + } + , is_safari = /constructor/i.test(view.HTMLElement) || view.safari + , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent) + , throw_outside = function(ex) { + (view.setImmediate || view.setTimeout)(function() { + throw ex; + }, 0); + } + , force_saveable_type = "application/octet-stream" + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + , arbitrary_revoke_timeout = 1000 * 40 // in ms + , revoke = function(file) { + var revoker = function() { + if (typeof file === "string") { // file is an object URL + get_URL().revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + }; + setTimeout(revoker, arbitrary_revoke_timeout); + } + , dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver["on" + event_types[i]]; + if (typeof listener === "function") { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + } + , auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type}); + } + return blob; + } + , FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var + filesaver = this + , type = blob.type + , force = type === force_saveable_type + , object_url + , dispatch_all = function() { + dispatch(filesaver, "writestart progress write writeend".split(" ")); + } + // on any filesys errors revert to saving with object URLs + , fs_error = function() { + if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); + var popup = view.open(url, '_blank'); + if(!popup) view.location.href = url; + url=undefined; // release reference before dispatching + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (!object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (force) { + view.location.href = object_url; + } else { + var opened = view.open(object_url, "_blank"); + if (!opened) { + // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html + view.location.href = object_url; + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + } + ; + filesaver.readyState = filesaver.INIT; + + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setTimeout(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }); + return; + } + + fs_error(); + } + , FS_proto = FileSaver.prototype + , saveAs = function(blob, name, no_auto_bom) { + return new FileSaver(blob, name || blob.name || "download", no_auto_bom); + } + ; + // IE 10+ (native saveAs) + if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + name = name || blob.name || "download"; + + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name); + }; + } + + FS_proto.abort = function(){}; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = + FS_proto.onwritestart = + FS_proto.onprogress = + FS_proto.onwrite = + FS_proto.onabort = + FS_proto.onerror = + FS_proto.onwriteend = + null; + + return saveAs; +}( + typeof self !== "undefined" && self + || typeof window !== "undefined" && window + || this.content +)); +// `self` is undefined in Firefox for Android content script context +// while `this` is nsIContentFrameMessageManager +// with an attribute `content` that corresponds to the window + +if (typeof module !== "undefined" && module.exports) { + module.exports.saveAs = saveAs; +} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { + define("FileSaver.js", function() { + return saveAs; + }); +} \ No newline at end of file diff --git a/public/svgnest/util/geometryutil.js b/public/svgnest/util/geometryutil.js new file mode 100644 index 00000000..bce07c54 --- /dev/null +++ b/public/svgnest/util/geometryutil.js @@ -0,0 +1,1891 @@ +/*! + * General purpose geometry functions for polygon/Bezier calculations + * Copyright 2015 Jack Qiao + * Licensed under the MIT license + */ + +(function(root){ + 'use strict'; + + // private shared variables/methods + + // floating point comparison tolerance + var TOL = Math.pow(10, -9); // Floating point error is likely to be above 1 epsilon + + function _almostEqual(a, b, tolerance){ + if(!tolerance){ + tolerance = TOL + } + return Math.abs(a - b) < tolerance; + } + + // returns true if points are within the given distance + function _withinDistance(p1, p2, distance){ + var dx = p1.x-p2.x; + var dy = p1.y-p2.y; + return ((dx*dx + dy*dy) < distance*distance); + } + + function _degreesToRadians(angle){ + return angle*(Math.PI/180); + } + + function _radiansToDegrees(angle){ + return angle*(180/Math.PI); + } + + // normalize vector into a unit vector + function _normalizeVector(v){ + if(_almostEqual(v.x*v.x + v.y*v.y, 1)){ + return v; // given vector was already a unit vector + } + var len = Math.sqrt(v.x*v.x + v.y*v.y); + var inverse = 1/len; + + return { + x: v.x*inverse, + y: v.y*inverse + }; + } + + // returns true if p lies on the line segment defined by AB, but not at any endpoints + // may need work! + function _onSegment(A,B,p){ + + // vertical line + if(_almostEqual(A.x, B.x) && _almostEqual(p.x, A.x)){ + if(!_almostEqual(p.y, B.y) && !_almostEqual(p.y, A.y) && p.y < Math.max(B.y, A.y) && p.y > Math.min(B.y, A.y)){ + return true; + } + else{ + return false; + } + } + + // horizontal line + if(_almostEqual(A.y, B.y) && _almostEqual(p.y, A.y)){ + if(!_almostEqual(p.x, B.x) && !_almostEqual(p.x, A.x) && p.x < Math.max(B.x, A.x) && p.x > Math.min(B.x, A.x)){ + return true; + } + else{ + return false; + } + } + + //range check + if((p.x < A.x && p.x < B.x) || (p.x > A.x && p.x > B.x) || (p.y < A.y && p.y < B.y) || (p.y > A.y && p.y > B.y)){ + return false; + } + + + // exclude end points + if((_almostEqual(p.x, A.x) && _almostEqual(p.y, A.y)) || (_almostEqual(p.x, B.x) && _almostEqual(p.y, B.y))){ + return false; + } + + var cross = (p.y - A.y) * (B.x - A.x) - (p.x - A.x) * (B.y - A.y); + + if(Math.abs(cross) > TOL){ + return false; + } + + var dot = (p.x - A.x) * (B.x - A.x) + (p.y - A.y)*(B.y - A.y); + + + + if(dot < 0 || _almostEqual(dot, 0)){ + return false; + } + + var len2 = (B.x - A.x)*(B.x - A.x) + (B.y - A.y)*(B.y - A.y); + + + + if(dot > len2 || _almostEqual(dot, len2)){ + return false; + } + + return true; + } + + // returns the intersection of AB and EF + // or null if there are no intersections or other numerical error + // if the infinite flag is set, AE and EF describe infinite lines without endpoints, they are finite line segments otherwise + function _lineIntersect(A,B,E,F,infinite){ + var a1, a2, b1, b2, c1, c2, x, y; + + a1= B.y-A.y; + b1= A.x-B.x; + c1= B.x*A.y - A.x*B.y; + a2= F.y-E.y; + b2= E.x-F.x; + c2= F.x*E.y - E.x*F.y; + + var denom=a1*b2 - a2*b1; + + x = (b1*c2 - b2*c1)/denom, + y = (a2*c1 - a1*c2)/denom + + if(!isFinite(x) || !isFinite(y)){ + return null; + } + + // lines are colinear + /*var crossABE = (E.y - A.y) * (B.x - A.x) - (E.x - A.x) * (B.y - A.y); + var crossABF = (F.y - A.y) * (B.x - A.x) - (F.x - A.x) * (B.y - A.y); + if(_almostEqual(crossABE,0) && _almostEqual(crossABF,0)){ + return null; + }*/ + + if(!infinite){ + // coincident points do not count as intersecting + if (Math.abs(A.x-B.x) > TOL && (( A.x < B.x ) ? x < A.x || x > B.x : x > A.x || x < B.x )) return null; + if (Math.abs(A.y-B.y) > TOL && (( A.y < B.y ) ? y < A.y || y > B.y : y > A.y || y < B.y )) return null; + + if (Math.abs(E.x-F.x) > TOL && (( E.x < F.x ) ? x < E.x || x > F.x : x > E.x || x < F.x )) return null; + if (Math.abs(E.y-F.y) > TOL && (( E.y < F.y ) ? y < E.y || y > F.y : y > E.y || y < F.y )) return null; + } + + return {x: x, y: y}; + } + + // public methods + root.GeometryUtil = { + + withinDistance: _withinDistance, + + lineIntersect: _lineIntersect, + + almostEqual: _almostEqual, + + // Bezier algos from http://algorithmist.net/docs/subdivision.pdf + QuadraticBezier: { + + // Roger Willcocks bezier flatness criterion + isFlat: function(p1, p2, c1, tol){ + tol = 4*tol*tol; + + var ux = 2*c1.x - p1.x - p2.x; + ux *= ux; + + var uy = 2*c1.y - p1.y - p2.y; + uy *= uy; + + return (ux+uy <= tol); + }, + + // turn Bezier into line segments via de Casteljau, returns an array of points + linearize: function(p1, p2, c1, tol){ + var finished = [p1]; // list of points to return + var todo = [{p1: p1, p2: p2, c1: c1}]; // list of Beziers to divide + + // recursion could stack overflow, loop instead + while(todo.length > 0){ + var segment = todo[0]; + + if(this.isFlat(segment.p1, segment.p2, segment.c1, tol)){ // reached subdivision limit + finished.push({x: segment.p2.x, y: segment.p2.y}); + todo.shift(); + } + else{ + var divided = this.subdivide(segment.p1, segment.p2, segment.c1, 0.5); + todo.splice(0,1,divided[0],divided[1]); + } + } + return finished; + }, + + // subdivide a single Bezier + // t is the percent along the Bezier to divide at. eg. 0.5 + subdivide: function(p1, p2, c1, t){ + var mid1 = { + x: p1.x+(c1.x-p1.x)*t, + y: p1.y+(c1.y-p1.y)*t + }; + + var mid2 = { + x: c1.x+(p2.x-c1.x)*t, + y: c1.y+(p2.y-c1.y)*t + }; + + var mid3 = { + x: mid1.x+(mid2.x-mid1.x)*t, + y: mid1.y+(mid2.y-mid1.y)*t + }; + + var seg1 = {p1: p1, p2: mid3, c1: mid1}; + var seg2 = {p1: mid3, p2: p2, c1: mid2}; + + return [seg1, seg2]; + } + }, + + CubicBezier: { + isFlat: function(p1, p2, c1, c2, tol){ + tol = 16*tol*tol; + + var ux = 3*c1.x - 2*p1.x - p2.x; + ux *= ux; + + var uy = 3*c1.y - 2*p1.y - p2.y; + uy *= uy; + + var vx = 3*c2.x - 2*p2.x - p1.x; + vx *= vx; + + var vy = 3*c2.y - 2*p2.y - p1.y; + vy *= vy; + + if (ux < vx){ + ux = vx; + } + if (uy < vy){ + uy = vy; + } + + return (ux+uy <= tol); + }, + + linearize: function(p1, p2, c1, c2, tol){ + var finished = [p1]; // list of points to return + var todo = [{p1: p1, p2: p2, c1: c1, c2: c2}]; // list of Beziers to divide + + // recursion could stack overflow, loop instead + + while(todo.length > 0){ + var segment = todo[0]; + + if(this.isFlat(segment.p1, segment.p2, segment.c1, segment.c2, tol)){ // reached subdivision limit + finished.push({x: segment.p2.x, y: segment.p2.y}); + todo.shift(); + } + else{ + var divided = this.subdivide(segment.p1, segment.p2, segment.c1, segment.c2, 0.5); + todo.splice(0,1,divided[0],divided[1]); + } + } + return finished; + }, + + subdivide: function(p1, p2, c1, c2, t){ + var mid1 = { + x: p1.x+(c1.x-p1.x)*t, + y: p1.y+(c1.y-p1.y)*t + }; + + var mid2 = { + x:c2.x+(p2.x-c2.x)*t, + y:c2.y+(p2.y-c2.y)*t + }; + + var mid3 = { + x: c1.x+(c2.x-c1.x)*t, + y: c1.y+(c2.y-c1.y)*t + }; + + var mida = { + x: mid1.x+(mid3.x-mid1.x)*t, + y: mid1.y+(mid3.y-mid1.y)*t + }; + + var midb = { + x: mid3.x+(mid2.x-mid3.x)*t, + y: mid3.y+(mid2.y-mid3.y)*t + }; + + var midx = { + x: mida.x+(midb.x-mida.x)*t, + y: mida.y+(midb.y-mida.y)*t + }; + + var seg1 = {p1: p1, p2: midx, c1: mid1, c2: mida}; + var seg2 = {p1: midx, p2: p2, c1: midb, c2: mid2}; + + return [seg1, seg2]; + } + }, + + Arc: { + + linearize: function(p1, p2, rx, ry, angle, largearc, sweep, tol){ + + var finished = [p2]; // list of points to return + + var arc = this.svgToCenter(p1, p2, rx, ry, angle, largearc, sweep); + var todo = [arc]; // list of arcs to divide + + // recursion could stack overflow, loop instead + while(todo.length > 0){ + arc = todo[0]; + + var fullarc = this.centerToSvg(arc.center, arc.rx, arc.ry, arc.theta, arc.extent, arc.angle); + var subarc = this.centerToSvg(arc.center, arc.rx, arc.ry, arc.theta, 0.5*arc.extent, arc.angle); + var arcmid = subarc.p2; + + var mid = { + x: 0.5*(fullarc.p1.x + fullarc.p2.x), + y: 0.5*(fullarc.p1.y + fullarc.p2.y) + } + + // compare midpoint of line with midpoint of arc + // this is not 100% accurate, but should be a good heuristic for flatness in most cases + if(_withinDistance(mid, arcmid, tol)){ + finished.unshift(fullarc.p2); + todo.shift(); + } + else{ + var arc1 = { + center: arc.center, + rx: arc.rx, + ry: arc.ry, + theta: arc.theta, + extent: 0.5*arc.extent, + angle: arc.angle + }; + var arc2 = { + center: arc.center, + rx: arc.rx, + ry: arc.ry, + theta: arc.theta+0.5*arc.extent, + extent: 0.5*arc.extent, + angle: arc.angle + }; + todo.splice(0,1,arc1,arc2); + } + } + return finished; + }, + + // convert from center point/angle sweep definition to SVG point and flag definition of arcs + // ported from http://commons.oreilly.com/wiki/index.php/SVG_Essentials/Paths + centerToSvg: function(center, rx, ry, theta1, extent, angleDegrees){ + + var theta2 = theta1 + extent; + + theta1 = _degreesToRadians(theta1); + theta2 = _degreesToRadians(theta2); + var angle = _degreesToRadians(angleDegrees); + + var cos = Math.cos(angle); + var sin = Math.sin(angle); + + var t1cos = Math.cos(theta1); + var t1sin = Math.sin(theta1); + + var t2cos = Math.cos(theta2); + var t2sin = Math.sin(theta2); + + var x0 = center.x + cos * rx * t1cos + (-sin) * ry * t1sin; + var y0 = center.y + sin * rx * t1cos + cos * ry * t1sin; + + var x1 = center.x + cos * rx * t2cos + (-sin) * ry * t2sin; + var y1 = center.y + sin * rx * t2cos + cos * ry * t2sin; + + var largearc = (extent > 180) ? 1 : 0; + var sweep = (extent > 0) ? 1 : 0; + + return { + p1: {x: x0, y: y0}, + p2: {x: x1, y: y1}, + rx: rx, + ry: ry, + angle: angle, + largearc: largearc, + sweep: sweep + }; + }, + + // convert from SVG format arc to center point arc + svgToCenter: function(p1, p2, rx, ry, angleDegrees, largearc, sweep){ + + var mid = { + x: 0.5*(p1.x+p2.x), + y: 0.5*(p1.y+p2.y) + } + + var diff = { + x: 0.5*(p2.x-p1.x), + y: 0.5*(p2.y-p1.y) + } + + var angle = _degreesToRadians(angleDegrees%360); + + var cos = Math.cos(angle); + var sin = Math.sin(angle); + + var x1 = cos * diff.x + sin * diff.y; + var y1 = -sin * diff.x + cos * diff.y; + + rx = Math.abs(rx); + ry = Math.abs(ry); + var Prx = rx * rx; + var Pry = ry * ry; + var Px1 = x1 * x1; + var Py1 = y1 * y1; + + var radiiCheck = Px1/Prx + Py1/Pry; + var radiiSqrt = Math.sqrt(radiiCheck); + if (radiiCheck > 1) { + rx = radiiSqrt * rx; + ry = radiiSqrt * ry; + Prx = rx * rx; + Pry = ry * ry; + } + + var sign = (largearc != sweep) ? -1 : 1; + var sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1)); + + sq = (sq < 0) ? 0 : sq; + + var coef = sign * Math.sqrt(sq); + var cx1 = coef * ((rx * y1) / ry); + var cy1 = coef * -((ry * x1) / rx); + + var cx = mid.x + (cos * cx1 - sin * cy1); + var cy = mid.y + (sin * cx1 + cos * cy1); + + var ux = (x1 - cx1) / rx; + var uy = (y1 - cy1) / ry; + var vx = (-x1 - cx1) / rx; + var vy = (-y1 - cy1) / ry; + var n = Math.sqrt( (ux * ux) + (uy * uy) ); + var p = ux; + sign = (uy < 0) ? -1 : 1; + + var theta = sign * Math.acos( p / n ); + theta = _radiansToDegrees(theta); + + n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); + p = ux * vx + uy * vy; + sign = ((ux * vy - uy * vx) < 0) ? -1 : 1; + var delta = sign * Math.acos( p / n ); + delta = _radiansToDegrees(delta); + + if (sweep == 1 && delta > 0) + { + delta -= 360; + } + else if (sweep == 0 && delta < 0) + { + delta += 360; + } + + delta %= 360; + theta %= 360; + + return { + center: {x: cx, y: cy}, + rx: rx, + ry: ry, + theta: theta, + extent: delta, + angle: angleDegrees + }; + } + + }, + + // returns the rectangular bounding box of the given polygon + getPolygonBounds: function(polygon){ + if(!polygon || polygon.length < 3){ + return null; + } + + var xmin = polygon[0].x; + var xmax = polygon[0].x; + var ymin = polygon[0].y; + var ymax = polygon[0].y; + + for(var i=1; i xmax){ + xmax = polygon[i].x; + } + else if(polygon[i].x < xmin){ + xmin = polygon[i].x; + } + + if(polygon[i].y > ymax){ + ymax = polygon[i].y; + } + else if(polygon[i].y < ymin){ + ymin = polygon[i].y; + } + } + + return { + x: xmin, + y: ymin, + width: xmax-xmin, + height: ymax-ymin + }; + }, + + // return true if point is in the polygon, false if outside, and null if exactly on a point or edge + pointInPolygon: function(point, polygon){ + if(!polygon || polygon.length < 3){ + return null; + } + + var inside = false; + var offsetx = polygon.offsetx || 0; + var offsety = polygon.offsety || 0; + + for (var i = 0, j = polygon.length - 1; i < polygon.length; j=i++) { + var xi = polygon[i].x + offsetx; + var yi = polygon[i].y + offsety; + var xj = polygon[j].x + offsetx; + var yj = polygon[j].y + offsety; + + if(_almostEqual(xi, point.x) && _almostEqual(yi, point.y)){ + return null; // no result + } + + if(_onSegment({x: xi, y: yi}, {x: xj, y: yj}, point)){ + return null; // exactly on the segment + } + + if(_almostEqual(xi, xj) && _almostEqual(yi, yj)){ // ignore very small lines + continue; + } + + var intersect = ((yi > point.y) != (yj > point.y)) && (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi); + if (intersect) inside = !inside; + } + + return inside; + }, + + // returns the area of the polygon, assuming no self-intersections + // a negative area indicates counter-clockwise winding direction + polygonArea: function(polygon){ + var area = 0; + var i, j; + for (i=0, j=polygon.length-1; i max){ + max = dot; + } + } + + // there may be multiple vertices with min/max values. In which case we choose the one that is normal-most (eg. left most) + var indexmin = 0; + var indexmax = 0; + + var normalmin = null; + var normalmax = null; + + for(i=0; i normalmin){ + normalmin = dot; + indexmin = i; + } + } + else if(_almostEqual(dotproduct[i] , max)){ + var dot = polygon[i].x*normal.x + polygon[i].y*normal.y; + if(normalmax === null || dot > normalmax){ + normalmax = dot; + indexmax = i; + } + } + } + + // now we have two edges bound by min and max points, figure out which edge faces our direction vector + + var indexleft = indexmin-1; + var indexright = indexmin+1; + + if(indexleft < 0){ + indexleft = polygon.length-1; + } + if(indexright >= polygon.length){ + indexright = 0; + } + + var minvertex = polygon[indexmin]; + var left = polygon[indexleft]; + var right = polygon[indexright]; + + var leftvector = { + x: left.x - minvertex.x, + y: left.y - minvertex.y + }; + + var rightvector = { + x: right.x - minvertex.x, + y: right.y - minvertex.y + }; + + var dotleft = leftvector.x*direction.x + leftvector.y*direction.y; + var dotright = rightvector.x*direction.x + rightvector.y*direction.y; + + // -1 = left, 1 = right + var scandirection = -1; + + if(_almostEqual(dotleft, 0)){ + scandirection = 1; + } + else if(_almostEqual(dotright, 0)){ + scandirection = -1; + } + else{ + var normaldotleft; + var normaldotright; + + if(_almostEqual(dotleft, dotright)){ + // the points line up exactly along the normal vector + normaldotleft = leftvector.x*normal.x + leftvector.y*normal.y; + normaldotright = rightvector.x*normal.x + rightvector.y*normal.y; + } + else if(dotleft < dotright){ + // normalize right vertex so normal projection can be directly compared + normaldotleft = leftvector.x*normal.x + leftvector.y*normal.y; + normaldotright = (rightvector.x*normal.x + rightvector.y*normal.y)*(dotleft/dotright); + } + else{ + // normalize left vertex so normal projection can be directly compared + normaldotleft = leftvector.x*normal.x + leftvector.y*normal.y * (dotright/dotleft); + normaldotright = rightvector.x*normal.x + rightvector.y*normal.y; + } + + if(normaldotleft > normaldotright){ + scandirection = -1; + } + else{ + // technically they could be equal, (ie. the segments bound by left and right points are incident) + // in which case we'll have to climb up the chain until lines are no longer incident + // for now we'll just not handle it and assume people aren't giving us garbage input.. + scandirection = 1; + } + } + + // connect all points between indexmin and indexmax along the scan direction + var edge = []; + var count = 0; + i=indexmin; + while(count < polygon.length){ + if(i >= polygon.length){ + i=0; + } + else if(i < 0){ + i=polygon.length-1; + } + + edge.push(polygon[i]); + + if(i == indexmax){ + break; + } + i += scandirection; + count++; + } + + return edge; + }, + + // returns the normal distance from p to a line segment defined by s1 s2 + // this is basically algo 9 in [1], generalized for any vector direction + // eg. normal of [-1, 0] returns the horizontal distance between the point and the line segment + // sxinclusive: if true, include endpoints instead of excluding them + + pointLineDistance: function(p, s1, s2, normal, s1inclusive, s2inclusive){ + + normal = _normalizeVector(normal); + + var dir = { + x: normal.y, + y: -normal.x + }; + + var pdot = p.x*dir.x + p.y*dir.y; + var s1dot = s1.x*dir.x + s1.y*dir.y; + var s2dot = s2.x*dir.x + s2.y*dir.y; + + var pdotnorm = p.x*normal.x + p.y*normal.y; + var s1dotnorm = s1.x*normal.x + s1.y*normal.y; + var s2dotnorm = s2.x*normal.x + s2.y*normal.y; + + + // point is exactly along the edge in the normal direction + if(_almostEqual(pdot, s1dot) && _almostEqual(pdot, s2dot)){ + // point lies on an endpoint + if(_almostEqual(pdotnorm, s1dotnorm) ){ + return null; + } + + if(_almostEqual(pdotnorm, s2dotnorm)){ + return null; + } + + // point is outside both endpoints + if (pdotnorm>s1dotnorm && pdotnorm>s2dotnorm){ + return Math.min(pdotnorm - s1dotnorm, pdotnorm - s2dotnorm); + } + if (pdotnorm 0){ + return diff1; + } + else{ + return diff2; + } + } + // point + else if(_almostEqual(pdot, s1dot)){ + if(s1inclusive){ + return pdotnorm-s1dotnorm; + } + else{ + return null; + } + } + else if(_almostEqual(pdot, s2dot)){ + if(s2inclusive){ + return pdotnorm-s2dotnorm; + } + else{ + return null; + } + } + else if ((pdots1dot && pdot>s2dot)){ + return null; // point doesn't collide with segment + } + + return (pdotnorm - s1dotnorm + (s1dotnorm - s2dotnorm)*(s1dot - pdot)/(s1dot - s2dot)); + }, + + pointDistance: function(p, s1, s2, normal, infinite){ + normal = _normalizeVector(normal); + + var dir = { + x: normal.y, + y: -normal.x + }; + + var pdot = p.x*dir.x + p.y*dir.y; + var s1dot = s1.x*dir.x + s1.y*dir.y; + var s2dot = s2.x*dir.x + s2.y*dir.y; + + var pdotnorm = p.x*normal.x + p.y*normal.y; + var s1dotnorm = s1.x*normal.x + s1.y*normal.y; + var s2dotnorm = s2.x*normal.x + s2.y*normal.y; + + if(!infinite){ + if (((pdots1dot || _almostEqual(pdot, s1dot)) && (pdot>s2dot || _almostEqual(pdot, s2dot)))){ + return null; // dot doesn't collide with segment, or lies directly on the vertex + } + if ((_almostEqual(pdot, s1dot) && _almostEqual(pdot, s2dot)) && (pdotnorm>s1dotnorm && pdotnorm>s2dotnorm)){ + return Math.min(pdotnorm - s1dotnorm, pdotnorm - s2dotnorm); + } + if ((_almostEqual(pdot, s1dot) && _almostEqual(pdot, s2dot)) && (pdotnorm EFmax){ + return null; + } + + var overlap; + + if((ABmax > EFmax && ABmin < EFmin) || (EFmax > ABmax && EFmin < ABmin)){ + overlap = 1; + } + else{ + var minMax = Math.min(ABmax, EFmax); + var maxMin = Math.max(ABmin, EFmin); + + var maxMax = Math.max(ABmax, EFmax); + var minMin = Math.min(ABmin, EFmin); + + overlap = (minMax-maxMin)/(maxMax-minMin); + } + + var crossABE = (E.y - A.y) * (B.x - A.x) - (E.x - A.x) * (B.y - A.y); + var crossABF = (F.y - A.y) * (B.x - A.x) - (F.x - A.x) * (B.y - A.y); + + // lines are colinear + if(_almostEqual(crossABE,0) && _almostEqual(crossABF,0)){ + + var ABnorm = {x: B.y-A.y, y: A.x-B.x}; + var EFnorm = {x: F.y-E.y, y: E.x-F.x}; + + var ABnormlength = Math.sqrt(ABnorm.x*ABnorm.x + ABnorm.y*ABnorm.y); + ABnorm.x /= ABnormlength; + ABnorm.y /= ABnormlength; + + var EFnormlength = Math.sqrt(EFnorm.x*EFnorm.x + EFnorm.y*EFnorm.y); + EFnorm.x /= EFnormlength; + EFnorm.y /= EFnormlength; + + // segment normals must point in opposite directions + if(Math.abs(ABnorm.y * EFnorm.x - ABnorm.x * EFnorm.y) < TOL && ABnorm.y * EFnorm.y + ABnorm.x * EFnorm.x < 0){ + // normal of AB segment must point in same direction as given direction vector + var normdot = ABnorm.y * direction.y + ABnorm.x * direction.x; + // the segments merely slide along eachother + if(_almostEqual(normdot,0, TOL)){ + return null; + } + if(normdot < 0){ + return 0; + } + } + return null; + } + + var distances = []; + + // coincident points + if(_almostEqual(dotA, dotE)){ + distances.push(crossA-crossE); + } + else if(_almostEqual(dotA, dotF)){ + distances.push(crossA-crossF); + } + else if(dotA > EFmin && dotA < EFmax){ + var d = this.pointDistance(A,E,F,reverse); + if(d !== null && _almostEqual(d, 0)){ // A currently touches EF, but AB is moving away from EF + var dB = this.pointDistance(B,E,F,reverse,true); + if(dB < 0 || _almostEqual(dB*overlap,0)){ + d = null; + } + } + if(d !== null){ + distances.push(d); + } + } + + if(_almostEqual(dotB, dotE)){ + distances.push(crossB-crossE); + } + else if(_almostEqual(dotB, dotF)){ + distances.push(crossB-crossF); + } + else if(dotB > EFmin && dotB < EFmax){ + var d = this.pointDistance(B,E,F,reverse); + + if(d !== null && _almostEqual(d, 0)){ // crossA>crossB A currently touches EF, but AB is moving away from EF + var dA = this.pointDistance(A,E,F,reverse,true); + if(dA < 0 || _almostEqual(dA*overlap,0)){ + d = null; + } + } + if(d !== null){ + distances.push(d); + } + } + + if(dotE > ABmin && dotE < ABmax){ + var d = this.pointDistance(E,A,B,direction); + if(d !== null && _almostEqual(d, 0)){ // crossF ABmin && dotF < ABmax){ + var d = this.pointDistance(F,A,B,direction); + if(d !== null && _almostEqual(d, 0)){ // && crossE 0 || _almostEqual(d, 0)){ + distance = d; + } + } + } + } + return distance; + }, + + // project each point of B onto A in the given direction, and return the + polygonProjectionDistance: function(A, B, direction){ + var Boffsetx = B.offsetx || 0; + var Boffsety = B.offsety || 0; + + var Aoffsetx = A.offsetx || 0; + var Aoffsety = A.offsety || 0; + + A = A.slice(0); + B = B.slice(0); + + // close the loop for polygons + if(A[0] != A[A.length-1]){ + A.push(A[0]); + } + + if(B[0] != B[B.length-1]){ + B.push(B[0]); + } + + var edgeA = A; + var edgeB = B; + + var distance = null; + var p, d, s1, s2; + + + for(var i=0; i distance)){ + distance = minprojection; + } + } + + return distance; + }, + + // searches for an arrangement of A and B such that they do not overlap + // if an NFP is given, only search for startpoints that have not already been traversed in the given NFP + searchStartPoint: function(A,B,inside,NFP){ + // clone arrays + A = A.slice(0); + B = B.slice(0); + + // close the loop for polygons + if(A[0] != A[A.length-1]){ + A.push(A[0]); + } + + if(B[0] != B[B.length-1]){ + B.push(B[0]); + } + + for(var i=0; i 0){ + + } + else{ + continue; + } + + var vd2 = vx*vx + vy*vy; + + if(d*d < vd2 && !_almostEqual(d*d, vd2)){ + var vd = Math.sqrt(vx*vx + vy*vy); + vx *= d/vd; + vy *= d/vd; + } + + B.offsetx += vx; + B.offsety += vy; + + for(k=0; k maxAx){ + maxAx = A[i].x; + } + if(A[i].y > maxAy){ + maxAy = A[i].y; + } + } + + var minBx = B[0].x; + var minBy = B[0].y; + var maxBx = B[0].x; + var maxBy = B[0].y; + for(i=1; i maxBx){ + maxBx = B[i].x; + } + if(B[i].y > maxBy){ + maxBy = B[i].y; + } + } + + if(maxBx-minBx > maxAx-minAx){ + return null; + } + if(maxBy-minBy > maxAy-minAy){ + return null; + } + + return [[ + {x: minAx-minBx+B[0].x, y: minAy-minBy+B[0].y}, + {x: maxAx-maxBx+B[0].x, y: minAy-minBy+B[0].y}, + {x: maxAx-maxBx+B[0].x, y: maxAy-maxBy+B[0].y}, + {x: minAx-minBx+B[0].x, y: maxAy-maxBy+B[0].y} + ]]; + }, + + // given a static polygon A and a movable polygon B, compute a no fit polygon by orbiting B about A + // if the inside flag is set, B is orbited inside of A rather than outside + // if the searchEdges flag is set, all edges of A are explored for NFPs - multiple + noFitPolygon: function(A, B, inside, searchEdges){ + if(!A || A.length < 3 || !B || B.length < 3){ + return null; + } + + A.offsetx = 0; + A.offsety = 0; + + var i, j; + + var minA = A[0].y; + var minAindex = 0; + + var maxB = B[0].y; + var maxBindex = 0; + + for(i=1; i maxB){ + maxB = B[i].y; + maxBindex = i; + } + } + + if(!inside){ + // shift B such that the bottom-most point of B is at the top-most point of A. This guarantees an initial placement with no intersections + var startpoint = { + x: A[minAindex].x-B[maxBindex].x, + y: A[minAindex].y-B[maxBindex].y + }; + } + else{ + // no reliable heuristic for inside + var startpoint = this.searchStartPoint(A,B,true); + } + + var NFPlist = []; + + while(startpoint !== null){ + + B.offsetx = startpoint.x; + B.offsety = startpoint.y; + + // maintain a list of touching points/edges + var touching; + + var prevvector = null; // keep track of previous vector + var NFP = [{ + x: B[0].x+B.offsetx, + y: B[0].y+B.offsety + }]; + + var referencex = B[0].x+B.offsetx; + var referencey = B[0].y+B.offsety; + var startx = referencex; + var starty = referencey; + var counter = 0; + + while(counter < 10*(A.length + B.length)){ // sanity check, prevent infinite loop + touching = []; + // find touching vertices/edges + for(i=0; i= A.length) ? 0 : nextAindex; // loop + + var prevA = A[prevAindex]; + var nextA = A[nextAindex]; + + // adjacent B vertices + var vertexB = B[touching[i].B]; + + var prevBindex = touching[i].B-1; + var nextBindex = touching[i].B+1; + + prevBindex = (prevBindex < 0) ? B.length-1 : prevBindex; // loop + nextBindex = (nextBindex >= B.length) ? 0 : nextBindex; // loop + + var prevB = B[prevBindex]; + var nextB = B[nextBindex]; + + if(touching[i].type == 0){ + + var vA1 = { + x: prevA.x-vertexA.x, + y: prevA.y-vertexA.y, + start: vertexA, + end: prevA + }; + + var vA2 = { + x: nextA.x-vertexA.x, + y: nextA.y-vertexA.y, + start: vertexA, + end: nextA + }; + + // B vectors need to be inverted + var vB1 = { + x: vertexB.x-prevB.x, + y: vertexB.y-prevB.y, + start: prevB, + end: vertexB + }; + + var vB2 = { + x: vertexB.x-nextB.x, + y: vertexB.y-nextB.y, + start: nextB, + end: vertexB + }; + + vectors.push(vA1); + vectors.push(vA2); + vectors.push(vB1); + vectors.push(vB2); + } + else if(touching[i].type == 1){ + vectors.push({ + x: vertexA.x-(vertexB.x+B.offsetx), + y: vertexA.y-(vertexB.y+B.offsety), + start: prevA, + end: vertexA + }); + + vectors.push({ + x: prevA.x-(vertexB.x+B.offsetx), + y: prevA.y-(vertexB.y+B.offsety), + start: vertexA, + end: prevA + }); + } + else if(touching[i].type == 2){ + vectors.push({ + x: vertexA.x-(vertexB.x+B.offsetx), + y: vertexA.y-(vertexB.y+B.offsety), + start: prevB, + end: vertexB + }); + + vectors.push({ + x: vertexA.x-(prevB.x+B.offsetx), + y: vertexA.y-(prevB.y+B.offsety), + start: vertexB, + end: prevB + }); + } + } + + // todo: there should be a faster way to reject vectors that will cause immediate intersection. For now just check them all + + var translate = null; + var maxd = 0; + + for(i=0; i vecd2){ + var vecd = Math.sqrt(vectors[i].x*vectors[i].x + vectors[i].y*vectors[i].y); + d = vecd; + } + + if(d !== null && d > maxd){ + maxd = d; + translate = vectors[i]; + } + } + + + if(translate === null || _almostEqual(maxd, 0)){ + // didn't close the loop, something went wrong here + NFP = null; + break; + } + + translate.start.marked = true; + translate.end.marked = true; + + prevvector = translate; + + // trim + var vlength2 = translate.x*translate.x + translate.y*translate.y; + if(maxd*maxd < vlength2 && !_almostEqual(maxd*maxd, vlength2)){ + var scale = Math.sqrt((maxd*maxd)/vlength2); + translate.x *= scale; + translate.y *= scale; + } + + referencex += translate.x; + referencey += translate.y; + + if(_almostEqual(referencex, startx) && _almostEqual(referencey, starty)){ + // we've made a full loop + break; + } + + // if A and B start on a touching horizontal line, the end point may not be the start point + var looped = false; + if(NFP.length > 0){ + for(i=0; i 0){ + NFPlist.push(NFP); + } + + if(!searchEdges){ + // only get outer NFP or first inner NFP + break; + } + + startpoint = this.searchStartPoint(A,B,inside,NFPlist); + + } + + return NFPlist; + }, + + // given two polygons that touch at at least one point, but do not intersect. Return the outer perimeter of both polygons as a single continuous polygon + // A and B must have the same winding direction + polygonHull: function(A,B){ + if(!A || A.length < 3 || !B || B.length < 3){ + return null; + } + + var i, j; + + var Aoffsetx = A.offsetx || 0; + var Aoffsety = A.offsety || 0; + var Boffsetx = B.offsetx || 0; + var Boffsety = B.offsety || 0; + + // start at an extreme point that is guaranteed to be on the final polygon + var miny = A[0].y; + var startPolygon = A; + var startIndex = 0; + + for(i=0; i 1) { + ++runningWorkers; + that._spawnReduceWorker([that.data[0], that.data[1]], cb, done, env, wrk); + that.data.splice(0, 2); + } else { + if (wrk) wrk.terminate(); + } + } + + var newOp = new Operation(); + this.operation.then(function () { + if (that.data.length === 1) { + newOp.resolve(null, that.data[0]); + } else { + for (var i = 0; i < that.options.maxWorkers && i < Math.floor(that.data.length / 2) ; ++i) { + ++runningWorkers; + that._spawnReduceWorker([that.data[i * 2], that.data[i * 2 + 1]], cb, done, env); + } + + that.data.splice(0, i * 2); + } + }); + this.operation = newOp; + return this; + }; + + Parallel.prototype.then = function (cb, errCb) { + var that = this; + var newOp = new Operation(); + errCb = typeof errCb === 'function' ? errCb : function(){}; + + this.operation.then(function () { + var retData; + + try { + if (cb) { + retData = cb(that.data); + if (retData !== undefined) { + that.data = retData; + } + } + newOp.resolve(null, that.data); + } catch (e) { + if (errCb) { + retData = errCb(e); + if (retData !== undefined) { + that.data = retData; + } + + newOp.resolve(null, that.data); + } else { + newOp.resolve(null, e); + } + } + }, function (err) { + if (errCb) { + var retData = errCb(err); + if (retData !== undefined) { + that.data = retData; + } + + newOp.resolve(null, that.data); + } else { + newOp.resolve(null, err); + } + }); + this.operation = newOp; + return this; + }; + + root.Parallel = Parallel; +})(typeof window !== 'undefined' ? window : self); diff --git a/public/svgnest/util/pathsegpolyfill.js b/public/svgnest/util/pathsegpolyfill.js new file mode 100644 index 00000000..2b0cc9bd --- /dev/null +++ b/public/svgnest/util/pathsegpolyfill.js @@ -0,0 +1,849 @@ +// SVGPathSeg API polyfill +// https://github.com/progers/pathseg +// +// This is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from +// SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec +// changes which were implemented in Firefox 43 and Chrome 46. + +(function() { "use strict"; + if (!("SVGPathSeg" in window)) { + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg + window.SVGPathSeg = function(type, typeAsLetter, owningPathSegList) { + this.pathSegType = type; + this.pathSegTypeAsLetter = typeAsLetter; + this._owningPathSegList = owningPathSegList; + } + + window.SVGPathSeg.prototype.classname = "SVGPathSeg"; + + window.SVGPathSeg.PATHSEG_UNKNOWN = 0; + window.SVGPathSeg.PATHSEG_CLOSEPATH = 1; + window.SVGPathSeg.PATHSEG_MOVETO_ABS = 2; + window.SVGPathSeg.PATHSEG_MOVETO_REL = 3; + window.SVGPathSeg.PATHSEG_LINETO_ABS = 4; + window.SVGPathSeg.PATHSEG_LINETO_REL = 5; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9; + window.SVGPathSeg.PATHSEG_ARC_ABS = 10; + window.SVGPathSeg.PATHSEG_ARC_REL = 11; + window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12; + window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13; + window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14; + window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; + + // Notify owning PathSegList on any changes so they can be synchronized back to the path element. + window.SVGPathSeg.prototype._segmentChanged = function() { + if (this._owningPathSegList) + this._owningPathSegList.segmentChanged(this); + } + + window.SVGPathSegClosePath = function(owningPathSegList) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList); + } + window.SVGPathSegClosePath.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegClosePath.prototype.toString = function() { return "[object SVGPathSegClosePath]"; } + window.SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; } + window.SVGPathSegClosePath.prototype.clone = function() { return new window.SVGPathSegClosePath(undefined); } + + window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegMovetoAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegMovetoAbs.prototype.toString = function() { return "[object SVGPathSegMovetoAbs]"; } + window.SVGPathSegMovetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; } + window.SVGPathSegMovetoAbs.prototype.clone = function() { return new window.SVGPathSegMovetoAbs(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegMovetoRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegMovetoRel.prototype.toString = function() { return "[object SVGPathSegMovetoRel]"; } + window.SVGPathSegMovetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; } + window.SVGPathSegMovetoRel.prototype.clone = function() { return new window.SVGPathSegMovetoRel(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegLinetoAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoAbs.prototype.toString = function() { return "[object SVGPathSegLinetoAbs]"; } + window.SVGPathSegLinetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; } + window.SVGPathSegLinetoAbs.prototype.clone = function() { return new window.SVGPathSegLinetoAbs(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegLinetoRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoRel.prototype.toString = function() { return "[object SVGPathSegLinetoRel]"; } + window.SVGPathSegLinetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; } + window.SVGPathSegLinetoRel.prototype.clone = function() { return new window.SVGPathSegLinetoRel(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicAbs]"; } + window.SVGPathSegCurvetoCubicAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoCubicAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicRel]"; } + window.SVGPathSegCurvetoCubicRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoCubicRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + } + window.SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticAbs]"; } + window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoQuadraticAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + } + window.SVGPathSegCurvetoQuadraticRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticRel]"; } + window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoQuadraticRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList); + this._x = x; + this._y = y; + this._r1 = r1; + this._r2 = r2; + this._angle = angle; + this._largeArcFlag = largeArcFlag; + this._sweepFlag = sweepFlag; + } + window.SVGPathSegArcAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegArcAbs.prototype.toString = function() { return "[object SVGPathSegArcAbs]"; } + window.SVGPathSegArcAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; } + window.SVGPathSegArcAbs.prototype.clone = function() { return new window.SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); } + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList); + this._x = x; + this._y = y; + this._r1 = r1; + this._r2 = r2; + this._angle = angle; + this._largeArcFlag = largeArcFlag; + this._sweepFlag = sweepFlag; + } + window.SVGPathSegArcRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegArcRel.prototype.toString = function() { return "[object SVGPathSegArcRel]"; } + window.SVGPathSegArcRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; } + window.SVGPathSegArcRel.prototype.clone = function() { return new window.SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); } + Object.defineProperty(window.SVGPathSegArcRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList); + this._x = x; + } + window.SVGPathSegLinetoHorizontalAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoHorizontalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalAbs]"; } + window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; } + window.SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalAbs(undefined, this._x); } + Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList); + this._x = x; + } + window.SVGPathSegLinetoHorizontalRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoHorizontalRel.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalRel]"; } + window.SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; } + window.SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalRel(undefined, this._x); } + Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList); + this._y = y; + } + window.SVGPathSegLinetoVerticalAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoVerticalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalAbs]"; } + window.SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; } + window.SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalAbs(undefined, this._y); } + Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList); + this._y = y; + } + window.SVGPathSegLinetoVerticalRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoVerticalRel.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalRel]"; } + window.SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; } + window.SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalRel(undefined, this._y); } + Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList); + this._x = x; + this._y = y; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothAbs]"; } + window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList); + this._x = x; + this._y = y; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothRel]"; } + window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothAbs]"; } + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothRel]"; } + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; } + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + // Add createSVGPathSeg* functions to window.SVGPathElement. + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-Interfacewindow.SVGPathElement. + window.SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new window.SVGPathSegClosePath(undefined); } + window.SVGPathElement.prototype.createSVGPathSegMovetoAbs = function(x, y) { return new window.SVGPathSegMovetoAbs(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegMovetoRel = function(x, y) { return new window.SVGPathSegMovetoRel(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegLinetoAbs = function(x, y) { return new window.SVGPathSegLinetoAbs(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegLinetoRel = function(x, y) { return new window.SVGPathSegLinetoRel(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); } + window.SVGPathElement.prototype.createSVGPathSegArcAbs = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); } + window.SVGPathElement.prototype.createSVGPathSegArcRel = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); } + window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function(x) { return new window.SVGPathSegLinetoHorizontalAbs(undefined, x); } + window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function(x) { return new window.SVGPathSegLinetoHorizontalRel(undefined, x); } + window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function(y) { return new window.SVGPathSegLinetoVerticalAbs(undefined, y); } + window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function(y) { return new window.SVGPathSegLinetoVerticalRel(undefined, y); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); } + + if (!("getPathSegAtLength" in window.SVGPathElement.prototype)) { + // Add getPathSegAtLength to SVGPathElement. + // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-__svg__SVGPathElement__getPathSegAtLength + // This polyfill requires SVGPathElement.getTotalLength to implement the distance-along-a-path algorithm. + window.SVGPathElement.prototype.getPathSegAtLength = function(distance) { + if (distance === undefined || !isFinite(distance)) + throw "Invalid arguments."; + + var measurementElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); + measurementElement.setAttribute("d", this.getAttribute("d")); + var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1; + + // If the path is empty, return 0. + if (lastPathSegment <= 0) + return 0; + + do { + measurementElement.pathSegList.removeItem(lastPathSegment); + if (distance > measurementElement.getTotalLength()) + break; + lastPathSegment--; + } while (lastPathSegment > 0); + return lastPathSegment; + } + } + } + + // Checking for SVGPathSegList in window checks for the case of an implementation without the + // SVGPathSegList API. + // The second check for appendItem is specific to Firefox 59+ which removed only parts of the + // SVGPathSegList API (e.g., appendItem). In this case we need to re-implement the entire API + // so the polyfill data (i.e., _list) is used throughout. + if (!("SVGPathSegList" in window) || !("appendItem" in window.SVGPathSegList.prototype)) { + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList + window.SVGPathSegList = function(pathElement) { + this._pathElement = pathElement; + this._list = this._parsePath(this._pathElement.getAttribute("d")); + + // Use a MutationObserver to catch changes to the path's "d" attribute. + this._mutationObserverConfig = { "attributes": true, "attributeFilter": ["d"] }; + this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this)); + this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); + } + + window.SVGPathSegList.prototype.classname = "SVGPathSegList"; + + Object.defineProperty(window.SVGPathSegList.prototype, "numberOfItems", { + get: function() { + this._checkPathSynchronizedToList(); + return this._list.length; + }, + enumerable: true + }); + + // Add the pathSegList accessors to window.SVGPathElement. + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData + Object.defineProperty(window.SVGPathElement.prototype, "pathSegList", { + get: function() { + if (!this._pathSegList) + this._pathSegList = new window.SVGPathSegList(this); + return this._pathSegList; + }, + enumerable: true + }); + // FIXME: The following are not implemented and simply return window.SVGPathElement.pathSegList. + Object.defineProperty(window.SVGPathElement.prototype, "normalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true }); + Object.defineProperty(window.SVGPathElement.prototype, "animatedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true }); + Object.defineProperty(window.SVGPathElement.prototype, "animatedNormalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true }); + + // Process any pending mutations to the path element and update the list as needed. + // This should be the first call of all public functions and is needed because + // MutationObservers are not synchronous so we can have pending asynchronous mutations. + window.SVGPathSegList.prototype._checkPathSynchronizedToList = function() { + this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords()); + } + + window.SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) { + if (!this._pathElement) + return; + var hasPathMutations = false; + mutationRecords.forEach(function(record) { + if (record.attributeName == "d") + hasPathMutations = true; + }); + if (hasPathMutations) + this._list = this._parsePath(this._pathElement.getAttribute("d")); + } + + // Serialize the list and update the path's 'd' attribute. + window.SVGPathSegList.prototype._writeListToPath = function() { + this._pathElementMutationObserver.disconnect(); + this._pathElement.setAttribute("d", window.SVGPathSegList._pathSegArrayAsString(this._list)); + this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); + } + + // When a path segment changes the list needs to be synchronized back to the path element. + window.SVGPathSegList.prototype.segmentChanged = function(pathSeg) { + this._writeListToPath(); + } + + window.SVGPathSegList.prototype.clear = function() { + this._checkPathSynchronizedToList(); + + this._list.forEach(function(pathSeg) { + pathSeg._owningPathSegList = null; + }); + this._list = []; + this._writeListToPath(); + } + + window.SVGPathSegList.prototype.initialize = function(newItem) { + this._checkPathSynchronizedToList(); + + this._list = [newItem]; + newItem._owningPathSegList = this; + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList.prototype._checkValidIndex = function(index) { + if (isNaN(index) || index < 0 || index >= this.numberOfItems) + throw "INDEX_SIZE_ERR"; + } + + window.SVGPathSegList.prototype.getItem = function(index) { + this._checkPathSynchronizedToList(); + + this._checkValidIndex(index); + return this._list[index]; + } + + window.SVGPathSegList.prototype.insertItemBefore = function(newItem, index) { + this._checkPathSynchronizedToList(); + + // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list. + if (index > this.numberOfItems) + index = this.numberOfItems; + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + this._list.splice(index, 0, newItem); + newItem._owningPathSegList = this; + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList.prototype.replaceItem = function(newItem, index) { + this._checkPathSynchronizedToList(); + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + this._checkValidIndex(index); + this._list[index] = newItem; + newItem._owningPathSegList = this; + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList.prototype.removeItem = function(index) { + this._checkPathSynchronizedToList(); + + this._checkValidIndex(index); + var item = this._list[index]; + this._list.splice(index, 1); + this._writeListToPath(); + return item; + } + + window.SVGPathSegList.prototype.appendItem = function(newItem) { + this._checkPathSynchronizedToList(); + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + this._list.push(newItem); + newItem._owningPathSegList = this; + // TODO: Optimize this to just append to the existing attribute. + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList._pathSegArrayAsString = function(pathSegArray) { + var string = ""; + var first = true; + pathSegArray.forEach(function(pathSeg) { + if (first) { + first = false; + string += pathSeg._asPathString(); + } else { + string += " " + pathSeg._asPathString(); + } + }); + return string; + } + + // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp. + window.SVGPathSegList.prototype._parsePath = function(string) { + if (!string || string.length == 0) + return []; + + var owningPathSegList = this; + + var Builder = function() { + this.pathSegList = []; + } + + Builder.prototype.appendSegment = function(pathSeg) { + this.pathSegList.push(pathSeg); + } + + var Source = function(string) { + this._string = string; + this._currentIndex = 0; + this._endIndex = this._string.length; + this._previousCommand = window.SVGPathSeg.PATHSEG_UNKNOWN; + + this._skipOptionalSpaces(); + } + + Source.prototype._isCurrentSpace = function() { + var character = this._string[this._currentIndex]; + return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f"); + } + + Source.prototype._skipOptionalSpaces = function() { + while (this._currentIndex < this._endIndex && this._isCurrentSpace()) + this._currentIndex++; + return this._currentIndex < this._endIndex; + } + + Source.prototype._skipOptionalSpacesOrDelimiter = function() { + if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",") + return false; + if (this._skipOptionalSpaces()) { + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ",") { + this._currentIndex++; + this._skipOptionalSpaces(); + } + } + return this._currentIndex < this._endIndex; + } + + Source.prototype.hasMoreData = function() { + return this._currentIndex < this._endIndex; + } + + Source.prototype.peekSegmentType = function() { + var lookahead = this._string[this._currentIndex]; + return this._pathSegTypeFromChar(lookahead); + } + + Source.prototype._pathSegTypeFromChar = function(lookahead) { + switch (lookahead) { + case "Z": + case "z": + return window.SVGPathSeg.PATHSEG_CLOSEPATH; + case "M": + return window.SVGPathSeg.PATHSEG_MOVETO_ABS; + case "m": + return window.SVGPathSeg.PATHSEG_MOVETO_REL; + case "L": + return window.SVGPathSeg.PATHSEG_LINETO_ABS; + case "l": + return window.SVGPathSeg.PATHSEG_LINETO_REL; + case "C": + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS; + case "c": + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL; + case "Q": + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS; + case "q": + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL; + case "A": + return window.SVGPathSeg.PATHSEG_ARC_ABS; + case "a": + return window.SVGPathSeg.PATHSEG_ARC_REL; + case "H": + return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS; + case "h": + return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL; + case "V": + return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS; + case "v": + return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL; + case "S": + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; + case "s": + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL; + case "T": + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; + case "t": + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; + default: + return window.SVGPathSeg.PATHSEG_UNKNOWN; + } + } + + Source.prototype._nextCommandHelper = function(lookahead, previousCommand) { + // Check for remaining coordinates in the current command. + if ((lookahead == "+" || lookahead == "-" || lookahead == "." || (lookahead >= "0" && lookahead <= "9")) && previousCommand != window.SVGPathSeg.PATHSEG_CLOSEPATH) { + if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_ABS) + return window.SVGPathSeg.PATHSEG_LINETO_ABS; + if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_REL) + return window.SVGPathSeg.PATHSEG_LINETO_REL; + return previousCommand; + } + return window.SVGPathSeg.PATHSEG_UNKNOWN; + } + + Source.prototype.initialCommandIsMoveTo = function() { + // If the path is empty it is still valid, so return true. + if (!this.hasMoreData()) + return true; + var command = this.peekSegmentType(); + // Path must start with moveTo. + return command == window.SVGPathSeg.PATHSEG_MOVETO_ABS || command == window.SVGPathSeg.PATHSEG_MOVETO_REL; + } + + // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp. + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF + Source.prototype._parseNumber = function() { + var exponent = 0; + var integer = 0; + var frac = 1; + var decimal = 0; + var sign = 1; + var expsign = 1; + + var startIndex = this._currentIndex; + + this._skipOptionalSpaces(); + + // Read the sign. + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+") + this._currentIndex++; + else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "-") { + this._currentIndex++; + sign = -1; + } + + if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != ".")) + // The first character of a number must be one of [0-9+-.]. + return undefined; + + // Read the integer part, build right-to-left. + var startIntPartIndex = this._currentIndex; + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") + this._currentIndex++; // Advance to first non-digit. + + if (this._currentIndex != startIntPartIndex) { + var scanIntPartIndex = this._currentIndex - 1; + var multiplier = 1; + while (scanIntPartIndex >= startIntPartIndex) { + integer += multiplier * (this._string.charAt(scanIntPartIndex--) - "0"); + multiplier *= 10; + } + } + + // Read the decimals. + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") { + this._currentIndex++; + + // There must be a least one digit following the . + if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") + return undefined; + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") { + frac *= 10; + decimal += (this._string.charAt(this._currentIndex) - "0") / frac; + this._currentIndex += 1; + } + } + + // Read the exponent part. + if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && (this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m")) { + this._currentIndex++; + + // Read the sign of the exponent. + if (this._string.charAt(this._currentIndex) == "+") { + this._currentIndex++; + } else if (this._string.charAt(this._currentIndex) == "-") { + this._currentIndex++; + expsign = -1; + } + + // There must be an exponent. + if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") + return undefined; + + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") { + exponent *= 10; + exponent += (this._string.charAt(this._currentIndex) - "0"); + this._currentIndex++; + } + } + + var number = integer + decimal; + number *= sign; + + if (exponent) + number *= Math.pow(10, expsign * exponent); + + if (startIndex == this._currentIndex) + return undefined; + + this._skipOptionalSpacesOrDelimiter(); + + return number; + } + + Source.prototype._parseArcFlag = function() { + if (this._currentIndex >= this._endIndex) + return undefined; + var flag = false; + var flagChar = this._string.charAt(this._currentIndex++); + if (flagChar == "0") + flag = false; + else if (flagChar == "1") + flag = true; + else + return undefined; + + this._skipOptionalSpacesOrDelimiter(); + return flag; + } + + Source.prototype.parseSegment = function() { + var lookahead = this._string[this._currentIndex]; + var command = this._pathSegTypeFromChar(lookahead); + if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) { + // Possibly an implicit command. Not allowed if this is the first command. + if (this._previousCommand == window.SVGPathSeg.PATHSEG_UNKNOWN) + return null; + command = this._nextCommandHelper(lookahead, this._previousCommand); + if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) + return null; + } else { + this._currentIndex++; + } + + this._previousCommand = command; + + switch (command) { + case window.SVGPathSeg.PATHSEG_MOVETO_REL: + return new window.SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_MOVETO_ABS: + return new window.SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_REL: + return new window.SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_ABS: + return new window.SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: + return new window.SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: + return new window.SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: + return new window.SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: + return new window.SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_CLOSEPATH: + this._skipOptionalSpaces(); + return new window.SVGPathSegClosePath(owningPathSegList); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + return new window.SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + return new window.SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_ARC_REL: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep); + case window.SVGPathSeg.PATHSEG_ARC_ABS: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep); + default: + throw "Unknown path seg type." + } + } + + var builder = new Builder(); + var source = new Source(string); + + if (!source.initialCommandIsMoveTo()) + return []; + while (source.hasMoreData()) { + var pathSeg = source.parseSegment(); + if (!pathSeg) + return []; + builder.appendSegment(pathSeg); + } + + return builder.pathSegList; + } + } +}()); \ No newline at end of file diff --git a/public/svgnest/util/placementworker.js b/public/svgnest/util/placementworker.js new file mode 100644 index 00000000..e51c95f8 --- /dev/null +++ b/public/svgnest/util/placementworker.js @@ -0,0 +1,297 @@ + +// jsClipper uses X/Y instead of x/y... +function toClipperCoordinates(polygon){ + var clone = []; + for(var i=0; i 0){ + rotated.children = []; + for(var j=0; j 0){ + + var placed = []; + var placements = []; + fitness += 1; // add 1 for each new bin opened (lower fitness is better) + + for(i=0; i 2 && area > 0.1*self.config.clipperScale*self.config.clipperScale){ + clipper.AddPath(clone, ClipperLib.PolyType.ptSubject, true); + } + } + } + + if(!clipper.Execute(ClipperLib.ClipType.ctUnion, combinedNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)){ + continue; + } + + // difference with bin polygon + var finalNfp = new ClipperLib.Paths(); + clipper = new ClipperLib.Clipper(); + + clipper.AddPaths(combinedNfp, ClipperLib.PolyType.ptClip, true); + clipper.AddPaths(clipperBinNfp, ClipperLib.PolyType.ptSubject, true); + if(!clipper.Execute(ClipperLib.ClipType.ctDifference, finalNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)){ + continue; + } + + finalNfp = ClipperLib.Clipper.CleanPolygons(finalNfp, 0.0001*self.config.clipperScale); + + for(j=0; j= 0){ + paths.splice(index,1); + } + } + + if(placements && placements.length > 0){ + allplacements.push(placements); + } + else{ + break; // something went wrong + } + } + + // there were parts that couldn't be placed + fitness += 2*paths.length; + + return {placements: allplacements, fitness: fitness, paths: paths, area: binarea }; + }; + +} +(typeof window !== 'undefined' ? window : self).PlacementWorker = PlacementWorker; + +// clipperjs uses alerts for warnings +function alert(message) { + console.log('alert: ', message); +}