blob: 246a29b1622b2f156d9dbf402093c5ce3fb65a34 [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
Cary Clark59d5a0e2017-01-23 14:38:52 +00003<div height="0" hidden="true">
Ben Wagner29380bd2017-10-09 14:43:00 -04004
Cary Clark3a4a3212018-06-06 15:22:08 -04005<div id="halbug">
6seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}}
7seg=2 {{{580.15918f, 155.747406f}, {580.15918f, 593.602051f}}}
8seg=3 {{{580.15918f, 593.602051f}, {278.653992f, 593.602051f}}}
9seg=4 {{{278.653992f, 593.602051f}, {278.653992f, 155.747406f}}}
10op sect
11seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}}
12seg=6 {{{580.238281f, 155.747314f}, {580.238281f, 594.114014f}}}
13seg=7 {{{580.238281f, 594.114014f}, {278.657715f, 594.114014f}}}
14seg=8 {{{278.657715f, 594.114014f}, {278.657715f, 155.747314f}}}
15debugShowLineIntersection wtTs[0]=0 {{{580.238281,155.747314}, {580.238281,594.114014}}} {{580.238281,155.747314}} wnTs[0]=1 {{{278.657715,155.747314}, {580.238281,155.747314}}}
16debugShowLineIntersection wtTs[0]=1 {{{278.657715,594.114014}, {278.657715,155.747314}}} {{278.657715,155.747314}} wnTs[0]=0 {{{278.657715,155.747314}, {580.238281,155.747314}}}
17debugShowLineIntersection wtTs[0]=0 {{{580.238281,594.114014}, {278.657715,594.114014}}} {{580.238281,594.114014}} wnTs[0]=1 {{{580.238281,155.747314}, {580.238281,594.114014}}}
18debugShowLineIntersection wtTs[0]=0 {{{278.657715,594.114014}, {278.657715,155.747314}}} {{278.657715,594.114014}} wnTs[0]=1 {{{580.238281,594.114014}, {278.657715,594.114014}}}
19debugShowLineIntersection no intersect {{{278.653992,155.747406}, {580.15918,155.747406}}} {{{278.657715,155.747314}, {580.238281,155.747314}}}
20debugShowLineIntersection no intersect {{{580.15918,155.747406}, {580.15918,593.602051}}} {{{278.657715,155.747314}, {580.238281,155.747314}}}
21debugShowLineIntersection wtTs[0]=1.23485256e-05 {{{278.653992,155.747406}, {580.15918,155.747406}}} {{278.657715,155.747406}} wnTs[0]=1 {{{278.657715,594.114014}, {278.657715,155.747314}}}
22SkOpSegment::addT insert t=1.23485256e-05 segID=1 spanID=17
23debugShowLineIntersection wtTs[0]=0.999987651 {{{580.15918,593.602051}, {278.653992,593.602051}}} {{278.657715,593.602051}} wnTs[0]=0.00116789 {{{278.657715,594.114014}, {278.657715,155.747314}}}
24SkOpSegment::addT insert t=0.00116788728 segID=8 spanID=18
25SkOpSegment::addT insert t=0.999987651 segID=3 spanID=19
26debugShowLineIntersection wtTs[0]=0 {{{580.15918,155.747406}, {580.15918,593.602051}}} {{580.15918,155.747406}} wnTs[0]=1 {{{278.653992,155.747406}, {580.15918,155.747406}}}
27debugShowLineIntersection wtTs[0]=1 {{{278.653992,593.602051}, {278.653992,155.747406}}} {{278.653992,155.747406}} wnTs[0]=0 {{{278.653992,155.747406}, {580.15918,155.747406}}}
28debugShowLineIntersection wtTs[0]=0 {{{580.15918,593.602051}, {278.653992,593.602051}}} {{580.15918,593.602051}} wnTs[0]=1 {{{580.15918,155.747406}, {580.15918,593.602051}}}
29debugShowLineIntersection wtTs[0]=0 {{{278.653992,593.602051}, {278.653992,155.747406}}} {{278.653992,593.602051}} wnTs[0]=1 {{{580.15918,593.602051}, {278.653992,593.602051}}}
30-------------------------------------- addExpanded
31SkOpSegment::debugShowActiveSpans id=5 (278.657715,155.747314 580.238281,155.747314) t=0 tEnd=1 windSum=? windValue=1
32SkOpSegment::debugShowActiveSpans id=6 (580.238281,155.747314 580.238281,594.114014) t=0 tEnd=1 windSum=? windValue=1
33SkOpSegment::debugShowActiveSpans id=7 (580.238281,594.114014 278.657715,594.114014) t=0 tEnd=1 windSum=? windValue=1
34SkOpSegment::debugShowActiveSpans id=8 (278.657715,594.114014 278.657715,593.602051) t=0 tEnd=0.00116788728 windSum=? windValue=1
35SkOpSegment::debugShowActiveSpans id=8 (278.657715,593.602051 278.657715,155.747314) t=0.00116788728 tEnd=1 windSum=? windValue=1
36SkOpSegment::debugShowActiveSpans id=1 (278.653992,155.747406 278.657715,155.747406) t=0 tEnd=1.23485256e-05 windSum=? windValue=1
37SkOpSegment::debugShowActiveSpans id=1 (278.657715,155.747406 580.15918,155.747406) t=1.23485256e-05 tEnd=1 windSum=? windValue=1
38SkOpSegment::debugShowActiveSpans id=2 (580.15918,155.747406 580.15918,593.602051) t=0 tEnd=1 windSum=? windValue=1
39SkOpSegment::debugShowActiveSpans id=3 (580.15918,593.602051 278.657715,593.602051) t=0 tEnd=0.999987651 windSum=? windValue=1
40SkOpSegment::debugShowActiveSpans id=3 (278.657715,593.602051 278.653992,593.602051) t=0.999987651 tEnd=1 windSum=? windValue=1
41SkOpSegment::debugShowActiveSpans id=4 (278.653992,593.602051 278.653992,155.747406) t=0 tEnd=1 windSum=? windValue=1
42-------------------------------------- move_multiples
43-------------------------------------- move_nearby
44-------------------------------------- correctEnds
45-------------------------------------- addEndMovedSpans
46-------------------------------------- expand
47-------------------------------------- addExpanded
48-------------------------------------- mark
49-------------------------------------- missing_coincidence
50-------------------------------------- expand
51-------------------------------------- expand
52-------------------------------------- apply
53-------------------------------------- findOverlaps
54-------------------------------------- calc_angles
55SkOpSegment::sortAngles [5] tStart=0 [9]
56SkOpAngle::after [5/1] 31/31 tStart=0 tEnd=1 < [1/5] 15/15 tStart=1.23485256e-05 tEnd=0 < [8/4] 23/23 tStart=1 tEnd=0.00116788728 T 4
57SkOpAngle::afterPart {{{278.657715,155.747406}, {580.238281,155.747406}}} id=5
58SkOpAngle::afterPart {{{278.657715,155.747406}, {278.653992,155.747406}}} id=1
59SkOpAngle::afterPart {{{278.657715,155.747406}, {278.657715,593.602142}}} id=8
60SkOpAngle::after [5/1] 31/31 tStart=0 tEnd=1 < [1/6] 31/31 tStart=1.23485256e-05 tEnd=1 < [1/5] 15/15 tStart=1.23485256e-05 tEnd=0 T 12
61SkOpAngle::afterPart {{{278.657715,155.747406}, {580.238281,155.747406}}} id=5
62SkOpAngle::afterPart {{{278.657715,155.747406}, {580.15918,155.747406}}} id=1
63SkOpAngle::afterPart {{{278.657715,155.747406}, {278.653992,155.747406}}} id=1
64SkOpSegment::sortAngles [8] tStart=0.00116788728 [18]
65SkOpAngle::after [8/2] 23/23 tStart=0.00116788728 tEnd=0 < [3/7] 31/31 tStart=0.999987651 tEnd=0 < [8/3] 7/7 tStart=0.00116788728 tEnd=1 T 4
66SkOpAngle::afterPart {{{278.657715,593.602051}, {278.657715,594.114014}}} id=8
67SkOpAngle::afterPart {{{278.657715,593.602051}, {580.15918,593.602051}}} id=3
68SkOpAngle::afterPart {{{278.657715,593.602051}, {278.657715,155.747314}}} id=8
69SkOpAngle::after [8/2] 23/23 tStart=0.00116788728 tEnd=0 < [3/8] 15/15 tStart=0.999987651 tEnd=1 < [3/7] 31/31 tStart=0.999987651 tEnd=0 F 4
70SkOpAngle::afterPart {{{278.657715,593.602051}, {278.657715,594.114014}}} id=8
71SkOpAngle::afterPart {{{278.657715,593.602051}, {278.653992,593.602051}}} id=3
72SkOpAngle::afterPart {{{278.657715,593.602051}, {580.15918,593.602051}}} id=3
73SkOpAngle::after [3/7] 31/31 tStart=0.999987651 tEnd=0 < [3/8] 15/15 tStart=0.999987651 tEnd=1 < [8/3] 7/7 tStart=0.00116788728 tEnd=1 F 4
74SkOpAngle::afterPart {{{278.657715,593.602051}, {580.15918,593.602051}}} id=3
75SkOpAngle::afterPart {{{278.657715,593.602051}, {278.653992,593.602051}}} id=3
76SkOpAngle::afterPart {{{278.657715,593.602051}, {278.657715,155.747314}}} id=8
77SkOpAngle::after [8/3] 7/7 tStart=0.00116788728 tEnd=1 < [3/8] 15/15 tStart=0.999987651 tEnd=1 < [8/2] 23/23 tStart=0.00116788728 tEnd=0 T 4
78SkOpAngle::afterPart {{{278.657715,593.602051}, {278.657715,155.747314}}} id=8
79SkOpAngle::afterPart {{{278.657715,593.602051}, {278.653992,593.602051}}} id=3
80SkOpAngle::afterPart {{{278.657715,593.602051}, {278.657715,594.114014}}} id=8
81SkOpSegment::sortAngles [8] tStart=1 [16]
82SkOpSegment::sortAngles [1] tStart=1.23485256e-05 [17]
83SkOpSegment::sortAngles [3] tStart=0.999987651 [19]
84SkOpSpan::sortableTop dir=kTop seg=5 t=0.5 pt=(429.447998,155.747314)
85SkOpSpan::sortableTop [0] valid=1 operand=1 span=9 ccw=1 seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}} t=0.5 pt=(429.447998,155.747314) slope=(301.580566,0)
86SkOpSegment::markWinding id=5 (278.657715,155.747314 580.238281,155.747314) t=0 [9] (278.657715,155.747314) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
87SkOpSegment::markWinding id=6 (580.238281,155.747314 580.238281,594.114014) t=0 [11] (580.238281,155.747314) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
88SkOpSegment::markWinding id=7 (580.238281,594.114014 278.657715,594.114014) t=0 [13] (580.238281,594.114014) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
89SkOpSegment::markWinding id=8 (278.657715,594.114014 278.657715,155.747314) t=0 [15] (278.657715,594.114014) tEnd=0.00116788728 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
90SkOpSegment::markWinding id=5 (278.657715,155.747314 580.238281,155.747314) t=0 [9] (278.657715,155.747314) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
91SkOpSegment::activeOp id=5 t=1 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
92SkOpSegment::markDone id=5 (278.657715,155.747314 580.238281,155.747314) t=0 [9] (278.657715,155.747314) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
93bridgeOp chase.append id=5 windSum=-1
94SkOpSpan::sortableTop dir=kTop seg=1 t=0.500006174 pt=(429.408447,155.747406)
95SkOpSpan::sortableTop [0] valid=0 operand=1 span=9 ccw=0 seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}} t=0.499868855 pt=(429.408447,155.747314) slope=(0,0)
96SkOpSpan::sortableTop [1] valid=1 operand=0 span=17 ccw=1 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.500006174 pt=(429.408447,155.747406) slope=(301.505188,0)
97SkOpSpan::sortableTop dir=kRight seg=1 t=0.500006174 pt=(429.408447,155.747406)
98SkOpSpan::sortableTop [0] valid=1 operand=1 span=11 ccw=1 seg=6 {{{580.238281f, 155.747314f}, {580.238281f, 594.114014f}}} t=2.08849656e-07 pt=(580.238281,155.747406) slope=(0,438.366699)
99SkOpSpan::sortableTop [1] valid=0 operand=0 span=3 ccw=0 seg=2 {{{580.15918f, 155.747406f}, {580.15918f, 593.602051f}}} t=0 pt=(580.15918,155.747406) slope=(0,0)
100SkOpSpan::sortableTop [2] valid=1 operand=0 span=17 ccw=0 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.500006174 pt=(429.408447,155.747406) slope=(301.505188,0)
101SkOpSpan::sortableTop dir=kTop seg=1 t=0.250009261 pt=(354.033081,155.747406)
102SkOpSpan::sortableTop [0] valid=0 operand=1 span=9 ccw=0 seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}} t=0.249934428 pt=(354.033081,155.747314) slope=(0,0)
103SkOpSpan::sortableTop [1] valid=1 operand=0 span=17 ccw=1 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.250009261 pt=(354.033081,155.747406) slope=(301.505188,0)
104SkOpSpan::sortableTop dir=kRight seg=1 t=0.250009261 pt=(354.033081,155.747406)
105SkOpSpan::sortableTop [0] valid=1 operand=1 span=11 ccw=1 seg=6 {{{580.238281f, 155.747314f}, {580.238281f, 594.114014f}}} t=2.08849656e-07 pt=(580.238281,155.747406) slope=(0,438.366699)
106SkOpSpan::sortableTop [1] valid=0 operand=0 span=3 ccw=0 seg=2 {{{580.15918f, 155.747406f}, {580.15918f, 593.602051f}}} t=0 pt=(580.15918,155.747406) slope=(0,0)
107SkOpSpan::sortableTop [2] valid=1 operand=0 span=17 ccw=0 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.250009261 pt=(354.033081,155.747406) slope=(301.505188,0)
108SkOpSpan::sortableTop dir=kTop seg=1 t=0.375007718 pt=(391.720764,155.747406)
109SkOpSpan::sortableTop [0] valid=0 operand=1 span=9 ccw=0 seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}} t=0.374901641 pt=(391.720764,155.747314) slope=(0,0)
110SkOpSpan::sortableTop [1] valid=1 operand=0 span=17 ccw=1 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.375007718 pt=(391.720764,155.747406) slope=(301.505188,0)
111SkOpSpan::sortableTop dir=kRight seg=1 t=0.375007718 pt=(391.720764,155.747406)
112SkOpSpan::sortableTop [0] valid=1 operand=1 span=11 ccw=1 seg=6 {{{580.238281f, 155.747314f}, {580.238281f, 594.114014f}}} t=2.08849656e-07 pt=(580.238281,155.747406) slope=(0,438.366699)
113SkOpSpan::sortableTop [1] valid=0 operand=0 span=3 ccw=0 seg=2 {{{580.15918f, 155.747406f}, {580.15918f, 593.602051f}}} t=0 pt=(580.15918,155.747406) slope=(0,0)
114SkOpSpan::sortableTop [2] valid=1 operand=0 span=17 ccw=0 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.375007718 pt=(391.720764,155.747406) slope=(301.505188,0)
115SkOpSpan::sortableTop dir=kTop seg=1 t=0.625004631 pt=(467.09613,155.747406)
116SkOpSpan::sortableTop [0] valid=0 operand=1 span=9 ccw=0 seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}} t=0.624836069 pt=(467.09613,155.747314) slope=(0,0)
117SkOpSpan::sortableTop [1] valid=1 operand=0 span=17 ccw=1 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.625004631 pt=(467.09613,155.747406) slope=(301.505188,0)
118SkOpSpan::sortableTop dir=kRight seg=1 t=0.625004631 pt=(467.09613,155.747406)
119SkOpSpan::sortableTop [0] valid=1 operand=1 span=11 ccw=1 seg=6 {{{580.238281f, 155.747314f}, {580.238281f, 594.114014f}}} t=2.08849656e-07 pt=(580.238281,155.747406) slope=(0,438.366699)
120SkOpSpan::sortableTop [1] valid=0 operand=0 span=3 ccw=0 seg=2 {{{580.15918f, 155.747406f}, {580.15918f, 593.602051f}}} t=0 pt=(580.15918,155.747406) slope=(0,0)
121SkOpSpan::sortableTop [2] valid=1 operand=0 span=17 ccw=0 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.625004631 pt=(467.09613,155.747406) slope=(301.505188,0)
122SkOpSpan::sortableTop dir=kTop seg=1 t=0.437506946 pt=(410.564606,155.747406)
123SkOpSpan::sortableTop [0] valid=0 operand=1 span=9 ccw=0 seg=5 {{{278.657715f, 155.747314f}, {580.238281f, 155.747314f}}} t=0.437385248 pt=(410.564606,155.747314) slope=(0,0)
124SkOpSpan::sortableTop [1] valid=1 operand=0 span=17 ccw=1 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.437506946 pt=(410.564606,155.747406) slope=(301.505188,0)
125SkOpSpan::sortableTop dir=kRight seg=1 t=0.437506946 pt=(410.564606,155.747406)
126SkOpSpan::sortableTop [0] valid=1 operand=1 span=11 ccw=1 seg=6 {{{580.238281f, 155.747314f}, {580.238281f, 594.114014f}}} t=2.08849656e-07 pt=(580.238281,155.747406) slope=(0,438.366699)
127SkOpSpan::sortableTop [1] valid=0 operand=0 span=3 ccw=0 seg=2 {{{580.15918f, 155.747406f}, {580.15918f, 593.602051f}}} t=0 pt=(580.15918,155.747406) slope=(0,0)
128SkOpSpan::sortableTop [2] valid=1 operand=0 span=17 ccw=0 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=0.437506946 pt=(410.564606,155.747406) slope=(301.505188,0)
129SkOpSpan::sortableTop dir=kTop seg=1 t=6.1742628e-06 pt=(278.655853,155.747406)
130SkOpSpan::sortableTop [0] valid=1 operand=0 span=1 ccw=1 seg=1 {{{278.653992f, 155.747406f}, {580.15918f, 155.747406f}}} t=6.1742628e-06 pt=(278.655853,155.747406) slope=(301.505188,0)
131SkOpSegment::markWinding id=1 (278.653992,155.747406 580.15918,155.747406) t=0 [1] (278.653992,155.747406) tEnd=1.23485256e-05 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
132SkOpSegment::markWinding id=1 (278.653992,155.747406 580.15918,155.747406) t=0 [1] (278.653992,155.747406) tEnd=1.23485256e-05 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
133SkOpSegment::markWinding id=4 (278.653992,593.602051 278.653992,155.747406) t=0 [7] (278.653992,593.602051) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
134SkOpSegment::markWinding id=3 (580.15918,593.602051 278.653992,593.602051) t=0.999987651 [19] (278.657715,593.602051) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
135SkOpSpan::sortableTop dir=kLeft seg=8 t=0.500583944 pt=(278.657715,374.674683)
136SkOpSpan::sortableTop [0] valid=1 operand=0 span=7 ccw=1 seg=4 {{{278.653992f, 593.602051f}, {278.653992f, 155.747406f}}} t=0.500000105 pt=(278.653992,374.674683) slope=(0,-437.854645)
137SkOpSpan::sortableTop [1] valid=1 operand=1 span=18 ccw=1 seg=8 {{{278.657715f, 594.114014f}, {278.657715f, 155.747314f}}} t=0.500583944 pt=(278.657715,374.674683) slope=(0,-438.366699)
138SkOpSegment::markWinding id=8 (278.657715,594.114014 278.657715,155.747314) t=0.00116788728 [18] (278.657715,593.602051) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
139SkOpSegment::markWinding id=8 (278.657715,594.114014 278.657715,155.747314) t=0.00116788728 [18] (278.657715,593.602051) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
140SkOpSegment::debugShowActiveSpans id=6 (580.238281,155.747314 580.238281,594.114014) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
141SkOpSegment::debugShowActiveSpans id=7 (580.238281,594.114014 278.657715,594.114014) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
142SkOpSegment::debugShowActiveSpans id=8 (278.657715,594.114014 278.657715,593.602051) t=0 tEnd=0.00116788728 windSum=-1 oppSum=0 windValue=1 oppValue=0
143SkOpSegment::debugShowActiveSpans id=8 (278.657715,593.602051 278.657715,155.747314) t=0.00116788728 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
144SkOpSegment::debugShowActiveSpans id=1 (278.653992,155.747406 278.657715,155.747406) t=0 tEnd=1.23485256e-05 windSum=-1 oppSum=0 windValue=1 oppValue=0
145SkOpSegment::debugShowActiveSpans id=1 (278.657715,155.747406 580.15918,155.747406) t=1.23485256e-05 tEnd=1 windSum=? windValue=1
146SkOpSegment::debugShowActiveSpans id=2 (580.15918,155.747406 580.15918,593.602051) t=0 tEnd=1 windSum=? windValue=1
147SkOpSegment::debugShowActiveSpans id=3 (580.15918,593.602051 278.657715,593.602051) t=0 tEnd=0.999987651 windSum=? windValue=1
148SkOpSegment::debugShowActiveSpans id=3 (278.657715,593.602051 278.653992,593.602051) t=0.999987651 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
149SkOpSegment::debugShowActiveSpans id=4 (278.653992,593.602051 278.653992,155.747406) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
150SkOpSegment::activeOp id=1 t=1.23485256e-05 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
151SkOpSegment::markDone id=1 (278.653992,155.747406 580.15918,155.747406) t=0 [1] (278.653992,155.747406) tEnd=1.23485256e-05 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
152SkOpSegment::markDone id=4 (278.653992,593.602051 278.653992,155.747406) t=0 [7] (278.653992,593.602051) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
153SkOpSegment::markDone id=3 (580.15918,593.602051 278.653992,593.602051) t=0.999987651 [19] (278.657715,593.602051) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
154bridgeOp chase.append id=3 windSum=-1
155SkOpSegment::debugShowActiveSpans id=6 (580.238281,155.747314 580.238281,594.114014) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
156SkOpSegment::debugShowActiveSpans id=7 (580.238281,594.114014 278.657715,594.114014) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
157SkOpSegment::debugShowActiveSpans id=8 (278.657715,594.114014 278.657715,593.602051) t=0 tEnd=0.00116788728 windSum=-1 oppSum=0 windValue=1 oppValue=0
158SkOpSegment::debugShowActiveSpans id=8 (278.657715,593.602051 278.657715,155.747314) t=0.00116788728 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
159SkOpSegment::debugShowActiveSpans id=1 (278.657715,155.747406 580.15918,155.747406) t=1.23485256e-05 tEnd=1 windSum=? windValue=1
160SkOpSegment::debugShowActiveSpans id=2 (580.15918,155.747406 580.15918,593.602051) t=0 tEnd=1 windSum=? windValue=1
161SkOpSegment::debugShowActiveSpans id=3 (580.15918,593.602051 278.657715,593.602051) t=0 tEnd=0.999987651 windSum=? windValue=1
162SkOpSegment::activeOp id=8 t=0.00116788728 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
163SkOpSegment::findNextOp
164SkOpAngle::dumpOne [8/4] next=5/1 sect=23/23 s=1 [16] e=0.00116788728 [18] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand
165SkOpAngle::dumpOne [5/1] next=1/6 sect=31/31 s=0 [9] e=1 [10] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done unorderable operand
166SkOpAngle::dumpOne [1/6] next=1/5 sect=31/31 s=1.23485256e-05 [17] e=1 [2] sgn=-1 windVal=1 windSum=? unorderable
167SkOpAngle::dumpOne [1/5] next=8/4 sect=15/15 s=1.23485256e-05 [17] e=0 [1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done
168SkOpSegment::activeOp id=5 t=0 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
169SkOpSegment::activeOp id=1 t=1.23485256e-05 tEnd=1 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
170SkOpSegment::markDone id=1 (278.653992,155.747406 580.15918,155.747406) t=1.23485256e-05 [17] (278.657715,155.747406) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
171SkOpSegment::markDone id=2 (580.15918,155.747406 580.15918,593.602051) t=0 [3] (580.15918,155.747406) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
172SkOpSegment::markDone id=3 (580.15918,593.602051 278.653992,593.602051) t=0 [5] (580.15918,593.602051) tEnd=0.999987651 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
173SkOpSegment::activeOp id=1 t=1.23485256e-05 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
174SkOpSegment::markDone id=8 (278.657715,594.114014 278.657715,155.747314) t=0.00116788728 [18] (278.657715,593.602051) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
175SkOpSegment::findNextOp from:[8] to:[5] start=1653597136 end=1653597280
176bridgeOp current id=8 from=(278.657715,593.602051) to=(278.657715,155.747314)
177path.moveTo(278.657715,593.602051);
178path.lineTo(278.657715,155.747314);
179SkOpSegment::debugShowActiveSpans id=6 (580.238281,155.747314 580.238281,594.114014) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
180SkOpSegment::debugShowActiveSpans id=7 (580.238281,594.114014 278.657715,594.114014) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
181SkOpSegment::debugShowActiveSpans id=8 (278.657715,594.114014 278.657715,593.602051) t=0 tEnd=0.00116788728 windSum=-1 oppSum=0 windValue=1 oppValue=0
182SkOpSegment::activeOp id=8 t=0.00116788728 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
183SkOpSegment::markDone id=8 (278.657715,594.114014 278.657715,155.747314) t=0 [15] (278.657715,594.114014) tEnd=0.00116788728 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
184SkOpSegment::markDone id=7 (580.238281,594.114014 278.657715,594.114014) t=0 [13] (580.238281,594.114014) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
185SkOpSegment::markDone id=6 (580.238281,155.747314 580.238281,594.114014) t=0 [11] (580.238281,155.747314) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
Ben Wagner29380bd2017-10-09 14:43:00 -0400186</div>
187
caryclarkdac1d172014-06-17 05:15:38 -0700188</div>
189
190<script type="text/javascript">
191
caryclark55888e42016-07-18 10:01:36 -0700192 var testDivs = [
Cary Clark3a4a3212018-06-06 15:22:08 -0400193 halbug,
caryclark30b9fdd2016-08-31 14:36:29 -0700194 ];
caryclarkdac1d172014-06-17 05:15:38 -0700195
196var decimal_places = 3; // make this 3 to show more precision
197
198var tests = [];
199var testLines = [];
200var testTitles = [];
201var testIndex = 0;
202var ctx;
203
204var xmin, xmax, focusXmin, focusXmax;
205var ymin, ymax, focusYmin, focusYmax;
206var scale;
207var mouseX, mouseY;
208var srcLeft, srcTop;
209var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700210var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700211var curveT = 0;
212
213var pt_labels = 2;
214var collect_bounds = false;
215var control_lines = 0;
216var curve_t = false;
217var debug_xy = 1;
218var focus_enabled = false;
219var focus_on_selection = false;
220var step_limit = 0;
221var draw_active = false;
222var draw_add = false;
223var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700224var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700225var draw_deriviatives = 0;
Cary Clarkff114282016-12-14 11:56:16 -0500226var draw_direction = false;
caryclarkdac1d172014-06-17 05:15:38 -0700227var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700228var draw_id = false;
229var draw_intersection = 0;
230var draw_intersectT = false;
231var draw_legend = true;
232var draw_log = false;
233var draw_mark = false;
234var draw_midpoint = false;
235var draw_op = 0;
236var draw_sequence = false;
237var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700238var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700239var draw_path = 3;
240var draw_computed = 0;
241var retina_scale = !!window.devicePixelRatio;
242
243var activeCount = 0;
244var addCount = 0;
245var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700246var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700247var opCount = 0;
248var sectCount = 0;
249var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700250var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700251var markCount = 0;
252var activeMax = 0;
253var addMax = 0;
254var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700255var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700256var sectMax = 0;
257var sectMax2 = 0;
258var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700259var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700260var markMax = 0;
261var opMax = 0;
262var stepMax = 0;
263var lastIndex = 0;
264var hasPath = false;
caryclark26ad22a2015-10-16 09:03:38 -0700265var hasAlignedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700266var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700267var angleBetween = false;
268var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700269
270var firstActiveSpan = -1;
271var logStart = -1;
272var logRange = 0;
273
274var SPAN_ID = 0;
275var SPAN_X1 = SPAN_ID + 1;
276var SPAN_Y1 = SPAN_X1 + 1;
277var SPAN_X2 = SPAN_Y1 + 1;
278var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700279
caryclark55888e42016-07-18 10:01:36 -0700280var SPAN_L_TX = SPAN_Y2 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700281var SPAN_L_TY = SPAN_L_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700282var SPAN_L_OTHER = SPAN_L_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700283var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
284var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
285var SPAN_L_SUM = SPAN_L_OTHERI + 1;
286var SPAN_L_VAL = SPAN_L_SUM + 1;
287var SPAN_L_OPP = SPAN_L_VAL + 1;
288
289var SPAN_X3 = SPAN_Y2 + 1;
290var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700291
caryclark55888e42016-07-18 10:01:36 -0700292var SPAN_Q_TX = SPAN_Y3 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700293var SPAN_Q_TY = SPAN_Q_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700294var SPAN_Q_OTHER = SPAN_Q_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700295var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
296var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
297var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
298var SPAN_Q_VAL = SPAN_Q_SUM + 1;
299var SPAN_Q_OPP = SPAN_Q_VAL + 1;
300
caryclark1049f122015-04-20 08:31:59 -0700301var SPAN_K_W = SPAN_Y3 + 1;
caryclark55888e42016-07-18 10:01:36 -0700302var SPAN_K_TX = SPAN_K_W + 1;
caryclark1049f122015-04-20 08:31:59 -0700303var SPAN_K_TY = SPAN_K_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700304var SPAN_K_OTHER = SPAN_K_TY + 1;
caryclark1049f122015-04-20 08:31:59 -0700305var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
306var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
307var SPAN_K_SUM = SPAN_K_OTHERI + 1;
308var SPAN_K_VAL = SPAN_K_SUM + 1;
309var SPAN_K_OPP = SPAN_K_VAL + 1;
310
caryclarkdac1d172014-06-17 05:15:38 -0700311var SPAN_X4 = SPAN_Y3 + 1;
312var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700313
caryclark55888e42016-07-18 10:01:36 -0700314var SPAN_C_TX = SPAN_Y4 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700315var SPAN_C_TY = SPAN_C_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700316var SPAN_C_OTHER = SPAN_C_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700317var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
318var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
319var SPAN_C_SUM = SPAN_C_OTHERI + 1;
320var SPAN_C_VAL = SPAN_C_SUM + 1;
321var SPAN_C_OPP = SPAN_C_VAL + 1;
322
323var ACTIVE_LINE_SPAN = 1;
324var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700325var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
326var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700327
328var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
329var ADD_LINETO = ADD_MOVETO + 1;
330var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700331var ADD_CONICTO = ADD_QUADTO + 1;
332var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700333var ADD_CLOSE = ADD_CUBICTO + 1;
334var ADD_FILL = ADD_CLOSE + 1;
335
336var PATH_LINE = ADD_FILL + 1;
337var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700338var PATH_CONIC = PATH_QUAD + 1;
339var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700340
341var INTERSECT_LINE = PATH_CUBIC + 1;
342var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
343var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
344var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
345var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
346var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
347var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
348var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
349var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700350var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
351var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
352var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
caryclark55888e42016-07-18 10:01:36 -0700353var INTERSECT_CONIC_QUAD = INTERSECT_CONIC_LINE_NO + 1;
354var INTERSECT_CONIC_QUAD_2 = INTERSECT_CONIC_QUAD + 1;
caryclark6c3b9cd2016-09-26 05:36:58 -0700355var INTERSECT_CONIC_QUAD_3 = INTERSECT_CONIC_QUAD_2 + 1;
356var INTERSECT_CONIC_QUAD_4 = INTERSECT_CONIC_QUAD_3 + 1;
357var INTERSECT_CONIC_QUAD_NO = INTERSECT_CONIC_QUAD_4 + 1;
caryclark55888e42016-07-18 10:01:36 -0700358var INTERSECT_CONIC = INTERSECT_CONIC_QUAD_NO + 1;
caryclark1049f122015-04-20 08:31:59 -0700359var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
360var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
361var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700362var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
363var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
364var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
365var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
366var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
367var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
368var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
369var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
370var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
371var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
372var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
373var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
374var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
375var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
376// FIXME: add cubic 5- 9
377var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
378
379var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
380var SORT_BINARY = SORT_UNARY + 1;
381
382var OP_DIFFERENCE = SORT_BINARY + 1;
383var OP_INTERSECT = OP_DIFFERENCE + 1;
384var OP_UNION = OP_INTERSECT + 1;
385var OP_XOR = OP_UNION + 1;
386
387var MARK_LINE = OP_XOR + 1;
388var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700389var MARK_CONIC = MARK_QUAD + 1;
390var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700391var MARK_DONE_LINE = MARK_CUBIC + 1;
392var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700393var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
394var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700395var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
396var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700397var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
398var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700399var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
400var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700401var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
402var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700403var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
404var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700405var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
406var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700407var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
408var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700409var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
410var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700411var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
412
413var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
414var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
415
caryclark624637c2015-05-11 07:21:27 -0700416var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700417var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700418
caryclark54359292015-03-26 07:52:43 -0700419var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700420
caryclark624637c2015-05-11 07:21:27 -0700421var COIN_MAIN_SPAN = ACTIVE_OP + 1;
422var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
423
424var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700425
426var REC_TYPE_UNKNOWN = -1;
427var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700428var REC_TYPE_PATH2 = 1;
429var REC_TYPE_SECT = 2;
430var REC_TYPE_ACTIVE = 3;
431var REC_TYPE_ADD = 4;
432var REC_TYPE_SORT = 5;
433var REC_TYPE_OP = 6;
434var REC_TYPE_MARK = 7;
435var REC_TYPE_COMPUTED = 8;
436var REC_TYPE_COIN = 9;
437var REC_TYPE_ANGLE = 10;
438var REC_TYPE_ACTIVE_OP = 11;
439var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700440var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700441var REC_TYPE_COINCIDENCE = 14;
caryclark26ad22a2015-10-16 09:03:38 -0700442var REC_TYPE_ALIGNED = 15;
443var REC_TYPE_LAST = REC_TYPE_ALIGNED;
caryclarkdac1d172014-06-17 05:15:38 -0700444
445function strs_to_nums(strs) {
446 var result = [];
447 for (var idx = 1; idx < strs.length; ++idx) {
448 var str = strs[idx];
449 var num = parseFloat(str);
450 if (isNaN(num)) {
451 result.push(str);
452 } else {
453 result.push(num);
454 }
455 }
456 return result;
457}
458
459function filter_str_by(id, str, regex, array) {
460 if (regex.test(str)) {
461 var strs = regex.exec(str);
462 var result = strs_to_nums(strs);
463 array.push(id);
464 array.push(result);
465 return true;
466 }
467 return false;
468}
469
470function construct_regexp2(pattern) {
471 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
472 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
473 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700474 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700475 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
476 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
477 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700478 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700479 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
480 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
481 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700482 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700483 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700484 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700485 escape = escape.replace(/NUM/g, "(-?\\d+)");
486 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
487 return new RegExp(escape, 'i');
488}
489
490function construct_regexp2c(pattern) {
491 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
492 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700493 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700494 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700495 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
496 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700497 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700498 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700499 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700500 escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700501 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700502 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700503 escape = escape.replace(/OPER/g, "[a-z]+");
504 escape = escape.replace(/PATH/g, "pathB?");
505 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700506 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700507 escape = escape.replace(/NUM/g, "(-?\\d+)");
508 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
509 return new RegExp(escape, 'i');
510}
511
512function match_regexp(str, lineNo, array, id, pattern) {
513 var regex = construct_regexp2(pattern);
514 if (filter_str_by(id, str, regex, array)) {
515 return true;
516 }
517 regex = construct_regexp2c(pattern);
518 return filter_str_by(id, str, regex, array);
519}
520
521function endsWith(str, suffix) {
522 return str.indexOf(suffix, str.length - suffix.length) !== -1;
523}
524
525function parse_all(test) {
526 var lines = test.match(/[^\r\n]+/g);
527 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
528 var record = [];
529 var recType = REC_TYPE_UNKNOWN;
530 var lastLineNo;
531 var moveX, moveY;
532 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
533 var line = lines[lineNo];
534 if (line.length == 0) {
535 continue;
536 }
537 var opStart = "SkOpSegment::";
538 if (line.lastIndexOf(opStart, 0) === 0) {
539 line = line.substr(opStart.length);
540 }
541 var angleStart = "SkOpAngle::";
542 if (line.lastIndexOf(angleStart, 0) === 0) {
543 line = line.substr(angleStart.length);
544 }
caryclark624637c2015-05-11 07:21:27 -0700545 var coinStart = "SkOpCoincidence::";
546 if (line.lastIndexOf(coinStart, 0) === 0) {
547 line = line.substr(coinStart.length);
548 }
caryclark54359292015-03-26 07:52:43 -0700549 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700550 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700551 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclark55888e42016-07-18 10:01:36 -0700552 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700553 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700554 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
555 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
556 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
557 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
caryclark26ad22a2015-10-16 09:03:38 -0700558 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
caryclarkdac1d172014-06-17 05:15:38 -0700559 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700560 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700561 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
562 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
Cary Clark59d5a0e2017-01-23 14:38:52 +0000563 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
caryclarkdac1d172014-06-17 05:15:38 -0700564 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
565 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700566 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700567 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
568 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
569 : REC_TYPE_UNKNOWN;
570 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
571 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
572 if (recType != REC_TYPE_UNKNOWN) {
573 records.push(recType);
574 records.push(lastLineNo);
575 records.push(record);
576 }
577 record = [];
578 recType = type;
579 lastLineNo = lineNo;
580 }
581 var found = false;
582 switch (recType) {
583 case REC_TYPE_ACTIVE:
584 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700585" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700586 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700587" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700588 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700589" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700590 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700591" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark624637c2015-05-11 07:21:27 -0700592 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700593" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700594 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700595" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700596 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700597" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700598 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700599" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700600 );
601 break;
602 case REC_TYPE_ACTIVE_OP:
603 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
604" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
605 );
606 break;
607 case REC_TYPE_ADD:
608 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
609 moveX = record[1][0];
610 moveY = record[1][1];
611 found = true;
612 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
613 record[1].unshift(moveY);
614 record[1].unshift(moveX);
615 moveX = record[1][2];
616 moveY = record[1][3];
617 found = true;
618 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
619 record[1].unshift(moveY);
620 record[1].unshift(moveX);
621 moveX = record[1][4];
622 moveY = record[1][5];
623 found = true;
caryclark1049f122015-04-20 08:31:59 -0700624 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
625 record[1].unshift(moveY);
626 record[1].unshift(moveX);
627 moveX = record[1][4];
628 moveY = record[1][5];
629 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700630 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
631 record[1].unshift(moveY);
632 record[1].unshift(moveX);
633 moveX = record[1][6];
634 moveY = record[1][7];
635 found = true;
636 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
637 found = true;
638 } else {
639 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
640 }
641 break;
caryclark54359292015-03-26 07:52:43 -0700642 case REC_TYPE_AFTERPART:
Cary Clarkff114282016-12-14 11:56:16 -0500643 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL id=IDX")
644 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL id=IDX")
645 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL id=IDX")
646 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL id=IDX")
caryclark54359292015-03-26 07:52:43 -0700647 break;
caryclark26ad22a2015-10-16 09:03:38 -0700648 case REC_TYPE_ALIGNED:
649 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL"
650 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL"
651 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL"
652 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL"
653 );
654 break;
caryclarkdac1d172014-06-17 05:15:38 -0700655 case REC_TYPE_ANGLE:
Cary Clark59d5a0e2017-01-23 14:38:52 +0000656 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700657"[IDX/IDX] NUM/NUM tStart=T_VAL tEnd=T_VAL < [IDX/IDX] NUM/NUM tStart=T_VAL tEnd=T_VAL < [IDX/IDX] NUM/NUM tStart=T_VAL tEnd=T_VAL T_F IDX");
658 break;
659 case REC_TYPE_COIN:
660 found = true;
661 break;
caryclark624637c2015-05-11 07:21:27 -0700662 case REC_TYPE_COINCIDENCE:
663 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
664" + id=IDX t=T_VAL tEnd=T_VAL"
665 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
666" - id=IDX t=T_VAL tEnd=T_VAL"
667 );
668 break;
caryclarkdac1d172014-06-17 05:15:38 -0700669 case REC_TYPE_COMPUTED:
670 found = line == "computed quadratics given"
671 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
672 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
673 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700674 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700675 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
676 );
677 break;
678 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700679 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
680 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700681 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700682 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
683 );
684 break;
685 case REC_TYPE_PATH2:
686 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
687 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700688 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700689 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700690 );
691 break;
692 case REC_TYPE_SECT:
693 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
694" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
695 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
696" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
697 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
698" no intersect LINE_VAL LINE_VAL"
699 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
700" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
701 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
702" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
703 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
704" no intersect QUAD_VAL LINE_VAL"
705 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
706" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
707 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
708" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
709 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
710" no intersect QUAD_VAL QUAD_VAL"
caryclark55888e42016-07-18 10:01:36 -0700711
caryclark1049f122015-04-20 08:31:59 -0700712 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
713" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
714 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
715" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
716 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
717" no intersect CONIC_VAL LINE_VAL"
caryclark55888e42016-07-18 10:01:36 -0700718
719 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD, "debugShowConicQuadIntersection" +
720" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
721 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_2, "debugShowConicQuadIntersection" +
722" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
caryclark6c3b9cd2016-09-26 05:36:58 -0700723 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_3, "debugShowConicQuadIntersection" +
724" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
725 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_4, "debugShowConicQuadIntersection" +
726" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL"
caryclark55888e42016-07-18 10:01:36 -0700727 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" +
728" no intersect CONIC_VAL QUAD_VAL"
729
caryclark1049f122015-04-20 08:31:59 -0700730 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
731" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
732 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
733" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
734 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
735" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700736 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
737" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
738 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
739" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
740 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
741" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
742 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
743" no intersect CUBIC_VAL LINE_VAL"
744 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
745" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
746 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
747" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
748 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
749" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
750 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
751" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL"
752 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
753" no intersect CUBIC_VAL QUAD_VAL"
754 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
755" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
756 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
757" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
758 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
759" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
760 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
761" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL"
762 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
763" no intersect CUBIC_VAL CUBIC_VAL"
764 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
765" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
766 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
767" no self intersect CUBIC_VAL"
768 );
769 break;
770 case REC_TYPE_SORT:
771 var hasDone = / done/.test(line);
772 var hasUnorderable = / unorderable/.test(line);
773 var hasSmall = / small/.test(line);
774 var hasTiny = / tiny/.test(line);
775 var hasOperand = / operand/.test(line);
776 var hasStop = / stop/.test(line);
777 line.replace(/[ a-z]+$/, "");
778 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
779" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
780 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
781" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT oppVal=IDX oppSum=OPT"
782 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
783" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
784 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
785" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT oppVal=IDX oppSum=OPT"
786 );
787 if (found) {
788 record[1].push(hasDone);
789 record[1].push(hasUnorderable);
790 record[1].push(hasSmall);
791 record[1].push(hasTiny);
792 record[1].push(hasOperand);
793 record[1].push(hasStop);
794 }
795 break;
caryclark03b03ca2015-04-23 09:13:37 -0700796 case REC_TYPE_TOP:
797 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
798" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
799 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
800" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
801 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
802" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
803 );
804 break;
caryclarkdac1d172014-06-17 05:15:38 -0700805 case REC_TYPE_MARK:
806 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700807" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700808 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700809" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700810 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
811" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700812 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700813" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
814 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
815" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
816 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
817" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
caryclark1049f122015-04-20 08:31:59 -0700818 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
819" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
caryclark54359292015-03-26 07:52:43 -0700820 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
821" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
caryclarkdac1d172014-06-17 05:15:38 -0700822 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
823" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
824 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
825" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700826 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
827" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700828 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
829" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700830 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700831" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700832 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark55888e42016-07-18 10:01:36 -0700833" last seg=IDX span=IDX"
834 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
835" last segment=IDX span=IDX windSum=OPT"
836 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
837" last seg=IDX span=IDX windSum=OPT"
838 );
caryclarkdac1d172014-06-17 05:15:38 -0700839 break;
840 case REC_TYPE_OP:
841 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
842 || line.lastIndexOf("operator<", 0) === 0) {
843 found = true;
844 break;
845 }
caryclark54359292015-03-26 07:52:43 -0700846 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700847 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700848 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700849 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
850 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
851 );
852 break;
853 case REC_TYPE_UNKNOWN:
854 found = true;
855 break;
856 }
857 if (!found) {
858 console.log(line + " [" + lineNo + "] of type " + type + " not found");
859 }
860 }
861 if (recType != REC_TYPE_UNKNOWN) {
862 records.push(recType);
863 records.push(lastLineNo);
864 records.push(record);
865 }
866 if (records.length >= 1) {
867 tests[testIndex] = records;
868 testLines[testIndex] = lines;
869 }
870}
871
872function init(test) {
873 var canvas = document.getElementById('canvas');
874 if (!canvas.getContext) return;
875 ctx = canvas.getContext('2d');
876 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
877 var unscaledWidth = window.innerWidth - 20;
878 var unscaledHeight = window.innerHeight - 20;
879 screenWidth = unscaledWidth;
880 screenHeight = unscaledHeight;
881 canvas.width = unscaledWidth * resScale;
882 canvas.height = unscaledHeight * resScale;
883 canvas.style.width = unscaledWidth + 'px';
884 canvas.style.height = unscaledHeight + 'px';
885 if (resScale != 1) {
886 ctx.scale(resScale, resScale);
887 }
888 xmin = Infinity;
889 xmax = -Infinity;
890 ymin = Infinity;
891 ymax = -Infinity;
caryclark26ad22a2015-10-16 09:03:38 -0700892 hasPath = hasAlignedPath = hasComputedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700893 firstActiveSpan = -1;
894 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
895 var recType = test[tIndex];
896 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
897 console.log("unknown rec type: " + recType);
898 throw "stop execution";
899 }
900 var records = test[tIndex + 2];
901 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
902 var fragType = records[recordIndex];
903 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
904 console.log("unknown in range frag type: " + fragType);
905 throw "stop execution";
906 }
907 var frags = records[recordIndex + 1];
908 var first = 0;
909 var last = -1;
910 var first2 = 0;
911 var last2 = 0;
912 switch (recType) {
caryclark26ad22a2015-10-16 09:03:38 -0700913 case REC_TYPE_ALIGNED:
914 hasAlignedPath = true;
caryclarkdac1d172014-06-17 05:15:38 -0700915 case REC_TYPE_COMPUTED:
916 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
917 break;
918 }
caryclark26ad22a2015-10-16 09:03:38 -0700919 if (REC_TYPE_COMPUTED == recType) {
920 hasComputedPath = true;
921 }
caryclarkdac1d172014-06-17 05:15:38 -0700922 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700923 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700924 switch (fragType) {
925 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700926 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700927 break;
caryclark1049f122015-04-20 08:31:59 -0700928 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700929 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700930 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700931 break;
932 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700933 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700934 break;
935 default:
caryclark55888e42016-07-18 10:01:36 -0700936 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
caryclarkdac1d172014-06-17 05:15:38 -0700937 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
938 throw "stop execution";
939 }
940 if (recType == REC_TYPE_PATH) {
941 hasPath = true;
942 }
943 break;
caryclark54359292015-03-26 07:52:43 -0700944 case REC_TYPE_PATH2:
945 first = 1;
946 switch (fragType) {
947 case PATH_LINE:
948 last = 5;
949 break;
caryclark1049f122015-04-20 08:31:59 -0700950 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700951 case PATH_QUAD:
952 last = 7;
953 break;
954 case PATH_CUBIC:
955 last = 9;
956 break;
957 default:
caryclark55888e42016-07-18 10:01:36 -0700958 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
caryclark54359292015-03-26 07:52:43 -0700959 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
960 throw "stop execution";
961 }
962 if (recType == REC_TYPE_PATH2) {
963 hasPath = true;
964 }
965 break;
caryclarkdac1d172014-06-17 05:15:38 -0700966 case REC_TYPE_ACTIVE:
967 if (firstActiveSpan < 0) {
968 firstActiveSpan = tIndex;
969 }
970 first = 1;
971 switch (fragType) {
972 case ACTIVE_LINE_SPAN:
973 last = 5;
974 break;
caryclark1049f122015-04-20 08:31:59 -0700975 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -0700976 case ACTIVE_QUAD_SPAN:
977 last = 7;
978 break;
979 case ACTIVE_CUBIC_SPAN:
980 last = 9;
981 break;
982 default:
983 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
984 throw "stop execution";
985 }
986 break;
987 case REC_TYPE_ADD:
988 switch (fragType) {
989 case ADD_MOVETO:
990 break;
991 case ADD_LINETO:
992 last = 4;
993 break;
caryclark1049f122015-04-20 08:31:59 -0700994 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -0700995 case ADD_QUADTO:
996 last = 6;
997 break;
998 case ADD_CUBICTO:
999 last = 8;
1000 break;
1001 case ADD_CLOSE:
1002 case ADD_FILL:
1003 break;
1004 default:
1005 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
1006 throw "stop execution";
1007 }
1008 break;
caryclark54359292015-03-26 07:52:43 -07001009 case REC_TYPE_AFTERPART:
1010 switch (fragType) {
1011 case PATH_LINE:
1012 last = 4;
1013 break;
caryclark1049f122015-04-20 08:31:59 -07001014 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -07001015 case PATH_QUAD:
1016 last = 6;
1017 break;
1018 case PATH_CUBIC:
1019 last = 8;
1020 break;
1021 default:
1022 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
1023 throw "stop execution";
1024 }
1025 break;
caryclarkdac1d172014-06-17 05:15:38 -07001026 case REC_TYPE_SECT:
1027 switch (fragType) {
1028 case INTERSECT_LINE:
1029 first = 1; last = 5; first2 = 8; last2 = 12;
1030 break;
1031 case INTERSECT_LINE_2:
1032 first = 1; last = 5; first2 = 11; last2 = 15;
1033 break;
1034 case INTERSECT_LINE_NO:
1035 first = 0; last = 4; first2 = 4; last2 = 8;
1036 break;
caryclark1049f122015-04-20 08:31:59 -07001037 case INTERSECT_CONIC_LINE:
1038 first = 1; last = 7; first2 = 11; last2 = 15;
1039 break;
caryclarkdac1d172014-06-17 05:15:38 -07001040 case INTERSECT_QUAD_LINE:
1041 first = 1; last = 7; first2 = 10; last2 = 14;
1042 break;
caryclark1049f122015-04-20 08:31:59 -07001043 case INTERSECT_CONIC_LINE_2:
1044 first = 1; last = 7; first2 = 14; last2 = 18;
1045 break;
caryclarkdac1d172014-06-17 05:15:38 -07001046 case INTERSECT_QUAD_LINE_2:
1047 first = 1; last = 7; first2 = 13; last2 = 17;
1048 break;
caryclark1049f122015-04-20 08:31:59 -07001049 case INTERSECT_CONIC_LINE_NO:
1050 first = 0; last = 6; first2 = 7; last2 = 11;
1051 break;
caryclarkdac1d172014-06-17 05:15:38 -07001052 case INTERSECT_QUAD_LINE_NO:
1053 first = 0; last = 6; first2 = 6; last2 = 10;
1054 break;
caryclark1049f122015-04-20 08:31:59 -07001055 case INTERSECT_CONIC:
1056 first = 1; last = 7; first2 = 11; last2 = 17;
1057 break;
caryclarkdac1d172014-06-17 05:15:38 -07001058 case INTERSECT_QUAD:
1059 first = 1; last = 7; first2 = 10; last2 = 16;
1060 break;
caryclark1049f122015-04-20 08:31:59 -07001061 case INTERSECT_CONIC_2:
1062 first = 1; last = 7; first2 = 14; last2 = 20;
1063 break;
caryclarkdac1d172014-06-17 05:15:38 -07001064 case INTERSECT_QUAD_2:
1065 first = 1; last = 7; first2 = 13; last2 = 19;
1066 break;
caryclark1049f122015-04-20 08:31:59 -07001067 case INTERSECT_CONIC_NO:
1068 first = 0; last = 6; first2 = 7; last2 = 13;
1069 break;
caryclarkdac1d172014-06-17 05:15:38 -07001070 case INTERSECT_QUAD_NO:
1071 first = 0; last = 6; first2 = 6; last2 = 12;
1072 break;
1073 case INTERSECT_SELF_CUBIC:
1074 first = 1; last = 9;
1075 break;
1076 case INTERSECT_SELF_CUBIC_NO:
1077 first = 0; last = 8;
1078 break;
1079 case INTERSECT_CUBIC_LINE:
1080 first = 1; last = 9; first2 = 12; last2 = 16;
1081 break;
1082 case INTERSECT_CUBIC_LINE_2:
1083 first = 1; last = 9; first2 = 15; last2 = 19;
1084 break;
1085 case INTERSECT_CUBIC_LINE_3:
1086 first = 1; last = 9; first2 = 18; last2 = 22;
1087 break;
1088 case INTERSECT_CUBIC_LINE_NO:
1089 first = 0; last = 8; first2 = 8; last2 = 12;
1090 break;
caryclark55888e42016-07-18 10:01:36 -07001091 case INTERSECT_CONIC_QUAD:
1092 first = 1; last = 7; first2 = 11; last2 = 17;
1093 break;
1094 case INTERSECT_CONIC_QUAD_2:
1095 first = 1; last = 7; first2 = 14; last2 = 20;
1096 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07001097 case INTERSECT_CONIC_QUAD_3:
1098 first = 1; last = 7; first2 = 17; last2 = 23;
1099 break;
1100 case INTERSECT_CONIC_QUAD_4:
1101 first = 1; last = 7; first2 = 20; last2 = 26;
1102 break;
caryclark55888e42016-07-18 10:01:36 -07001103 case INTERSECT_CONIC_QUAD_NO:
1104 first = 0; last = 6; first2 = 7; last2 = 13;
1105 break;
caryclarkdac1d172014-06-17 05:15:38 -07001106 case INTERSECT_CUBIC_QUAD:
1107 first = 1; last = 9; first2 = 12; last2 = 18;
1108 break;
1109 case INTERSECT_CUBIC_QUAD_2:
1110 first = 1; last = 9; first2 = 15; last2 = 21;
1111 break;
1112 case INTERSECT_CUBIC_QUAD_3:
1113 first = 1; last = 9; first2 = 18; last2 = 24;
1114 break;
1115 case INTERSECT_CUBIC_QUAD_4:
1116 first = 1; last = 9; first2 = 21; last2 = 27;
1117 break;
1118 case INTERSECT_CUBIC_QUAD_NO:
1119 first = 0; last = 8; first2 = 8; last2 = 14;
1120 break;
1121 case INTERSECT_CUBIC:
1122 first = 1; last = 9; first2 = 12; last2 = 20;
1123 break;
1124 case INTERSECT_CUBIC_2:
1125 first = 1; last = 9; first2 = 15; last2 = 23;
1126 break;
1127 case INTERSECT_CUBIC_3:
1128 first = 1; last = 9; first2 = 18; last2 = 26;
1129 break;
1130 case INTERSECT_CUBIC_4:
1131 first = 1; last = 9; first2 = 21; last2 = 29;
1132 break;
1133 case INTERSECT_CUBIC_NO:
1134 first = 0; last = 8; first2 = 8; last2 = 16;
1135 break;
1136 default:
1137 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1138 throw "stop execution";
1139 }
1140 break;
1141 default:
1142 continue;
1143 }
1144 for (var idx = first; idx < last; idx += 2) {
1145 xmin = Math.min(xmin, frags[idx]);
1146 xmax = Math.max(xmax, frags[idx]);
1147 ymin = Math.min(ymin, frags[idx + 1]);
1148 ymax = Math.max(ymax, frags[idx + 1]);
1149 }
1150 for (var idx = first2; idx < last2; idx += 2) {
1151 xmin = Math.min(xmin, frags[idx]);
1152 xmax = Math.max(xmax, frags[idx]);
1153 ymin = Math.min(ymin, frags[idx + 1]);
1154 ymax = Math.max(ymax, frags[idx + 1]);
1155 }
1156 }
1157 }
1158 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1159 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1160 var recType = test[tIndex];
1161 var records = test[tIndex + 2];
1162 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1163 var fragType = records[recordIndex];
1164 var frags = records[recordIndex + 1];
1165 switch (recType) {
1166 case REC_TYPE_ACTIVE_OP:
1167 if (!draw_op) {
1168 break;
1169 }
1170 {
1171 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1172 curve_extremes(curve, angleBounds);
1173 }
1174 break;
1175 case REC_TYPE_ANGLE:
1176 if (!draw_angle) {
1177 break;
1178 }
caryclark54359292015-03-26 07:52:43 -07001179 {
caryclarkdac1d172014-06-17 05:15:38 -07001180 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1181 curve_extremes(curve, angleBounds);
1182 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1183 curve_extremes(curve, angleBounds);
1184 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1185 }
1186 break;
caryclark624637c2015-05-11 07:21:27 -07001187 case REC_TYPE_COINCIDENCE:
1188 if (!draw_coincidence) {
1189 break;
1190 }
1191 {
1192 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1193 curve_extremes(curve, angleBounds);
1194 }
1195 break;
caryclarkdac1d172014-06-17 05:15:38 -07001196 case REC_TYPE_SORT:
1197 if (!draw_sort) {
1198 break;
1199 }
1200 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1201 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1202 curve_extremes(curve, angleBounds);
1203 }
1204 break;
caryclark03b03ca2015-04-23 09:13:37 -07001205 case REC_TYPE_TOP:
1206 if (!draw_top) {
1207 break;
1208 }
1209 {
1210 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1211 curve_extremes(curve, angleBounds);
1212 }
1213 break;
caryclarkdac1d172014-06-17 05:15:38 -07001214 }
1215 }
1216 }
1217 xmin = Math.min(xmin, angleBounds[0]);
1218 ymin = Math.min(ymin, angleBounds[1]);
1219 xmax = Math.max(xmax, angleBounds[2]);
1220 ymax = Math.max(ymax, angleBounds[3]);
1221 setScale(xmin, xmax, ymin, ymax);
1222 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001223 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001224 }
1225 if (hasPath == true && hasComputedPath == false && draw_computed) {
1226 draw_computed = 0;
1227 }
1228}
1229
caryclark26ad22a2015-10-16 09:03:38 -07001230function curveByIDMatch(test, id, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001231 var tIndex = -3;
1232 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001233 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001234 if (recType == REC_TYPE_OP) {
1235 continue;
1236 }
caryclark26ad22a2015-10-16 09:03:38 -07001237 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001238 return [];
1239 }
1240 var records = test[tIndex + 2];
1241 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1242 var fragType = records[recordIndex];
1243 var frags = records[recordIndex + 1];
1244 if (frags[0] == id) {
1245 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001246 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001247 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001248 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001249 return [frags[1], frags[2], frags[3], frags[4],
1250 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001251 case PATH_CONIC:
1252 return [frags[1], frags[2], frags[3], frags[4],
1253 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001254 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001255 return [frags[1], frags[2], frags[3], frags[4],
1256 frags[5], frags[6], frags[7], frags[8]];
1257 }
1258 }
1259 }
caryclarkdac1d172014-06-17 05:15:38 -07001260 }
1261 return [];
1262}
1263
caryclark26ad22a2015-10-16 09:03:38 -07001264function curveByID(test, id) {
1265 var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : [];
1266 if (!result.length) {
1267 result = curveByIDMatch(test, id, REC_TYPE_PATH);
1268 }
1269 return result;
1270}
1271
1272function curvePartialByIDMatch(test, id, t0, t1, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001273 var tIndex = -3;
1274 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001275 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001276 if (recType == REC_TYPE_OP) {
1277 continue;
1278 }
caryclark26ad22a2015-10-16 09:03:38 -07001279 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001280 return [];
1281 }
1282 var records = test[tIndex + 2];
1283 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1284 var fragType = records[recordIndex];
1285 var frags = records[recordIndex + 1];
1286 if (frags[0] == id) {
1287 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001288 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001289 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001290 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001291 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1292 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001293 case PATH_CONIC:
1294 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1295 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001296 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001297 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1298 frags[5], frags[6], frags[7], frags[8], t0, t1);
1299 }
1300 }
1301 }
caryclarkdac1d172014-06-17 05:15:38 -07001302 }
1303 return [];
1304}
1305
caryclark26ad22a2015-10-16 09:03:38 -07001306function curvePartialByID(test, id, t0, t1) {
1307 var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : [];
1308 if (!result.length) {
1309 result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH);
1310 }
1311 return result;
1312}
1313
1314function idByCurveIDMatch(test, frag, type, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001315 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001316 while (tIndex < test.length) {
1317 var recType = test[tIndex];
caryclark26ad22a2015-10-16 09:03:38 -07001318 if (recType != recMatch) {
caryclark54359292015-03-26 07:52:43 -07001319 ++tIndex;
1320 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001321 }
1322 var records = test[tIndex + 2];
1323 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1324 var fragType = records[recordIndex];
1325 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001326 if (frag.length != frags.length - 1) {
1327 continue;
1328 }
caryclarkdac1d172014-06-17 05:15:38 -07001329 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001330 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001331 if (frag[0] != frags[1] || frag[1] != frags[2]
1332 || frag[2] != frags[3] || frag[3] != frags[4]) {
1333 continue;
1334 }
1335 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001336 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001337 if (frag[0] != frags[1] || frag[1] != frags[2]
1338 || frag[2] != frags[3] || frag[3] != frags[4]
1339 || frag[4] != frags[5] || frag[5] != frags[6]) {
1340 continue;
1341 }
1342 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001343 case PATH_CONIC:
1344 if (frag[0] != frags[1] || frag[1] != frags[2]
1345 || frag[2] != frags[3] || frag[3] != frags[4]
1346 || frag[4] != frags[5] || frag[5] != frags[6]
1347 || frag[6] != frags[7]) {
1348 continue;
1349 }
1350 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001351 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001352 if (frag[0] != frags[1] || frag[1] != frags[2]
1353 || frag[2] != frags[3] || frag[3] != frags[4]
1354 || frag[4] != frags[5] || frag[5] != frags[6]
1355 || frag[6] != frags[7] || frag[7] != frags[8]) {
1356 continue;
1357 }
1358 return frags[0];
1359 }
1360 }
1361 ++tIndex;
1362 }
1363 return -1;
1364}
1365
caryclark26ad22a2015-10-16 09:03:38 -07001366function idByCurve(test, frag, type) {
1367 var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : [];
1368 if (!result.length) {
1369 result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH);
1370 }
1371 return result;
1372}
1373
caryclarkdac1d172014-06-17 05:15:38 -07001374function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001375 var length = curve.length == 7 ? 6 : curve.length;
caryclarked0935a2015-10-22 07:23:52 -07001376 for (var index = 0; index < length; index += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001377 var x = curve[index];
1378 var y = curve[index + 1];
1379 bounds[0] = Math.min(bounds[0], x);
1380 bounds[1] = Math.min(bounds[1], y);
1381 bounds[2] = Math.max(bounds[2], x);
1382 bounds[3] = Math.max(bounds[3], y);
1383 }
1384}
1385
1386function setScale(x0, x1, y0, y1) {
1387 var srcWidth = x1 - x0;
1388 var srcHeight = y1 - y0;
1389 var usableWidth = screenWidth;
1390 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1391 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1392 usableWidth -= (xDigits + yDigits) * 10;
1393 usableWidth -= decimal_places * 10;
1394 if (draw_legend) {
1395 usableWidth -= 40;
1396 }
1397 var hscale = usableWidth / srcWidth;
1398 var vscale = screenHeight / srcHeight;
1399 scale = Math.min(hscale, vscale);
1400 var invScale = 1 / scale;
1401 var sxmin = x0 - invScale * 5;
1402 var symin = y0 - invScale * 10;
1403 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1404 var symax = y1 + invScale * 10;
1405 srcWidth = sxmax - sxmin;
1406 srcHeight = symax - symin;
1407 hscale = usableWidth / srcWidth;
1408 vscale = screenHeight / srcHeight;
1409 scale = Math.min(hscale, vscale);
1410 srcLeft = sxmin;
1411 srcTop = symin;
1412}
1413
1414function drawArc(curve, op, from, to) {
1415 var type = PATH_LINE + (curve.length / 2 - 2);
1416 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1417 var dy = pt.y - curve[1];
1418 var dx = pt.x - curve[0];
1419 var dist = Math.sqrt(dy * dy + dx * dx);
1420 var _dist = dist * scale;
1421 var angle = Math.atan2(dy, dx);
1422 var _px = (curve[0] - srcLeft) * scale;
1423 var _py = (curve[1] - srcTop) * scale;
1424 var divisor = 4;
1425 var endDist;
1426 do {
1427 var ends = [];
1428 for (var index = -1; index <= 1; index += 2) {
1429 var px = Math.cos(index * Math.PI / divisor);
1430 var py = Math.sin(index * Math.PI / divisor);
1431 ends.push(px);
1432 ends.push(py);
1433 }
1434 var endDx = (ends[2] - ends[0]) * scale * dist;
1435 var endDy = (ends[3] - ends[1]) * scale * dist;
1436 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1437 if (endDist < 100) {
1438 break;
1439 }
1440 divisor *= 2;
1441 } while (true);
1442 if (endDist < 30) {
1443 return;
1444 }
1445 if (op) {
1446 divisor *= 2;
1447 }
1448 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1449 ctx.beginPath();
1450 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1451 ctx.stroke();
1452 var saveAlign = ctx.textAlign;
1453 var saveStyle = ctx.fillStyle;
1454 var saveFont = ctx.font;
1455 ctx.textAlign = "center";
1456 ctx.fillStyle = "black";
1457 ctx.font = "normal 24px Arial";
1458 divisor *= 0.8;
1459 for (var index = -1; index <= 1; index += 2) {
1460 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1461 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1462 var _px = (px - srcLeft) * scale;
1463 var _py = (py - srcTop) * scale;
1464 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1465 }
1466 ctx.textAlign = saveAlign;
1467 ctx.fillStyle = saveStyle;
1468 ctx.font = saveFont;
1469}
1470
1471function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001472 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1473 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001474 var x = drawnPts[pts];
1475 var y = drawnPts[pts + 1];
1476 if (px == x && py == y) {
1477 return;
1478 }
1479 }
1480 drawnPts.push(px);
1481 drawnPts.push(py);
1482 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1483 var _px = (px - srcLeft) * scale;
1484 var _py = (py - srcTop) * scale;
1485 ctx.beginPath();
1486 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1487 ctx.closePath();
1488 if (end) {
1489 ctx.fill();
1490 } else {
1491 ctx.stroke();
1492 }
1493 if (debug_xy) {
1494 ctx.textAlign = "left";
1495 ctx.fillText(label, _px + 5, _py);
1496 }
1497}
1498
caryclark1049f122015-04-20 08:31:59 -07001499function coordCount(curveType) {
1500 switch (curveType) {
1501 case PATH_LINE:
1502 return 4;
1503 case PATH_QUAD:
1504 return 6;
1505 case PATH_CONIC:
1506 return 6;
1507 case PATH_CUBIC:
1508 return 8;
1509 }
1510 return -1;
1511}
1512
caryclarkdac1d172014-06-17 05:15:38 -07001513function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001514 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001515 for (var idx = 0; idx < count; idx += 2) {
1516 if (!drawControls && idx != 0 && idx != count - 2) {
1517 continue;
1518 }
1519 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1520 }
1521}
1522
1523function drawControlLines(curve, curveType, drawEnd) {
1524 if (curveType == PATH_LINE) {
1525 return;
1526 }
1527 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1528 drawLine(curve[0], curve[1], curve[2], curve[3]);
1529 drawLine(curve[2], curve[3], curve[4], curve[5]);
1530 if (curveType == PATH_CUBIC) {
1531 drawLine(curve[4], curve[5], curve[6], curve[7]);
1532 if (drawEnd > 1) {
1533 drawLine(curve[6], curve[7], curve[0], curve[1]);
1534 if (drawEnd > 2) {
1535 drawLine(curve[0], curve[1], curve[4], curve[5]);
1536 drawLine(curve[6], curve[7], curve[2], curve[3]);
1537 }
1538 }
1539 } else if (drawEnd > 1) {
1540 drawLine(curve[4], curve[5], curve[0], curve[1]);
1541 }
1542}
1543
1544function pointAtT(curve, curveType, t) {
1545 var xy = {};
1546 switch (curveType) {
1547 case PATH_LINE:
1548 var a = 1 - t;
1549 var b = t;
1550 xy.x = a * curve[0] + b * curve[2];
1551 xy.y = a * curve[1] + b * curve[3];
1552 break;
1553 case PATH_QUAD:
1554 var one_t = 1 - t;
1555 var a = one_t * one_t;
1556 var b = 2 * one_t * t;
1557 var c = t * t;
1558 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1559 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1560 break;
caryclark1049f122015-04-20 08:31:59 -07001561 case PATH_CONIC:
1562 var one_t = 1 - t;
1563 var a = one_t * one_t;
1564 var b = 2 * one_t * t;
1565 var c = t * t;
1566 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1567 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1568 var d = a + b * curve[6] + c;
1569 xy.x /= d;
1570 xy.y /= d;
1571 break;
caryclarkdac1d172014-06-17 05:15:38 -07001572 case PATH_CUBIC:
1573 var one_t = 1 - t;
1574 var one_t2 = one_t * one_t;
1575 var a = one_t2 * one_t;
1576 var b = 3 * one_t2 * t;
1577 var t2 = t * t;
1578 var c = 3 * one_t * t2;
1579 var d = t2 * t;
1580 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1581 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1582 break;
1583 }
1584 return xy;
1585}
caryclark55888e42016-07-18 10:01:36 -07001586
caryclarkdac1d172014-06-17 05:15:38 -07001587function drawPointAtT(curve, curveType) {
1588 var x, y;
1589 var xy = pointAtT(curve, curveType, curveT);
1590 drawPoint(xy.x, xy.y, true);
1591 if (!draw_intersectT) {
1592 return;
1593 }
1594 ctx.fillStyle = "red";
1595 drawTAtPointUp(xy.x, xy.y, curveT);
1596}
1597
1598function drawTAtPointUp(px, py, t) {
1599 var label = t.toFixed(decimal_places);
1600 var _px = (px - srcLeft)* scale;
1601 var _py = (py - srcTop) * scale;
1602 ctx.fillText(label, _px + 5, _py - 10);
1603}
1604
1605function drawTAtPointDown(px, py, t) {
1606 var label = t.toFixed(decimal_places);
1607 var _px = (px - srcLeft)* scale;
1608 var _py = (py - srcTop) * scale;
1609 ctx.fillText(label, _px + 5, _py + 10);
1610}
1611
1612function alreadyDrawnLine(x1, y1, x2, y2) {
1613 if (collect_bounds) {
1614 if (focus_enabled) {
1615 focusXmin = Math.min(focusXmin, x1, x2);
1616 focusYmin = Math.min(focusYmin, y1, y2);
1617 focusXmax = Math.max(focusXmax, x1, x2);
1618 focusYmax = Math.max(focusYmax, y1, y2);
1619 }
1620 return true;
1621 }
1622 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1623 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1624 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1625 return true;
1626 }
1627 }
1628 drawnLines.push(x1);
1629 drawnLines.push(y1);
1630 drawnLines.push(x2);
1631 drawnLines.push(y2);
1632 return false;
1633}
1634
1635function drawLine(x1, y1, x2, y2) {
1636 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1637 return;
1638 }
1639 ctx.beginPath();
1640 ctx.moveTo((x1 - srcLeft) * scale,
1641 (y1 - srcTop) * scale);
1642 ctx.lineTo((x2 - srcLeft) * scale,
1643 (y2 - srcTop) * scale);
1644 ctx.stroke();
1645}
1646
1647function linePartial(x1, y1, x2, y2, t1, t2) {
1648 var dx = x1 - x2;
1649 var dy = y1 - y2;
1650 var array = [
1651 x1 - t1 * dx,
1652 y1 - t1 * dy,
1653 x1 - t2 * dx,
1654 y1 - t2 * dy
1655 ];
1656 return array;
1657}
1658
1659function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1660 var a = linePartial(x1, y1, x2, y2, t1, t2);
1661 var ax = a[0];
1662 var ay = a[1];
1663 var bx = a[2];
1664 var by = a[3];
1665 if (alreadyDrawnLine(ax, ay, bx, by)) {
1666 return;
1667 }
1668 ctx.beginPath();
1669 ctx.moveTo((ax - srcLeft) * scale,
1670 (ay - srcTop) * scale);
1671 ctx.lineTo((bx - srcLeft) * scale,
1672 (by - srcTop) * scale);
1673 ctx.stroke();
1674}
1675
1676function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1677 if (collect_bounds) {
1678 if (focus_enabled) {
1679 focusXmin = Math.min(focusXmin, x1, x2, x3);
1680 focusYmin = Math.min(focusYmin, y1, y2, y3);
1681 focusXmax = Math.max(focusXmax, x1, x2, x3);
1682 focusYmax = Math.max(focusYmax, y1, y2, y3);
1683 }
1684 return true;
1685 }
1686 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1687 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1688 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1689 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1690 return true;
1691 }
1692 }
1693 drawnQuads.push(x1);
1694 drawnQuads.push(y1);
1695 drawnQuads.push(x2);
1696 drawnQuads.push(y2);
1697 drawnQuads.push(x3);
1698 drawnQuads.push(y3);
1699 return false;
1700}
1701
1702function drawQuad(x1, y1, x2, y2, x3, y3) {
1703 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1704 return;
1705 }
1706 ctx.beginPath();
1707 ctx.moveTo((x1 - srcLeft) * scale,
1708 (y1 - srcTop) * scale);
1709 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1710 (y2 - srcTop) * scale,
1711 (x3 - srcLeft) * scale,
1712 (y3 - srcTop) * scale);
1713 ctx.stroke();
1714}
1715
1716function interp(A, B, t) {
1717 return A + (B - A) * t;
1718}
1719
1720function interp_quad_coords(x1, x2, x3, t)
1721{
1722 var ab = interp(x1, x2, t);
1723 var bc = interp(x2, x3, t);
1724 var abc = interp(ab, bc, t);
1725 return abc;
1726}
1727
1728function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1729 var ax = interp_quad_coords(x1, x2, x3, t1);
1730 var ay = interp_quad_coords(y1, y2, y3, t1);
1731 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1732 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1733 var cx = interp_quad_coords(x1, x2, x3, t2);
1734 var cy = interp_quad_coords(y1, y2, y3, t2);
1735 var bx = 2*dx - (ax + cx)/2;
1736 var by = 2*dy - (ay + cy)/2;
1737 var array = [
1738 ax, ay, bx, by, cx, cy
1739 ];
1740 return array;
1741}
1742
1743function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1744 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1745 var ax = a[0];
1746 var ay = a[1];
1747 var bx = a[2];
1748 var by = a[3];
1749 var cx = a[4];
1750 var cy = a[5];
1751 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1752 return;
1753 }
1754 ctx.beginPath();
1755 ctx.moveTo((ax - srcLeft) * scale,
1756 (ay - srcTop) * scale);
1757 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1758 (by - srcTop) * scale,
1759 (cx - srcLeft) * scale,
1760 (cy - srcTop) * scale);
1761 ctx.stroke();
1762}
1763
caryclark1049f122015-04-20 08:31:59 -07001764function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1765 if (collect_bounds) {
1766 if (focus_enabled) {
1767 focusXmin = Math.min(focusXmin, x1, x2, x3);
1768 focusYmin = Math.min(focusYmin, y1, y2, y3);
1769 focusXmax = Math.max(focusXmax, x1, x2, x3);
1770 focusYmax = Math.max(focusYmax, y1, y2, y3);
1771 }
1772 return true;
1773 }
1774 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1775 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001776 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1777 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclark1049f122015-04-20 08:31:59 -07001778 && w == drawnCubics[pts + 6]) {
1779 return true;
1780 }
1781 }
1782 drawnConics.push(x1);
1783 drawnConics.push(y1);
1784 drawnConics.push(x2);
1785 drawnConics.push(y2);
1786 drawnConics.push(x3);
1787 drawnConics.push(y3);
1788 drawnCubics.push(w);
1789 return false;
1790}
1791
1792var kMaxConicToQuadPOW2 = 5;
1793
1794function computeQuadPOW2(curve, tol) {
1795 var a = curve[6] - 1;
1796 var k = a / (4 * (2 + a));
1797 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1798 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1799
1800 var error = Math.sqrt(x * x + y * y);
1801 var pow2;
1802 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1803 if (error <= tol) {
1804 break;
1805 }
1806 error *= 0.25;
1807 }
1808 return pow2;
1809}
1810
1811function subdivide_w_value(w) {
1812 return Math.sqrt(0.5 + w * 0.5);
1813}
1814
1815function chop(curve, part1, part2) {
1816 var w = curve[6];
1817 var scale = 1 / (1 + w);
1818 part1[0] = curve[0];
1819 part1[1] = curve[1];
1820 part1[2] = (curve[0] + curve[2] * w) * scale;
1821 part1[3] = (curve[1] + curve[3] * w) * scale;
1822 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1823 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1824 part2[2] = (curve[2] * w + curve[4]) * scale;
1825 part2[3] = (curve[3] * w + curve[5]) * scale;
1826 part2[4] = curve[4];
1827 part2[5] = curve[5];
1828 part1[6] = part2[6] = subdivide_w_value(w);
1829}
1830
1831function subdivide(curve, level, pts) {
1832 if (0 == level) {
1833 pts.push(curve[2]);
1834 pts.push(curve[3]);
1835 pts.push(curve[4]);
1836 pts.push(curve[5]);
1837 } else {
1838 var part1 = [], part2 = [];
1839 chop(curve, part1, part2);
1840 --level;
1841 subdivide(part1, level, pts);
1842 subdivide(part2, level, pts);
1843 }
1844}
1845
1846function chopIntoQuadsPOW2(curve, pow2, pts) {
1847 subdivide(curve, pow2, pts);
1848 return 1 << pow2;
1849}
1850
1851function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1852 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1853 return;
1854 }
1855 ctx.beginPath();
1856 ctx.moveTo((x1 - srcLeft) * scale,
1857 (y1 - srcTop) * scale);
1858 var tol = 1 / scale;
1859 var curve = [x1, y1, x2, y2, x3, y3, w];
1860 var pow2 = computeQuadPOW2(curve, tol);
1861 var pts = [];
1862 chopIntoQuadsPOW2(curve, pow2, pts);
1863 for (var i = 0; i < pts.length; i += 4) {
1864 ctx.quadraticCurveTo(
1865 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1866 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1867 }
1868 ctx.stroke();
1869}
1870
1871function conic_eval_numerator(x1, x2, x3, w, t) {
1872 var src2w = x2 * w;
1873 var C = x1;
1874 var A = x3 - 2 * src2w + C;
1875 var B = 2 * (src2w - C);
1876 return (A * t + B) * t + C;
1877}
1878
1879
1880function conic_eval_denominator(w, t) {
1881 var B = 2 * (w - 1);
1882 var C = 1;
1883 var A = -B;
1884 return (A * t + B) * t + C;
1885}
1886
1887function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1888 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1889 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1890 var az = conic_eval_denominator(w, t1);
1891 var midT = (t1 + t2) / 2;
1892 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1893 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1894 var dz = conic_eval_denominator(w, midT);
1895 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1896 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1897 var cz = conic_eval_denominator(w, t2);
1898 var bx = 2 * dx - (ax + cx) / 2;
1899 var by = 2 * dy - (ay + cy) / 2;
1900 var bz = 2 * dz - (az + cz) / 2;
1901 var dt = t2 - t1;
1902 var dt_1 = 1 - dt;
caryclark1049f122015-04-20 08:31:59 -07001903 var array = [
caryclarked0935a2015-10-22 07:23:52 -07001904 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
caryclark1049f122015-04-20 08:31:59 -07001905 ];
caryclarked0935a2015-10-22 07:23:52 -07001906 var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 };
1907 var dMid = { x:dx / dz, y:dy / dz };
1908 var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y };
1909 var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] };
1910 var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y)
1911 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y);
1912 array[6] = partW;
caryclark1049f122015-04-20 08:31:59 -07001913 return array;
1914}
caryclark55888e42016-07-18 10:01:36 -07001915
caryclark1049f122015-04-20 08:31:59 -07001916function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1917 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1918 var ax = a[0];
1919 var ay = a[1];
1920 var bx = a[2];
1921 var by = a[3];
1922 var cx = a[4];
1923 var cy = a[5];
1924 var w_ = a[6];
1925 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1926}
1927
caryclarkdac1d172014-06-17 05:15:38 -07001928function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1929 if (collect_bounds) {
1930 if (focus_enabled) {
1931 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1932 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1933 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1934 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1935 }
1936 return true;
1937 }
1938 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1939 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001940 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1941 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclarkdac1d172014-06-17 05:15:38 -07001942 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1943 return true;
1944 }
1945 }
1946 drawnCubics.push(x1);
1947 drawnCubics.push(y1);
1948 drawnCubics.push(x2);
1949 drawnCubics.push(y2);
1950 drawnCubics.push(x3);
1951 drawnCubics.push(y3);
1952 drawnCubics.push(x4);
1953 drawnCubics.push(y4);
1954 return false;
1955}
1956
1957function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1958 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1959 return;
1960 }
1961 ctx.beginPath();
1962 ctx.moveTo((x1 - srcLeft) * scale,
1963 (y1 - srcTop) * scale);
1964 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1965 (y2 - srcTop) * scale,
1966 (x3 - srcLeft) * scale,
1967 (y3 - srcTop) * scale,
1968 (x4 - srcLeft) * scale,
1969 (y4 - srcTop) * scale);
1970 ctx.stroke();
1971}
1972
1973function interp_cubic_coords(x1, x2, x3, x4, t)
1974{
1975 var ab = interp(x1, x2, t);
1976 var bc = interp(x2, x3, t);
1977 var cd = interp(x3, x4, t);
1978 var abc = interp(ab, bc, t);
1979 var bcd = interp(bc, cd, t);
1980 var abcd = interp(abc, bcd, t);
1981 return abcd;
1982}
1983
1984function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1985 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1986 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1987 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1988 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1989 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1990 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1991 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1992 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1993 var mx = ex * 27 - ax * 8 - dx;
1994 var my = ey * 27 - ay * 8 - dy;
1995 var nx = fx * 27 - ax - dx * 8;
1996 var ny = fy * 27 - ay - dy * 8;
1997 var bx = (mx * 2 - nx) / 18;
1998 var by = (my * 2 - ny) / 18;
1999 var cx = (nx * 2 - mx) / 18;
2000 var cy = (ny * 2 - my) / 18;
2001 var array = [
2002 ax, ay, bx, by, cx, cy, dx, dy
2003 ];
2004 return array;
2005}
caryclark55888e42016-07-18 10:01:36 -07002006
caryclarkdac1d172014-06-17 05:15:38 -07002007function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2008 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2009 var ax = a[0];
2010 var ay = a[1];
2011 var bx = a[2];
2012 var by = a[3];
2013 var cx = a[4];
2014 var cy = a[5];
2015 var dx = a[6];
2016 var dy = a[7];
2017 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
2018 return;
2019 }
2020 ctx.beginPath();
2021 ctx.moveTo((ax - srcLeft) * scale,
2022 (ay - srcTop) * scale);
2023 ctx.bezierCurveTo((bx - srcLeft) * scale,
2024 (by - srcTop) * scale,
2025 (cx - srcLeft) * scale,
2026 (cy - srcTop) * scale,
2027 (dx - srcLeft) * scale,
2028 (dy - srcTop) * scale);
2029 ctx.stroke();
2030}
2031
2032function drawCurve(c) {
2033 switch (c.length) {
2034 case 4:
2035 drawLine(c[0], c[1], c[2], c[3]);
2036 break;
2037 case 6:
2038 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
2039 break;
caryclark1049f122015-04-20 08:31:59 -07002040 case 7:
2041 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
2042 break;
caryclarkdac1d172014-06-17 05:15:38 -07002043 case 8:
2044 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
2045 break;
2046 }
2047}
2048
2049function boundsWidth(pts) {
2050 var min = pts[0];
2051 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07002052 var length = pts.length == 7 ? 6 : pts.length;
2053 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002054 min = Math.min(min, pts[idx]);
2055 max = Math.max(max, pts[idx]);
2056 }
2057 return max - min;
2058}
2059
2060function boundsHeight(pts) {
2061 var min = pts[1];
2062 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07002063 var length = pts.length == 7 ? 6 : pts.length;
2064 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002065 min = Math.min(min, pts[idx]);
2066 max = Math.max(max, pts[idx]);
2067 }
2068 return max - min;
2069}
2070
2071function tangent(pts) {
2072 var dx = pts[2] - pts[0];
2073 var dy = pts[3] - pts[1];
2074 if (dx == 0 && dy == 0 && pts.length > 4) {
2075 dx = pts[4] - pts[0];
2076 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07002077 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002078 dx = pts[6] - pts[0];
2079 dy = pts[7] - pts[1];
2080 }
2081 }
2082 return Math.atan2(-dy, dx);
2083}
2084
2085function hodograph(cubic) {
2086 var hodo = [];
2087 hodo[0] = 3 * (cubic[2] - cubic[0]);
2088 hodo[1] = 3 * (cubic[3] - cubic[1]);
2089 hodo[2] = 3 * (cubic[4] - cubic[2]);
2090 hodo[3] = 3 * (cubic[5] - cubic[3]);
2091 hodo[4] = 3 * (cubic[6] - cubic[4]);
2092 hodo[5] = 3 * (cubic[7] - cubic[5]);
2093 return hodo;
2094}
2095
2096function hodograph2(cubic) {
2097 var quad = hodograph(cubic);
2098 var hodo = [];
2099 hodo[0] = 2 * (quad[2] - quad[0]);
2100 hodo[1] = 2 * (quad[3] - quad[1]);
2101 hodo[2] = 2 * (quad[4] - quad[2]);
2102 hodo[3] = 2 * (quad[5] - quad[3]);
2103 return hodo;
2104}
2105
2106function quadraticRootsReal(A, B, C, s) {
2107 if (A == 0) {
2108 if (B == 0) {
2109 s[0] = 0;
2110 return C == 0;
2111 }
2112 s[0] = -C / B;
2113 return 1;
2114 }
2115 /* normal form: x^2 + px + q = 0 */
2116 var p = B / (2 * A);
2117 var q = C / A;
2118 var p2 = p * p;
2119 if (p2 < q) {
2120 return 0;
2121 }
2122 var sqrt_D = 0;
2123 if (p2 > q) {
2124 sqrt_D = sqrt(p2 - q);
2125 }
2126 s[0] = sqrt_D - p;
2127 s[1] = -sqrt_D - p;
2128 return 1 + s[0] != s[1];
2129}
2130
2131function add_valid_ts(s, realRoots, t) {
2132 var foundRoots = 0;
2133 for (var index = 0; index < realRoots; ++index) {
2134 var tValue = s[index];
2135 if (tValue >= 0 && tValue <= 1) {
2136 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2137 if (t[idx2] != tValue) {
2138 t[foundRoots++] = tValue;
2139 }
2140 }
2141 }
2142 }
2143 return foundRoots;
2144}
2145
2146function quadraticRootsValidT(a, b, c, t) {
2147 var s = [];
2148 var realRoots = quadraticRootsReal(A, B, C, s);
2149 var foundRoots = add_valid_ts(s, realRoots, t);
2150 return foundRoots != 0;
2151}
2152
2153function find_cubic_inflections(cubic, tValues) {
2154 var Ax = src[2] - src[0];
2155 var Ay = src[3] - src[1];
2156 var Bx = src[4] - 2 * src[2] + src[0];
2157 var By = src[5] - 2 * src[3] + src[1];
2158 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2159 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2160 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2161 Ax * By - Ay * Bx, tValues);
2162}
2163
2164function dxy_at_t(curve, type, t) {
2165 var dxy = {};
Cary Clarkff114282016-12-14 11:56:16 -05002166 if (type == PATH_LINE) {
2167 dxy.x = curve[2] - curve[0];
2168 dxy.y = curve[3] - curve[1];
2169 } else if (type == PATH_QUAD) {
caryclarkdac1d172014-06-17 05:15:38 -07002170 var a = t - 1;
2171 var b = 1 - 2 * t;
2172 var c = t;
2173 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2174 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002175 } else if (type == PATH_CONIC) {
2176 var p20x = curve[4] - curve[0];
2177 var p20y = curve[5] - curve[1];
2178 var p10xw = (curve[2] - curve[0]) * curve[6];
2179 var p10yw = (curve[3] - curve[1]) * curve[6];
2180 var coeff0x = curve[6] * p20x - p20x;
2181 var coeff0y = curve[6] * p20y - p20y;
2182 var coeff1x = p20x - 2 * p10xw;
2183 var coeff1y = p20y - 2 * p10yw;
2184 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2185 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002186 } else if (type == PATH_CUBIC) {
2187 var one_t = 1 - t;
2188 var a = curve[0];
2189 var b = curve[2];
2190 var c = curve[4];
2191 var d = curve[6];
2192 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2193 a = curve[1];
2194 b = curve[3];
2195 c = curve[5];
2196 d = curve[7];
2197 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2198 }
2199 return dxy;
2200}
2201
Ben Wagner29380bd2017-10-09 14:43:00 -04002202function dpt_at_t(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002203 var type = PATH_LINE + (curve.length / 2 - 2);
Ben Wagner29380bd2017-10-09 14:43:00 -04002204 return dxy_at_t(curve, type, t);
Cary Clarkff114282016-12-14 11:56:16 -05002205}
2206
caryclarkdac1d172014-06-17 05:15:38 -07002207function drawLabel(num, px, py) {
2208 ctx.beginPath();
2209 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2210 ctx.closePath();
2211 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2212 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2213 ctx.stroke();
2214 ctx.fillStyle = "black";
2215 ctx.font = "normal 10px Arial";
2216 // ctx.rotate(0.001);
2217 ctx.fillText(num, px - 2, py + 3);
2218 // ctx.rotate(-0.001);
2219}
2220
2221function drawLabelX(ymin, num, loc) {
2222 var px = (loc - srcLeft) * scale;
2223 var py = (ymin - srcTop) * scale - 20;
2224 drawLabel(num, px, py);
2225}
2226
2227function drawLabelY(xmin, num, loc) {
2228 var px = (xmin - srcLeft) * scale - 20;
2229 var py = (loc - srcTop) * scale;
2230 drawLabel(num, px, py);
2231}
2232
2233function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2234 ctx.beginPath();
2235 ctx.moveTo(hx, hy - 100);
2236 ctx.lineTo(hx, hy);
2237 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2238 ctx.stroke();
2239 ctx.beginPath();
2240 ctx.moveTo(hx, hy);
2241 ctx.lineTo(hx, hy + 100);
2242 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2243 ctx.stroke();
2244 ctx.beginPath();
2245 ctx.moveTo(hx - 100, hy);
2246 ctx.lineTo(hx, hy);
2247 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2248 ctx.stroke();
2249 ctx.beginPath();
2250 ctx.moveTo(hx, hy);
2251 ctx.lineTo(hx + 100, hy);
2252 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2253 ctx.stroke();
2254}
2255
2256function scalexy(x, y, mag) {
2257 var length = Math.sqrt(x * x + y * y);
2258 return mag / length;
2259}
2260
caryclark03b03ca2015-04-23 09:13:37 -07002261function drawArrow(x, y, dx, dy, s) {
2262 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002263 dx *= dscale;
2264 dy *= dscale;
2265 ctx.beginPath();
2266 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2267 x += dx;
2268 y += dy;
2269 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2270 dx /= 10;
2271 dy /= 10;
2272 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2273 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2274 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2275 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2276 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2277 ctx.stroke();
2278}
2279
2280function x_at_t(curve, t) {
2281 var one_t = 1 - t;
2282 if (curve.length == 4) {
2283 return one_t * curve[0] + t * curve[2];
2284 }
2285 var one_t2 = one_t * one_t;
2286 var t2 = t * t;
2287 if (curve.length == 6) {
2288 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2289 }
caryclark1049f122015-04-20 08:31:59 -07002290 if (curve.length == 7) {
2291 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2292 / (one_t2 +2 * one_t * t * curve[6] + t2);
2293 }
caryclarkdac1d172014-06-17 05:15:38 -07002294 var a = one_t2 * one_t;
2295 var b = 3 * one_t2 * t;
2296 var c = 3 * one_t * t2;
2297 var d = t2 * t;
2298 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2299}
2300
2301function y_at_t(curve, t) {
2302 var one_t = 1 - t;
2303 if (curve.length == 4) {
2304 return one_t * curve[1] + t * curve[3];
2305 }
2306 var one_t2 = one_t * one_t;
2307 var t2 = t * t;
2308 if (curve.length == 6) {
2309 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2310 }
caryclark1049f122015-04-20 08:31:59 -07002311 if (curve.length == 7) {
2312 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2313 / (one_t2 +2 * one_t * t * curve[6] + t2);
2314 }
caryclarkdac1d172014-06-17 05:15:38 -07002315 var a = one_t2 * one_t;
2316 var b = 3 * one_t2 * t;
2317 var c = 3 * one_t * t2;
2318 var d = t2 * t;
2319 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2320}
2321
Ben Wagner29380bd2017-10-09 14:43:00 -04002322function pt_at_t(curve, t) {
2323 var pt = {};
2324 pt.x = x_at_t(curve, t);
2325 pt.y = y_at_t(curve, t);
2326 return pt;
Cary Clarkff114282016-12-14 11:56:16 -05002327}
2328
2329function drawOrder(curve, t, label) {
2330 var px = x_at_t(curve, t);
2331 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002332 var _px = (px - srcLeft) * scale;
2333 var _py = (py - srcTop) * scale;
2334 ctx.beginPath();
2335 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2336 ctx.closePath();
2337 ctx.fillStyle = "white";
2338 ctx.fill();
2339 if (label == 'L') {
2340 ctx.strokeStyle = "rgba(255,0,0, 1)";
2341 ctx.fillStyle = "rgba(255,0,0, 1)";
2342 } else {
2343 ctx.strokeStyle = "rgba(0,0,255, 1)";
2344 ctx.fillStyle = "rgba(0,0,255, 1)";
2345 }
2346 ctx.stroke();
2347 ctx.font = "normal 16px Arial";
2348 ctx.textAlign = "center";
2349 ctx.fillText(label, _px, _py + 5);
2350 ctx.font = "normal 10px Arial";
2351}
2352
Ben Wagner29380bd2017-10-09 14:43:00 -04002353function drawVisibleOrder(curve, label) {
2354 var s = pt_at_t(curve, 0);
2355 var e = pt_at_t(curve, 1);
2356 var sOn = ptOnScreen(s);
2357 var eOn = ptOnScreen(e);
2358 var defaultT = 0.85;
2359 if (sOn && eOn)
2360 return drawOrder(curve, defaultT, label);
2361 if (sOn || eOn) {
2362 if (eOn) {
2363 defaultT = 1 - defaultT;
2364 }
2365 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2366 var t = defaultT;
2367 var tries = 16;
2368 do {
2369 var mid = pt_at_t(curve, t);
2370 if (ptOnScreen(mid))
2371 return drawOrder(curve, t, label);
2372 t += step;
2373 step /= 2;
2374 } while (--tries > 0);
2375 drawOrder(curve, defaultT, label);
2376 }
2377 // scattershot until we find a visible point
2378 var denom = 2; // visit odd number num / denom to hit unique pts
2379 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2380 do {
2381 for (var numer = 1; numer < denom; numer += 2) {
2382 var t = numer / denom + 0.1;
2383 if (t >= 1) {
2384 break;
2385 }
2386 var mid = pt_at_t(curve, t);
2387 if (ptOnScreen(mid))
2388 return drawOrder(curve, t, label);
2389 }
2390 denom *= 2;
2391 } while (--tries > 0);
2392 drawOrder(curve, defaultT, label);
Cary Clarkff114282016-12-14 11:56:16 -05002393}
2394
Ben Wagner29380bd2017-10-09 14:43:00 -04002395function set_length(pt, newLen) {
2396 var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y);
2397 var scale = newLen / len;
2398 var newPt = { x: pt.x * scale, y: pt.y * scale };
2399 return newPt;
Cary Clarkff114282016-12-14 11:56:16 -05002400}
2401
Ben Wagner29380bd2017-10-09 14:43:00 -04002402function drawDirection(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002403 var d = dpt_at_t(curve, t);
2404 d = set_length(d, 16);
Ben Wagner29380bd2017-10-09 14:43:00 -04002405 var pt = localToGlobal(pt_at_t(curve, t));
Cary Clarkff114282016-12-14 11:56:16 -05002406 ctx.beginPath();
2407 ctx.moveTo(pt.x - d.y, pt.y + d.x);
2408 ctx.lineTo(pt.x + d.x, pt.y + d.y);
2409 ctx.lineTo(pt.x + d.y, pt.y - d.x);
2410 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2411 ctx.stroke();
2412}
2413
Ben Wagner29380bd2017-10-09 14:43:00 -04002414function drawVisibleDirection(curve) {
2415 var s = pt_at_t(curve, 0);
2416 var e = pt_at_t(curve, 1);
2417 var sOn = ptOnScreen(s);
2418 var eOn = ptOnScreen(e);
2419 var defaultT = 0.65;
2420 if (sOn && eOn) {
2421 return drawDirection(curve, defaultT);
2422 }
2423 if (sOn || eOn) {
2424 if (eOn) {
2425 defaultT = 1 - defaultT;
2426 }
2427 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2428 var t = defaultT;
2429 var tries = 16;
2430 do {
2431 var mid = pt_at_t(curve, t);
2432 if (ptOnScreen(mid))
2433 return drawDirection(curve, t);
2434 t += step;
2435 step /= 2;
2436 } while (--tries > 0);
2437 drawDirection(curve, defaultT);
2438 }
2439 // scattershot until we find a visible point
2440 var denom = 2; // visit odd number num / denom to hit unique pts
2441 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2442 do {
2443 for (var numer = 1; numer < denom; numer += 2) {
2444 var t = numer / denom + 0.1;
2445 if (t >= 1) {
2446 break;
2447 }
2448 var mid = pt_at_t(curve, t);
2449 if (ptOnScreen(mid))
2450 return drawDirection(curve, t);
2451 }
2452 denom *= 2;
2453 } while (--tries > 0);
2454 drawDirection(curve, defaultT);
Cary Clarkff114282016-12-14 11:56:16 -05002455}
2456
2457function drawID(curve, t, id) {
2458 var px = x_at_t(curve, t);
2459 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002460 var _px = (px - srcLeft) * scale;
2461 var _py = (py - srcTop) * scale;
2462 draw_id_at(id, _px, _py);
2463}
2464
Ben Wagner29380bd2017-10-09 14:43:00 -04002465function localToGlobal(local) {
2466 var global = {};
2467 global.x = (local.x - srcLeft) * scale;
2468 global.y = (local.y - srcTop) * scale;
2469 return global;
Cary Clarkff114282016-12-14 11:56:16 -05002470}
2471
Ben Wagner29380bd2017-10-09 14:43:00 -04002472function ptOnScreen(local) {
2473 var pt = localToGlobal(local);
2474 return 10 <= pt.x && pt.x <= screenWidth - 10
2475 && 10 <= pt.y && pt.y <= screenHeight - 10;
Cary Clarkff114282016-12-14 11:56:16 -05002476}
2477
Ben Wagner29380bd2017-10-09 14:43:00 -04002478function drawVisibleID(curve, defaultT, id) {
2479 // determine if either or both ends are visible
2480 var s = pt_at_t(curve, 0);
2481 var e = pt_at_t(curve, 1);
2482 var sOn = ptOnScreen(s);
2483 var eOn = ptOnScreen(e);
2484 if (sOn && eOn)
2485 return drawID(curve, defaultT, id);
2486 if (sOn || eOn) {
2487 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2488 var t = defaultT;
2489 var tries = 16;
2490 do {
2491 var mid = pt_at_t(curve, t);
2492 if (ptOnScreen(mid))
2493 return drawID(curve, t, id);
2494 t += step;
2495 step /= 2;
2496 } while (--tries > 0);
2497 drawID(curve, defaultT, id);
2498 }
2499 // scattershot until we find a visible point
2500 var denom = 2; // visit odd number num / denom to hit unique pts
2501 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2502 do {
2503 for (var numer = 1; numer < denom; numer += 2) {
2504 var t = numer / denom;
2505 var mid = pt_at_t(curve, t);
2506 if (ptOnScreen(mid))
2507 return drawID(curve, t, id);
2508 }
2509 denom *= 2;
2510 } while (--tries > 0);
2511 drawID(curve, defaultT, id);
Cary Clarkff114282016-12-14 11:56:16 -05002512}
2513
caryclarkdac1d172014-06-17 05:15:38 -07002514function draw_id_at(id, _px, _py) {
2515 ctx.beginPath();
2516 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2517 ctx.closePath();
2518 ctx.fillStyle = "white";
2519 ctx.fill();
2520 ctx.strokeStyle = "rgba(127,127,0, 1)";
2521 ctx.fillStyle = "rgba(127,127,0, 1)";
2522 ctx.stroke();
2523 ctx.font = "normal 16px Arial";
2524 ctx.textAlign = "center";
2525 ctx.fillText(id, _px, _py + 5);
2526 ctx.font = "normal 10px Arial";
2527}
2528
2529function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2530 var curve = [x1, y1, x2, y2];
2531 drawCurvePartialID(id, curve, t1, t2);
2532}
2533
caryclark55888e42016-07-18 10:01:36 -07002534function drawLineID(id, x1, y1, x2, y2) {
2535 drawLinePartialID(id, x1, y1, x2, y2, 0, 1);
2536}
2537
caryclarkdac1d172014-06-17 05:15:38 -07002538function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2539 var curve = [x1, y1, x2, y2, x3, y3];
2540 drawCurvePartialID(id, curve, t1, t2);
2541}
2542
caryclark55888e42016-07-18 10:01:36 -07002543function drawQuadID(id, x1, y1, x2, y2, x3, y3) {
2544 drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1);
2545}
2546
caryclark1049f122015-04-20 08:31:59 -07002547function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2548 var curve = [x1, y1, x2, y2, x3, y3, w];
2549 drawCurvePartialID(id, curve, t1, t2);
2550}
2551
caryclark55888e42016-07-18 10:01:36 -07002552function drawConicID(id, x1, y1, x2, y2, x3, y3, w) {
2553 drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1);
2554}
2555
caryclarkdac1d172014-06-17 05:15:38 -07002556function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2557 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2558 drawCurvePartialID(id, curve, t1, t2);
2559}
2560
caryclark55888e42016-07-18 10:01:36 -07002561function drawCubicID(id, x1, y1, x2, y2, x3, y3, x4, y4) {
2562 drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, 0, 1);
2563}
2564
caryclarkdac1d172014-06-17 05:15:38 -07002565function drawCurvePartialID(id, curve, t1, t2) {
Cary Clarkff114282016-12-14 11:56:16 -05002566 drawVisibleID(curve, (t1 + t2) / 2, id);
caryclarkdac1d172014-06-17 05:15:38 -07002567}
2568
2569function drawCurveSpecials(test, curve, type) {
2570 if (pt_labels) {
2571 drawPoints(curve, type, pt_labels == 2);
2572 }
2573 if (control_lines != 0) {
2574 drawControlLines(curve, type, control_lines);
2575 }
2576 if (curve_t) {
2577 drawPointAtT(curve, type);
2578 }
2579 if (draw_midpoint) {
2580 var mid = pointAtT(curve, type, 0.5);
2581 drawPoint(mid.x, mid.y, true);
2582 }
2583 if (draw_id) {
2584 var id = idByCurve(test, curve, type);
2585 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05002586 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07002587 }
2588 }
Ben Wagner29380bd2017-10-09 14:43:00 -04002589 if (draw_direction) {
2590 drawVisibleDirection(curve);
Cary Clarkff114282016-12-14 11:56:16 -05002591 }
caryclarkdac1d172014-06-17 05:15:38 -07002592 if (type == PATH_LINE) {
2593 return;
2594 }
2595 if (draw_deriviatives > 0) {
2596 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002597 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002598 if (draw_deriviatives == 2) {
2599 d = dxy_at_t(curve, type, 1);
2600 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002601 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002602 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002603 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002604 }
2605 }
2606 if (draw_midpoint) {
2607 var mid = pointAtT(curve, type, 0.5);
2608 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002609 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002610 }
2611 }
2612 if (type != PATH_CUBIC) {
2613 return;
2614 }
caryclarkdac1d172014-06-17 05:15:38 -07002615 if (draw_sequence) {
2616 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2617 for (var i = 0; i < 8; i+= 2) {
2618 drawLabelX(ymin, i >> 1, curve[i]);
2619 }
2620 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2621 for (var i = 1; i < 8; i+= 2) {
2622 drawLabelY(xmin, i >> 1, curve[i]);
2623 }
2624 }
2625}
2626
2627function logCurves(test) {
2628 for (curves in test) {
2629 var curve = test[curves];
2630 dumpCurve(curve);
2631 }
2632}
2633
2634function curveToString(curve) {
2635 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002636 var length = curve.length == 7 ? 6 : curve.length;
2637 if (curve.length == 7) {
2638 str += "{";
2639 }
2640 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002641 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2642 if (i < curve.length - 2) {
2643 str += "}, {";
2644 }
2645 }
caryclark1049f122015-04-20 08:31:59 -07002646 str += "}";
2647 if (curve.length == 7) {
2648 str += "}, " + curve[6].toFixed(decimal_places);
2649 }
2650 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002651 return str;
2652}
2653
2654function dumpCurve(curve) {
2655 console.log(curveToString(curve));
2656}
2657
2658function draw(test, lines, title) {
2659 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2660 ctx.font = "normal 50px Arial";
2661 ctx.textAlign = "left";
2662 ctx.fillText(title, 50, 50);
2663 ctx.font = "normal 10px Arial";
2664 ctx.lineWidth = "1.001"; "0.999";
2665 var secondPath = test.length;
2666 var closeCount = 0;
2667 logStart = -1;
2668 logRange = 0;
2669 // find last active rec type at this step
2670 var curType = test[0];
2671 var curStep = 0;
2672 var hasOp = false;
2673 var lastActive = 0;
2674 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002675 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002676 var lastSect = 0;
2677 var lastSort = 0;
2678 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002679 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002680 activeCount = 0;
2681 addCount = 0;
2682 angleCount = 0;
2683 opCount = 0;
2684 sectCount = 0;
2685 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002686 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002687 markCount = 0;
2688 activeMax = 0;
2689 addMax = 0;
2690 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002691 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002692 opMax = 0;
2693 sectMax = 0;
2694 sectMax2 = 0;
2695 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002696 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002697 markMax = 0;
2698 lastIndex = test.length - 3;
2699 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2700 var recType = test[tIndex];
2701 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2702 console.log("unknown rec type: " + recType);
2703 throw "stop execution";
2704 }
2705 // if (curType == recType && curType != REC_TYPE_ADD) {
2706 // continue;
2707 // }
2708 var inStepRange = step_limit == 0 || curStep < step_limit;
2709 curType = recType;
2710 if (recType == REC_TYPE_OP) {
2711 hasOp = true;
2712 continue;
2713 }
2714 if (recType == REC_TYPE_UNKNOWN) {
2715 // these types do not advance step
2716 continue;
2717 }
2718 var bumpStep = false;
2719 var records = test[tIndex + 2];
2720 var fragType = records[0];
2721 if (recType == REC_TYPE_ADD) {
2722 if (records.length != 2) {
2723 console.log("expect only two elements: " + records.length);
2724 throw "stop execution";
2725 }
2726 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2727 continue;
2728 }
2729 ++addMax;
2730 if (!draw_add || !inStepRange) {
2731 continue;
2732 }
2733 lastAdd = tIndex;
2734 ++addCount;
2735 bumpStep = true;
2736 }
2737 if (recType == REC_TYPE_PATH && hasOp) {
2738 secondPath = tIndex;
2739 }
caryclark54359292015-03-26 07:52:43 -07002740 if (recType == REC_TYPE_PATH2 && hasOp) {
2741 secondPath = tIndex;
2742 }
caryclarkdac1d172014-06-17 05:15:38 -07002743 if (recType == REC_TYPE_ACTIVE) {
2744 ++activeMax;
2745 if (!draw_active || !inStepRange) {
2746 continue;
2747 }
2748 lastActive = tIndex;
2749 ++activeCount;
2750 bumpStep = true;
2751 }
2752 if (recType == REC_TYPE_ACTIVE_OP) {
2753 ++opMax;
2754 if (!draw_op || !inStepRange) {
2755 continue;
2756 }
2757 lastOp = tIndex;
2758 ++opCount;
2759 bumpStep = true;
2760 }
caryclark54359292015-03-26 07:52:43 -07002761 if (recType == REC_TYPE_AFTERPART) {
2762 if (draw_angle != 3 || !inStepRange) {
2763 continue;
2764 }
2765 lastAngle = tIndex;
2766 ++angleCount;
2767 bumpStep = true;
2768 }
caryclarkdac1d172014-06-17 05:15:38 -07002769 if (recType == REC_TYPE_ANGLE) {
2770 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002771 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002772 continue;
2773 }
2774 lastAngle = tIndex;
2775 ++angleCount;
2776 bumpStep = true;
2777 }
caryclark624637c2015-05-11 07:21:27 -07002778 if (recType == REC_TYPE_COINCIDENCE) {
2779 ++coinMax;
2780 if (!draw_coincidence || !inStepRange) {
2781 continue;
2782 }
2783 lastCoin = tIndex;
2784 ++coinCount;
2785 bumpStep = true;
2786 }
caryclarkdac1d172014-06-17 05:15:38 -07002787 if (recType == REC_TYPE_SECT) {
2788 if (records.length != 2) {
2789 console.log("expect only two elements: " + records.length);
2790 throw "stop execution";
2791 }
2792 ++sectMax;
2793 var sectBump = 1;
2794 switch (fragType) {
2795 case INTERSECT_LINE:
2796 case INTERSECT_QUAD_LINE:
2797 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002798 case INTERSECT_CONIC_LINE:
caryclark55888e42016-07-18 10:01:36 -07002799 case INTERSECT_CONIC_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002800 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002801 case INTERSECT_SELF_CUBIC:
2802 case INTERSECT_CUBIC_LINE:
2803 case INTERSECT_CUBIC_QUAD:
2804 case INTERSECT_CUBIC:
2805 sectBump = 1;
2806 break;
2807 case INTERSECT_LINE_2:
2808 case INTERSECT_QUAD_LINE_2:
2809 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002810 case INTERSECT_CONIC_LINE_2:
caryclark55888e42016-07-18 10:01:36 -07002811 case INTERSECT_CONIC_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002812 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002813 case INTERSECT_CUBIC_LINE_2:
2814 case INTERSECT_CUBIC_QUAD_2:
2815 case INTERSECT_CUBIC_2:
2816 sectBump = 2;
2817 break;
2818 case INTERSECT_LINE_NO:
2819 case INTERSECT_QUAD_LINE_NO:
2820 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002821 case INTERSECT_CONIC_LINE_NO:
caryclark55888e42016-07-18 10:01:36 -07002822 case INTERSECT_CONIC_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002823 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002824 case INTERSECT_SELF_CUBIC_NO:
2825 case INTERSECT_CUBIC_LINE_NO:
2826 case INTERSECT_CUBIC_QUAD_NO:
2827 case INTERSECT_CUBIC_NO:
2828 sectBump = 0;
2829 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002830 case INTERSECT_CONIC_QUAD_3:
caryclarkdac1d172014-06-17 05:15:38 -07002831 case INTERSECT_CUBIC_LINE_3:
2832 case INTERSECT_CUBIC_QUAD_3:
2833 case INTERSECT_CUBIC_3:
2834 sectBump = 3;
2835 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002836 case INTERSECT_CONIC_QUAD_4:
caryclarkdac1d172014-06-17 05:15:38 -07002837 case INTERSECT_CUBIC_QUAD_4:
2838 case INTERSECT_CUBIC_4:
2839 sectBump = 4;
2840 break;
2841 default:
2842 console.log("missing case " + records.length);
2843 throw "stop execution";
2844 }
2845 sectMax2 += sectBump;
2846 if (draw_intersection <= 1 || !inStepRange) {
2847 continue;
2848 }
2849 lastSect = tIndex;
2850 sectCount += sectBump;
2851 bumpStep = true;
2852 }
2853 if (recType == REC_TYPE_SORT) {
2854 ++sortMax;
2855 if (!draw_sort || !inStepRange) {
2856 continue;
2857 }
2858 lastSort = tIndex;
2859 ++sortCount;
2860 bumpStep = true;
2861 }
caryclark03b03ca2015-04-23 09:13:37 -07002862 if (recType == REC_TYPE_TOP) {
2863 ++topMax;
2864 if (!draw_top || !inStepRange) {
2865 continue;
2866 }
2867 lastTop = tIndex;
2868 ++topCount;
2869 bumpStep = true;
2870 }
caryclarkdac1d172014-06-17 05:15:38 -07002871 if (recType == REC_TYPE_MARK) {
2872 ++markMax;
2873 if (!draw_mark || !inStepRange) {
2874 continue;
2875 }
2876 lastMark = tIndex;
2877 ++markCount;
2878 bumpStep = true;
2879 }
2880 if (bumpStep) {
2881 lastIndex = tIndex;
2882 logStart = test[tIndex + 1];
2883 logRange = records.length / 2;
2884 ++curStep;
2885 }
2886 }
2887 stepMax = (draw_add ? addMax : 0)
2888 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002889 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002890 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002891 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002892 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002893 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002894 + (draw_mark ? markMax : 0)
2895 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2896 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002897 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002898 }
2899 drawnPts = [];
2900 drawnLines = [];
2901 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002902 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002903 drawnCubics = [];
2904 focusXmin = focusYmin = Infinity;
2905 focusXmax = focusYmax = -Infinity;
2906 var pathIndex = 0;
2907 var opLetter = 'S';
2908 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2909 var recType = test[tIndex];
2910 var records = test[tIndex + 2];
2911 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2912 var fragType = records[recordIndex];
2913 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2914 console.log("unknown in range frag type: " + fragType);
2915 throw "stop execution";
2916 }
2917 var frags = records[recordIndex + 1];
2918 focus_enabled = false;
2919 switch (recType) {
2920 case REC_TYPE_COMPUTED:
2921 if (draw_computed == 0) {
2922 continue;
2923 }
2924 ctx.lineWidth = 1;
2925 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2926 ctx.fillStyle = "blue";
2927 var drawThis = false;
2928 switch (fragType) {
2929 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002930 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2931 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002932 drawQuad(frags[0], frags[1], frags[2], frags[3],
2933 frags[4], frags[5]);
2934 drawThis = true;
2935 }
2936 break;
caryclark1049f122015-04-20 08:31:59 -07002937 case PATH_CONIC:
2938 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2939 && (draw_computed & 7) == pathIndex)) {
2940 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2941 frags[4], frags[5], frags[6]);
2942 drawThis = true;
2943 }
2944 break;
caryclarkdac1d172014-06-17 05:15:38 -07002945 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002946 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2947 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002948 drawCubic(frags[0], frags[1], frags[2], frags[3],
2949 frags[4], frags[5], frags[6], frags[7]);
2950 drawThis = true;
2951 }
2952 ++pathIndex;
2953 break;
2954 case COMPUTED_SET_1:
2955 pathIndex = 0;
2956 break;
2957 case COMPUTED_SET_2:
2958 pathIndex = 1;
2959 break;
2960 default:
2961 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2962 throw "stop execution";
2963 }
2964 if (!drawThis || collect_bounds) {
2965 break;
2966 }
2967 drawCurveSpecials(test, frags, fragType);
2968 break;
caryclark26ad22a2015-10-16 09:03:38 -07002969 case REC_TYPE_ALIGNED:
2970 if (draw_path < 4) {
2971 continue;
2972 }
caryclarkdac1d172014-06-17 05:15:38 -07002973 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002974 case REC_TYPE_PATH2:
caryclark26ad22a2015-10-16 09:03:38 -07002975 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
2976 continue;
2977 }
caryclarkdac1d172014-06-17 05:15:38 -07002978 if (!draw_path) {
2979 continue;
2980 }
2981 var firstPath = tIndex < secondPath;
2982 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2983 continue;
2984 }
2985 ctx.lineWidth = 1;
2986 ctx.strokeStyle = firstPath ? "black" : "red";
2987 ctx.fillStyle = "blue";
caryclark55888e42016-07-18 10:01:36 -07002988 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002989 switch (fragType) {
2990 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002991 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2992 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002993 break;
2994 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002995 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2996 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2997 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002998 break;
caryclark1049f122015-04-20 08:31:59 -07002999 case PATH_CONIC:
3000 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
3001 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
3002 frags2[4], frags2[5], frags2[6]);
3003 break;
caryclarkdac1d172014-06-17 05:15:38 -07003004 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07003005 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
3006 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
3007 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07003008 break;
3009 default:
caryclark26ad22a2015-10-16 09:03:38 -07003010 console.log("unknown " + recType + " frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003011 throw "stop execution";
3012 }
3013 if (collect_bounds) {
3014 break;
3015 }
caryclark54359292015-03-26 07:52:43 -07003016 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003017 break;
3018 case REC_TYPE_OP:
3019 switch (fragType) {
3020 case OP_INTERSECT: opLetter = 'I'; break;
3021 case OP_DIFFERENCE: opLetter = 'D'; break;
3022 case OP_UNION: opLetter = 'U'; break;
3023 case OP_XOR: opLetter = 'X'; break;
3024 default:
3025 console.log("unknown REC_TYPE_OP frag type: " + fragType);
3026 throw "stop execution";
3027 }
3028 break;
3029 case REC_TYPE_ACTIVE:
3030 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
3031 continue;
3032 }
3033 var x1 = frags[SPAN_X1];
3034 var y1 = frags[SPAN_Y1];
3035 var x2 = frags[SPAN_X2];
3036 var y2 = frags[SPAN_Y2];
caryclark55888e42016-07-18 10:01:36 -07003037 var x3, y3, x3, y4, w;
caryclarkdac1d172014-06-17 05:15:38 -07003038 ctx.lineWidth = 3;
3039 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3040 focus_enabled = true;
3041 switch (fragType) {
3042 case ACTIVE_LINE_SPAN:
caryclark55888e42016-07-18 10:01:36 -07003043 drawLine(x1, y1, x2, y2);
caryclarkdac1d172014-06-17 05:15:38 -07003044 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003045 drawLineID(frags[0], x1, y1, x2, y2);
3046 }
3047 if (pt_labels) {
3048 var curve = [x1, y1, x2, y2];
3049 ctx.fillStyle = "blue";
3050 drawPoints(curve, PATH_LINE, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003051 }
3052 break;
3053 case ACTIVE_QUAD_SPAN:
3054 x3 = frags[SPAN_X3];
3055 y3 = frags[SPAN_Y3];
caryclark55888e42016-07-18 10:01:36 -07003056 drawQuad(x1, y1, x2, y2, x3, y3);
caryclarkdac1d172014-06-17 05:15:38 -07003057 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003058 drawQuadID(frags[0], x1, y1, x2, y2, x3, y3);
3059 }
3060 if (pt_labels) {
3061 var curve = [x1, y1, x2, y2, x3, y3];
3062 ctx.fillStyle = "blue";
3063 drawPoints(curve, PATH_QUAD, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003064 }
3065 break;
caryclark1049f122015-04-20 08:31:59 -07003066 case ACTIVE_CONIC_SPAN:
3067 x3 = frags[SPAN_X3];
3068 y3 = frags[SPAN_Y3];
caryclark1049f122015-04-20 08:31:59 -07003069 w = frags[SPAN_K_W];
caryclark55888e42016-07-18 10:01:36 -07003070 drawConicWithQuads(x1, y1, x2, y2, x3, y3, w);
caryclark1049f122015-04-20 08:31:59 -07003071 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003072 drawConicID(frags[0], x1, y1, x2, y2, x3, y3, w);
3073 }
3074 if (pt_labels) {
3075 var curve = [x1, y1, x2, y2, x3, y3, w];
3076 ctx.fillStyle = "blue";
3077 drawPoints(curve, PATH_CONIC, pt_labels == 2);
caryclark1049f122015-04-20 08:31:59 -07003078 }
3079 break;
caryclarkdac1d172014-06-17 05:15:38 -07003080 case ACTIVE_CUBIC_SPAN:
3081 x3 = frags[SPAN_X3];
3082 y3 = frags[SPAN_Y3];
3083 x4 = frags[SPAN_X4];
3084 y4 = frags[SPAN_Y4];
caryclark55888e42016-07-18 10:01:36 -07003085 drawCubic(x1, y1, x2, y2, x3, y3, x4, y4);
caryclarkdac1d172014-06-17 05:15:38 -07003086 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003087 drawCubicID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4);
3088 }
3089 if (pt_labels) {
3090 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
3091 ctx.fillStyle = "blue";
3092 drawPoints(curve, PATH_CUBIC, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003093 }
3094 break;
3095 default:
3096 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
3097 throw "stop execution";
3098 }
3099 break;
3100 case REC_TYPE_ACTIVE_OP:
3101 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
3102 continue;
3103 }
3104 focus_enabled = true;
3105 ctx.lineWidth = 3;
3106 var activeSpan = frags[7] == "1";
3107 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
3108 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3109 drawCurve(curve);
3110 if (draw_op > 1) {
3111 drawArc(curve, false, frags[3], frags[4]);
3112 drawArc(curve, true, frags[5], frags[6]);
3113 }
3114 break;
3115 case REC_TYPE_ADD:
3116 if (!draw_add) {
3117 continue;
3118 }
3119 ctx.lineWidth = 3;
3120 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
3121 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
3122 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
3123 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
3124 : "rgba(127,0,127, 0.3)";
3125 focus_enabled = true;
3126 switch (fragType) {
3127 case ADD_MOVETO:
3128 break;
3129 case ADD_LINETO:
3130 if (step_limit == 0 || tIndex >= lastAdd) {
3131 drawLine(frags[0], frags[1], frags[2], frags[3]);
3132 }
3133 break;
3134 case ADD_QUADTO:
3135 if (step_limit == 0 || tIndex >= lastAdd) {
3136 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
3137 }
3138 break;
caryclark1049f122015-04-20 08:31:59 -07003139 case ADD_CONICTO:
3140 if (step_limit == 0 || tIndex >= lastAdd) {
3141 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
3142 frags[4], frags[5], frags[6]);
3143 }
3144 break;
caryclarkdac1d172014-06-17 05:15:38 -07003145 case ADD_CUBICTO:
3146 if (step_limit == 0 || tIndex >= lastAdd) {
3147 drawCubic(frags[0], frags[1], frags[2], frags[3],
3148 frags[4], frags[5], frags[6], frags[7]);
3149 }
3150 break;
3151 case ADD_CLOSE:
3152 ++closeCount;
3153 break;
3154 case ADD_FILL:
3155 break;
3156 default:
3157 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
3158 throw "stop execution";
3159 }
3160 break;
3161 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07003162 angleBetween = frags[18] == "T";
3163 afterIndex = 0;
3164 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07003165 continue;
3166 }
3167 focus_enabled = true;
3168 ctx.lineWidth = 3;
3169 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07003170 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
3171 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
3172 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07003173 drawCurve(leftCurve);
3174 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07003175 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07003176 drawCurve(midCurve);
3177 if (draw_angle > 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003178 drawVisibleOrder(leftCurve, 'L');
3179 drawVisibleOrder(rightCurve, 'R');
3180 }
Ben Wagner29380bd2017-10-09 14:43:00 -04003181 if (draw_id) {
3182 drawVisibleID(leftCurve, 0.5, frags[0]);
3183 drawVisibleID(midCurve, 0.5, frags[6]);
3184 drawVisibleID(rightCurve, 0.5, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003185 }
3186 break;
caryclark54359292015-03-26 07:52:43 -07003187 case REC_TYPE_AFTERPART:
3188 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
3189 continue;
3190 }
3191 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
3192 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
Cary Clarkff114282016-12-14 11:56:16 -05003193 : "rgba(0,0,255, 1.0)";
3194 var curve;
3195 var id;
caryclark54359292015-03-26 07:52:43 -07003196 switch (fragType) {
3197 case PATH_LINE:
Cary Clarkff114282016-12-14 11:56:16 -05003198 curve = [ frags[0], frags[1], frags[2], frags[3] ];
3199 id = frags[4];
caryclark54359292015-03-26 07:52:43 -07003200 break;
3201 case PATH_QUAD:
Cary Clarkff114282016-12-14 11:56:16 -05003202 curve = [ frags[0], frags[1], frags[2], frags[3],
3203 frags[4], frags[5] ];
3204 id = frags[6];
caryclark54359292015-03-26 07:52:43 -07003205 break;
caryclark1049f122015-04-20 08:31:59 -07003206 case PATH_CONIC:
Cary Clarkff114282016-12-14 11:56:16 -05003207 curve = [ frags[0], frags[1], frags[2], frags[3],
3208 frags[4], frags[5], frags[6] ];
3209 id = frags[7];
caryclark1049f122015-04-20 08:31:59 -07003210 break;
caryclark54359292015-03-26 07:52:43 -07003211 case PATH_CUBIC:
Cary Clarkff114282016-12-14 11:56:16 -05003212 curve = [ frags[0], frags[1], frags[2], frags[3],
3213 frags[4], frags[5], frags[6], frags[7] ];
3214 id = frags[8];
caryclark54359292015-03-26 07:52:43 -07003215 break;
3216 default:
3217 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
3218 throw "stop execution";
3219 }
Cary Clarkff114282016-12-14 11:56:16 -05003220 drawCurve(curve);
Ben Wagner29380bd2017-10-09 14:43:00 -04003221 if (draw_id) {
3222 drawVisibleID(curve, 0.5, id);
Cary Clarkff114282016-12-14 11:56:16 -05003223 }
caryclark54359292015-03-26 07:52:43 -07003224 ++afterIndex;
3225 break;
caryclark624637c2015-05-11 07:21:27 -07003226 case REC_TYPE_COINCIDENCE:
3227 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
3228 continue;
3229 }
3230 focus_enabled = true;
3231 ctx.lineWidth = 3;
3232 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
3233 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3234 drawCurve(curve);
3235 break;
caryclarkdac1d172014-06-17 05:15:38 -07003236 case REC_TYPE_SECT:
3237 if (!draw_intersection) {
3238 continue;
3239 }
3240 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
3241 continue;
3242 }
3243 // draw_intersection == 1 : show all
3244 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
3245 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
3246 ctx.lineWidth = 1;
3247 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3248 ctx.fillStyle = "blue";
3249 focus_enabled = true;
3250 var f = [];
3251 var c1s;
3252 var c1l;
3253 var c2s;
3254 var c2l;
3255 switch (fragType) {
3256 case INTERSECT_LINE:
3257 f.push(5, 6, 0, 7);
3258 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
3259 break;
3260 case INTERSECT_LINE_2:
3261 f.push(5, 6, 0, 10);
3262 f.push(8, 9, 7, 15);
3263 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
3264 break;
3265 case INTERSECT_LINE_NO:
3266 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
3267 break;
3268 case INTERSECT_QUAD_LINE:
3269 f.push(7, 8, 0, 9);
3270 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
3271 break;
3272 case INTERSECT_QUAD_LINE_2:
3273 f.push(7, 8, 0, 12);
3274 f.push(10, 11, 9, 17);
3275 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
3276 break;
3277 case INTERSECT_QUAD_LINE_NO:
3278 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
3279 break;
3280 case INTERSECT_QUAD:
3281 f.push(7, 8, 0, 9);
3282 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
3283 break;
3284 case INTERSECT_QUAD_2:
3285 f.push(7, 8, 0, 12);
3286 f.push(10, 11, 9, 19);
3287 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
3288 break;
3289 case INTERSECT_QUAD_NO:
3290 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
3291 break;
caryclark1049f122015-04-20 08:31:59 -07003292 case INTERSECT_CONIC_LINE:
3293 f.push(8, 9, 0, 10);
3294 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
3295 break;
3296 case INTERSECT_CONIC_LINE_2:
3297 f.push(8, 9, 0, 12);
3298 f.push(11, 12, 10, 18);
3299 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
3300 break;
3301 case INTERSECT_CONIC_LINE_NO:
3302 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
3303 break;
caryclark55888e42016-07-18 10:01:36 -07003304 case INTERSECT_CONIC_QUAD:
3305 f.push(8, 9, 0, 10);
3306 c1s = 1; c1l = 7; c2s = 11; c2l = 6;
3307 break;
3308 case INTERSECT_CONIC_QUAD_2:
3309 f.push(8, 9, 0, 12);
3310 f.push(11, 12, 10, 18);
3311 c1s = 1; c1l = 7; c2s = 14; c2l = 6;
3312 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07003313 case INTERSECT_CONIC_QUAD_3:
3314 f.push(8, 9, 0, 15);
3315 f.push(11, 12, 10, 21);
3316 f.push(14, 15, 13, 22);
3317 c1s = 1; c1l = 7; c2s = 17; c2l = 6;
3318 break;
3319 case INTERSECT_CONIC_QUAD_4:
3320 f.push(8, 9, 0, 18);
3321 f.push(11, 12, 10, 24);
3322 f.push(14, 15, 13, 25);
3323 f.push(17, 18, 16, 26);
3324 c1s = 1; c1l = 7; c2s = 20; c2l = 6;
3325 break;
caryclark55888e42016-07-18 10:01:36 -07003326 case INTERSECT_CONIC_QUAD_NO:
3327 c1s = 0; c1l = 7; c2s = 7; c2l = 6;
3328 break;
caryclark1049f122015-04-20 08:31:59 -07003329 case INTERSECT_CONIC:
3330 f.push(8, 9, 0, 10);
3331 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
3332 break;
3333 case INTERSECT_CONIC_2:
3334 f.push(8, 9, 0, 13);
3335 f.push(11, 12, 10, 21);
3336 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
3337 break;
3338 case INTERSECT_CONIC_NO:
3339 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
3340 break;
caryclarkdac1d172014-06-17 05:15:38 -07003341 case INTERSECT_SELF_CUBIC:
3342 f.push(9, 10, 0, 11);
3343 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3344 break;
3345 case INTERSECT_SELF_CUBIC_NO:
3346 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3347 break;
3348 case INTERSECT_CUBIC_LINE:
3349 f.push(9, 10, 0, 11);
3350 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3351 break;
3352 case INTERSECT_CUBIC_LINE_2:
3353 f.push(9, 10, 0, 14);
3354 f.push(12, 13, 11, 19);
3355 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3356 break;
3357 case INTERSECT_CUBIC_LINE_3:
3358 f.push(9, 10, 0, 17);
3359 f.push(12, 13, 11, 22);
3360 f.push(15, 16, 14, 23);
3361 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3362 break;
3363 case INTERSECT_CUBIC_QUAD_NO:
3364 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3365 break;
3366 case INTERSECT_CUBIC_QUAD:
3367 f.push(9, 10, 0, 11);
3368 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3369 break;
3370 case INTERSECT_CUBIC_QUAD_2:
3371 f.push(9, 10, 0, 14);
3372 f.push(12, 13, 11, 21);
3373 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3374 break;
3375 case INTERSECT_CUBIC_QUAD_3:
3376 f.push(9, 10, 0, 17);
3377 f.push(12, 13, 11, 24);
3378 f.push(15, 16, 14, 25);
3379 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3380 break;
3381 case INTERSECT_CUBIC_QUAD_4:
3382 f.push(9, 10, 0, 20);
3383 f.push(12, 13, 11, 27);
3384 f.push(15, 16, 14, 28);
3385 f.push(18, 19, 17, 29);
3386 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3387 break;
3388 case INTERSECT_CUBIC_LINE_NO:
3389 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3390 break;
3391 case INTERSECT_CUBIC:
3392 f.push(9, 10, 0, 11);
3393 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3394 break;
3395 case INTERSECT_CUBIC_2:
3396 f.push(9, 10, 0, 14);
3397 f.push(12, 13, 11, 23);
3398 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3399 break;
3400 case INTERSECT_CUBIC_3:
3401 f.push(9, 10, 0, 17);
3402 f.push(12, 13, 11, 26);
3403 f.push(15, 16, 14, 27);
3404 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3405 break;
3406 case INTERSECT_CUBIC_4:
3407 f.push(9, 10, 0, 20);
3408 f.push(12, 13, 11, 29);
3409 f.push(15, 16, 14, 30);
3410 f.push(18, 19, 17, 31);
3411 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3412 break;
3413 case INTERSECT_CUBIC_NO:
3414 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3415 break;
3416 default:
3417 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3418 throw "stop execution";
3419 }
3420 if (draw_intersection != 1) {
3421 var id = -1;
3422 var curve;
3423 switch (c1l) {
caryclark55888e42016-07-18 10:01:36 -07003424 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003425 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3426 if (draw_id) {
3427 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3428 id = idByCurve(test, curve, PATH_LINE);
3429 }
3430 break;
3431 case 6:
3432 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3433 frags[c1s + 4], frags[c1s + 5]);
3434 if (draw_id) {
3435 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3436 frags[c1s + 4], frags[c1s + 5]];
3437 id = idByCurve(test, curve, PATH_QUAD);
3438 }
3439 break;
caryclark1049f122015-04-20 08:31:59 -07003440 case 7:
3441 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3442 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3443 if (draw_id) {
3444 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3445 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3446 id = idByCurve(test, curve, PATH_CONIC);
3447 }
3448 break;
caryclarkdac1d172014-06-17 05:15:38 -07003449 case 8:
3450 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3451 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3452 if (draw_id) {
3453 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3454 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3455 id = idByCurve(test, curve, PATH_CUBIC);
3456 }
3457 break;
3458 }
3459 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05003460 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003461 }
3462 id = -1;
3463 switch (c2l) {
3464 case 0:
3465 break;
caryclark55888e42016-07-18 10:01:36 -07003466 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003467 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3468 if (draw_id) {
3469 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3470 id = idByCurve(test, curve, PATH_LINE);
3471 }
3472 break;
3473 case 6:
3474 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3475 frags[c2s + 4], frags[c2s + 5]);
3476 if (draw_id) {
3477 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3478 frags[c2s + 4], frags[c2s + 5]];
3479 id = idByCurve(test, curve, PATH_QUAD);
3480 }
3481 break;
caryclark1049f122015-04-20 08:31:59 -07003482 case 7:
3483 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3484 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3485 if (draw_id) {
3486 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3487 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3488 id = idByCurve(test, curve, PATH_CONIC);
3489 }
3490 break;
caryclarkdac1d172014-06-17 05:15:38 -07003491 case 8:
3492 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3493 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3494 if (draw_id) {
3495 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3496 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3497 id = idByCurve(test, curve, PATH_CUBIC);
3498 }
3499 break;
3500 }
3501 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05003502 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003503 }
3504 }
3505 if (collect_bounds) {
3506 break;
3507 }
caryclark54359292015-03-26 07:52:43 -07003508 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3509 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003510 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3511 }
3512 }
3513 if (!draw_intersectT) {
3514 break;
3515 }
3516 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003517 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3518 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003519 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3520 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3521 }
3522 }
3523 break;
3524 case REC_TYPE_SORT:
3525 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3526 continue;
3527 }
3528 ctx.lineWidth = 3;
3529 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3530 focus_enabled = true;
3531 switch (fragType) {
3532 case SORT_UNARY:
3533 case SORT_BINARY:
3534 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3535 drawCurve(curve);
3536 break;
3537 default:
3538 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3539 throw "stop execution";
3540 }
3541 break;
caryclark03b03ca2015-04-23 09:13:37 -07003542 case REC_TYPE_TOP:
3543 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3544 continue;
3545 }
3546 ctx.lineWidth = 3;
3547 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3548 focus_enabled = true;
3549 {
3550 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3551 drawCurve(curve);
3552 var type = PATH_LINE + (curve.length / 2 - 2);
3553 var mid = pointAtT(curve, type, 0.5);
3554 var d = dxy_at_t(curve, type, 0.5);
3555 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3556 }
3557 break;
caryclarkdac1d172014-06-17 05:15:38 -07003558 case REC_TYPE_MARK:
3559 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3560 continue;
3561 }
3562 ctx.lineWidth = 3;
3563 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3564 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3565 focus_enabled = true;
3566 switch (fragType) {
3567 case MARK_LINE:
3568 case MARK_DONE_LINE:
3569 case MARK_UNSORTABLE_LINE:
3570 case MARK_SIMPLE_LINE:
3571 case MARK_SIMPLE_DONE_LINE:
3572 case MARK_DONE_UNARY_LINE:
3573 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3574 frags[5], frags[9]);
3575 if (draw_id) {
3576 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3577 frags[5], frags[9]);
3578 }
3579 break;
3580 case MARK_QUAD:
3581 case MARK_DONE_QUAD:
3582 case MARK_UNSORTABLE_QUAD:
3583 case MARK_SIMPLE_QUAD:
3584 case MARK_SIMPLE_DONE_QUAD:
3585 case MARK_DONE_UNARY_QUAD:
3586 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3587 frags[5], frags[6], frags[7], frags[11]);
3588 if (draw_id) {
3589 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3590 frags[5], frags[6], frags[7], frags[11]);
3591 }
3592 break;
3593 case MARK_CUBIC:
3594 case MARK_DONE_CUBIC:
3595 case MARK_UNSORTABLE_CUBIC:
3596 case MARK_SIMPLE_CUBIC:
3597 case MARK_SIMPLE_DONE_CUBIC:
3598 case MARK_DONE_UNARY_CUBIC:
3599 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3600 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3601 if (draw_id) {
3602 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3603 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3604 }
3605 break;
3606 case MARK_ANGLE_LAST:
3607 // FIXME: ignored for now
3608 break;
3609 default:
3610 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3611 throw "stop execution";
3612 }
3613 break;
3614 default:
3615 continue;
3616 }
3617 }
3618 switch (recType) {
3619 case REC_TYPE_SORT:
3620 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3621 break;
3622 }
3623 var angles = []; // use tangent lines to describe arcs
3624 var windFrom = [];
3625 var windTo = [];
3626 var opp = [];
3627 var minXY = Number.MAX_VALUE;
3628 var partial;
3629 focus_enabled = true;
3630 var someUnsortable = false;
3631 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3632 var fragType = records[recordIndex];
3633 var frags = records[recordIndex + 1];
3634 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3635 (fragType == SORT_BINARY && frags[16]);
3636 someUnsortable |= unsortable;
3637 switch (fragType) {
3638 case SORT_UNARY:
3639 case SORT_BINARY:
3640 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3641 break;
3642 default:
3643 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3644 throw "stop execution";
3645 }
3646 var dx = boundsWidth(partial);
3647 var dy = boundsHeight(partial);
3648 minXY = Math.min(minXY, dx * dx + dy * dy);
3649 if (collect_bounds) {
3650 continue;
3651 }
3652 angles.push(tangent(partial));
3653 var from = frags[12];
3654 var to = frags[12];
3655 var sgn = frags[10];
3656 if (sgn < 0) {
3657 from -= frags[11];
3658 } else if (sgn > 0) {
3659 to -= frags[11];
3660 }
3661 windFrom.push(from + (unsortable ? "!" : ""));
3662 windTo.push(to + (unsortable ? "!" : ""));
3663 opp.push(fragType == SORT_BINARY);
3664 if (draw_sort == 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003665 drawVisibleOrder(partial, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003666 } else {
Cary Clarkff114282016-12-14 11:56:16 -05003667 drawVisibleOrder(partial, (recordIndex / 2) + 1);
caryclarkdac1d172014-06-17 05:15:38 -07003668 }
3669 }
3670 var radius = Math.sqrt(minXY) / 2 * scale;
3671 radius = Math.min(50, radius);
3672 var scaledRadius = radius / scale;
3673 var centerX = partial[0];
3674 var centerY = partial[1];
3675 if (collect_bounds) {
3676 if (focus_enabled) {
3677 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3678 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3679 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3680 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3681 }
3682 break;
3683 }
3684 break;
3685 default:
3686 break;
3687 }
3688 }
3689 if (collect_bounds) {
3690 return;
3691 }
3692 if (draw_log && logStart >= 0) {
3693 ctx.font = "normal 10px Arial";
3694 ctx.textAlign = "left";
3695 ctx.beginPath();
3696 var top = screenHeight - 20 - (logRange + 2) * 10;
3697 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3698 ctx.fillStyle = "white";
3699 ctx.fill();
3700 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3701 if (logStart > 0) {
3702 ctx.fillText(lines[logStart - 1], 50, top + 8);
3703 }
3704 ctx.fillStyle = "black";
3705 for (var idx = 0; idx < logRange; ++idx) {
3706 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3707 }
3708 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3709 if (logStart + logRange < lines.length) {
3710 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3711 }
3712 }
3713 if (draw_legend) {
3714 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003715 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003716 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3717 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3718 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3719 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3720 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003721 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003722 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3723 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003724 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003725 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
caryclark55888e42016-07-18 10:01:36 -07003726 drawBox(pos++, "black", "white",
caryclark26ad22a2015-10-16 09:03:38 -07003727 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
caryclarkdac1d172014-06-17 05:15:38 -07003728 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3729 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3730 draw_computed != 0, computedKey);
3731 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3732 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3733 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3734 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3735 if (curve_t) {
3736 drawCurveTControl();
3737 }
3738 ctx.font = "normal 20px Arial";
3739 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3740 ctx.textAlign = "right";
3741 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3742 }
3743 if (draw_hints) {
3744 ctx.font = "normal 10px Arial";
3745 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3746 ctx.textAlign = "right";
3747 var y = 4;
3748 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3749 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3750 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3751 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003752 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3753 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3754 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3755 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3756 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3757 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3758 }
3759}
3760
3761function drawBox(y, backC, foreC, str, enable, label) {
3762 ctx.beginPath();
3763 ctx.fillStyle = backC;
3764 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3765 ctx.fill();
3766 ctx.font = "normal 16px Arial";
3767 ctx.fillStyle = foreC;
3768 ctx.textAlign = "center";
3769 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3770 if (!enable) {
3771 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3772 ctx.fill();
3773 }
3774 if (label != '') {
3775 ctx.font = "normal 9px Arial";
3776 ctx.fillStyle = "black";
3777 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3778 }
3779}
3780
3781function drawCurveTControl() {
3782 ctx.lineWidth = 2;
3783 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3784 ctx.beginPath();
3785 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3786 ctx.stroke();
3787 var ty = 40 + curveT * (screenHeight - 80);
3788 ctx.beginPath();
3789 ctx.moveTo(screenWidth - 80, ty);
3790 ctx.lineTo(screenWidth - 85, ty - 5);
3791 ctx.lineTo(screenWidth - 85, ty + 5);
3792 ctx.lineTo(screenWidth - 80, ty);
3793 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3794 ctx.fill();
3795 var num = curveT.toFixed(decimal_places);
3796 ctx.font = "normal 10px Arial";
3797 ctx.textAlign = "left";
3798 ctx.fillText(num, screenWidth - 78, ty);
3799}
3800
3801function ptInTControl() {
3802 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07003803 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07003804 var left = tgt.offsetLeft;
3805 var top = tgt.offsetTop;
3806 var x = (e.clientX - left);
3807 var y = (e.clientY - top);
3808 if (x < screenWidth - 80 || x > screenWidth - 50) {
3809 return false;
3810 }
3811 if (y < 40 || y > screenHeight - 80) {
3812 return false;
3813 }
3814 curveT = (y - 40) / (screenHeight - 120);
3815 if (curveT < 0 || curveT > 1) {
3816 throw "stop execution";
3817 }
3818 return true;
3819}
3820
3821function drawTop() {
3822 if (tests[testIndex] == null) {
3823 var str = testDivs[testIndex].textContent;
3824 parse_all(str);
3825 var title = testDivs[testIndex].id.toString();
3826 testTitles[testIndex] = title;
3827 }
3828 init(tests[testIndex]);
3829 redraw();
3830}
3831
3832function redraw() {
3833 if (focus_on_selection) {
3834 collect_bounds = true;
3835 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3836 collect_bounds = false;
3837 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3838 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3839 }
3840 }
3841 ctx.beginPath();
3842 ctx.fillStyle = "white";
3843 ctx.rect(0, 0, screenWidth, screenHeight);
3844 ctx.fill();
3845 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3846}
3847
3848function dumpCurvePartial(test, id, t0, t1) {
3849 var curve = curveByID(test, id);
3850 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3851 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3852 + " t0=" + t0 + " t1=" + t1
3853 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3854}
3855
3856function dumpAngleTest(test, id, t0, t1) {
3857 var curve = curveByID(test, id);
caryclark55888e42016-07-18 10:01:36 -07003858 console.log(" { {" + curveToString(curve) + "}, "
caryclarkdac1d172014-06-17 05:15:38 -07003859 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3860}
3861
3862function dumpLogToConsole() {
3863 if (logStart < 0) {
3864 return;
3865 }
3866 var test = tests[testIndex];
3867 var recType = REC_TYPE_UNKNOWN;
3868 var records;
3869 for (var index = 0; index < test.length; index += 3) {
3870 var lastLineNo = test[index + 1];
3871 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3872 recType = test[index];
3873 records = test[index + 2];
3874 break;
3875 }
3876 }
3877 if (recType == REC_TYPE_UNKNOWN) {
3878 return;
3879 }
3880 var lines = testLines[testIndex];
3881 for (var idx = 0; idx < logRange; ++idx) {
3882 var line = lines[logStart + idx];
3883 console.log(line);
3884 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3885 var fragType = records[recordIndex];
3886 var frags = records[recordIndex + 1];
3887 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003888 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3889 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3890 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3891 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3892 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3893 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3894 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3895 console.log("}; //");
3896 }
3897 }
3898 }
3899}
3900
3901var activeKey = 'a';
3902var pathKey = 'b';
3903var pathBackKey = 'B';
3904var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07003905var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003906var addKey = 'd';
3907var deriviativesKey = 'f';
3908var angleKey = 'g';
3909var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003910var intersectionKey = 'i';
3911var intersectionBackKey = 'I';
3912var sequenceKey = 'j';
3913var midpointKey = 'k';
3914var logKey = 'l';
3915var logToConsoleKey = 'L';
3916var markKey = 'm';
3917var sortKey = 'o';
3918var opKey = 'p';
3919var opBackKey = 'P';
3920var computedKey = 'q';
3921var computedBackKey = 'Q';
Cary Clarkff114282016-12-14 11:56:16 -05003922var directionKey = 'r';
caryclarkdac1d172014-06-17 05:15:38 -07003923var stepKey = 's';
3924var stepBackKey = 'S';
3925var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003926var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003927var curveTKey = 'u';
3928var controlLinesBackKey = 'V';
3929var controlLinesKey = 'v';
3930var ptsKey = 'x';
3931var xyKey = 'y';
3932var logCurvesKey = 'z';
3933var focusKey = '`';
3934var idKey = '.';
3935var retinaKey = '\\';
3936
3937function doKeyPress(evt) {
3938 var char = String.fromCharCode(evt.charCode);
3939 var focusWasOn = false;
3940 switch (char) {
3941 case '0':
3942 case '1':
3943 case '2':
3944 case '3':
3945 case '4':
3946 case '5':
3947 case '6':
3948 case '7':
3949 case '8':
3950 case '9':
3951 decimal_places = char - '0';
3952 redraw();
3953 break;
3954 case activeKey:
3955 draw_active ^= true;
caryclark55888e42016-07-18 10:01:36 -07003956 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003957 break;
3958 case addKey:
3959 draw_add ^= true;
caryclark55888e42016-07-18 10:01:36 -07003960 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003961 break;
3962 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003963 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003964 redraw();
3965 break;
3966 case angleBackKey:
3967 draw_angle = (draw_angle + 2) % 3;
3968 redraw();
3969 break;
3970 case centerKey:
3971 setScale(xmin, xmax, ymin, ymax);
caryclark55888e42016-07-18 10:01:36 -07003972 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003973 break;
caryclark624637c2015-05-11 07:21:27 -07003974 case coincidenceKey:
3975 draw_coincidence ^= true;
3976 redraw();
3977 break;
caryclarkdac1d172014-06-17 05:15:38 -07003978 case controlLinesBackKey:
3979 control_lines = (control_lines + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07003980 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003981 break;
3982 case controlLinesKey:
3983 control_lines = (control_lines + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07003984 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003985 break;
3986 case computedBackKey:
3987 draw_computed = (draw_computed + 5) % 6;
caryclark55888e42016-07-18 10:01:36 -07003988 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003989 break;
3990 case computedKey:
3991 draw_computed = (draw_computed + 1) % 6;
caryclark55888e42016-07-18 10:01:36 -07003992 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003993 break;
3994 case curveTKey:
3995 curve_t ^= true;
3996 if (curve_t) {
3997 draw_legend = true;
3998 }
3999 redraw();
4000 break;
4001 case deriviativesKey:
4002 draw_deriviatives = (draw_deriviatives + 1) % 3;
4003 redraw();
4004 break;
Cary Clarkff114282016-12-14 11:56:16 -05004005 case directionKey:
4006 draw_direction ^= true;
4007 redraw();
4008 break;
caryclarkdac1d172014-06-17 05:15:38 -07004009 case focusKey:
4010 focus_on_selection ^= true;
4011 setScale(xmin, xmax, ymin, ymax);
4012 redraw();
4013 break;
caryclarkdac1d172014-06-17 05:15:38 -07004014 case idKey:
4015 draw_id ^= true;
4016 redraw();
4017 break;
4018 case intersectionBackKey:
4019 draw_intersection = (draw_intersection + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07004020 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004021 break;
4022 case intersectionKey:
4023 draw_intersection = (draw_intersection + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07004024 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004025 break;
4026 case intersectTKey:
4027 draw_intersectT ^= true;
4028 redraw();
4029 break;
4030 case logCurvesKey:
4031 logCurves(tests[testIndex]);
4032 break;
4033 case logKey:
4034 draw_log ^= true;
4035 redraw();
4036 break;
4037 case logToConsoleKey:
4038 if (draw_log) {
4039 dumpLogToConsole();
4040 }
4041 break;
4042 case markKey:
4043 draw_mark ^= true;
4044 redraw();
4045 break;
4046 case midpointKey:
4047 draw_midpoint ^= true;
4048 redraw();
4049 break;
4050 case opKey:
4051 draw_op = (draw_op + 1) % 3;
4052 redraw();
4053 break;
4054 case opBackKey:
4055 draw_op = (draw_op + 2) % 3;
4056 redraw();
4057 break;
4058 case pathKey:
caryclark26ad22a2015-10-16 09:03:38 -07004059 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004060 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004061 break;
4062 case pathBackKey:
caryclark26ad22a2015-10-16 09:03:38 -07004063 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004064 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004065 break;
4066 case ptsKey:
4067 pt_labels = (pt_labels + 1) % 3;
4068 redraw();
4069 break;
4070 case retinaKey:
4071 retina_scale ^= true;
4072 drawTop();
4073 break;
4074 case sequenceKey:
4075 draw_sequence ^= true;
4076 redraw();
4077 break;
4078 case sortKey:
4079 draw_sort = (draw_sort + 1) % 3;
4080 drawTop();
4081 break;
4082 case stepKey:
4083 step_limit++;
4084 if (step_limit > stepMax) {
4085 step_limit = stepMax;
4086 }
4087 redraw();
4088 break;
4089 case stepBackKey:
4090 step_limit--;
4091 if (step_limit < 0) {
4092 step_limit = 0;
4093 }
4094 redraw();
4095 break;
caryclark03b03ca2015-04-23 09:13:37 -07004096 case topKey:
4097 draw_top ^= true;
4098 redraw();
4099 break;
caryclarkdac1d172014-06-17 05:15:38 -07004100 case xyKey:
4101 debug_xy = (debug_xy + 1) % 3;
4102 redraw();
4103 break;
4104 case '-':
4105 focusWasOn = focus_on_selection;
4106 if (focusWasOn) {
4107 focus_on_selection = false;
4108 scale /= 1.2;
4109 } else {
4110 scale /= 2;
4111 calcLeftTop();
4112 }
4113 redraw();
4114 focus_on_selection = focusWasOn;
4115 break;
4116 case '=':
4117 case '+':
4118 focusWasOn = focus_on_selection;
4119 if (focusWasOn) {
4120 focus_on_selection = false;
4121 scale *= 1.2;
4122 } else {
4123 scale *= 2;
4124 calcLeftTop();
4125 }
4126 redraw();
4127 focus_on_selection = focusWasOn;
4128 break;
4129 case '?':
4130 draw_hints ^= true;
4131 if (draw_hints && !draw_legend) {
4132 draw_legend = true;
4133 }
4134 redraw();
4135 break;
4136 case '/':
4137 draw_legend ^= true;
4138 redraw();
4139 break;
4140 }
4141}
4142
4143function doKeyDown(evt) {
4144 var char = evt.keyCode;
4145 var preventDefault = false;
4146 switch (char) {
4147 case 37: // left arrow
4148 if (evt.shiftKey) {
4149 testIndex -= 9;
4150 }
4151 if (--testIndex < 0)
4152 testIndex = tests.length - 1;
4153 drawTop();
4154 preventDefault = true;
4155 break;
4156 case 39: // right arrow
4157 if (evt.shiftKey) {
4158 testIndex += 9;
4159 }
4160 if (++testIndex >= tests.length)
4161 testIndex = 0;
4162 drawTop();
4163 preventDefault = true;
4164 break;
4165 }
4166 if (preventDefault) {
4167 evt.preventDefault();
4168 return false;
4169 }
4170 return true;
4171}
4172
4173(function() {
4174 var hidden = "hidden";
4175
4176 // Standards:
4177 if (hidden in document)
4178 document.addEventListener("visibilitychange", onchange);
4179 else if ((hidden = "mozHidden") in document)
4180 document.addEventListener("mozvisibilitychange", onchange);
4181 else if ((hidden = "webkitHidden") in document)
4182 document.addEventListener("webkitvisibilitychange", onchange);
4183 else if ((hidden = "msHidden") in document)
4184 document.addEventListener("msvisibilitychange", onchange);
4185 // IE 9 and lower:
4186 else if ('onfocusin' in document)
4187 document.onfocusin = document.onfocusout = onchange;
4188 // All others:
4189 else
caryclark55888e42016-07-18 10:01:36 -07004190 window.onpageshow = window.onpagehide
caryclarkdac1d172014-06-17 05:15:38 -07004191 = window.onfocus = window.onblur = onchange;
4192
4193 function onchange (evt) {
4194 var v = 'visible', h = 'hidden',
caryclark55888e42016-07-18 10:01:36 -07004195 evtMap = {
4196 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
caryclarkdac1d172014-06-17 05:15:38 -07004197 };
4198
4199 evt = evt || window.event;
4200 if (evt.type in evtMap)
4201 document.body.className = evtMap[evt.type];
caryclark55888e42016-07-18 10:01:36 -07004202 else
caryclarkdac1d172014-06-17 05:15:38 -07004203 document.body.className = this[hidden] ? "hidden" : "visible";
4204 }
4205})();
4206
4207function calcXY() {
4208 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07004209 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07004210 var left = tgt.offsetLeft;
4211 var top = tgt.offsetTop;
4212 mouseX = (e.clientX - left) / scale + srcLeft;
4213 mouseY = (e.clientY - top) / scale + srcTop;
4214}
4215
4216function calcLeftTop() {
4217 srcLeft = mouseX - screenWidth / 2 / scale;
4218 srcTop = mouseY - screenHeight / 2 / scale;
4219}
4220
4221var disableClick = false;
4222
4223function handleMouseClick() {
4224 if (disableClick) {
4225 return;
4226 }
4227 if (!curve_t || !ptInTControl()) {
4228 calcXY();
4229 calcLeftTop();
4230 }
4231 redraw();
4232// if (!curve_t || !ptInTControl()) {
4233// mouseX = screenWidth / 2 / scale + srcLeft;
4234// mouseY = screenHeight / 2 / scale + srcTop;
4235// }
4236}
4237
4238function handleMouseOver() {
4239 calcXY();
4240 if (debug_xy != 2) {
4241 return;
4242 }
4243 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
4244 ctx.beginPath();
4245 ctx.rect(300,100,num.length * 6,10);
4246 ctx.fillStyle="white";
4247 ctx.fill();
4248 ctx.font = "normal 10px Arial";
4249 ctx.fillStyle="black";
4250 ctx.textAlign = "left";
4251 ctx.fillText(num, 300, 108);
4252}
4253
4254function start() {
4255 for (var i = 0; i < testDivs.length; ++i) {
4256 tests[i] = null;
4257 }
4258 testIndex = 0;
4259 drawTop();
4260 window.addEventListener('keypress', doKeyPress, true);
4261 window.addEventListener('keydown', doKeyDown, true);
4262 window.onresize = function() {
4263 drawTop();
4264 }
4265 /*
4266 window.onpagehide = function() {
4267 disableClick = true;
4268 }
4269 */
4270 window.onpageshow = function () {
4271 disableClick = false;
4272 }
4273}
4274
4275</script>
4276</head>
4277
4278<body onLoad="start();">
4279<canvas id="canvas" width="750" height="500"
4280 onmousemove="handleMouseOver()"
4281 onclick="handleMouseClick()"
4282 ></canvas >
4283</body>
4284</html>