blob: ca520cd363fa3137c279192283ca8a588423df5d [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 Clarkcadc5062018-08-06 17:24:04 -04005<div id="op_4">
6seg=1 {{{6.74738312f, 1.29324913f}, {5.41376638f, 1.29324913f}}}
7seg=2 {{{5.41376638f, 1.29324913f}, {5.41376638f, 0.429016858f}}}
8seg=3 {{{5.41376638f, 0.429016858f}, {7.88304138f, 0.429016858f}}}
9seg=4 {{{7.88304138f, 0.429016858f}, {7.88304138f, 0.732369661f}}}
10seg=5 {{{7.88304138f, 0.732369661f}, {6.74738312f, 0.732369661f}}}
11seg=6 {{{6.74738312f, 0.732369661f}, {6.74738312f, 1.29324913f}}}
12op diff
13seg=7 {{{6.74737978f, 4.82642984f}, {9.66343975f, 4.82642984f}}}
14seg=8 {{{9.66343975f, 4.82642984f}, {9.66343975f, 0.732370019f}}}
15seg=9 {{{9.66343975f, 0.732370019f}, {6.74737978f, 0.732370019f}}}
16seg=10 {{{6.74737978f, 0.732370019f}, {6.74737978f, 4.82642984f}}}
17debugShowLineIntersection wtTs[0]=0 {{{5.41376638,1.29324913}, {5.41376638,0.429016858}}} {{5.41376638,1.29324913}} wnTs[0]=1 {{{6.74738312,1.29324913}, {5.41376638,1.29324913}}}
18debugShowLineIntersection wtTs[0]=1 {{{6.74738312,0.732369661}, {6.74738312,1.29324913}}} {{6.74738312,1.29324913}} wnTs[0]=0 {{{6.74738312,1.29324913}, {5.41376638,1.29324913}}}
19debugShowLineIntersection wtTs[0]=0 {{{5.41376638,0.429016858}, {7.88304138,0.429016858}}} {{5.41376638,0.429016858}} wnTs[0]=1 {{{5.41376638,1.29324913}, {5.41376638,0.429016858}}}
20debugShowLineIntersection wtTs[0]=0 {{{7.88304138,0.429016858}, {7.88304138,0.732369661}}} {{7.88304138,0.429016858}} wnTs[0]=1 {{{5.41376638,0.429016858}, {7.88304138,0.429016858}}}
21debugShowLineIntersection wtTs[0]=0 {{{7.88304138,0.732369661}, {6.74738312,0.732369661}}} {{7.88304138,0.732369661}} wnTs[0]=1 {{{7.88304138,0.429016858}, {7.88304138,0.732369661}}}
22debugShowLineIntersection wtTs[0]=0 {{{6.74738312,0.732369661}, {6.74738312,1.29324913}}} {{6.74738312,0.732369661}} wnTs[0]=1 {{{7.88304138,0.732369661}, {6.74738312,0.732369661}}}
23debugShowLineIntersection wtTs[0]=0.13699827 {{{6.74737978,0.732370019}, {6.74737978,4.82642984}}} {{6.74737978,1.29324913}} wnTs[0]=2.50286e-06 {{{6.74738312,1.29324913}, {5.41376638,1.29324913}}}
24SkOpSegment::addT insert t=0.13699827 segID=10 spanID=21
25debugShowLineIntersection no intersect {{{9.66343975,0.732370019}, {6.74737978,0.732370019}}} {{{7.88304138,0.429016858}, {7.88304138,0.732369661}}}
26debugShowLineIntersection no intersect {{{9.66343975,0.732370019}, {6.74737978,0.732370019}}} {{{7.88304138,0.732369661}, {6.74738312,0.732369661}}}
27debugShowLineIntersection no intersect {{{6.74737978,0.732370019}, {6.74737978,4.82642984}}} {{{7.88304138,0.732369661}, {6.74738312,0.732369661}}}
28debugShowLineIntersection wtTs[0]=0.999998855 {{{9.66343975,0.732370019}, {6.74737978,0.732370019}}} {{6.74738312,0.732370019}} wnTs[0]=6.3762e-07 {{{6.74738312,0.732369661}, {6.74738312,1.29324913}}}
29debugShowLineIntersection no intersect {{{6.74737978,0.732370019}, {6.74737978,4.82642984}}} {{{6.74738312,0.732369661}, {6.74738312,1.29324913}}}
30debugShowLineIntersection wtTs[0]=0 {{{9.66343975,4.82642984}, {9.66343975,0.732370019}}} {{9.66343975,4.82642984}} wnTs[0]=1 {{{6.74737978,4.82642984}, {9.66343975,4.82642984}}}
31debugShowLineIntersection wtTs[0]=1 {{{6.74737978,0.732370019}, {6.74737978,4.82642984}}} {{6.74737978,4.82642984}} wnTs[0]=0 {{{6.74737978,4.82642984}, {9.66343975,4.82642984}}}
32debugShowLineIntersection wtTs[0]=0 {{{9.66343975,0.732370019}, {6.74737978,0.732370019}}} {{9.66343975,0.732370019}} wnTs[0]=1 {{{9.66343975,4.82642984}, {9.66343975,0.732370019}}}
33debugShowLineIntersection wtTs[0]=0 {{{6.74737978,0.732370019}, {6.74737978,4.82642984}}} {{6.74737978,0.732370019}} wnTs[0]=1 {{{9.66343975,0.732370019}, {6.74737978,0.732370019}}}
34-----------------------x-------------- addExpanded
3500: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
3601: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
3702: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
3803: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
39SkOpSegment::debugShowActiveSpans id=1 (6.74738312,1.29324913 5.41376638,1.29324913) t=0 tEnd=1 windSum=? windValue=1
40SkOpSegment::debugShowActiveSpans id=2 (5.41376638,1.29324913 5.41376638,0.429016858) t=0 tEnd=1 windSum=? windValue=1
41SkOpSegment::debugShowActiveSpans id=3 (5.41376638,0.429016858 7.88304138,0.429016858) t=0 tEnd=1 windSum=? windValue=1
42SkOpSegment::debugShowActiveSpans id=4 (7.88304138,0.429016858 7.88304138,0.732369661) t=0 tEnd=1 windSum=? windValue=1
43SkOpSegment::debugShowActiveSpans id=5 (7.88304138,0.732369661 6.74738312,0.732369661) t=0 tEnd=1 windSum=? windValue=1
44SkOpSegment::debugShowActiveSpans id=6 (6.74738312,0.732369661 6.74738312,1.29324913) t=0 tEnd=1 windSum=? windValue=1
45SkOpSegment::debugShowActiveSpans id=7 (6.74737978,4.82642984 9.66343975,4.82642984) t=0 tEnd=1 windSum=? windValue=1
46SkOpSegment::debugShowActiveSpans id=8 (9.66343975,4.82642984 9.66343975,0.732370019) t=0 tEnd=1 windSum=? windValue=1
47SkOpSegment::debugShowActiveSpans id=9 (9.66343975,0.732370019 6.74737978,0.732370019) t=0 tEnd=1 windSum=? windValue=1
48SkOpSegment::debugShowActiveSpans id=10 (6.74737978,0.732370019 6.74737978,1.29324913) t=0 tEnd=0.13699827 windSum=? windValue=1
49SkOpSegment::debugShowActiveSpans id=10 (6.74737978,1.29324913 6.74737978,4.82642984) t=0.13699827 tEnd=1 windSum=? windValue=1
50-----------------------x-------------- move_multiples
5100: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
5201: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
5302: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
5403: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
55-----------------------x-------------- move_nearby
5600: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
5701: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
5802: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
5903: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
60-----------------------x-------------- correctEnds
6100: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
6201: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
6302: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
6403: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
65-----------------------x-------------- addEndMovedSpans
6600: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
6701: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
6802: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
6903: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
70-----------------------x-------------- expand
7100: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
7201: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
7302: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
7403: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
75-----------------------x-------------- addExpanded
7600: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
7701: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
7802: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
7903: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
80-----------------------x-------------- mark
8100: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
8201: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
8302: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
8403: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
85-----------------------x-------------- missing_coincidence
8600: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
8701: coinSeg/Span/PtT=10/19/19 endSpan=21 oppSeg/Span/PtT=6/11/11 oppEndSpan=12 MissingCoin
8802: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
8903: coinSeg/Span/PtT=6/11/11 endSpan=12 oppSeg/Span/PtT=10/19/19 oppEndSpan=21 MissingCoin
90SkOpSegment::missingCoincidence coinSpan=19 endSpan=21 oppSpan=11 oppEndSpan=12
91------------------x--x---------------- expand
9200: seg/base=10/19 seg/base=6/11 MarkCoinStart
9301: seg/base=10/21 seg/base=6/12 MarkCoinEnd
94------------------x--x---------------- addExpanded
9500: seg/base=10/19 seg/base=6/11 MarkCoinStart
9601: seg/base=10/21 seg/base=6/12 MarkCoinEnd
97------------------x--x---------------- mark
9800: seg/base=10/19 seg/base=6/11 MarkCoinStart
9901: seg/base=10/21 seg/base=6/12 MarkCoinEnd
Cary Clark3a4a3212018-06-06 15:22:08 -0400100-------------------------------------- expand
101-------------------------------------- apply
Cary Clarkcadc5062018-08-06 17:24:04 -0400102SkOpSegment::markDone id=6 (6.74738312,0.732369661 6.74738312,1.29324913) t=0 [11] (6.74738312,0.732369661) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
Cary Clark3a4a3212018-06-06 15:22:08 -0400103-------------------------------------- findOverlaps
Cary Clarkcadc5062018-08-06 17:24:04 -0400104SkOpSegment::debugShowActiveSpans id=1 (6.74738312,1.29324913 5.41376638,1.29324913) t=0 tEnd=1 windSum=? windValue=1
105SkOpSegment::debugShowActiveSpans id=2 (5.41376638,1.29324913 5.41376638,0.429016858) t=0 tEnd=1 windSum=? windValue=1
106SkOpSegment::debugShowActiveSpans id=3 (5.41376638,0.429016858 7.88304138,0.429016858) t=0 tEnd=1 windSum=? windValue=1
107SkOpSegment::debugShowActiveSpans id=4 (7.88304138,0.429016858 7.88304138,0.732369661) t=0 tEnd=1 windSum=? windValue=1
108SkOpSegment::debugShowActiveSpans id=5 (7.88304138,0.732369661 6.74738312,0.732369661) t=0 tEnd=1 windSum=? windValue=1
109SkOpSegment::debugShowActiveSpans id=7 (6.74737978,4.82642984 9.66343975,4.82642984) t=0 tEnd=1 windSum=? windValue=1
110SkOpSegment::debugShowActiveSpans id=8 (9.66343975,4.82642984 9.66343975,0.732370019) t=0 tEnd=1 windSum=? windValue=1
111SkOpSegment::debugShowActiveSpans id=9 (9.66343975,0.732370019 6.74737978,0.732370019) t=0 tEnd=1 windSum=? windValue=1
112SkOpSegment::debugShowActiveSpans id=10 (6.74737978,0.732370019 6.74737978,1.29324913) t=0 tEnd=0.13699827 windSum=? oppSum=? windValue=1 oppValue=1
113SkOpSegment::debugShowActiveSpans id=10 (6.74737978,1.29324913 6.74737978,4.82642984) t=0.13699827 tEnd=1 windSum=? windValue=1
Cary Clark3a4a3212018-06-06 15:22:08 -0400114-------------------------------------- calc_angles
Cary Clarkcadc5062018-08-06 17:24:04 -0400115SkOpSegment::sortAngles [1] tStart=0 [1]
116SkOpAngle::after [1/1] 15/15 tStart=0 tEnd=1 < [10/6] 23/23 tStart=0.13699827 tEnd=1 < [10/5] 7/7 tStart=0.13699827 tEnd=0 T 4
117SkOpAngle::afterPart {{{6.74737978,1.29324913}, {5.41376305,1.29324913}}} id=1
118SkOpAngle::afterPart {{{6.74737978,1.29324913}, {6.74737978,4.82642984}}} id=10
119SkOpAngle::afterPart {{{6.74737978,1.29324913}, {6.74737978,0.732370019}}} id=10
Cary Clark1d314432018-07-10 10:57:54 -0400120SkOpSegment::sortAngles [5] tStart=1 [10]
Cary Clarkcadc5062018-08-06 17:24:04 -0400121SkOpAngle::after [5/2] 31/31 tStart=1 tEnd=0 < [10/4] 23/23 tStart=0 tEnd=0.13699827 < [9/3] 31/31 tStart=1 tEnd=0 F 5
122SkOpAngle::afterPart {{{6.74737978,0.732370019}, {7.88303804,0.732370019}}} id=5
123SkOpAngle::afterPart {{{6.74737978,0.732370019}, {6.74737978,1.29324913}}} id=10
124SkOpAngle::afterPart {{{6.74737978,0.732370019}, {9.66343975,0.732370019}}} id=9
125SkOpSegment::sortAngles [9] tStart=1 [18]
126SkOpSegment::sortAngles [10] tStart=0 [19]
127SkOpSegment::sortAngles [10] tStart=0.13699827 [21]
128coinSpan - id=10 t=0 tEnd=0.13699827
129coinSpan + id=6 t=0 tEnd=1
130SkOpSpan::sortableTop dir=kTop seg=1 t=0.5 pt=(6.08057499,1.29324913)
131SkOpSpan::sortableTop [0] valid=1 operand=0 span=5 ccw=1 seg=3 {{{5.41376638f, 0.429016858f}, {7.88304138f, 0.429016858f}}} t=0.270042262 pt=(6.08057499,0.429016858) slope=(2.469275,0)
132SkOpSpan::sortableTop [1] valid=1 operand=0 span=1 ccw=0 seg=1 {{{6.74738312f, 1.29324913f}, {5.41376638f, 1.29324913f}}} t=0.5 pt=(6.08057499,1.29324913) slope=(-1.33361673,0)
133SkOpSegment::markWinding id=3 (5.41376638,0.429016858 7.88304138,0.429016858) t=0 [5] (5.41376638,0.429016858) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
134SkOpSegment::markWinding id=4 (7.88304138,0.429016858 7.88304138,0.732369661) t=0 [7] (7.88304138,0.429016858) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
135SkOpSegment::markWinding id=5 (7.88304138,0.732369661 6.74738312,0.732369661) t=0 [9] (7.88304138,0.732369661) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
136SkOpSegment::markWinding id=3 (5.41376638,0.429016858 7.88304138,0.429016858) t=0 [5] (5.41376638,0.429016858) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
137SkOpSegment::markWinding id=2 (5.41376638,1.29324913 5.41376638,0.429016858) t=0 [3] (5.41376638,1.29324913) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
138SkOpSegment::markWinding id=1 (6.74738312,1.29324913 5.41376638,1.29324913) t=0 [1] (6.74738312,1.29324913) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
139SkOpSegment::activeOp id=1 t=1 tEnd=0 op=diff miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
140SkOpSegment::markWinding id=10 (6.74737978,0.732370019 6.74737978,4.82642984) t=0.13699827 [21] (6.74737978,1.29324913) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
141SkOpSegment::markWinding id=7 (6.74737978,4.82642984 9.66343975,4.82642984) t=0 [13] (6.74737978,4.82642984) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
142SkOpSegment::markWinding id=8 (9.66343975,4.82642984 9.66343975,0.732370019) t=0 [15] (9.66343975,4.82642984) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
143SkOpSegment::markWinding id=9 (9.66343975,0.732370019 6.74737978,0.732370019) t=0 [17] (9.66343975,0.732370019) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
144SkOpSegment::markAngle last segment=9 span=18
145SkOpSegment::markWinding id=10 (6.74737978,0.732370019 6.74737978,4.82642984) t=0 [19] (6.74737978,0.732370019) tEnd=0.13699827 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1
146SkOpSegment::markAngle last segment=10 span=19 windSum=1
147SkOpSegment::findNextOp
148SkOpAngle::dumpOne [1/1] next=10/6 sect=15/15 s=0 [1] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
149SkOpAngle::dumpOne [10/6] next=10/5 sect=23/23 s=0.13699827 [21] e=1 [20] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
150SkOpAngle::dumpOne [10/5] next=1/1 sect=7/7 s=0.13699827 [21] e=0 [19] sgn=1 windVal=1 windSum=1 oppVal=1 oppSum=-1 operand
151SkOpSegment::activeOp id=10 t=0.13699827 tEnd=1 op=diff miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
152SkOpSegment::markDone id=10 (6.74737978,0.732370019 6.74737978,4.82642984) t=0.13699827 [21] (6.74737978,1.29324913) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
153SkOpSegment::markDone id=7 (6.74737978,4.82642984 9.66343975,4.82642984) t=0 [13] (6.74737978,4.82642984) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
154SkOpSegment::markDone id=8 (9.66343975,4.82642984 9.66343975,0.732370019) t=0 [15] (9.66343975,4.82642984) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
155SkOpSegment::markDone id=9 (9.66343975,0.732370019 6.74737978,0.732370019) t=0 [17] (9.66343975,0.732370019) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
156SkOpSegment::findNextOp chase.append segment=9 span=18
157SkOpSegment::activeOp id=10 t=0.13699827 tEnd=0 op=diff miFrom=0 miTo=1 suFrom=1 suTo=0 result=1
158SkOpSegment::findNextOp chase.append segment=10 span=19 windSum=1
159SkOpSegment::markDone id=1 (6.74738312,1.29324913 5.41376638,1.29324913) t=0 [1] (6.74738312,1.29324913) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
160SkOpSegment::findNextOp from:[1] to:[10] start=-1039144456 end=-1039144768
161bridgeOp current id=1 from=(5.41376638,1.29324913) to=(6.74738312,1.29324913)
162SkOpSegment::findNextOp
163SkOpAngle::dumpOne [10/4] next=5/2 sect=23/23 s=0 [19] e=0.13699827 [21] sgn=-1 windVal=1 windSum=1 oppVal=1 oppSum=-1 operand
164SkOpAngle::dumpOne [5/2] next=9/3 sect=31/31 s=1 [10] e=0 [9] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 unorderable
165SkOpAngle::dumpOne [9/3] next=10/4 sect=31/31 s=1 [18] e=0 [17] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done unorderable operand
166SkOpSegment::activeOp id=5 t=1 tEnd=0 op=diff miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
167SkOpSegment::markDone id=5 (7.88304138,0.732369661 6.74738312,0.732369661) t=0 [9] (7.88304138,0.732369661) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
168SkOpSegment::markDone id=4 (7.88304138,0.429016858 7.88304138,0.732369661) t=0 [7] (7.88304138,0.429016858) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
169SkOpSegment::markDone id=3 (5.41376638,0.429016858 7.88304138,0.429016858) t=0 [5] (5.41376638,0.429016858) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
170SkOpSegment::markDone id=2 (5.41376638,1.29324913 5.41376638,0.429016858) t=0 [3] (5.41376638,1.29324913) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
171SkOpSegment::activeOp id=9 t=1 tEnd=0 op=diff miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
172SkOpSegment::markDone id=10 (6.74737978,0.732370019 6.74737978,4.82642984) t=0 [19] (6.74737978,0.732370019) tEnd=0.13699827 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=1
173SkOpSegment::findNextOp from:[10] to:[9] start=-1039144952 end=-1039145096
174bridgeOp current id=10 from=(6.74737978,1.29324913) to=(6.74737978,0.732370019)
175path.moveTo(5.41376638,1.29324913);
176path.lineTo(6.74738312,1.29324913);
177path.lineTo(6.74737978,0.732370019);
Cary Clark1d314432018-07-10 10:57:54 -0400178</div>
179
caryclarkdac1d172014-06-17 05:15:38 -0700180</div>
181
182<script type="text/javascript">
183
caryclark55888e42016-07-18 10:01:36 -0700184 var testDivs = [
Cary Clarkcadc5062018-08-06 17:24:04 -0400185 op_4,
caryclark30b9fdd2016-08-31 14:36:29 -0700186 ];
caryclarkdac1d172014-06-17 05:15:38 -0700187
188var decimal_places = 3; // make this 3 to show more precision
189
190var tests = [];
191var testLines = [];
192var testTitles = [];
193var testIndex = 0;
194var ctx;
195
196var xmin, xmax, focusXmin, focusXmax;
197var ymin, ymax, focusYmin, focusYmax;
198var scale;
199var mouseX, mouseY;
200var srcLeft, srcTop;
201var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700202var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700203var curveT = 0;
204
205var pt_labels = 2;
206var collect_bounds = false;
207var control_lines = 0;
208var curve_t = false;
209var debug_xy = 1;
210var focus_enabled = false;
211var focus_on_selection = false;
212var step_limit = 0;
213var draw_active = false;
214var draw_add = false;
215var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700216var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700217var draw_deriviatives = 0;
Cary Clarkff114282016-12-14 11:56:16 -0500218var draw_direction = false;
caryclarkdac1d172014-06-17 05:15:38 -0700219var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700220var draw_id = false;
221var draw_intersection = 0;
222var draw_intersectT = false;
223var draw_legend = true;
224var draw_log = false;
225var draw_mark = false;
226var draw_midpoint = false;
227var draw_op = 0;
228var draw_sequence = false;
229var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700230var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700231var draw_path = 3;
232var draw_computed = 0;
233var retina_scale = !!window.devicePixelRatio;
234
235var activeCount = 0;
236var addCount = 0;
237var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700238var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700239var opCount = 0;
240var sectCount = 0;
241var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700242var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700243var markCount = 0;
244var activeMax = 0;
245var addMax = 0;
246var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700247var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700248var sectMax = 0;
249var sectMax2 = 0;
250var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700251var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700252var markMax = 0;
253var opMax = 0;
254var stepMax = 0;
255var lastIndex = 0;
256var hasPath = false;
caryclark26ad22a2015-10-16 09:03:38 -0700257var hasAlignedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700258var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700259var angleBetween = false;
260var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700261
262var firstActiveSpan = -1;
263var logStart = -1;
264var logRange = 0;
265
266var SPAN_ID = 0;
267var SPAN_X1 = SPAN_ID + 1;
268var SPAN_Y1 = SPAN_X1 + 1;
269var SPAN_X2 = SPAN_Y1 + 1;
270var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700271
caryclark55888e42016-07-18 10:01:36 -0700272var SPAN_L_TX = SPAN_Y2 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700273var SPAN_L_TY = SPAN_L_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700274var SPAN_L_OTHER = SPAN_L_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700275var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
276var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
277var SPAN_L_SUM = SPAN_L_OTHERI + 1;
278var SPAN_L_VAL = SPAN_L_SUM + 1;
279var SPAN_L_OPP = SPAN_L_VAL + 1;
280
281var SPAN_X3 = SPAN_Y2 + 1;
282var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700283
caryclark55888e42016-07-18 10:01:36 -0700284var SPAN_Q_TX = SPAN_Y3 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700285var SPAN_Q_TY = SPAN_Q_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700286var SPAN_Q_OTHER = SPAN_Q_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700287var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
288var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
289var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
290var SPAN_Q_VAL = SPAN_Q_SUM + 1;
291var SPAN_Q_OPP = SPAN_Q_VAL + 1;
292
caryclark1049f122015-04-20 08:31:59 -0700293var SPAN_K_W = SPAN_Y3 + 1;
caryclark55888e42016-07-18 10:01:36 -0700294var SPAN_K_TX = SPAN_K_W + 1;
caryclark1049f122015-04-20 08:31:59 -0700295var SPAN_K_TY = SPAN_K_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700296var SPAN_K_OTHER = SPAN_K_TY + 1;
caryclark1049f122015-04-20 08:31:59 -0700297var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
298var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
299var SPAN_K_SUM = SPAN_K_OTHERI + 1;
300var SPAN_K_VAL = SPAN_K_SUM + 1;
301var SPAN_K_OPP = SPAN_K_VAL + 1;
302
caryclarkdac1d172014-06-17 05:15:38 -0700303var SPAN_X4 = SPAN_Y3 + 1;
304var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700305
caryclark55888e42016-07-18 10:01:36 -0700306var SPAN_C_TX = SPAN_Y4 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700307var SPAN_C_TY = SPAN_C_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700308var SPAN_C_OTHER = SPAN_C_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700309var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
310var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
311var SPAN_C_SUM = SPAN_C_OTHERI + 1;
312var SPAN_C_VAL = SPAN_C_SUM + 1;
313var SPAN_C_OPP = SPAN_C_VAL + 1;
314
315var ACTIVE_LINE_SPAN = 1;
316var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700317var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
318var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700319
320var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
321var ADD_LINETO = ADD_MOVETO + 1;
322var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700323var ADD_CONICTO = ADD_QUADTO + 1;
324var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700325var ADD_CLOSE = ADD_CUBICTO + 1;
326var ADD_FILL = ADD_CLOSE + 1;
327
328var PATH_LINE = ADD_FILL + 1;
329var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700330var PATH_CONIC = PATH_QUAD + 1;
331var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700332
333var INTERSECT_LINE = PATH_CUBIC + 1;
334var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
335var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
336var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
337var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
338var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
339var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
340var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
341var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700342var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
343var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
344var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
caryclark55888e42016-07-18 10:01:36 -0700345var INTERSECT_CONIC_QUAD = INTERSECT_CONIC_LINE_NO + 1;
346var INTERSECT_CONIC_QUAD_2 = INTERSECT_CONIC_QUAD + 1;
caryclark6c3b9cd2016-09-26 05:36:58 -0700347var INTERSECT_CONIC_QUAD_3 = INTERSECT_CONIC_QUAD_2 + 1;
348var INTERSECT_CONIC_QUAD_4 = INTERSECT_CONIC_QUAD_3 + 1;
349var INTERSECT_CONIC_QUAD_NO = INTERSECT_CONIC_QUAD_4 + 1;
caryclark55888e42016-07-18 10:01:36 -0700350var INTERSECT_CONIC = INTERSECT_CONIC_QUAD_NO + 1;
caryclark1049f122015-04-20 08:31:59 -0700351var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
352var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
353var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700354var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
355var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
356var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
357var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
358var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
359var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
360var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
361var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
362var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
363var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
364var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
365var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
366var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
367var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
368// FIXME: add cubic 5- 9
369var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
370
371var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
372var SORT_BINARY = SORT_UNARY + 1;
373
374var OP_DIFFERENCE = SORT_BINARY + 1;
375var OP_INTERSECT = OP_DIFFERENCE + 1;
376var OP_UNION = OP_INTERSECT + 1;
377var OP_XOR = OP_UNION + 1;
378
379var MARK_LINE = OP_XOR + 1;
380var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700381var MARK_CONIC = MARK_QUAD + 1;
382var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700383var MARK_DONE_LINE = MARK_CUBIC + 1;
384var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700385var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
386var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700387var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
388var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700389var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
390var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700391var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
392var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700393var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
394var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700395var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
396var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700397var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
398var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700399var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
400var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700401var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
402var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700403var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
404
405var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
406var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
407
caryclark624637c2015-05-11 07:21:27 -0700408var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700409var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700410
caryclark54359292015-03-26 07:52:43 -0700411var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700412
caryclark624637c2015-05-11 07:21:27 -0700413var COIN_MAIN_SPAN = ACTIVE_OP + 1;
414var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
415
416var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700417
418var REC_TYPE_UNKNOWN = -1;
419var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700420var REC_TYPE_PATH2 = 1;
421var REC_TYPE_SECT = 2;
422var REC_TYPE_ACTIVE = 3;
423var REC_TYPE_ADD = 4;
424var REC_TYPE_SORT = 5;
425var REC_TYPE_OP = 6;
426var REC_TYPE_MARK = 7;
427var REC_TYPE_COMPUTED = 8;
428var REC_TYPE_COIN = 9;
429var REC_TYPE_ANGLE = 10;
430var REC_TYPE_ACTIVE_OP = 11;
431var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700432var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700433var REC_TYPE_COINCIDENCE = 14;
caryclark26ad22a2015-10-16 09:03:38 -0700434var REC_TYPE_ALIGNED = 15;
435var REC_TYPE_LAST = REC_TYPE_ALIGNED;
caryclarkdac1d172014-06-17 05:15:38 -0700436
437function strs_to_nums(strs) {
438 var result = [];
439 for (var idx = 1; idx < strs.length; ++idx) {
440 var str = strs[idx];
441 var num = parseFloat(str);
442 if (isNaN(num)) {
443 result.push(str);
444 } else {
445 result.push(num);
446 }
447 }
448 return result;
449}
450
451function filter_str_by(id, str, regex, array) {
452 if (regex.test(str)) {
453 var strs = regex.exec(str);
454 var result = strs_to_nums(strs);
455 array.push(id);
456 array.push(result);
457 return true;
458 }
459 return false;
460}
461
462function construct_regexp2(pattern) {
463 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
464 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
465 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700466 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700467 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
468 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
469 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700470 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700471 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
472 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
473 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700474 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700475 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700476 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700477 escape = escape.replace(/NUM/g, "(-?\\d+)");
478 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
479 return new RegExp(escape, 'i');
480}
481
482function construct_regexp2c(pattern) {
483 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
484 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700485 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700486 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700487 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
488 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700489 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700490 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700491 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700492 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 -0700493 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700494 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700495 escape = escape.replace(/OPER/g, "[a-z]+");
496 escape = escape.replace(/PATH/g, "pathB?");
497 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700498 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700499 escape = escape.replace(/NUM/g, "(-?\\d+)");
500 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
501 return new RegExp(escape, 'i');
502}
503
504function match_regexp(str, lineNo, array, id, pattern) {
505 var regex = construct_regexp2(pattern);
506 if (filter_str_by(id, str, regex, array)) {
507 return true;
508 }
509 regex = construct_regexp2c(pattern);
510 return filter_str_by(id, str, regex, array);
511}
512
513function endsWith(str, suffix) {
514 return str.indexOf(suffix, str.length - suffix.length) !== -1;
515}
516
517function parse_all(test) {
518 var lines = test.match(/[^\r\n]+/g);
519 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
520 var record = [];
521 var recType = REC_TYPE_UNKNOWN;
522 var lastLineNo;
523 var moveX, moveY;
524 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
525 var line = lines[lineNo];
526 if (line.length == 0) {
527 continue;
528 }
529 var opStart = "SkOpSegment::";
530 if (line.lastIndexOf(opStart, 0) === 0) {
531 line = line.substr(opStart.length);
532 }
533 var angleStart = "SkOpAngle::";
534 if (line.lastIndexOf(angleStart, 0) === 0) {
535 line = line.substr(angleStart.length);
536 }
caryclark624637c2015-05-11 07:21:27 -0700537 var coinStart = "SkOpCoincidence::";
538 if (line.lastIndexOf(coinStart, 0) === 0) {
539 line = line.substr(coinStart.length);
540 }
caryclark54359292015-03-26 07:52:43 -0700541 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700542 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700543 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclark55888e42016-07-18 10:01:36 -0700544 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700545 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700546 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
547 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
548 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
549 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
caryclark26ad22a2015-10-16 09:03:38 -0700550 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
caryclarkdac1d172014-06-17 05:15:38 -0700551 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700552 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700553 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
554 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
Cary Clark59d5a0e2017-01-23 14:38:52 +0000555 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
caryclarkdac1d172014-06-17 05:15:38 -0700556 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
557 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700558 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700559 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
560 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
561 : REC_TYPE_UNKNOWN;
562 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
563 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
564 if (recType != REC_TYPE_UNKNOWN) {
565 records.push(recType);
566 records.push(lastLineNo);
567 records.push(record);
568 }
569 record = [];
570 recType = type;
571 lastLineNo = lineNo;
572 }
573 var found = false;
574 switch (recType) {
575 case REC_TYPE_ACTIVE:
576 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700577" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700578 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700579" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700580 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700581" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700582 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700583" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark624637c2015-05-11 07:21:27 -0700584 ) || 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 oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -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 oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -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 oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -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 oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700592 );
593 break;
594 case REC_TYPE_ACTIVE_OP:
595 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
596" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
597 );
598 break;
599 case REC_TYPE_ADD:
600 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
601 moveX = record[1][0];
602 moveY = record[1][1];
603 found = true;
604 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
605 record[1].unshift(moveY);
606 record[1].unshift(moveX);
607 moveX = record[1][2];
608 moveY = record[1][3];
609 found = true;
610 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
611 record[1].unshift(moveY);
612 record[1].unshift(moveX);
613 moveX = record[1][4];
614 moveY = record[1][5];
615 found = true;
caryclark1049f122015-04-20 08:31:59 -0700616 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
617 record[1].unshift(moveY);
618 record[1].unshift(moveX);
619 moveX = record[1][4];
620 moveY = record[1][5];
621 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700622 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
623 record[1].unshift(moveY);
624 record[1].unshift(moveX);
625 moveX = record[1][6];
626 moveY = record[1][7];
627 found = true;
628 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
629 found = true;
630 } else {
631 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
632 }
633 break;
caryclark54359292015-03-26 07:52:43 -0700634 case REC_TYPE_AFTERPART:
Cary Clarkff114282016-12-14 11:56:16 -0500635 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL id=IDX")
636 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL id=IDX")
637 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL id=IDX")
638 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL id=IDX")
caryclark54359292015-03-26 07:52:43 -0700639 break;
caryclark26ad22a2015-10-16 09:03:38 -0700640 case REC_TYPE_ALIGNED:
641 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL"
642 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL"
643 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL"
644 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL"
645 );
646 break;
caryclarkdac1d172014-06-17 05:15:38 -0700647 case REC_TYPE_ANGLE:
Cary Clark59d5a0e2017-01-23 14:38:52 +0000648 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700649"[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");
650 break;
651 case REC_TYPE_COIN:
652 found = true;
653 break;
caryclark624637c2015-05-11 07:21:27 -0700654 case REC_TYPE_COINCIDENCE:
655 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
656" + id=IDX t=T_VAL tEnd=T_VAL"
657 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
658" - id=IDX t=T_VAL tEnd=T_VAL"
659 );
660 break;
caryclarkdac1d172014-06-17 05:15:38 -0700661 case REC_TYPE_COMPUTED:
662 found = line == "computed quadratics given"
663 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
664 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
665 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700666 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700667 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
668 );
669 break;
670 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700671 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
672 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700673 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700674 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
675 );
676 break;
677 case REC_TYPE_PATH2:
678 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
679 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700680 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700681 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700682 );
683 break;
684 case REC_TYPE_SECT:
685 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
686" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
687 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
688" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
689 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
690" no intersect LINE_VAL LINE_VAL"
691 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
692" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
693 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
694" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
695 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
696" no intersect QUAD_VAL LINE_VAL"
697 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
698" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
699 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
700" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
701 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
702" no intersect QUAD_VAL QUAD_VAL"
caryclark55888e42016-07-18 10:01:36 -0700703
caryclark1049f122015-04-20 08:31:59 -0700704 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
705" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
706 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
707" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
708 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
709" no intersect CONIC_VAL LINE_VAL"
caryclark55888e42016-07-18 10:01:36 -0700710
711 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD, "debugShowConicQuadIntersection" +
712" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
713 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_2, "debugShowConicQuadIntersection" +
714" 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 -0700715 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_3, "debugShowConicQuadIntersection" +
716" 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"
717 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_4, "debugShowConicQuadIntersection" +
718" 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 -0700719 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" +
720" no intersect CONIC_VAL QUAD_VAL"
721
caryclark1049f122015-04-20 08:31:59 -0700722 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
723" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
724 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
725" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
726 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
727" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700728 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
729" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
730 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
731" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
732 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
733" 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"
734 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
735" no intersect CUBIC_VAL LINE_VAL"
736 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
737" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
738 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
739" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
740 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
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 QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
742 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
743" 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"
744 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
745" no intersect CUBIC_VAL QUAD_VAL"
746 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
747" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
748 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
749" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
750 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
751" 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"
752 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
753" 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"
754 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
755" no intersect CUBIC_VAL CUBIC_VAL"
756 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
757" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
758 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
759" no self intersect CUBIC_VAL"
760 );
761 break;
762 case REC_TYPE_SORT:
763 var hasDone = / done/.test(line);
764 var hasUnorderable = / unorderable/.test(line);
765 var hasSmall = / small/.test(line);
766 var hasTiny = / tiny/.test(line);
767 var hasOperand = / operand/.test(line);
768 var hasStop = / stop/.test(line);
769 line.replace(/[ a-z]+$/, "");
770 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
771" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
772 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
773" [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"
774 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
775" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
776 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
777" [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"
778 );
779 if (found) {
780 record[1].push(hasDone);
781 record[1].push(hasUnorderable);
782 record[1].push(hasSmall);
783 record[1].push(hasTiny);
784 record[1].push(hasOperand);
785 record[1].push(hasStop);
786 }
787 break;
caryclark03b03ca2015-04-23 09:13:37 -0700788 case REC_TYPE_TOP:
789 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
790" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
791 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
792" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
793 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
794" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
795 );
796 break;
caryclarkdac1d172014-06-17 05:15:38 -0700797 case REC_TYPE_MARK:
798 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700799" 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 -0700800 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700801" 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 -0700802 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
803" 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 -0700804 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700805" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
806 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
807" 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"
808 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
809" 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 -0700810 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
811" 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 -0700812 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
813" 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 -0700814 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
815" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
816 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
817" 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 -0700818 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
819" 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 -0700820 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
821" 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 -0700822 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700823" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700824 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark55888e42016-07-18 10:01:36 -0700825" last seg=IDX span=IDX"
826 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
827" last segment=IDX span=IDX windSum=OPT"
828 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
829" last seg=IDX span=IDX windSum=OPT"
830 );
caryclarkdac1d172014-06-17 05:15:38 -0700831 break;
832 case REC_TYPE_OP:
833 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
834 || line.lastIndexOf("operator<", 0) === 0) {
835 found = true;
836 break;
837 }
caryclark54359292015-03-26 07:52:43 -0700838 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700839 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700840 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700841 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
842 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
843 );
844 break;
845 case REC_TYPE_UNKNOWN:
846 found = true;
847 break;
848 }
849 if (!found) {
850 console.log(line + " [" + lineNo + "] of type " + type + " not found");
851 }
852 }
853 if (recType != REC_TYPE_UNKNOWN) {
854 records.push(recType);
855 records.push(lastLineNo);
856 records.push(record);
857 }
858 if (records.length >= 1) {
859 tests[testIndex] = records;
860 testLines[testIndex] = lines;
861 }
862}
863
864function init(test) {
865 var canvas = document.getElementById('canvas');
866 if (!canvas.getContext) return;
867 ctx = canvas.getContext('2d');
868 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
869 var unscaledWidth = window.innerWidth - 20;
870 var unscaledHeight = window.innerHeight - 20;
871 screenWidth = unscaledWidth;
872 screenHeight = unscaledHeight;
873 canvas.width = unscaledWidth * resScale;
874 canvas.height = unscaledHeight * resScale;
875 canvas.style.width = unscaledWidth + 'px';
876 canvas.style.height = unscaledHeight + 'px';
877 if (resScale != 1) {
878 ctx.scale(resScale, resScale);
879 }
880 xmin = Infinity;
881 xmax = -Infinity;
882 ymin = Infinity;
883 ymax = -Infinity;
caryclark26ad22a2015-10-16 09:03:38 -0700884 hasPath = hasAlignedPath = hasComputedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700885 firstActiveSpan = -1;
886 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
887 var recType = test[tIndex];
888 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
889 console.log("unknown rec type: " + recType);
890 throw "stop execution";
891 }
892 var records = test[tIndex + 2];
893 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
894 var fragType = records[recordIndex];
895 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
896 console.log("unknown in range frag type: " + fragType);
897 throw "stop execution";
898 }
899 var frags = records[recordIndex + 1];
900 var first = 0;
901 var last = -1;
902 var first2 = 0;
903 var last2 = 0;
904 switch (recType) {
caryclark26ad22a2015-10-16 09:03:38 -0700905 case REC_TYPE_ALIGNED:
906 hasAlignedPath = true;
caryclarkdac1d172014-06-17 05:15:38 -0700907 case REC_TYPE_COMPUTED:
908 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
909 break;
910 }
caryclark26ad22a2015-10-16 09:03:38 -0700911 if (REC_TYPE_COMPUTED == recType) {
912 hasComputedPath = true;
913 }
caryclarkdac1d172014-06-17 05:15:38 -0700914 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700915 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700916 switch (fragType) {
917 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700918 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700919 break;
caryclark1049f122015-04-20 08:31:59 -0700920 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700921 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700922 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700923 break;
924 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700925 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700926 break;
927 default:
caryclark55888e42016-07-18 10:01:36 -0700928 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
caryclarkdac1d172014-06-17 05:15:38 -0700929 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
930 throw "stop execution";
931 }
932 if (recType == REC_TYPE_PATH) {
933 hasPath = true;
934 }
935 break;
caryclark54359292015-03-26 07:52:43 -0700936 case REC_TYPE_PATH2:
937 first = 1;
938 switch (fragType) {
939 case PATH_LINE:
940 last = 5;
941 break;
caryclark1049f122015-04-20 08:31:59 -0700942 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700943 case PATH_QUAD:
944 last = 7;
945 break;
946 case PATH_CUBIC:
947 last = 9;
948 break;
949 default:
caryclark55888e42016-07-18 10:01:36 -0700950 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
caryclark54359292015-03-26 07:52:43 -0700951 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
952 throw "stop execution";
953 }
954 if (recType == REC_TYPE_PATH2) {
955 hasPath = true;
956 }
957 break;
caryclarkdac1d172014-06-17 05:15:38 -0700958 case REC_TYPE_ACTIVE:
959 if (firstActiveSpan < 0) {
960 firstActiveSpan = tIndex;
961 }
962 first = 1;
963 switch (fragType) {
964 case ACTIVE_LINE_SPAN:
965 last = 5;
966 break;
caryclark1049f122015-04-20 08:31:59 -0700967 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -0700968 case ACTIVE_QUAD_SPAN:
969 last = 7;
970 break;
971 case ACTIVE_CUBIC_SPAN:
972 last = 9;
973 break;
974 default:
975 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
976 throw "stop execution";
977 }
978 break;
979 case REC_TYPE_ADD:
980 switch (fragType) {
981 case ADD_MOVETO:
982 break;
983 case ADD_LINETO:
984 last = 4;
985 break;
caryclark1049f122015-04-20 08:31:59 -0700986 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -0700987 case ADD_QUADTO:
988 last = 6;
989 break;
990 case ADD_CUBICTO:
991 last = 8;
992 break;
993 case ADD_CLOSE:
994 case ADD_FILL:
995 break;
996 default:
997 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
998 throw "stop execution";
999 }
1000 break;
caryclark54359292015-03-26 07:52:43 -07001001 case REC_TYPE_AFTERPART:
1002 switch (fragType) {
1003 case PATH_LINE:
1004 last = 4;
1005 break;
caryclark1049f122015-04-20 08:31:59 -07001006 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -07001007 case PATH_QUAD:
1008 last = 6;
1009 break;
1010 case PATH_CUBIC:
1011 last = 8;
1012 break;
1013 default:
1014 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
1015 throw "stop execution";
1016 }
1017 break;
caryclarkdac1d172014-06-17 05:15:38 -07001018 case REC_TYPE_SECT:
1019 switch (fragType) {
1020 case INTERSECT_LINE:
1021 first = 1; last = 5; first2 = 8; last2 = 12;
1022 break;
1023 case INTERSECT_LINE_2:
1024 first = 1; last = 5; first2 = 11; last2 = 15;
1025 break;
1026 case INTERSECT_LINE_NO:
1027 first = 0; last = 4; first2 = 4; last2 = 8;
1028 break;
caryclark1049f122015-04-20 08:31:59 -07001029 case INTERSECT_CONIC_LINE:
1030 first = 1; last = 7; first2 = 11; last2 = 15;
1031 break;
caryclarkdac1d172014-06-17 05:15:38 -07001032 case INTERSECT_QUAD_LINE:
1033 first = 1; last = 7; first2 = 10; last2 = 14;
1034 break;
caryclark1049f122015-04-20 08:31:59 -07001035 case INTERSECT_CONIC_LINE_2:
1036 first = 1; last = 7; first2 = 14; last2 = 18;
1037 break;
caryclarkdac1d172014-06-17 05:15:38 -07001038 case INTERSECT_QUAD_LINE_2:
1039 first = 1; last = 7; first2 = 13; last2 = 17;
1040 break;
caryclark1049f122015-04-20 08:31:59 -07001041 case INTERSECT_CONIC_LINE_NO:
1042 first = 0; last = 6; first2 = 7; last2 = 11;
1043 break;
caryclarkdac1d172014-06-17 05:15:38 -07001044 case INTERSECT_QUAD_LINE_NO:
1045 first = 0; last = 6; first2 = 6; last2 = 10;
1046 break;
caryclark1049f122015-04-20 08:31:59 -07001047 case INTERSECT_CONIC:
1048 first = 1; last = 7; first2 = 11; last2 = 17;
1049 break;
caryclarkdac1d172014-06-17 05:15:38 -07001050 case INTERSECT_QUAD:
1051 first = 1; last = 7; first2 = 10; last2 = 16;
1052 break;
caryclark1049f122015-04-20 08:31:59 -07001053 case INTERSECT_CONIC_2:
1054 first = 1; last = 7; first2 = 14; last2 = 20;
1055 break;
caryclarkdac1d172014-06-17 05:15:38 -07001056 case INTERSECT_QUAD_2:
1057 first = 1; last = 7; first2 = 13; last2 = 19;
1058 break;
caryclark1049f122015-04-20 08:31:59 -07001059 case INTERSECT_CONIC_NO:
1060 first = 0; last = 6; first2 = 7; last2 = 13;
1061 break;
caryclarkdac1d172014-06-17 05:15:38 -07001062 case INTERSECT_QUAD_NO:
1063 first = 0; last = 6; first2 = 6; last2 = 12;
1064 break;
1065 case INTERSECT_SELF_CUBIC:
1066 first = 1; last = 9;
1067 break;
1068 case INTERSECT_SELF_CUBIC_NO:
1069 first = 0; last = 8;
1070 break;
1071 case INTERSECT_CUBIC_LINE:
1072 first = 1; last = 9; first2 = 12; last2 = 16;
1073 break;
1074 case INTERSECT_CUBIC_LINE_2:
1075 first = 1; last = 9; first2 = 15; last2 = 19;
1076 break;
1077 case INTERSECT_CUBIC_LINE_3:
1078 first = 1; last = 9; first2 = 18; last2 = 22;
1079 break;
1080 case INTERSECT_CUBIC_LINE_NO:
1081 first = 0; last = 8; first2 = 8; last2 = 12;
1082 break;
caryclark55888e42016-07-18 10:01:36 -07001083 case INTERSECT_CONIC_QUAD:
1084 first = 1; last = 7; first2 = 11; last2 = 17;
1085 break;
1086 case INTERSECT_CONIC_QUAD_2:
1087 first = 1; last = 7; first2 = 14; last2 = 20;
1088 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07001089 case INTERSECT_CONIC_QUAD_3:
1090 first = 1; last = 7; first2 = 17; last2 = 23;
1091 break;
1092 case INTERSECT_CONIC_QUAD_4:
1093 first = 1; last = 7; first2 = 20; last2 = 26;
1094 break;
caryclark55888e42016-07-18 10:01:36 -07001095 case INTERSECT_CONIC_QUAD_NO:
1096 first = 0; last = 6; first2 = 7; last2 = 13;
1097 break;
caryclarkdac1d172014-06-17 05:15:38 -07001098 case INTERSECT_CUBIC_QUAD:
1099 first = 1; last = 9; first2 = 12; last2 = 18;
1100 break;
1101 case INTERSECT_CUBIC_QUAD_2:
1102 first = 1; last = 9; first2 = 15; last2 = 21;
1103 break;
1104 case INTERSECT_CUBIC_QUAD_3:
1105 first = 1; last = 9; first2 = 18; last2 = 24;
1106 break;
1107 case INTERSECT_CUBIC_QUAD_4:
1108 first = 1; last = 9; first2 = 21; last2 = 27;
1109 break;
1110 case INTERSECT_CUBIC_QUAD_NO:
1111 first = 0; last = 8; first2 = 8; last2 = 14;
1112 break;
1113 case INTERSECT_CUBIC:
1114 first = 1; last = 9; first2 = 12; last2 = 20;
1115 break;
1116 case INTERSECT_CUBIC_2:
1117 first = 1; last = 9; first2 = 15; last2 = 23;
1118 break;
1119 case INTERSECT_CUBIC_3:
1120 first = 1; last = 9; first2 = 18; last2 = 26;
1121 break;
1122 case INTERSECT_CUBIC_4:
1123 first = 1; last = 9; first2 = 21; last2 = 29;
1124 break;
1125 case INTERSECT_CUBIC_NO:
1126 first = 0; last = 8; first2 = 8; last2 = 16;
1127 break;
1128 default:
1129 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1130 throw "stop execution";
1131 }
1132 break;
1133 default:
1134 continue;
1135 }
1136 for (var idx = first; idx < last; idx += 2) {
1137 xmin = Math.min(xmin, frags[idx]);
1138 xmax = Math.max(xmax, frags[idx]);
1139 ymin = Math.min(ymin, frags[idx + 1]);
1140 ymax = Math.max(ymax, frags[idx + 1]);
1141 }
1142 for (var idx = first2; idx < last2; idx += 2) {
1143 xmin = Math.min(xmin, frags[idx]);
1144 xmax = Math.max(xmax, frags[idx]);
1145 ymin = Math.min(ymin, frags[idx + 1]);
1146 ymax = Math.max(ymax, frags[idx + 1]);
1147 }
1148 }
1149 }
1150 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1151 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1152 var recType = test[tIndex];
1153 var records = test[tIndex + 2];
1154 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1155 var fragType = records[recordIndex];
1156 var frags = records[recordIndex + 1];
1157 switch (recType) {
1158 case REC_TYPE_ACTIVE_OP:
1159 if (!draw_op) {
1160 break;
1161 }
1162 {
1163 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1164 curve_extremes(curve, angleBounds);
1165 }
1166 break;
1167 case REC_TYPE_ANGLE:
1168 if (!draw_angle) {
1169 break;
1170 }
caryclark54359292015-03-26 07:52:43 -07001171 {
caryclarkdac1d172014-06-17 05:15:38 -07001172 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1173 curve_extremes(curve, angleBounds);
1174 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1175 curve_extremes(curve, angleBounds);
1176 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1177 }
1178 break;
caryclark624637c2015-05-11 07:21:27 -07001179 case REC_TYPE_COINCIDENCE:
1180 if (!draw_coincidence) {
1181 break;
1182 }
1183 {
1184 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1185 curve_extremes(curve, angleBounds);
1186 }
1187 break;
caryclarkdac1d172014-06-17 05:15:38 -07001188 case REC_TYPE_SORT:
1189 if (!draw_sort) {
1190 break;
1191 }
1192 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1193 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1194 curve_extremes(curve, angleBounds);
1195 }
1196 break;
caryclark03b03ca2015-04-23 09:13:37 -07001197 case REC_TYPE_TOP:
1198 if (!draw_top) {
1199 break;
1200 }
1201 {
1202 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1203 curve_extremes(curve, angleBounds);
1204 }
1205 break;
caryclarkdac1d172014-06-17 05:15:38 -07001206 }
1207 }
1208 }
1209 xmin = Math.min(xmin, angleBounds[0]);
1210 ymin = Math.min(ymin, angleBounds[1]);
1211 xmax = Math.max(xmax, angleBounds[2]);
1212 ymax = Math.max(ymax, angleBounds[3]);
1213 setScale(xmin, xmax, ymin, ymax);
1214 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001215 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001216 }
1217 if (hasPath == true && hasComputedPath == false && draw_computed) {
1218 draw_computed = 0;
1219 }
1220}
1221
caryclark26ad22a2015-10-16 09:03:38 -07001222function curveByIDMatch(test, id, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001223 var tIndex = -3;
1224 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001225 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001226 if (recType == REC_TYPE_OP) {
1227 continue;
1228 }
caryclark26ad22a2015-10-16 09:03:38 -07001229 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001230 return [];
1231 }
1232 var records = test[tIndex + 2];
1233 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1234 var fragType = records[recordIndex];
1235 var frags = records[recordIndex + 1];
1236 if (frags[0] == id) {
1237 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001238 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001239 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001240 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001241 return [frags[1], frags[2], frags[3], frags[4],
1242 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001243 case PATH_CONIC:
1244 return [frags[1], frags[2], frags[3], frags[4],
1245 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001246 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001247 return [frags[1], frags[2], frags[3], frags[4],
1248 frags[5], frags[6], frags[7], frags[8]];
1249 }
1250 }
1251 }
caryclarkdac1d172014-06-17 05:15:38 -07001252 }
1253 return [];
1254}
1255
caryclark26ad22a2015-10-16 09:03:38 -07001256function curveByID(test, id) {
1257 var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : [];
1258 if (!result.length) {
1259 result = curveByIDMatch(test, id, REC_TYPE_PATH);
1260 }
1261 return result;
1262}
1263
1264function curvePartialByIDMatch(test, id, t0, t1, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001265 var tIndex = -3;
1266 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001267 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001268 if (recType == REC_TYPE_OP) {
1269 continue;
1270 }
caryclark26ad22a2015-10-16 09:03:38 -07001271 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001272 return [];
1273 }
1274 var records = test[tIndex + 2];
1275 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1276 var fragType = records[recordIndex];
1277 var frags = records[recordIndex + 1];
1278 if (frags[0] == id) {
1279 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001280 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001281 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001282 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001283 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1284 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001285 case PATH_CONIC:
1286 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1287 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001288 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001289 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1290 frags[5], frags[6], frags[7], frags[8], t0, t1);
1291 }
1292 }
1293 }
caryclarkdac1d172014-06-17 05:15:38 -07001294 }
1295 return [];
1296}
1297
caryclark26ad22a2015-10-16 09:03:38 -07001298function curvePartialByID(test, id, t0, t1) {
1299 var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : [];
1300 if (!result.length) {
1301 result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH);
1302 }
1303 return result;
1304}
1305
1306function idByCurveIDMatch(test, frag, type, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001307 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001308 while (tIndex < test.length) {
1309 var recType = test[tIndex];
caryclark26ad22a2015-10-16 09:03:38 -07001310 if (recType != recMatch) {
caryclark54359292015-03-26 07:52:43 -07001311 ++tIndex;
1312 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001313 }
1314 var records = test[tIndex + 2];
1315 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1316 var fragType = records[recordIndex];
1317 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001318 if (frag.length != frags.length - 1) {
1319 continue;
1320 }
caryclarkdac1d172014-06-17 05:15:38 -07001321 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001322 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001323 if (frag[0] != frags[1] || frag[1] != frags[2]
1324 || frag[2] != frags[3] || frag[3] != frags[4]) {
1325 continue;
1326 }
1327 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001328 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001329 if (frag[0] != frags[1] || frag[1] != frags[2]
1330 || frag[2] != frags[3] || frag[3] != frags[4]
1331 || frag[4] != frags[5] || frag[5] != frags[6]) {
1332 continue;
1333 }
1334 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001335 case PATH_CONIC:
1336 if (frag[0] != frags[1] || frag[1] != frags[2]
1337 || frag[2] != frags[3] || frag[3] != frags[4]
1338 || frag[4] != frags[5] || frag[5] != frags[6]
1339 || frag[6] != frags[7]) {
1340 continue;
1341 }
1342 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001343 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001344 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] || frag[7] != frags[8]) {
1348 continue;
1349 }
1350 return frags[0];
1351 }
1352 }
1353 ++tIndex;
1354 }
1355 return -1;
1356}
1357
caryclark26ad22a2015-10-16 09:03:38 -07001358function idByCurve(test, frag, type) {
1359 var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : [];
1360 if (!result.length) {
1361 result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH);
1362 }
1363 return result;
1364}
1365
caryclarkdac1d172014-06-17 05:15:38 -07001366function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001367 var length = curve.length == 7 ? 6 : curve.length;
caryclarked0935a2015-10-22 07:23:52 -07001368 for (var index = 0; index < length; index += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001369 var x = curve[index];
1370 var y = curve[index + 1];
1371 bounds[0] = Math.min(bounds[0], x);
1372 bounds[1] = Math.min(bounds[1], y);
1373 bounds[2] = Math.max(bounds[2], x);
1374 bounds[3] = Math.max(bounds[3], y);
1375 }
1376}
1377
1378function setScale(x0, x1, y0, y1) {
1379 var srcWidth = x1 - x0;
1380 var srcHeight = y1 - y0;
1381 var usableWidth = screenWidth;
1382 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1383 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1384 usableWidth -= (xDigits + yDigits) * 10;
1385 usableWidth -= decimal_places * 10;
1386 if (draw_legend) {
1387 usableWidth -= 40;
1388 }
1389 var hscale = usableWidth / srcWidth;
1390 var vscale = screenHeight / srcHeight;
1391 scale = Math.min(hscale, vscale);
1392 var invScale = 1 / scale;
1393 var sxmin = x0 - invScale * 5;
1394 var symin = y0 - invScale * 10;
1395 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1396 var symax = y1 + invScale * 10;
1397 srcWidth = sxmax - sxmin;
1398 srcHeight = symax - symin;
1399 hscale = usableWidth / srcWidth;
1400 vscale = screenHeight / srcHeight;
1401 scale = Math.min(hscale, vscale);
1402 srcLeft = sxmin;
1403 srcTop = symin;
1404}
1405
1406function drawArc(curve, op, from, to) {
1407 var type = PATH_LINE + (curve.length / 2 - 2);
1408 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1409 var dy = pt.y - curve[1];
1410 var dx = pt.x - curve[0];
1411 var dist = Math.sqrt(dy * dy + dx * dx);
1412 var _dist = dist * scale;
1413 var angle = Math.atan2(dy, dx);
1414 var _px = (curve[0] - srcLeft) * scale;
1415 var _py = (curve[1] - srcTop) * scale;
1416 var divisor = 4;
1417 var endDist;
1418 do {
1419 var ends = [];
1420 for (var index = -1; index <= 1; index += 2) {
1421 var px = Math.cos(index * Math.PI / divisor);
1422 var py = Math.sin(index * Math.PI / divisor);
1423 ends.push(px);
1424 ends.push(py);
1425 }
1426 var endDx = (ends[2] - ends[0]) * scale * dist;
1427 var endDy = (ends[3] - ends[1]) * scale * dist;
1428 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1429 if (endDist < 100) {
1430 break;
1431 }
1432 divisor *= 2;
1433 } while (true);
1434 if (endDist < 30) {
1435 return;
1436 }
1437 if (op) {
1438 divisor *= 2;
1439 }
1440 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1441 ctx.beginPath();
1442 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1443 ctx.stroke();
1444 var saveAlign = ctx.textAlign;
1445 var saveStyle = ctx.fillStyle;
1446 var saveFont = ctx.font;
1447 ctx.textAlign = "center";
1448 ctx.fillStyle = "black";
1449 ctx.font = "normal 24px Arial";
1450 divisor *= 0.8;
1451 for (var index = -1; index <= 1; index += 2) {
1452 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1453 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1454 var _px = (px - srcLeft) * scale;
1455 var _py = (py - srcTop) * scale;
1456 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1457 }
1458 ctx.textAlign = saveAlign;
1459 ctx.fillStyle = saveStyle;
1460 ctx.font = saveFont;
1461}
1462
1463function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001464 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1465 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001466 var x = drawnPts[pts];
1467 var y = drawnPts[pts + 1];
1468 if (px == x && py == y) {
1469 return;
1470 }
1471 }
1472 drawnPts.push(px);
1473 drawnPts.push(py);
1474 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1475 var _px = (px - srcLeft) * scale;
1476 var _py = (py - srcTop) * scale;
1477 ctx.beginPath();
1478 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1479 ctx.closePath();
1480 if (end) {
1481 ctx.fill();
1482 } else {
1483 ctx.stroke();
1484 }
1485 if (debug_xy) {
1486 ctx.textAlign = "left";
1487 ctx.fillText(label, _px + 5, _py);
1488 }
1489}
1490
caryclark1049f122015-04-20 08:31:59 -07001491function coordCount(curveType) {
1492 switch (curveType) {
1493 case PATH_LINE:
1494 return 4;
1495 case PATH_QUAD:
1496 return 6;
1497 case PATH_CONIC:
1498 return 6;
1499 case PATH_CUBIC:
1500 return 8;
1501 }
1502 return -1;
1503}
1504
caryclarkdac1d172014-06-17 05:15:38 -07001505function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001506 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001507 for (var idx = 0; idx < count; idx += 2) {
1508 if (!drawControls && idx != 0 && idx != count - 2) {
1509 continue;
1510 }
1511 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1512 }
1513}
1514
1515function drawControlLines(curve, curveType, drawEnd) {
1516 if (curveType == PATH_LINE) {
1517 return;
1518 }
1519 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1520 drawLine(curve[0], curve[1], curve[2], curve[3]);
1521 drawLine(curve[2], curve[3], curve[4], curve[5]);
1522 if (curveType == PATH_CUBIC) {
1523 drawLine(curve[4], curve[5], curve[6], curve[7]);
1524 if (drawEnd > 1) {
1525 drawLine(curve[6], curve[7], curve[0], curve[1]);
1526 if (drawEnd > 2) {
1527 drawLine(curve[0], curve[1], curve[4], curve[5]);
1528 drawLine(curve[6], curve[7], curve[2], curve[3]);
1529 }
1530 }
1531 } else if (drawEnd > 1) {
1532 drawLine(curve[4], curve[5], curve[0], curve[1]);
1533 }
1534}
1535
1536function pointAtT(curve, curveType, t) {
1537 var xy = {};
1538 switch (curveType) {
1539 case PATH_LINE:
1540 var a = 1 - t;
1541 var b = t;
1542 xy.x = a * curve[0] + b * curve[2];
1543 xy.y = a * curve[1] + b * curve[3];
1544 break;
1545 case PATH_QUAD:
1546 var one_t = 1 - t;
1547 var a = one_t * one_t;
1548 var b = 2 * one_t * t;
1549 var c = t * t;
1550 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1551 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1552 break;
caryclark1049f122015-04-20 08:31:59 -07001553 case PATH_CONIC:
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] * curve[6] + c * curve[4];
1559 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1560 var d = a + b * curve[6] + c;
1561 xy.x /= d;
1562 xy.y /= d;
1563 break;
caryclarkdac1d172014-06-17 05:15:38 -07001564 case PATH_CUBIC:
1565 var one_t = 1 - t;
1566 var one_t2 = one_t * one_t;
1567 var a = one_t2 * one_t;
1568 var b = 3 * one_t2 * t;
1569 var t2 = t * t;
1570 var c = 3 * one_t * t2;
1571 var d = t2 * t;
1572 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1573 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1574 break;
1575 }
1576 return xy;
1577}
caryclark55888e42016-07-18 10:01:36 -07001578
caryclarkdac1d172014-06-17 05:15:38 -07001579function drawPointAtT(curve, curveType) {
1580 var x, y;
1581 var xy = pointAtT(curve, curveType, curveT);
1582 drawPoint(xy.x, xy.y, true);
1583 if (!draw_intersectT) {
1584 return;
1585 }
1586 ctx.fillStyle = "red";
1587 drawTAtPointUp(xy.x, xy.y, curveT);
1588}
1589
1590function drawTAtPointUp(px, py, t) {
1591 var label = t.toFixed(decimal_places);
1592 var _px = (px - srcLeft)* scale;
1593 var _py = (py - srcTop) * scale;
1594 ctx.fillText(label, _px + 5, _py - 10);
1595}
1596
1597function drawTAtPointDown(px, py, t) {
1598 var label = t.toFixed(decimal_places);
1599 var _px = (px - srcLeft)* scale;
1600 var _py = (py - srcTop) * scale;
1601 ctx.fillText(label, _px + 5, _py + 10);
1602}
1603
1604function alreadyDrawnLine(x1, y1, x2, y2) {
1605 if (collect_bounds) {
1606 if (focus_enabled) {
1607 focusXmin = Math.min(focusXmin, x1, x2);
1608 focusYmin = Math.min(focusYmin, y1, y2);
1609 focusXmax = Math.max(focusXmax, x1, x2);
1610 focusYmax = Math.max(focusYmax, y1, y2);
1611 }
1612 return true;
1613 }
1614 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1615 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1616 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1617 return true;
1618 }
1619 }
1620 drawnLines.push(x1);
1621 drawnLines.push(y1);
1622 drawnLines.push(x2);
1623 drawnLines.push(y2);
1624 return false;
1625}
1626
1627function drawLine(x1, y1, x2, y2) {
1628 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1629 return;
1630 }
1631 ctx.beginPath();
1632 ctx.moveTo((x1 - srcLeft) * scale,
1633 (y1 - srcTop) * scale);
1634 ctx.lineTo((x2 - srcLeft) * scale,
1635 (y2 - srcTop) * scale);
1636 ctx.stroke();
1637}
1638
1639function linePartial(x1, y1, x2, y2, t1, t2) {
1640 var dx = x1 - x2;
1641 var dy = y1 - y2;
1642 var array = [
1643 x1 - t1 * dx,
1644 y1 - t1 * dy,
1645 x1 - t2 * dx,
1646 y1 - t2 * dy
1647 ];
1648 return array;
1649}
1650
1651function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1652 var a = linePartial(x1, y1, x2, y2, t1, t2);
1653 var ax = a[0];
1654 var ay = a[1];
1655 var bx = a[2];
1656 var by = a[3];
1657 if (alreadyDrawnLine(ax, ay, bx, by)) {
1658 return;
1659 }
1660 ctx.beginPath();
1661 ctx.moveTo((ax - srcLeft) * scale,
1662 (ay - srcTop) * scale);
1663 ctx.lineTo((bx - srcLeft) * scale,
1664 (by - srcTop) * scale);
1665 ctx.stroke();
1666}
1667
1668function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1669 if (collect_bounds) {
1670 if (focus_enabled) {
1671 focusXmin = Math.min(focusXmin, x1, x2, x3);
1672 focusYmin = Math.min(focusYmin, y1, y2, y3);
1673 focusXmax = Math.max(focusXmax, x1, x2, x3);
1674 focusYmax = Math.max(focusYmax, y1, y2, y3);
1675 }
1676 return true;
1677 }
1678 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1679 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1680 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1681 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1682 return true;
1683 }
1684 }
1685 drawnQuads.push(x1);
1686 drawnQuads.push(y1);
1687 drawnQuads.push(x2);
1688 drawnQuads.push(y2);
1689 drawnQuads.push(x3);
1690 drawnQuads.push(y3);
1691 return false;
1692}
1693
1694function drawQuad(x1, y1, x2, y2, x3, y3) {
1695 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1696 return;
1697 }
1698 ctx.beginPath();
1699 ctx.moveTo((x1 - srcLeft) * scale,
1700 (y1 - srcTop) * scale);
1701 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1702 (y2 - srcTop) * scale,
1703 (x3 - srcLeft) * scale,
1704 (y3 - srcTop) * scale);
1705 ctx.stroke();
1706}
1707
1708function interp(A, B, t) {
1709 return A + (B - A) * t;
1710}
1711
1712function interp_quad_coords(x1, x2, x3, t)
1713{
1714 var ab = interp(x1, x2, t);
1715 var bc = interp(x2, x3, t);
1716 var abc = interp(ab, bc, t);
1717 return abc;
1718}
1719
1720function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1721 var ax = interp_quad_coords(x1, x2, x3, t1);
1722 var ay = interp_quad_coords(y1, y2, y3, t1);
1723 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1724 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1725 var cx = interp_quad_coords(x1, x2, x3, t2);
1726 var cy = interp_quad_coords(y1, y2, y3, t2);
1727 var bx = 2*dx - (ax + cx)/2;
1728 var by = 2*dy - (ay + cy)/2;
1729 var array = [
1730 ax, ay, bx, by, cx, cy
1731 ];
1732 return array;
1733}
1734
1735function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1736 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1737 var ax = a[0];
1738 var ay = a[1];
1739 var bx = a[2];
1740 var by = a[3];
1741 var cx = a[4];
1742 var cy = a[5];
1743 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1744 return;
1745 }
1746 ctx.beginPath();
1747 ctx.moveTo((ax - srcLeft) * scale,
1748 (ay - srcTop) * scale);
1749 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1750 (by - srcTop) * scale,
1751 (cx - srcLeft) * scale,
1752 (cy - srcTop) * scale);
1753 ctx.stroke();
1754}
1755
caryclark1049f122015-04-20 08:31:59 -07001756function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1757 if (collect_bounds) {
1758 if (focus_enabled) {
1759 focusXmin = Math.min(focusXmin, x1, x2, x3);
1760 focusYmin = Math.min(focusYmin, y1, y2, y3);
1761 focusXmax = Math.max(focusXmax, x1, x2, x3);
1762 focusYmax = Math.max(focusYmax, y1, y2, y3);
1763 }
1764 return true;
1765 }
1766 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1767 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001768 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1769 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclark1049f122015-04-20 08:31:59 -07001770 && w == drawnCubics[pts + 6]) {
1771 return true;
1772 }
1773 }
1774 drawnConics.push(x1);
1775 drawnConics.push(y1);
1776 drawnConics.push(x2);
1777 drawnConics.push(y2);
1778 drawnConics.push(x3);
1779 drawnConics.push(y3);
1780 drawnCubics.push(w);
1781 return false;
1782}
1783
1784var kMaxConicToQuadPOW2 = 5;
1785
1786function computeQuadPOW2(curve, tol) {
1787 var a = curve[6] - 1;
1788 var k = a / (4 * (2 + a));
1789 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1790 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1791
1792 var error = Math.sqrt(x * x + y * y);
1793 var pow2;
1794 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1795 if (error <= tol) {
1796 break;
1797 }
1798 error *= 0.25;
1799 }
1800 return pow2;
1801}
1802
1803function subdivide_w_value(w) {
1804 return Math.sqrt(0.5 + w * 0.5);
1805}
1806
1807function chop(curve, part1, part2) {
1808 var w = curve[6];
1809 var scale = 1 / (1 + w);
1810 part1[0] = curve[0];
1811 part1[1] = curve[1];
1812 part1[2] = (curve[0] + curve[2] * w) * scale;
1813 part1[3] = (curve[1] + curve[3] * w) * scale;
1814 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1815 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1816 part2[2] = (curve[2] * w + curve[4]) * scale;
1817 part2[3] = (curve[3] * w + curve[5]) * scale;
1818 part2[4] = curve[4];
1819 part2[5] = curve[5];
1820 part1[6] = part2[6] = subdivide_w_value(w);
1821}
1822
1823function subdivide(curve, level, pts) {
1824 if (0 == level) {
1825 pts.push(curve[2]);
1826 pts.push(curve[3]);
1827 pts.push(curve[4]);
1828 pts.push(curve[5]);
1829 } else {
1830 var part1 = [], part2 = [];
1831 chop(curve, part1, part2);
1832 --level;
1833 subdivide(part1, level, pts);
1834 subdivide(part2, level, pts);
1835 }
1836}
1837
1838function chopIntoQuadsPOW2(curve, pow2, pts) {
1839 subdivide(curve, pow2, pts);
1840 return 1 << pow2;
1841}
1842
1843function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1844 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1845 return;
1846 }
1847 ctx.beginPath();
1848 ctx.moveTo((x1 - srcLeft) * scale,
1849 (y1 - srcTop) * scale);
1850 var tol = 1 / scale;
1851 var curve = [x1, y1, x2, y2, x3, y3, w];
1852 var pow2 = computeQuadPOW2(curve, tol);
1853 var pts = [];
1854 chopIntoQuadsPOW2(curve, pow2, pts);
1855 for (var i = 0; i < pts.length; i += 4) {
1856 ctx.quadraticCurveTo(
1857 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1858 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1859 }
1860 ctx.stroke();
1861}
1862
1863function conic_eval_numerator(x1, x2, x3, w, t) {
1864 var src2w = x2 * w;
1865 var C = x1;
1866 var A = x3 - 2 * src2w + C;
1867 var B = 2 * (src2w - C);
1868 return (A * t + B) * t + C;
1869}
1870
1871
1872function conic_eval_denominator(w, t) {
1873 var B = 2 * (w - 1);
1874 var C = 1;
1875 var A = -B;
1876 return (A * t + B) * t + C;
1877}
1878
1879function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1880 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1881 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1882 var az = conic_eval_denominator(w, t1);
1883 var midT = (t1 + t2) / 2;
1884 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1885 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1886 var dz = conic_eval_denominator(w, midT);
1887 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1888 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1889 var cz = conic_eval_denominator(w, t2);
1890 var bx = 2 * dx - (ax + cx) / 2;
1891 var by = 2 * dy - (ay + cy) / 2;
1892 var bz = 2 * dz - (az + cz) / 2;
1893 var dt = t2 - t1;
1894 var dt_1 = 1 - dt;
caryclark1049f122015-04-20 08:31:59 -07001895 var array = [
caryclarked0935a2015-10-22 07:23:52 -07001896 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
caryclark1049f122015-04-20 08:31:59 -07001897 ];
caryclarked0935a2015-10-22 07:23:52 -07001898 var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 };
1899 var dMid = { x:dx / dz, y:dy / dz };
1900 var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y };
1901 var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] };
1902 var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y)
1903 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y);
1904 array[6] = partW;
caryclark1049f122015-04-20 08:31:59 -07001905 return array;
1906}
caryclark55888e42016-07-18 10:01:36 -07001907
caryclark1049f122015-04-20 08:31:59 -07001908function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1909 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1910 var ax = a[0];
1911 var ay = a[1];
1912 var bx = a[2];
1913 var by = a[3];
1914 var cx = a[4];
1915 var cy = a[5];
1916 var w_ = a[6];
1917 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1918}
1919
caryclarkdac1d172014-06-17 05:15:38 -07001920function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1921 if (collect_bounds) {
1922 if (focus_enabled) {
1923 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1924 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1925 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1926 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1927 }
1928 return true;
1929 }
1930 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1931 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001932 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1933 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclarkdac1d172014-06-17 05:15:38 -07001934 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1935 return true;
1936 }
1937 }
1938 drawnCubics.push(x1);
1939 drawnCubics.push(y1);
1940 drawnCubics.push(x2);
1941 drawnCubics.push(y2);
1942 drawnCubics.push(x3);
1943 drawnCubics.push(y3);
1944 drawnCubics.push(x4);
1945 drawnCubics.push(y4);
1946 return false;
1947}
1948
1949function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1950 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1951 return;
1952 }
1953 ctx.beginPath();
1954 ctx.moveTo((x1 - srcLeft) * scale,
1955 (y1 - srcTop) * scale);
1956 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1957 (y2 - srcTop) * scale,
1958 (x3 - srcLeft) * scale,
1959 (y3 - srcTop) * scale,
1960 (x4 - srcLeft) * scale,
1961 (y4 - srcTop) * scale);
1962 ctx.stroke();
1963}
1964
1965function interp_cubic_coords(x1, x2, x3, x4, t)
1966{
1967 var ab = interp(x1, x2, t);
1968 var bc = interp(x2, x3, t);
1969 var cd = interp(x3, x4, t);
1970 var abc = interp(ab, bc, t);
1971 var bcd = interp(bc, cd, t);
1972 var abcd = interp(abc, bcd, t);
1973 return abcd;
1974}
1975
1976function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1977 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1978 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1979 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1980 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1981 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1982 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1983 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1984 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1985 var mx = ex * 27 - ax * 8 - dx;
1986 var my = ey * 27 - ay * 8 - dy;
1987 var nx = fx * 27 - ax - dx * 8;
1988 var ny = fy * 27 - ay - dy * 8;
1989 var bx = (mx * 2 - nx) / 18;
1990 var by = (my * 2 - ny) / 18;
1991 var cx = (nx * 2 - mx) / 18;
1992 var cy = (ny * 2 - my) / 18;
1993 var array = [
1994 ax, ay, bx, by, cx, cy, dx, dy
1995 ];
1996 return array;
1997}
caryclark55888e42016-07-18 10:01:36 -07001998
caryclarkdac1d172014-06-17 05:15:38 -07001999function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2000 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2001 var ax = a[0];
2002 var ay = a[1];
2003 var bx = a[2];
2004 var by = a[3];
2005 var cx = a[4];
2006 var cy = a[5];
2007 var dx = a[6];
2008 var dy = a[7];
2009 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
2010 return;
2011 }
2012 ctx.beginPath();
2013 ctx.moveTo((ax - srcLeft) * scale,
2014 (ay - srcTop) * scale);
2015 ctx.bezierCurveTo((bx - srcLeft) * scale,
2016 (by - srcTop) * scale,
2017 (cx - srcLeft) * scale,
2018 (cy - srcTop) * scale,
2019 (dx - srcLeft) * scale,
2020 (dy - srcTop) * scale);
2021 ctx.stroke();
2022}
2023
2024function drawCurve(c) {
2025 switch (c.length) {
2026 case 4:
2027 drawLine(c[0], c[1], c[2], c[3]);
2028 break;
2029 case 6:
2030 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
2031 break;
caryclark1049f122015-04-20 08:31:59 -07002032 case 7:
2033 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
2034 break;
caryclarkdac1d172014-06-17 05:15:38 -07002035 case 8:
2036 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
2037 break;
2038 }
2039}
2040
2041function boundsWidth(pts) {
2042 var min = pts[0];
2043 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07002044 var length = pts.length == 7 ? 6 : pts.length;
2045 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002046 min = Math.min(min, pts[idx]);
2047 max = Math.max(max, pts[idx]);
2048 }
2049 return max - min;
2050}
2051
2052function boundsHeight(pts) {
2053 var min = pts[1];
2054 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07002055 var length = pts.length == 7 ? 6 : pts.length;
2056 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002057 min = Math.min(min, pts[idx]);
2058 max = Math.max(max, pts[idx]);
2059 }
2060 return max - min;
2061}
2062
2063function tangent(pts) {
2064 var dx = pts[2] - pts[0];
2065 var dy = pts[3] - pts[1];
2066 if (dx == 0 && dy == 0 && pts.length > 4) {
2067 dx = pts[4] - pts[0];
2068 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07002069 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002070 dx = pts[6] - pts[0];
2071 dy = pts[7] - pts[1];
2072 }
2073 }
2074 return Math.atan2(-dy, dx);
2075}
2076
2077function hodograph(cubic) {
2078 var hodo = [];
2079 hodo[0] = 3 * (cubic[2] - cubic[0]);
2080 hodo[1] = 3 * (cubic[3] - cubic[1]);
2081 hodo[2] = 3 * (cubic[4] - cubic[2]);
2082 hodo[3] = 3 * (cubic[5] - cubic[3]);
2083 hodo[4] = 3 * (cubic[6] - cubic[4]);
2084 hodo[5] = 3 * (cubic[7] - cubic[5]);
2085 return hodo;
2086}
2087
2088function hodograph2(cubic) {
2089 var quad = hodograph(cubic);
2090 var hodo = [];
2091 hodo[0] = 2 * (quad[2] - quad[0]);
2092 hodo[1] = 2 * (quad[3] - quad[1]);
2093 hodo[2] = 2 * (quad[4] - quad[2]);
2094 hodo[3] = 2 * (quad[5] - quad[3]);
2095 return hodo;
2096}
2097
2098function quadraticRootsReal(A, B, C, s) {
2099 if (A == 0) {
2100 if (B == 0) {
2101 s[0] = 0;
2102 return C == 0;
2103 }
2104 s[0] = -C / B;
2105 return 1;
2106 }
2107 /* normal form: x^2 + px + q = 0 */
2108 var p = B / (2 * A);
2109 var q = C / A;
2110 var p2 = p * p;
2111 if (p2 < q) {
2112 return 0;
2113 }
2114 var sqrt_D = 0;
2115 if (p2 > q) {
2116 sqrt_D = sqrt(p2 - q);
2117 }
2118 s[0] = sqrt_D - p;
2119 s[1] = -sqrt_D - p;
2120 return 1 + s[0] != s[1];
2121}
2122
2123function add_valid_ts(s, realRoots, t) {
2124 var foundRoots = 0;
2125 for (var index = 0; index < realRoots; ++index) {
2126 var tValue = s[index];
2127 if (tValue >= 0 && tValue <= 1) {
2128 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2129 if (t[idx2] != tValue) {
2130 t[foundRoots++] = tValue;
2131 }
2132 }
2133 }
2134 }
2135 return foundRoots;
2136}
2137
2138function quadraticRootsValidT(a, b, c, t) {
2139 var s = [];
2140 var realRoots = quadraticRootsReal(A, B, C, s);
2141 var foundRoots = add_valid_ts(s, realRoots, t);
2142 return foundRoots != 0;
2143}
2144
2145function find_cubic_inflections(cubic, tValues) {
2146 var Ax = src[2] - src[0];
2147 var Ay = src[3] - src[1];
2148 var Bx = src[4] - 2 * src[2] + src[0];
2149 var By = src[5] - 2 * src[3] + src[1];
2150 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2151 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2152 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2153 Ax * By - Ay * Bx, tValues);
2154}
2155
2156function dxy_at_t(curve, type, t) {
2157 var dxy = {};
Cary Clarkff114282016-12-14 11:56:16 -05002158 if (type == PATH_LINE) {
2159 dxy.x = curve[2] - curve[0];
2160 dxy.y = curve[3] - curve[1];
2161 } else if (type == PATH_QUAD) {
caryclarkdac1d172014-06-17 05:15:38 -07002162 var a = t - 1;
2163 var b = 1 - 2 * t;
2164 var c = t;
2165 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2166 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002167 } else if (type == PATH_CONIC) {
2168 var p20x = curve[4] - curve[0];
2169 var p20y = curve[5] - curve[1];
2170 var p10xw = (curve[2] - curve[0]) * curve[6];
2171 var p10yw = (curve[3] - curve[1]) * curve[6];
2172 var coeff0x = curve[6] * p20x - p20x;
2173 var coeff0y = curve[6] * p20y - p20y;
2174 var coeff1x = p20x - 2 * p10xw;
2175 var coeff1y = p20y - 2 * p10yw;
2176 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2177 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002178 } else if (type == PATH_CUBIC) {
2179 var one_t = 1 - t;
2180 var a = curve[0];
2181 var b = curve[2];
2182 var c = curve[4];
2183 var d = curve[6];
2184 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2185 a = curve[1];
2186 b = curve[3];
2187 c = curve[5];
2188 d = curve[7];
2189 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2190 }
2191 return dxy;
2192}
2193
Ben Wagner29380bd2017-10-09 14:43:00 -04002194function dpt_at_t(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002195 var type = PATH_LINE + (curve.length / 2 - 2);
Ben Wagner29380bd2017-10-09 14:43:00 -04002196 return dxy_at_t(curve, type, t);
Cary Clarkff114282016-12-14 11:56:16 -05002197}
2198
caryclarkdac1d172014-06-17 05:15:38 -07002199function drawLabel(num, px, py) {
2200 ctx.beginPath();
2201 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2202 ctx.closePath();
2203 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2204 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2205 ctx.stroke();
2206 ctx.fillStyle = "black";
2207 ctx.font = "normal 10px Arial";
2208 // ctx.rotate(0.001);
2209 ctx.fillText(num, px - 2, py + 3);
2210 // ctx.rotate(-0.001);
2211}
2212
2213function drawLabelX(ymin, num, loc) {
2214 var px = (loc - srcLeft) * scale;
2215 var py = (ymin - srcTop) * scale - 20;
2216 drawLabel(num, px, py);
2217}
2218
2219function drawLabelY(xmin, num, loc) {
2220 var px = (xmin - srcLeft) * scale - 20;
2221 var py = (loc - srcTop) * scale;
2222 drawLabel(num, px, py);
2223}
2224
2225function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2226 ctx.beginPath();
2227 ctx.moveTo(hx, hy - 100);
2228 ctx.lineTo(hx, hy);
2229 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2230 ctx.stroke();
2231 ctx.beginPath();
2232 ctx.moveTo(hx, hy);
2233 ctx.lineTo(hx, hy + 100);
2234 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2235 ctx.stroke();
2236 ctx.beginPath();
2237 ctx.moveTo(hx - 100, hy);
2238 ctx.lineTo(hx, hy);
2239 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2240 ctx.stroke();
2241 ctx.beginPath();
2242 ctx.moveTo(hx, hy);
2243 ctx.lineTo(hx + 100, hy);
2244 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2245 ctx.stroke();
2246}
2247
2248function scalexy(x, y, mag) {
2249 var length = Math.sqrt(x * x + y * y);
2250 return mag / length;
2251}
2252
caryclark03b03ca2015-04-23 09:13:37 -07002253function drawArrow(x, y, dx, dy, s) {
2254 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002255 dx *= dscale;
2256 dy *= dscale;
2257 ctx.beginPath();
2258 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2259 x += dx;
2260 y += dy;
2261 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2262 dx /= 10;
2263 dy /= 10;
2264 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2265 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2266 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2267 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2268 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2269 ctx.stroke();
2270}
2271
2272function x_at_t(curve, t) {
2273 var one_t = 1 - t;
2274 if (curve.length == 4) {
2275 return one_t * curve[0] + t * curve[2];
2276 }
2277 var one_t2 = one_t * one_t;
2278 var t2 = t * t;
2279 if (curve.length == 6) {
2280 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2281 }
caryclark1049f122015-04-20 08:31:59 -07002282 if (curve.length == 7) {
2283 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2284 / (one_t2 +2 * one_t * t * curve[6] + t2);
2285 }
caryclarkdac1d172014-06-17 05:15:38 -07002286 var a = one_t2 * one_t;
2287 var b = 3 * one_t2 * t;
2288 var c = 3 * one_t * t2;
2289 var d = t2 * t;
2290 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2291}
2292
2293function y_at_t(curve, t) {
2294 var one_t = 1 - t;
2295 if (curve.length == 4) {
2296 return one_t * curve[1] + t * curve[3];
2297 }
2298 var one_t2 = one_t * one_t;
2299 var t2 = t * t;
2300 if (curve.length == 6) {
2301 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2302 }
caryclark1049f122015-04-20 08:31:59 -07002303 if (curve.length == 7) {
2304 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2305 / (one_t2 +2 * one_t * t * curve[6] + t2);
2306 }
caryclarkdac1d172014-06-17 05:15:38 -07002307 var a = one_t2 * one_t;
2308 var b = 3 * one_t2 * t;
2309 var c = 3 * one_t * t2;
2310 var d = t2 * t;
2311 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2312}
2313
Ben Wagner29380bd2017-10-09 14:43:00 -04002314function pt_at_t(curve, t) {
2315 var pt = {};
2316 pt.x = x_at_t(curve, t);
2317 pt.y = y_at_t(curve, t);
2318 return pt;
Cary Clarkff114282016-12-14 11:56:16 -05002319}
2320
2321function drawOrder(curve, t, label) {
2322 var px = x_at_t(curve, t);
2323 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002324 var _px = (px - srcLeft) * scale;
2325 var _py = (py - srcTop) * scale;
2326 ctx.beginPath();
2327 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2328 ctx.closePath();
2329 ctx.fillStyle = "white";
2330 ctx.fill();
2331 if (label == 'L') {
2332 ctx.strokeStyle = "rgba(255,0,0, 1)";
2333 ctx.fillStyle = "rgba(255,0,0, 1)";
2334 } else {
2335 ctx.strokeStyle = "rgba(0,0,255, 1)";
2336 ctx.fillStyle = "rgba(0,0,255, 1)";
2337 }
2338 ctx.stroke();
2339 ctx.font = "normal 16px Arial";
2340 ctx.textAlign = "center";
2341 ctx.fillText(label, _px, _py + 5);
2342 ctx.font = "normal 10px Arial";
2343}
2344
Ben Wagner29380bd2017-10-09 14:43:00 -04002345function drawVisibleOrder(curve, label) {
2346 var s = pt_at_t(curve, 0);
2347 var e = pt_at_t(curve, 1);
2348 var sOn = ptOnScreen(s);
2349 var eOn = ptOnScreen(e);
2350 var defaultT = 0.85;
2351 if (sOn && eOn)
2352 return drawOrder(curve, defaultT, label);
2353 if (sOn || eOn) {
2354 if (eOn) {
2355 defaultT = 1 - defaultT;
2356 }
2357 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2358 var t = defaultT;
2359 var tries = 16;
2360 do {
2361 var mid = pt_at_t(curve, t);
2362 if (ptOnScreen(mid))
2363 return drawOrder(curve, t, label);
2364 t += step;
2365 step /= 2;
2366 } while (--tries > 0);
2367 drawOrder(curve, defaultT, label);
2368 }
2369 // scattershot until we find a visible point
2370 var denom = 2; // visit odd number num / denom to hit unique pts
2371 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2372 do {
2373 for (var numer = 1; numer < denom; numer += 2) {
2374 var t = numer / denom + 0.1;
2375 if (t >= 1) {
2376 break;
2377 }
2378 var mid = pt_at_t(curve, t);
2379 if (ptOnScreen(mid))
2380 return drawOrder(curve, t, label);
2381 }
2382 denom *= 2;
2383 } while (--tries > 0);
2384 drawOrder(curve, defaultT, label);
Cary Clarkff114282016-12-14 11:56:16 -05002385}
2386
Ben Wagner29380bd2017-10-09 14:43:00 -04002387function set_length(pt, newLen) {
2388 var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y);
2389 var scale = newLen / len;
2390 var newPt = { x: pt.x * scale, y: pt.y * scale };
2391 return newPt;
Cary Clarkff114282016-12-14 11:56:16 -05002392}
2393
Ben Wagner29380bd2017-10-09 14:43:00 -04002394function drawDirection(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002395 var d = dpt_at_t(curve, t);
2396 d = set_length(d, 16);
Ben Wagner29380bd2017-10-09 14:43:00 -04002397 var pt = localToGlobal(pt_at_t(curve, t));
Cary Clarkff114282016-12-14 11:56:16 -05002398 ctx.beginPath();
2399 ctx.moveTo(pt.x - d.y, pt.y + d.x);
2400 ctx.lineTo(pt.x + d.x, pt.y + d.y);
2401 ctx.lineTo(pt.x + d.y, pt.y - d.x);
2402 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2403 ctx.stroke();
2404}
2405
Ben Wagner29380bd2017-10-09 14:43:00 -04002406function drawVisibleDirection(curve) {
2407 var s = pt_at_t(curve, 0);
2408 var e = pt_at_t(curve, 1);
2409 var sOn = ptOnScreen(s);
2410 var eOn = ptOnScreen(e);
2411 var defaultT = 0.65;
2412 if (sOn && eOn) {
2413 return drawDirection(curve, defaultT);
2414 }
2415 if (sOn || eOn) {
2416 if (eOn) {
2417 defaultT = 1 - defaultT;
2418 }
2419 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2420 var t = defaultT;
2421 var tries = 16;
2422 do {
2423 var mid = pt_at_t(curve, t);
2424 if (ptOnScreen(mid))
2425 return drawDirection(curve, t);
2426 t += step;
2427 step /= 2;
2428 } while (--tries > 0);
2429 drawDirection(curve, defaultT);
2430 }
2431 // scattershot until we find a visible point
2432 var denom = 2; // visit odd number num / denom to hit unique pts
2433 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2434 do {
2435 for (var numer = 1; numer < denom; numer += 2) {
2436 var t = numer / denom + 0.1;
2437 if (t >= 1) {
2438 break;
2439 }
2440 var mid = pt_at_t(curve, t);
2441 if (ptOnScreen(mid))
2442 return drawDirection(curve, t);
2443 }
2444 denom *= 2;
2445 } while (--tries > 0);
2446 drawDirection(curve, defaultT);
Cary Clarkff114282016-12-14 11:56:16 -05002447}
2448
2449function drawID(curve, t, id) {
2450 var px = x_at_t(curve, t);
2451 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002452 var _px = (px - srcLeft) * scale;
2453 var _py = (py - srcTop) * scale;
2454 draw_id_at(id, _px, _py);
2455}
2456
Ben Wagner29380bd2017-10-09 14:43:00 -04002457function localToGlobal(local) {
2458 var global = {};
2459 global.x = (local.x - srcLeft) * scale;
2460 global.y = (local.y - srcTop) * scale;
2461 return global;
Cary Clarkff114282016-12-14 11:56:16 -05002462}
2463
Ben Wagner29380bd2017-10-09 14:43:00 -04002464function ptOnScreen(local) {
2465 var pt = localToGlobal(local);
2466 return 10 <= pt.x && pt.x <= screenWidth - 10
2467 && 10 <= pt.y && pt.y <= screenHeight - 10;
Cary Clarkff114282016-12-14 11:56:16 -05002468}
2469
Ben Wagner29380bd2017-10-09 14:43:00 -04002470function drawVisibleID(curve, defaultT, id) {
2471 // determine if either or both ends are visible
2472 var s = pt_at_t(curve, 0);
2473 var e = pt_at_t(curve, 1);
2474 var sOn = ptOnScreen(s);
2475 var eOn = ptOnScreen(e);
2476 if (sOn && eOn)
2477 return drawID(curve, defaultT, id);
2478 if (sOn || eOn) {
2479 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2480 var t = defaultT;
2481 var tries = 16;
2482 do {
2483 var mid = pt_at_t(curve, t);
2484 if (ptOnScreen(mid))
2485 return drawID(curve, t, id);
2486 t += step;
2487 step /= 2;
2488 } while (--tries > 0);
2489 drawID(curve, defaultT, id);
2490 }
2491 // scattershot until we find a visible point
2492 var denom = 2; // visit odd number num / denom to hit unique pts
2493 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2494 do {
2495 for (var numer = 1; numer < denom; numer += 2) {
2496 var t = numer / denom;
2497 var mid = pt_at_t(curve, t);
2498 if (ptOnScreen(mid))
2499 return drawID(curve, t, id);
2500 }
2501 denom *= 2;
2502 } while (--tries > 0);
2503 drawID(curve, defaultT, id);
Cary Clarkff114282016-12-14 11:56:16 -05002504}
2505
caryclarkdac1d172014-06-17 05:15:38 -07002506function draw_id_at(id, _px, _py) {
2507 ctx.beginPath();
2508 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2509 ctx.closePath();
2510 ctx.fillStyle = "white";
2511 ctx.fill();
2512 ctx.strokeStyle = "rgba(127,127,0, 1)";
2513 ctx.fillStyle = "rgba(127,127,0, 1)";
2514 ctx.stroke();
2515 ctx.font = "normal 16px Arial";
2516 ctx.textAlign = "center";
2517 ctx.fillText(id, _px, _py + 5);
2518 ctx.font = "normal 10px Arial";
2519}
2520
2521function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2522 var curve = [x1, y1, x2, y2];
2523 drawCurvePartialID(id, curve, t1, t2);
2524}
2525
caryclark55888e42016-07-18 10:01:36 -07002526function drawLineID(id, x1, y1, x2, y2) {
2527 drawLinePartialID(id, x1, y1, x2, y2, 0, 1);
2528}
2529
caryclarkdac1d172014-06-17 05:15:38 -07002530function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2531 var curve = [x1, y1, x2, y2, x3, y3];
2532 drawCurvePartialID(id, curve, t1, t2);
2533}
2534
caryclark55888e42016-07-18 10:01:36 -07002535function drawQuadID(id, x1, y1, x2, y2, x3, y3) {
2536 drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1);
2537}
2538
caryclark1049f122015-04-20 08:31:59 -07002539function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2540 var curve = [x1, y1, x2, y2, x3, y3, w];
2541 drawCurvePartialID(id, curve, t1, t2);
2542}
2543
caryclark55888e42016-07-18 10:01:36 -07002544function drawConicID(id, x1, y1, x2, y2, x3, y3, w) {
2545 drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1);
2546}
2547
caryclarkdac1d172014-06-17 05:15:38 -07002548function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2549 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2550 drawCurvePartialID(id, curve, t1, t2);
2551}
2552
caryclark55888e42016-07-18 10:01:36 -07002553function drawCubicID(id, x1, y1, x2, y2, x3, y3, x4, y4) {
2554 drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, 0, 1);
2555}
2556
caryclarkdac1d172014-06-17 05:15:38 -07002557function drawCurvePartialID(id, curve, t1, t2) {
Cary Clarkff114282016-12-14 11:56:16 -05002558 drawVisibleID(curve, (t1 + t2) / 2, id);
caryclarkdac1d172014-06-17 05:15:38 -07002559}
2560
2561function drawCurveSpecials(test, curve, type) {
2562 if (pt_labels) {
2563 drawPoints(curve, type, pt_labels == 2);
2564 }
2565 if (control_lines != 0) {
2566 drawControlLines(curve, type, control_lines);
2567 }
2568 if (curve_t) {
2569 drawPointAtT(curve, type);
2570 }
2571 if (draw_midpoint) {
2572 var mid = pointAtT(curve, type, 0.5);
2573 drawPoint(mid.x, mid.y, true);
2574 }
2575 if (draw_id) {
2576 var id = idByCurve(test, curve, type);
2577 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05002578 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07002579 }
2580 }
Ben Wagner29380bd2017-10-09 14:43:00 -04002581 if (draw_direction) {
2582 drawVisibleDirection(curve);
Cary Clarkff114282016-12-14 11:56:16 -05002583 }
caryclarkdac1d172014-06-17 05:15:38 -07002584 if (type == PATH_LINE) {
2585 return;
2586 }
2587 if (draw_deriviatives > 0) {
2588 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002589 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002590 if (draw_deriviatives == 2) {
2591 d = dxy_at_t(curve, type, 1);
2592 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002593 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002594 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002595 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002596 }
2597 }
2598 if (draw_midpoint) {
2599 var mid = pointAtT(curve, type, 0.5);
2600 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002601 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002602 }
2603 }
2604 if (type != PATH_CUBIC) {
2605 return;
2606 }
caryclarkdac1d172014-06-17 05:15:38 -07002607 if (draw_sequence) {
2608 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2609 for (var i = 0; i < 8; i+= 2) {
2610 drawLabelX(ymin, i >> 1, curve[i]);
2611 }
2612 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2613 for (var i = 1; i < 8; i+= 2) {
2614 drawLabelY(xmin, i >> 1, curve[i]);
2615 }
2616 }
2617}
2618
2619function logCurves(test) {
2620 for (curves in test) {
2621 var curve = test[curves];
2622 dumpCurve(curve);
2623 }
2624}
2625
2626function curveToString(curve) {
2627 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002628 var length = curve.length == 7 ? 6 : curve.length;
2629 if (curve.length == 7) {
2630 str += "{";
2631 }
2632 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002633 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2634 if (i < curve.length - 2) {
2635 str += "}, {";
2636 }
2637 }
caryclark1049f122015-04-20 08:31:59 -07002638 str += "}";
2639 if (curve.length == 7) {
2640 str += "}, " + curve[6].toFixed(decimal_places);
2641 }
2642 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002643 return str;
2644}
2645
2646function dumpCurve(curve) {
2647 console.log(curveToString(curve));
2648}
2649
2650function draw(test, lines, title) {
2651 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2652 ctx.font = "normal 50px Arial";
2653 ctx.textAlign = "left";
2654 ctx.fillText(title, 50, 50);
2655 ctx.font = "normal 10px Arial";
2656 ctx.lineWidth = "1.001"; "0.999";
2657 var secondPath = test.length;
2658 var closeCount = 0;
2659 logStart = -1;
2660 logRange = 0;
2661 // find last active rec type at this step
2662 var curType = test[0];
2663 var curStep = 0;
2664 var hasOp = false;
2665 var lastActive = 0;
2666 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002667 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002668 var lastSect = 0;
2669 var lastSort = 0;
2670 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002671 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002672 activeCount = 0;
2673 addCount = 0;
2674 angleCount = 0;
2675 opCount = 0;
2676 sectCount = 0;
2677 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002678 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002679 markCount = 0;
2680 activeMax = 0;
2681 addMax = 0;
2682 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002683 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002684 opMax = 0;
2685 sectMax = 0;
2686 sectMax2 = 0;
2687 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002688 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002689 markMax = 0;
2690 lastIndex = test.length - 3;
2691 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2692 var recType = test[tIndex];
2693 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2694 console.log("unknown rec type: " + recType);
2695 throw "stop execution";
2696 }
2697 // if (curType == recType && curType != REC_TYPE_ADD) {
2698 // continue;
2699 // }
2700 var inStepRange = step_limit == 0 || curStep < step_limit;
2701 curType = recType;
2702 if (recType == REC_TYPE_OP) {
2703 hasOp = true;
2704 continue;
2705 }
2706 if (recType == REC_TYPE_UNKNOWN) {
2707 // these types do not advance step
2708 continue;
2709 }
2710 var bumpStep = false;
2711 var records = test[tIndex + 2];
2712 var fragType = records[0];
2713 if (recType == REC_TYPE_ADD) {
2714 if (records.length != 2) {
2715 console.log("expect only two elements: " + records.length);
2716 throw "stop execution";
2717 }
2718 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2719 continue;
2720 }
2721 ++addMax;
2722 if (!draw_add || !inStepRange) {
2723 continue;
2724 }
2725 lastAdd = tIndex;
2726 ++addCount;
2727 bumpStep = true;
2728 }
2729 if (recType == REC_TYPE_PATH && hasOp) {
2730 secondPath = tIndex;
2731 }
caryclark54359292015-03-26 07:52:43 -07002732 if (recType == REC_TYPE_PATH2 && hasOp) {
2733 secondPath = tIndex;
2734 }
caryclarkdac1d172014-06-17 05:15:38 -07002735 if (recType == REC_TYPE_ACTIVE) {
2736 ++activeMax;
2737 if (!draw_active || !inStepRange) {
2738 continue;
2739 }
2740 lastActive = tIndex;
2741 ++activeCount;
2742 bumpStep = true;
2743 }
2744 if (recType == REC_TYPE_ACTIVE_OP) {
2745 ++opMax;
2746 if (!draw_op || !inStepRange) {
2747 continue;
2748 }
2749 lastOp = tIndex;
2750 ++opCount;
2751 bumpStep = true;
2752 }
caryclark54359292015-03-26 07:52:43 -07002753 if (recType == REC_TYPE_AFTERPART) {
2754 if (draw_angle != 3 || !inStepRange) {
2755 continue;
2756 }
2757 lastAngle = tIndex;
2758 ++angleCount;
2759 bumpStep = true;
2760 }
caryclarkdac1d172014-06-17 05:15:38 -07002761 if (recType == REC_TYPE_ANGLE) {
2762 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002763 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002764 continue;
2765 }
2766 lastAngle = tIndex;
2767 ++angleCount;
2768 bumpStep = true;
2769 }
caryclark624637c2015-05-11 07:21:27 -07002770 if (recType == REC_TYPE_COINCIDENCE) {
2771 ++coinMax;
2772 if (!draw_coincidence || !inStepRange) {
2773 continue;
2774 }
2775 lastCoin = tIndex;
2776 ++coinCount;
2777 bumpStep = true;
2778 }
caryclarkdac1d172014-06-17 05:15:38 -07002779 if (recType == REC_TYPE_SECT) {
2780 if (records.length != 2) {
2781 console.log("expect only two elements: " + records.length);
2782 throw "stop execution";
2783 }
2784 ++sectMax;
2785 var sectBump = 1;
2786 switch (fragType) {
2787 case INTERSECT_LINE:
2788 case INTERSECT_QUAD_LINE:
2789 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002790 case INTERSECT_CONIC_LINE:
caryclark55888e42016-07-18 10:01:36 -07002791 case INTERSECT_CONIC_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002792 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002793 case INTERSECT_SELF_CUBIC:
2794 case INTERSECT_CUBIC_LINE:
2795 case INTERSECT_CUBIC_QUAD:
2796 case INTERSECT_CUBIC:
2797 sectBump = 1;
2798 break;
2799 case INTERSECT_LINE_2:
2800 case INTERSECT_QUAD_LINE_2:
2801 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002802 case INTERSECT_CONIC_LINE_2:
caryclark55888e42016-07-18 10:01:36 -07002803 case INTERSECT_CONIC_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002804 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002805 case INTERSECT_CUBIC_LINE_2:
2806 case INTERSECT_CUBIC_QUAD_2:
2807 case INTERSECT_CUBIC_2:
2808 sectBump = 2;
2809 break;
2810 case INTERSECT_LINE_NO:
2811 case INTERSECT_QUAD_LINE_NO:
2812 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002813 case INTERSECT_CONIC_LINE_NO:
caryclark55888e42016-07-18 10:01:36 -07002814 case INTERSECT_CONIC_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002815 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002816 case INTERSECT_SELF_CUBIC_NO:
2817 case INTERSECT_CUBIC_LINE_NO:
2818 case INTERSECT_CUBIC_QUAD_NO:
2819 case INTERSECT_CUBIC_NO:
2820 sectBump = 0;
2821 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002822 case INTERSECT_CONIC_QUAD_3:
caryclarkdac1d172014-06-17 05:15:38 -07002823 case INTERSECT_CUBIC_LINE_3:
2824 case INTERSECT_CUBIC_QUAD_3:
2825 case INTERSECT_CUBIC_3:
2826 sectBump = 3;
2827 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002828 case INTERSECT_CONIC_QUAD_4:
caryclarkdac1d172014-06-17 05:15:38 -07002829 case INTERSECT_CUBIC_QUAD_4:
2830 case INTERSECT_CUBIC_4:
2831 sectBump = 4;
2832 break;
2833 default:
2834 console.log("missing case " + records.length);
2835 throw "stop execution";
2836 }
2837 sectMax2 += sectBump;
2838 if (draw_intersection <= 1 || !inStepRange) {
2839 continue;
2840 }
2841 lastSect = tIndex;
2842 sectCount += sectBump;
2843 bumpStep = true;
2844 }
2845 if (recType == REC_TYPE_SORT) {
2846 ++sortMax;
2847 if (!draw_sort || !inStepRange) {
2848 continue;
2849 }
2850 lastSort = tIndex;
2851 ++sortCount;
2852 bumpStep = true;
2853 }
caryclark03b03ca2015-04-23 09:13:37 -07002854 if (recType == REC_TYPE_TOP) {
2855 ++topMax;
2856 if (!draw_top || !inStepRange) {
2857 continue;
2858 }
2859 lastTop = tIndex;
2860 ++topCount;
2861 bumpStep = true;
2862 }
caryclarkdac1d172014-06-17 05:15:38 -07002863 if (recType == REC_TYPE_MARK) {
2864 ++markMax;
2865 if (!draw_mark || !inStepRange) {
2866 continue;
2867 }
2868 lastMark = tIndex;
2869 ++markCount;
2870 bumpStep = true;
2871 }
2872 if (bumpStep) {
2873 lastIndex = tIndex;
2874 logStart = test[tIndex + 1];
2875 logRange = records.length / 2;
2876 ++curStep;
2877 }
2878 }
2879 stepMax = (draw_add ? addMax : 0)
2880 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002881 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002882 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002883 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002884 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002885 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002886 + (draw_mark ? markMax : 0)
2887 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2888 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002889 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002890 }
2891 drawnPts = [];
2892 drawnLines = [];
2893 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002894 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002895 drawnCubics = [];
2896 focusXmin = focusYmin = Infinity;
2897 focusXmax = focusYmax = -Infinity;
2898 var pathIndex = 0;
2899 var opLetter = 'S';
2900 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2901 var recType = test[tIndex];
2902 var records = test[tIndex + 2];
2903 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2904 var fragType = records[recordIndex];
2905 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2906 console.log("unknown in range frag type: " + fragType);
2907 throw "stop execution";
2908 }
2909 var frags = records[recordIndex + 1];
2910 focus_enabled = false;
2911 switch (recType) {
2912 case REC_TYPE_COMPUTED:
2913 if (draw_computed == 0) {
2914 continue;
2915 }
2916 ctx.lineWidth = 1;
2917 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2918 ctx.fillStyle = "blue";
2919 var drawThis = false;
2920 switch (fragType) {
2921 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002922 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2923 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002924 drawQuad(frags[0], frags[1], frags[2], frags[3],
2925 frags[4], frags[5]);
2926 drawThis = true;
2927 }
2928 break;
caryclark1049f122015-04-20 08:31:59 -07002929 case PATH_CONIC:
2930 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2931 && (draw_computed & 7) == pathIndex)) {
2932 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2933 frags[4], frags[5], frags[6]);
2934 drawThis = true;
2935 }
2936 break;
caryclarkdac1d172014-06-17 05:15:38 -07002937 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002938 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2939 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002940 drawCubic(frags[0], frags[1], frags[2], frags[3],
2941 frags[4], frags[5], frags[6], frags[7]);
2942 drawThis = true;
2943 }
2944 ++pathIndex;
2945 break;
2946 case COMPUTED_SET_1:
2947 pathIndex = 0;
2948 break;
2949 case COMPUTED_SET_2:
2950 pathIndex = 1;
2951 break;
2952 default:
2953 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2954 throw "stop execution";
2955 }
2956 if (!drawThis || collect_bounds) {
2957 break;
2958 }
2959 drawCurveSpecials(test, frags, fragType);
2960 break;
caryclark26ad22a2015-10-16 09:03:38 -07002961 case REC_TYPE_ALIGNED:
2962 if (draw_path < 4) {
2963 continue;
2964 }
caryclarkdac1d172014-06-17 05:15:38 -07002965 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002966 case REC_TYPE_PATH2:
caryclark26ad22a2015-10-16 09:03:38 -07002967 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
2968 continue;
2969 }
caryclarkdac1d172014-06-17 05:15:38 -07002970 if (!draw_path) {
2971 continue;
2972 }
2973 var firstPath = tIndex < secondPath;
2974 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2975 continue;
2976 }
2977 ctx.lineWidth = 1;
2978 ctx.strokeStyle = firstPath ? "black" : "red";
2979 ctx.fillStyle = "blue";
caryclark55888e42016-07-18 10:01:36 -07002980 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002981 switch (fragType) {
2982 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002983 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2984 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002985 break;
2986 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002987 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2988 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2989 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002990 break;
caryclark1049f122015-04-20 08:31:59 -07002991 case PATH_CONIC:
2992 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
2993 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
2994 frags2[4], frags2[5], frags2[6]);
2995 break;
caryclarkdac1d172014-06-17 05:15:38 -07002996 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07002997 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
2998 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
2999 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07003000 break;
3001 default:
caryclark26ad22a2015-10-16 09:03:38 -07003002 console.log("unknown " + recType + " frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003003 throw "stop execution";
3004 }
3005 if (collect_bounds) {
3006 break;
3007 }
caryclark54359292015-03-26 07:52:43 -07003008 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003009 break;
3010 case REC_TYPE_OP:
3011 switch (fragType) {
3012 case OP_INTERSECT: opLetter = 'I'; break;
3013 case OP_DIFFERENCE: opLetter = 'D'; break;
3014 case OP_UNION: opLetter = 'U'; break;
3015 case OP_XOR: opLetter = 'X'; break;
3016 default:
3017 console.log("unknown REC_TYPE_OP frag type: " + fragType);
3018 throw "stop execution";
3019 }
3020 break;
3021 case REC_TYPE_ACTIVE:
3022 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
3023 continue;
3024 }
3025 var x1 = frags[SPAN_X1];
3026 var y1 = frags[SPAN_Y1];
3027 var x2 = frags[SPAN_X2];
3028 var y2 = frags[SPAN_Y2];
caryclark55888e42016-07-18 10:01:36 -07003029 var x3, y3, x3, y4, w;
caryclarkdac1d172014-06-17 05:15:38 -07003030 ctx.lineWidth = 3;
3031 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3032 focus_enabled = true;
3033 switch (fragType) {
3034 case ACTIVE_LINE_SPAN:
caryclark55888e42016-07-18 10:01:36 -07003035 drawLine(x1, y1, x2, y2);
caryclarkdac1d172014-06-17 05:15:38 -07003036 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003037 drawLineID(frags[0], x1, y1, x2, y2);
3038 }
3039 if (pt_labels) {
3040 var curve = [x1, y1, x2, y2];
3041 ctx.fillStyle = "blue";
3042 drawPoints(curve, PATH_LINE, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003043 }
3044 break;
3045 case ACTIVE_QUAD_SPAN:
3046 x3 = frags[SPAN_X3];
3047 y3 = frags[SPAN_Y3];
caryclark55888e42016-07-18 10:01:36 -07003048 drawQuad(x1, y1, x2, y2, x3, y3);
caryclarkdac1d172014-06-17 05:15:38 -07003049 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003050 drawQuadID(frags[0], x1, y1, x2, y2, x3, y3);
3051 }
3052 if (pt_labels) {
3053 var curve = [x1, y1, x2, y2, x3, y3];
3054 ctx.fillStyle = "blue";
3055 drawPoints(curve, PATH_QUAD, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003056 }
3057 break;
caryclark1049f122015-04-20 08:31:59 -07003058 case ACTIVE_CONIC_SPAN:
3059 x3 = frags[SPAN_X3];
3060 y3 = frags[SPAN_Y3];
caryclark1049f122015-04-20 08:31:59 -07003061 w = frags[SPAN_K_W];
caryclark55888e42016-07-18 10:01:36 -07003062 drawConicWithQuads(x1, y1, x2, y2, x3, y3, w);
caryclark1049f122015-04-20 08:31:59 -07003063 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003064 drawConicID(frags[0], x1, y1, x2, y2, x3, y3, w);
3065 }
3066 if (pt_labels) {
3067 var curve = [x1, y1, x2, y2, x3, y3, w];
3068 ctx.fillStyle = "blue";
3069 drawPoints(curve, PATH_CONIC, pt_labels == 2);
caryclark1049f122015-04-20 08:31:59 -07003070 }
3071 break;
caryclarkdac1d172014-06-17 05:15:38 -07003072 case ACTIVE_CUBIC_SPAN:
3073 x3 = frags[SPAN_X3];
3074 y3 = frags[SPAN_Y3];
3075 x4 = frags[SPAN_X4];
3076 y4 = frags[SPAN_Y4];
caryclark55888e42016-07-18 10:01:36 -07003077 drawCubic(x1, y1, x2, y2, x3, y3, x4, y4);
caryclarkdac1d172014-06-17 05:15:38 -07003078 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003079 drawCubicID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4);
3080 }
3081 if (pt_labels) {
3082 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
3083 ctx.fillStyle = "blue";
3084 drawPoints(curve, PATH_CUBIC, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003085 }
3086 break;
3087 default:
3088 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
3089 throw "stop execution";
3090 }
3091 break;
3092 case REC_TYPE_ACTIVE_OP:
3093 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
3094 continue;
3095 }
3096 focus_enabled = true;
3097 ctx.lineWidth = 3;
3098 var activeSpan = frags[7] == "1";
3099 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
3100 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3101 drawCurve(curve);
3102 if (draw_op > 1) {
3103 drawArc(curve, false, frags[3], frags[4]);
3104 drawArc(curve, true, frags[5], frags[6]);
3105 }
3106 break;
3107 case REC_TYPE_ADD:
3108 if (!draw_add) {
3109 continue;
3110 }
3111 ctx.lineWidth = 3;
3112 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
3113 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
3114 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
3115 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
3116 : "rgba(127,0,127, 0.3)";
3117 focus_enabled = true;
3118 switch (fragType) {
3119 case ADD_MOVETO:
3120 break;
3121 case ADD_LINETO:
3122 if (step_limit == 0 || tIndex >= lastAdd) {
3123 drawLine(frags[0], frags[1], frags[2], frags[3]);
3124 }
3125 break;
3126 case ADD_QUADTO:
3127 if (step_limit == 0 || tIndex >= lastAdd) {
3128 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
3129 }
3130 break;
caryclark1049f122015-04-20 08:31:59 -07003131 case ADD_CONICTO:
3132 if (step_limit == 0 || tIndex >= lastAdd) {
3133 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
3134 frags[4], frags[5], frags[6]);
3135 }
3136 break;
caryclarkdac1d172014-06-17 05:15:38 -07003137 case ADD_CUBICTO:
3138 if (step_limit == 0 || tIndex >= lastAdd) {
3139 drawCubic(frags[0], frags[1], frags[2], frags[3],
3140 frags[4], frags[5], frags[6], frags[7]);
3141 }
3142 break;
3143 case ADD_CLOSE:
3144 ++closeCount;
3145 break;
3146 case ADD_FILL:
3147 break;
3148 default:
3149 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
3150 throw "stop execution";
3151 }
3152 break;
3153 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07003154 angleBetween = frags[18] == "T";
3155 afterIndex = 0;
3156 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07003157 continue;
3158 }
3159 focus_enabled = true;
3160 ctx.lineWidth = 3;
3161 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07003162 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
3163 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
3164 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07003165 drawCurve(leftCurve);
3166 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07003167 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07003168 drawCurve(midCurve);
3169 if (draw_angle > 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003170 drawVisibleOrder(leftCurve, 'L');
3171 drawVisibleOrder(rightCurve, 'R');
3172 }
Ben Wagner29380bd2017-10-09 14:43:00 -04003173 if (draw_id) {
3174 drawVisibleID(leftCurve, 0.5, frags[0]);
3175 drawVisibleID(midCurve, 0.5, frags[6]);
3176 drawVisibleID(rightCurve, 0.5, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003177 }
3178 break;
caryclark54359292015-03-26 07:52:43 -07003179 case REC_TYPE_AFTERPART:
3180 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
3181 continue;
3182 }
3183 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
3184 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
Cary Clarkff114282016-12-14 11:56:16 -05003185 : "rgba(0,0,255, 1.0)";
3186 var curve;
3187 var id;
caryclark54359292015-03-26 07:52:43 -07003188 switch (fragType) {
3189 case PATH_LINE:
Cary Clarkff114282016-12-14 11:56:16 -05003190 curve = [ frags[0], frags[1], frags[2], frags[3] ];
3191 id = frags[4];
caryclark54359292015-03-26 07:52:43 -07003192 break;
3193 case PATH_QUAD:
Cary Clarkff114282016-12-14 11:56:16 -05003194 curve = [ frags[0], frags[1], frags[2], frags[3],
3195 frags[4], frags[5] ];
3196 id = frags[6];
caryclark54359292015-03-26 07:52:43 -07003197 break;
caryclark1049f122015-04-20 08:31:59 -07003198 case PATH_CONIC:
Cary Clarkff114282016-12-14 11:56:16 -05003199 curve = [ frags[0], frags[1], frags[2], frags[3],
3200 frags[4], frags[5], frags[6] ];
3201 id = frags[7];
caryclark1049f122015-04-20 08:31:59 -07003202 break;
caryclark54359292015-03-26 07:52:43 -07003203 case PATH_CUBIC:
Cary Clarkff114282016-12-14 11:56:16 -05003204 curve = [ frags[0], frags[1], frags[2], frags[3],
3205 frags[4], frags[5], frags[6], frags[7] ];
3206 id = frags[8];
caryclark54359292015-03-26 07:52:43 -07003207 break;
3208 default:
3209 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
3210 throw "stop execution";
3211 }
Cary Clarkff114282016-12-14 11:56:16 -05003212 drawCurve(curve);
Ben Wagner29380bd2017-10-09 14:43:00 -04003213 if (draw_id) {
3214 drawVisibleID(curve, 0.5, id);
Cary Clarkff114282016-12-14 11:56:16 -05003215 }
caryclark54359292015-03-26 07:52:43 -07003216 ++afterIndex;
3217 break;
caryclark624637c2015-05-11 07:21:27 -07003218 case REC_TYPE_COINCIDENCE:
3219 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
3220 continue;
3221 }
3222 focus_enabled = true;
3223 ctx.lineWidth = 3;
3224 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
3225 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3226 drawCurve(curve);
3227 break;
caryclarkdac1d172014-06-17 05:15:38 -07003228 case REC_TYPE_SECT:
3229 if (!draw_intersection) {
3230 continue;
3231 }
3232 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
3233 continue;
3234 }
3235 // draw_intersection == 1 : show all
3236 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
3237 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
3238 ctx.lineWidth = 1;
3239 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3240 ctx.fillStyle = "blue";
3241 focus_enabled = true;
3242 var f = [];
3243 var c1s;
3244 var c1l;
3245 var c2s;
3246 var c2l;
3247 switch (fragType) {
3248 case INTERSECT_LINE:
3249 f.push(5, 6, 0, 7);
3250 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
3251 break;
3252 case INTERSECT_LINE_2:
3253 f.push(5, 6, 0, 10);
3254 f.push(8, 9, 7, 15);
3255 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
3256 break;
3257 case INTERSECT_LINE_NO:
3258 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
3259 break;
3260 case INTERSECT_QUAD_LINE:
3261 f.push(7, 8, 0, 9);
3262 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
3263 break;
3264 case INTERSECT_QUAD_LINE_2:
3265 f.push(7, 8, 0, 12);
3266 f.push(10, 11, 9, 17);
3267 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
3268 break;
3269 case INTERSECT_QUAD_LINE_NO:
3270 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
3271 break;
3272 case INTERSECT_QUAD:
3273 f.push(7, 8, 0, 9);
3274 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
3275 break;
3276 case INTERSECT_QUAD_2:
3277 f.push(7, 8, 0, 12);
3278 f.push(10, 11, 9, 19);
3279 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
3280 break;
3281 case INTERSECT_QUAD_NO:
3282 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
3283 break;
caryclark1049f122015-04-20 08:31:59 -07003284 case INTERSECT_CONIC_LINE:
3285 f.push(8, 9, 0, 10);
3286 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
3287 break;
3288 case INTERSECT_CONIC_LINE_2:
3289 f.push(8, 9, 0, 12);
3290 f.push(11, 12, 10, 18);
3291 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
3292 break;
3293 case INTERSECT_CONIC_LINE_NO:
3294 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
3295 break;
caryclark55888e42016-07-18 10:01:36 -07003296 case INTERSECT_CONIC_QUAD:
3297 f.push(8, 9, 0, 10);
3298 c1s = 1; c1l = 7; c2s = 11; c2l = 6;
3299 break;
3300 case INTERSECT_CONIC_QUAD_2:
3301 f.push(8, 9, 0, 12);
3302 f.push(11, 12, 10, 18);
3303 c1s = 1; c1l = 7; c2s = 14; c2l = 6;
3304 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07003305 case INTERSECT_CONIC_QUAD_3:
3306 f.push(8, 9, 0, 15);
3307 f.push(11, 12, 10, 21);
3308 f.push(14, 15, 13, 22);
3309 c1s = 1; c1l = 7; c2s = 17; c2l = 6;
3310 break;
3311 case INTERSECT_CONIC_QUAD_4:
3312 f.push(8, 9, 0, 18);
3313 f.push(11, 12, 10, 24);
3314 f.push(14, 15, 13, 25);
3315 f.push(17, 18, 16, 26);
3316 c1s = 1; c1l = 7; c2s = 20; c2l = 6;
3317 break;
caryclark55888e42016-07-18 10:01:36 -07003318 case INTERSECT_CONIC_QUAD_NO:
3319 c1s = 0; c1l = 7; c2s = 7; c2l = 6;
3320 break;
caryclark1049f122015-04-20 08:31:59 -07003321 case INTERSECT_CONIC:
3322 f.push(8, 9, 0, 10);
3323 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
3324 break;
3325 case INTERSECT_CONIC_2:
3326 f.push(8, 9, 0, 13);
3327 f.push(11, 12, 10, 21);
3328 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
3329 break;
3330 case INTERSECT_CONIC_NO:
3331 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
3332 break;
caryclarkdac1d172014-06-17 05:15:38 -07003333 case INTERSECT_SELF_CUBIC:
3334 f.push(9, 10, 0, 11);
3335 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3336 break;
3337 case INTERSECT_SELF_CUBIC_NO:
3338 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3339 break;
3340 case INTERSECT_CUBIC_LINE:
3341 f.push(9, 10, 0, 11);
3342 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3343 break;
3344 case INTERSECT_CUBIC_LINE_2:
3345 f.push(9, 10, 0, 14);
3346 f.push(12, 13, 11, 19);
3347 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3348 break;
3349 case INTERSECT_CUBIC_LINE_3:
3350 f.push(9, 10, 0, 17);
3351 f.push(12, 13, 11, 22);
3352 f.push(15, 16, 14, 23);
3353 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3354 break;
3355 case INTERSECT_CUBIC_QUAD_NO:
3356 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3357 break;
3358 case INTERSECT_CUBIC_QUAD:
3359 f.push(9, 10, 0, 11);
3360 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3361 break;
3362 case INTERSECT_CUBIC_QUAD_2:
3363 f.push(9, 10, 0, 14);
3364 f.push(12, 13, 11, 21);
3365 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3366 break;
3367 case INTERSECT_CUBIC_QUAD_3:
3368 f.push(9, 10, 0, 17);
3369 f.push(12, 13, 11, 24);
3370 f.push(15, 16, 14, 25);
3371 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3372 break;
3373 case INTERSECT_CUBIC_QUAD_4:
3374 f.push(9, 10, 0, 20);
3375 f.push(12, 13, 11, 27);
3376 f.push(15, 16, 14, 28);
3377 f.push(18, 19, 17, 29);
3378 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3379 break;
3380 case INTERSECT_CUBIC_LINE_NO:
3381 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3382 break;
3383 case INTERSECT_CUBIC:
3384 f.push(9, 10, 0, 11);
3385 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3386 break;
3387 case INTERSECT_CUBIC_2:
3388 f.push(9, 10, 0, 14);
3389 f.push(12, 13, 11, 23);
3390 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3391 break;
3392 case INTERSECT_CUBIC_3:
3393 f.push(9, 10, 0, 17);
3394 f.push(12, 13, 11, 26);
3395 f.push(15, 16, 14, 27);
3396 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3397 break;
3398 case INTERSECT_CUBIC_4:
3399 f.push(9, 10, 0, 20);
3400 f.push(12, 13, 11, 29);
3401 f.push(15, 16, 14, 30);
3402 f.push(18, 19, 17, 31);
3403 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3404 break;
3405 case INTERSECT_CUBIC_NO:
3406 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3407 break;
3408 default:
3409 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3410 throw "stop execution";
3411 }
3412 if (draw_intersection != 1) {
3413 var id = -1;
3414 var curve;
3415 switch (c1l) {
caryclark55888e42016-07-18 10:01:36 -07003416 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003417 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3418 if (draw_id) {
3419 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3420 id = idByCurve(test, curve, PATH_LINE);
3421 }
3422 break;
3423 case 6:
3424 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3425 frags[c1s + 4], frags[c1s + 5]);
3426 if (draw_id) {
3427 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3428 frags[c1s + 4], frags[c1s + 5]];
3429 id = idByCurve(test, curve, PATH_QUAD);
3430 }
3431 break;
caryclark1049f122015-04-20 08:31:59 -07003432 case 7:
3433 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3434 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3435 if (draw_id) {
3436 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3437 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3438 id = idByCurve(test, curve, PATH_CONIC);
3439 }
3440 break;
caryclarkdac1d172014-06-17 05:15:38 -07003441 case 8:
3442 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3443 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3444 if (draw_id) {
3445 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3446 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3447 id = idByCurve(test, curve, PATH_CUBIC);
3448 }
3449 break;
3450 }
3451 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05003452 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003453 }
3454 id = -1;
3455 switch (c2l) {
3456 case 0:
3457 break;
caryclark55888e42016-07-18 10:01:36 -07003458 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003459 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3460 if (draw_id) {
3461 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3462 id = idByCurve(test, curve, PATH_LINE);
3463 }
3464 break;
3465 case 6:
3466 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3467 frags[c2s + 4], frags[c2s + 5]);
3468 if (draw_id) {
3469 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3470 frags[c2s + 4], frags[c2s + 5]];
3471 id = idByCurve(test, curve, PATH_QUAD);
3472 }
3473 break;
caryclark1049f122015-04-20 08:31:59 -07003474 case 7:
3475 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3476 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3477 if (draw_id) {
3478 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3479 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3480 id = idByCurve(test, curve, PATH_CONIC);
3481 }
3482 break;
caryclarkdac1d172014-06-17 05:15:38 -07003483 case 8:
3484 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3485 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3486 if (draw_id) {
3487 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3488 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3489 id = idByCurve(test, curve, PATH_CUBIC);
3490 }
3491 break;
3492 }
3493 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05003494 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003495 }
3496 }
3497 if (collect_bounds) {
3498 break;
3499 }
caryclark54359292015-03-26 07:52:43 -07003500 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3501 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003502 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3503 }
3504 }
3505 if (!draw_intersectT) {
3506 break;
3507 }
3508 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003509 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3510 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003511 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3512 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3513 }
3514 }
3515 break;
3516 case REC_TYPE_SORT:
3517 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3518 continue;
3519 }
3520 ctx.lineWidth = 3;
3521 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3522 focus_enabled = true;
3523 switch (fragType) {
3524 case SORT_UNARY:
3525 case SORT_BINARY:
3526 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3527 drawCurve(curve);
3528 break;
3529 default:
3530 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3531 throw "stop execution";
3532 }
3533 break;
caryclark03b03ca2015-04-23 09:13:37 -07003534 case REC_TYPE_TOP:
3535 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3536 continue;
3537 }
3538 ctx.lineWidth = 3;
3539 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3540 focus_enabled = true;
3541 {
3542 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3543 drawCurve(curve);
3544 var type = PATH_LINE + (curve.length / 2 - 2);
3545 var mid = pointAtT(curve, type, 0.5);
3546 var d = dxy_at_t(curve, type, 0.5);
3547 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3548 }
3549 break;
caryclarkdac1d172014-06-17 05:15:38 -07003550 case REC_TYPE_MARK:
3551 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3552 continue;
3553 }
3554 ctx.lineWidth = 3;
3555 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3556 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3557 focus_enabled = true;
3558 switch (fragType) {
3559 case MARK_LINE:
3560 case MARK_DONE_LINE:
3561 case MARK_UNSORTABLE_LINE:
3562 case MARK_SIMPLE_LINE:
3563 case MARK_SIMPLE_DONE_LINE:
3564 case MARK_DONE_UNARY_LINE:
3565 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3566 frags[5], frags[9]);
3567 if (draw_id) {
3568 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3569 frags[5], frags[9]);
3570 }
3571 break;
3572 case MARK_QUAD:
3573 case MARK_DONE_QUAD:
3574 case MARK_UNSORTABLE_QUAD:
3575 case MARK_SIMPLE_QUAD:
3576 case MARK_SIMPLE_DONE_QUAD:
3577 case MARK_DONE_UNARY_QUAD:
3578 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3579 frags[5], frags[6], frags[7], frags[11]);
3580 if (draw_id) {
3581 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3582 frags[5], frags[6], frags[7], frags[11]);
3583 }
3584 break;
3585 case MARK_CUBIC:
3586 case MARK_DONE_CUBIC:
3587 case MARK_UNSORTABLE_CUBIC:
3588 case MARK_SIMPLE_CUBIC:
3589 case MARK_SIMPLE_DONE_CUBIC:
3590 case MARK_DONE_UNARY_CUBIC:
3591 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3592 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3593 if (draw_id) {
3594 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3595 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3596 }
3597 break;
3598 case MARK_ANGLE_LAST:
3599 // FIXME: ignored for now
3600 break;
3601 default:
3602 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3603 throw "stop execution";
3604 }
3605 break;
3606 default:
3607 continue;
3608 }
3609 }
3610 switch (recType) {
3611 case REC_TYPE_SORT:
3612 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3613 break;
3614 }
3615 var angles = []; // use tangent lines to describe arcs
3616 var windFrom = [];
3617 var windTo = [];
3618 var opp = [];
3619 var minXY = Number.MAX_VALUE;
3620 var partial;
3621 focus_enabled = true;
3622 var someUnsortable = false;
3623 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3624 var fragType = records[recordIndex];
3625 var frags = records[recordIndex + 1];
3626 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3627 (fragType == SORT_BINARY && frags[16]);
3628 someUnsortable |= unsortable;
3629 switch (fragType) {
3630 case SORT_UNARY:
3631 case SORT_BINARY:
3632 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3633 break;
3634 default:
3635 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3636 throw "stop execution";
3637 }
3638 var dx = boundsWidth(partial);
3639 var dy = boundsHeight(partial);
3640 minXY = Math.min(minXY, dx * dx + dy * dy);
3641 if (collect_bounds) {
3642 continue;
3643 }
3644 angles.push(tangent(partial));
3645 var from = frags[12];
3646 var to = frags[12];
3647 var sgn = frags[10];
3648 if (sgn < 0) {
3649 from -= frags[11];
3650 } else if (sgn > 0) {
3651 to -= frags[11];
3652 }
3653 windFrom.push(from + (unsortable ? "!" : ""));
3654 windTo.push(to + (unsortable ? "!" : ""));
3655 opp.push(fragType == SORT_BINARY);
3656 if (draw_sort == 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003657 drawVisibleOrder(partial, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003658 } else {
Cary Clarkff114282016-12-14 11:56:16 -05003659 drawVisibleOrder(partial, (recordIndex / 2) + 1);
caryclarkdac1d172014-06-17 05:15:38 -07003660 }
3661 }
3662 var radius = Math.sqrt(minXY) / 2 * scale;
3663 radius = Math.min(50, radius);
3664 var scaledRadius = radius / scale;
3665 var centerX = partial[0];
3666 var centerY = partial[1];
3667 if (collect_bounds) {
3668 if (focus_enabled) {
3669 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3670 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3671 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3672 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3673 }
3674 break;
3675 }
3676 break;
3677 default:
3678 break;
3679 }
3680 }
3681 if (collect_bounds) {
3682 return;
3683 }
3684 if (draw_log && logStart >= 0) {
3685 ctx.font = "normal 10px Arial";
3686 ctx.textAlign = "left";
3687 ctx.beginPath();
3688 var top = screenHeight - 20 - (logRange + 2) * 10;
3689 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3690 ctx.fillStyle = "white";
3691 ctx.fill();
3692 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3693 if (logStart > 0) {
3694 ctx.fillText(lines[logStart - 1], 50, top + 8);
3695 }
3696 ctx.fillStyle = "black";
3697 for (var idx = 0; idx < logRange; ++idx) {
3698 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3699 }
3700 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3701 if (logStart + logRange < lines.length) {
3702 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3703 }
3704 }
3705 if (draw_legend) {
3706 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003707 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003708 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3709 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3710 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3711 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3712 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003713 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003714 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3715 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003716 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003717 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
caryclark55888e42016-07-18 10:01:36 -07003718 drawBox(pos++, "black", "white",
caryclark26ad22a2015-10-16 09:03:38 -07003719 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
caryclarkdac1d172014-06-17 05:15:38 -07003720 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3721 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3722 draw_computed != 0, computedKey);
3723 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3724 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3725 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3726 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3727 if (curve_t) {
3728 drawCurveTControl();
3729 }
3730 ctx.font = "normal 20px Arial";
3731 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3732 ctx.textAlign = "right";
3733 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3734 }
3735 if (draw_hints) {
3736 ctx.font = "normal 10px Arial";
3737 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3738 ctx.textAlign = "right";
3739 var y = 4;
3740 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3741 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3742 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3743 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003744 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3745 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3746 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3747 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3748 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3749 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3750 }
3751}
3752
3753function drawBox(y, backC, foreC, str, enable, label) {
3754 ctx.beginPath();
3755 ctx.fillStyle = backC;
3756 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3757 ctx.fill();
3758 ctx.font = "normal 16px Arial";
3759 ctx.fillStyle = foreC;
3760 ctx.textAlign = "center";
3761 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3762 if (!enable) {
3763 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3764 ctx.fill();
3765 }
3766 if (label != '') {
3767 ctx.font = "normal 9px Arial";
3768 ctx.fillStyle = "black";
3769 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3770 }
3771}
3772
3773function drawCurveTControl() {
3774 ctx.lineWidth = 2;
3775 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3776 ctx.beginPath();
3777 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3778 ctx.stroke();
3779 var ty = 40 + curveT * (screenHeight - 80);
3780 ctx.beginPath();
3781 ctx.moveTo(screenWidth - 80, ty);
3782 ctx.lineTo(screenWidth - 85, ty - 5);
3783 ctx.lineTo(screenWidth - 85, ty + 5);
3784 ctx.lineTo(screenWidth - 80, ty);
3785 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3786 ctx.fill();
3787 var num = curveT.toFixed(decimal_places);
3788 ctx.font = "normal 10px Arial";
3789 ctx.textAlign = "left";
3790 ctx.fillText(num, screenWidth - 78, ty);
3791}
3792
3793function ptInTControl() {
3794 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07003795 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07003796 var left = tgt.offsetLeft;
3797 var top = tgt.offsetTop;
3798 var x = (e.clientX - left);
3799 var y = (e.clientY - top);
3800 if (x < screenWidth - 80 || x > screenWidth - 50) {
3801 return false;
3802 }
3803 if (y < 40 || y > screenHeight - 80) {
3804 return false;
3805 }
3806 curveT = (y - 40) / (screenHeight - 120);
3807 if (curveT < 0 || curveT > 1) {
3808 throw "stop execution";
3809 }
3810 return true;
3811}
3812
3813function drawTop() {
3814 if (tests[testIndex] == null) {
3815 var str = testDivs[testIndex].textContent;
3816 parse_all(str);
3817 var title = testDivs[testIndex].id.toString();
3818 testTitles[testIndex] = title;
3819 }
3820 init(tests[testIndex]);
3821 redraw();
3822}
3823
3824function redraw() {
3825 if (focus_on_selection) {
3826 collect_bounds = true;
3827 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3828 collect_bounds = false;
3829 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3830 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3831 }
3832 }
3833 ctx.beginPath();
3834 ctx.fillStyle = "white";
3835 ctx.rect(0, 0, screenWidth, screenHeight);
3836 ctx.fill();
3837 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3838}
3839
3840function dumpCurvePartial(test, id, t0, t1) {
3841 var curve = curveByID(test, id);
3842 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3843 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3844 + " t0=" + t0 + " t1=" + t1
3845 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3846}
3847
3848function dumpAngleTest(test, id, t0, t1) {
3849 var curve = curveByID(test, id);
caryclark55888e42016-07-18 10:01:36 -07003850 console.log(" { {" + curveToString(curve) + "}, "
caryclarkdac1d172014-06-17 05:15:38 -07003851 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3852}
3853
3854function dumpLogToConsole() {
3855 if (logStart < 0) {
3856 return;
3857 }
3858 var test = tests[testIndex];
3859 var recType = REC_TYPE_UNKNOWN;
3860 var records;
3861 for (var index = 0; index < test.length; index += 3) {
3862 var lastLineNo = test[index + 1];
3863 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3864 recType = test[index];
3865 records = test[index + 2];
3866 break;
3867 }
3868 }
3869 if (recType == REC_TYPE_UNKNOWN) {
3870 return;
3871 }
3872 var lines = testLines[testIndex];
3873 for (var idx = 0; idx < logRange; ++idx) {
3874 var line = lines[logStart + idx];
3875 console.log(line);
3876 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3877 var fragType = records[recordIndex];
3878 var frags = records[recordIndex + 1];
3879 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003880 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3881 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3882 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3883 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3884 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3885 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3886 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3887 console.log("}; //");
3888 }
3889 }
3890 }
3891}
3892
3893var activeKey = 'a';
3894var pathKey = 'b';
3895var pathBackKey = 'B';
3896var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07003897var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003898var addKey = 'd';
3899var deriviativesKey = 'f';
3900var angleKey = 'g';
3901var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003902var intersectionKey = 'i';
3903var intersectionBackKey = 'I';
3904var sequenceKey = 'j';
3905var midpointKey = 'k';
3906var logKey = 'l';
3907var logToConsoleKey = 'L';
3908var markKey = 'm';
3909var sortKey = 'o';
3910var opKey = 'p';
3911var opBackKey = 'P';
3912var computedKey = 'q';
3913var computedBackKey = 'Q';
Cary Clarkff114282016-12-14 11:56:16 -05003914var directionKey = 'r';
caryclarkdac1d172014-06-17 05:15:38 -07003915var stepKey = 's';
3916var stepBackKey = 'S';
3917var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003918var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003919var curveTKey = 'u';
3920var controlLinesBackKey = 'V';
3921var controlLinesKey = 'v';
3922var ptsKey = 'x';
3923var xyKey = 'y';
3924var logCurvesKey = 'z';
3925var focusKey = '`';
3926var idKey = '.';
3927var retinaKey = '\\';
3928
3929function doKeyPress(evt) {
3930 var char = String.fromCharCode(evt.charCode);
3931 var focusWasOn = false;
3932 switch (char) {
3933 case '0':
3934 case '1':
3935 case '2':
3936 case '3':
3937 case '4':
3938 case '5':
3939 case '6':
3940 case '7':
3941 case '8':
3942 case '9':
3943 decimal_places = char - '0';
3944 redraw();
3945 break;
3946 case activeKey:
3947 draw_active ^= true;
caryclark55888e42016-07-18 10:01:36 -07003948 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003949 break;
3950 case addKey:
3951 draw_add ^= true;
caryclark55888e42016-07-18 10:01:36 -07003952 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003953 break;
3954 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003955 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003956 redraw();
3957 break;
3958 case angleBackKey:
3959 draw_angle = (draw_angle + 2) % 3;
3960 redraw();
3961 break;
3962 case centerKey:
3963 setScale(xmin, xmax, ymin, ymax);
caryclark55888e42016-07-18 10:01:36 -07003964 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003965 break;
caryclark624637c2015-05-11 07:21:27 -07003966 case coincidenceKey:
3967 draw_coincidence ^= true;
3968 redraw();
3969 break;
caryclarkdac1d172014-06-17 05:15:38 -07003970 case controlLinesBackKey:
3971 control_lines = (control_lines + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07003972 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003973 break;
3974 case controlLinesKey:
3975 control_lines = (control_lines + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07003976 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003977 break;
3978 case computedBackKey:
3979 draw_computed = (draw_computed + 5) % 6;
caryclark55888e42016-07-18 10:01:36 -07003980 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003981 break;
3982 case computedKey:
3983 draw_computed = (draw_computed + 1) % 6;
caryclark55888e42016-07-18 10:01:36 -07003984 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003985 break;
3986 case curveTKey:
3987 curve_t ^= true;
3988 if (curve_t) {
3989 draw_legend = true;
3990 }
3991 redraw();
3992 break;
3993 case deriviativesKey:
3994 draw_deriviatives = (draw_deriviatives + 1) % 3;
3995 redraw();
3996 break;
Cary Clarkff114282016-12-14 11:56:16 -05003997 case directionKey:
3998 draw_direction ^= true;
3999 redraw();
4000 break;
caryclarkdac1d172014-06-17 05:15:38 -07004001 case focusKey:
4002 focus_on_selection ^= true;
4003 setScale(xmin, xmax, ymin, ymax);
4004 redraw();
4005 break;
caryclarkdac1d172014-06-17 05:15:38 -07004006 case idKey:
4007 draw_id ^= true;
4008 redraw();
4009 break;
4010 case intersectionBackKey:
4011 draw_intersection = (draw_intersection + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07004012 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004013 break;
4014 case intersectionKey:
4015 draw_intersection = (draw_intersection + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07004016 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004017 break;
4018 case intersectTKey:
4019 draw_intersectT ^= true;
4020 redraw();
4021 break;
4022 case logCurvesKey:
4023 logCurves(tests[testIndex]);
4024 break;
4025 case logKey:
4026 draw_log ^= true;
4027 redraw();
4028 break;
4029 case logToConsoleKey:
4030 if (draw_log) {
4031 dumpLogToConsole();
4032 }
4033 break;
4034 case markKey:
4035 draw_mark ^= true;
4036 redraw();
4037 break;
4038 case midpointKey:
4039 draw_midpoint ^= true;
4040 redraw();
4041 break;
4042 case opKey:
4043 draw_op = (draw_op + 1) % 3;
4044 redraw();
4045 break;
4046 case opBackKey:
4047 draw_op = (draw_op + 2) % 3;
4048 redraw();
4049 break;
4050 case pathKey:
caryclark26ad22a2015-10-16 09:03:38 -07004051 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004052 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004053 break;
4054 case pathBackKey:
caryclark26ad22a2015-10-16 09:03:38 -07004055 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004056 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004057 break;
4058 case ptsKey:
4059 pt_labels = (pt_labels + 1) % 3;
4060 redraw();
4061 break;
4062 case retinaKey:
4063 retina_scale ^= true;
4064 drawTop();
4065 break;
4066 case sequenceKey:
4067 draw_sequence ^= true;
4068 redraw();
4069 break;
4070 case sortKey:
4071 draw_sort = (draw_sort + 1) % 3;
4072 drawTop();
4073 break;
4074 case stepKey:
4075 step_limit++;
4076 if (step_limit > stepMax) {
4077 step_limit = stepMax;
4078 }
4079 redraw();
4080 break;
4081 case stepBackKey:
4082 step_limit--;
4083 if (step_limit < 0) {
4084 step_limit = 0;
4085 }
4086 redraw();
4087 break;
caryclark03b03ca2015-04-23 09:13:37 -07004088 case topKey:
4089 draw_top ^= true;
4090 redraw();
4091 break;
caryclarkdac1d172014-06-17 05:15:38 -07004092 case xyKey:
4093 debug_xy = (debug_xy + 1) % 3;
4094 redraw();
4095 break;
4096 case '-':
4097 focusWasOn = focus_on_selection;
4098 if (focusWasOn) {
4099 focus_on_selection = false;
4100 scale /= 1.2;
4101 } else {
4102 scale /= 2;
4103 calcLeftTop();
4104 }
4105 redraw();
4106 focus_on_selection = focusWasOn;
4107 break;
4108 case '=':
4109 case '+':
4110 focusWasOn = focus_on_selection;
4111 if (focusWasOn) {
4112 focus_on_selection = false;
4113 scale *= 1.2;
4114 } else {
4115 scale *= 2;
4116 calcLeftTop();
4117 }
4118 redraw();
4119 focus_on_selection = focusWasOn;
4120 break;
4121 case '?':
4122 draw_hints ^= true;
4123 if (draw_hints && !draw_legend) {
4124 draw_legend = true;
4125 }
4126 redraw();
4127 break;
4128 case '/':
4129 draw_legend ^= true;
4130 redraw();
4131 break;
4132 }
4133}
4134
4135function doKeyDown(evt) {
4136 var char = evt.keyCode;
4137 var preventDefault = false;
4138 switch (char) {
4139 case 37: // left arrow
4140 if (evt.shiftKey) {
4141 testIndex -= 9;
4142 }
4143 if (--testIndex < 0)
4144 testIndex = tests.length - 1;
4145 drawTop();
4146 preventDefault = true;
4147 break;
4148 case 39: // right arrow
4149 if (evt.shiftKey) {
4150 testIndex += 9;
4151 }
4152 if (++testIndex >= tests.length)
4153 testIndex = 0;
4154 drawTop();
4155 preventDefault = true;
4156 break;
4157 }
4158 if (preventDefault) {
4159 evt.preventDefault();
4160 return false;
4161 }
4162 return true;
4163}
4164
4165(function() {
4166 var hidden = "hidden";
4167
4168 // Standards:
4169 if (hidden in document)
4170 document.addEventListener("visibilitychange", onchange);
4171 else if ((hidden = "mozHidden") in document)
4172 document.addEventListener("mozvisibilitychange", onchange);
4173 else if ((hidden = "webkitHidden") in document)
4174 document.addEventListener("webkitvisibilitychange", onchange);
4175 else if ((hidden = "msHidden") in document)
4176 document.addEventListener("msvisibilitychange", onchange);
4177 // IE 9 and lower:
4178 else if ('onfocusin' in document)
4179 document.onfocusin = document.onfocusout = onchange;
4180 // All others:
4181 else
caryclark55888e42016-07-18 10:01:36 -07004182 window.onpageshow = window.onpagehide
caryclarkdac1d172014-06-17 05:15:38 -07004183 = window.onfocus = window.onblur = onchange;
4184
4185 function onchange (evt) {
4186 var v = 'visible', h = 'hidden',
caryclark55888e42016-07-18 10:01:36 -07004187 evtMap = {
4188 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
caryclarkdac1d172014-06-17 05:15:38 -07004189 };
4190
4191 evt = evt || window.event;
4192 if (evt.type in evtMap)
4193 document.body.className = evtMap[evt.type];
caryclark55888e42016-07-18 10:01:36 -07004194 else
caryclarkdac1d172014-06-17 05:15:38 -07004195 document.body.className = this[hidden] ? "hidden" : "visible";
4196 }
4197})();
4198
4199function calcXY() {
4200 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07004201 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07004202 var left = tgt.offsetLeft;
4203 var top = tgt.offsetTop;
4204 mouseX = (e.clientX - left) / scale + srcLeft;
4205 mouseY = (e.clientY - top) / scale + srcTop;
4206}
4207
4208function calcLeftTop() {
4209 srcLeft = mouseX - screenWidth / 2 / scale;
4210 srcTop = mouseY - screenHeight / 2 / scale;
4211}
4212
4213var disableClick = false;
4214
4215function handleMouseClick() {
4216 if (disableClick) {
4217 return;
4218 }
4219 if (!curve_t || !ptInTControl()) {
4220 calcXY();
4221 calcLeftTop();
4222 }
4223 redraw();
4224// if (!curve_t || !ptInTControl()) {
4225// mouseX = screenWidth / 2 / scale + srcLeft;
4226// mouseY = screenHeight / 2 / scale + srcTop;
4227// }
4228}
4229
4230function handleMouseOver() {
4231 calcXY();
4232 if (debug_xy != 2) {
4233 return;
4234 }
4235 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
4236 ctx.beginPath();
4237 ctx.rect(300,100,num.length * 6,10);
4238 ctx.fillStyle="white";
4239 ctx.fill();
4240 ctx.font = "normal 10px Arial";
4241 ctx.fillStyle="black";
4242 ctx.textAlign = "left";
4243 ctx.fillText(num, 300, 108);
4244}
4245
4246function start() {
4247 for (var i = 0; i < testDivs.length; ++i) {
4248 tests[i] = null;
4249 }
4250 testIndex = 0;
4251 drawTop();
4252 window.addEventListener('keypress', doKeyPress, true);
4253 window.addEventListener('keydown', doKeyDown, true);
4254 window.onresize = function() {
4255 drawTop();
4256 }
4257 /*
4258 window.onpagehide = function() {
4259 disableClick = true;
4260 }
4261 */
4262 window.onpageshow = function () {
4263 disableClick = false;
4264 }
4265}
4266
4267</script>
4268</head>
4269
4270<body onLoad="start();">
4271<canvas id="canvas" width="750" height="500"
4272 onmousemove="handleMouseOver()"
4273 onclick="handleMouseClick()"
4274 ></canvas >
4275</body>
4276</html>