blob: 945a6a9e6ce834859494f9cc4b0befa0e39e5185 [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
3<div height="0" hidden="true">
caryclarkdac1d172014-06-17 05:15:38 -07004
caryclark81a478c2016-09-09 09:37:57 -07005<div id="tiger8b_h_1">
caryclarke839e782016-09-15 07:48:18 -07006seg=1 {{{{494.348663f, 224.583771f}, {494.365143f, 224.633194f}, {494.376404f, 224.684067f}}}, 0.998645842f}
7seg=2 {{{494.376404f, 224.684067f}, {492.527069f, 224.218475f}, {492.952789f, 224.005585f}}}
8seg=3 {{{492.952789f, 224.005585f}, {494.375336f, 224.679337f}, {494.376038f, 224.682449f}}}
9seg=4 {{{494.376038f, 224.682449f}, {494.37619f, 224.68309f}}}
10seg=5 {{{494.37619f, 224.68309f}, {494.634338f, 225.414886f}, {494.895874f, 225.840698f}}}
11seg=6 {{{494.895874f, 225.840698f}, {494.348663f, 224.583771f}}}
12debugShowConicQuadIntersection wtTs[0]=1 {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{494.376404,224.684067}} wnTs[0]=0 {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}}
13id=1 1=(0,1) [4] id=2 4=(0.5,1) [1]
14id=1 1=(0,1) [6] id=2 6=(0.75,1) [1]
15id=1 3=(0.5,1) [6] id=2 6=(0.75,1) [3]
16id=1 3=(0.5,1) [8] id=2 8=(0.875,1) [3]
17id=1 5=(0.75,1) [8] id=2 8=(0.875,1) [5]
18id=1 7=(0.875,1) [8] id=2 8=(0.875,1) [7]
19id=1 7=(0.875,1) [10] id=2 10=(0.9375,1) [7]
20id=1 (empty) id=2 (empty)
21debugShowConicQuadIntersection no intersect {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}}
22debugShowConicLineIntersection wtTs[0]=0.988457533 {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{494.376038,224.682449}} wnTs[0]=0 {{{494.376038,224.682449}, {494.37619,224.68309}}}
23SkOpSegment::addT insert t=0.988457533 segID=1 spanID=13
24debugShowConicQuadIntersection no intersect {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}}
25debugShowConicLineIntersection wtTs[0]=0 {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{494.348663,224.583771}} wnTs[0]=1 {{{494.895874,225.840698}, {494.348663,224.583771}}}
26debugShowQuadIntersection wtTs[0]=1 {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{492.952789,224.005585}} wnTs[0]=0 {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}}
27debugShowQuadLineIntersection no intersect {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{{494.376038,224.682449}, {494.37619,224.68309}}}
28id=1 1=(0,0.5) [2] id=2 2=(0,1) [1]
29id=1 1=(0,0.25) [2] id=2 2=(0,1) [1]
30id=1 (empty) id=2 (empty)
31debugShowQuadIntersection no intersect {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}}
32debugShowQuadLineIntersection no intersect {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{{494.895874,225.840698}, {494.348663,224.583771}}}
33debugShowQuadLineIntersection wtTs[0]=1 {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}} {{494.376038,224.682449}} wnTs[0]=0 {{{494.376038,224.682449}, {494.37619,224.68309}}}
34debugShowQuadLineIntersection no intersect {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}} {{{494.895874,225.840698}, {494.348663,224.583771}}}
35debugShowQuadLineIntersection wtTs[0]=0 {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}} {{494.37619,224.68309}} wnTs[0]=1 {{{494.376038,224.682449}, {494.37619,224.68309}}}
36debugShowLineIntersection no intersect {{{494.376038,224.682449}, {494.37619,224.68309}}} {{{494.895874,225.840698}, {494.348663,224.583771}}}
37debugShowQuadLineIntersection wtTs[0]=1 {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}} {{494.895874,225.840698}} wnTs[0]=0 {{{494.895874,225.840698}, {494.348663,224.583771}}}
38SkOpSegment::markDone id=4 (494.376038,224.682449 494.37619,224.68309) t=0 [7] (494.376038,224.682449) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
39SkOpSegment::sortAngles [1] tStart=0.988457533 [13]
40SkOpAngle::after [1/1] 9/9 tStart=0.988457533 tEnd=0 < [3/3] 13/13 tStart=1 tEnd=0 < [1/2] 25/25 tStart=0.988457533 tEnd=1 T 4
41SkOpAngle::afterPart {{{{494.376038,224.682449}, {494.364861,224.63218}, {494.348663,224.583771}}}, 0.998676896} id=1
42SkOpAngle::afterPart {{{494.376038,224.682449}, {492.952789,224.005585}, {492.952789,224.005585}}} id=3
43SkOpAngle::afterPart {{{{494.376038,224.682449}, {494.376312,224.683624}, {494.376404,224.684067}}}, 0.999999821} id=1
44SkOpSegment::sortAngles [3] tStart=1 [6]
45SkOpSegment::debugShowActiveSpans id=1 (494.348663,224.583771 494.364952,224.632623 494.376129,224.682892 0.998676896f) t=0 tEnd=0.988457533 windSum=? windValue=1
46SkOpSegment::debugShowActiveSpans id=1 (494.376129,224.682892 494.376274,224.68348 494.376404,224.684067 0.999999821f) t=0.988457533 tEnd=1 windSum=? windValue=1
47SkOpSegment::debugShowActiveSpans id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 tEnd=1 windSum=? windValue=1
48SkOpSegment::debugShowActiveSpans id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 tEnd=1 windSum=? windValue=1
49SkOpSegment::debugShowActiveSpans id=5 (494.37619,224.68309 494.634338,225.414886 494.895874,225.840698) t=0 tEnd=1 windSum=? windValue=1
50SkOpSegment::debugShowActiveSpans id=6 (494.895874,225.840698 494.348663,224.583771) t=0 tEnd=1 windSum=? windValue=1
51SkOpSpan::sortableTop dir=kLeft seg=1 t=0.494228767 pt=(494.363678,224.63298)
52SkOpSpan::sortableTop [0] valid=1 operand=0 span=3 ccw=1 seg=2 {{{494.376404f, 224.684067f}, {492.527069f, 224.218475f}, {492.952789f, 224.005585f}}} t=0.0557039225 pt=(494.177429,224.63298) slope=(-1.72260523,-0.451515005)
53SkOpSpan::sortableTop [1] valid=1 operand=0 span=5 ccw=0 seg=3 {{{492.952789f, 224.005585f}, {494.375336f, 224.679337f}, {494.376038f, 224.682449f}}} t=0.733006652 pt=(494.274292,224.63298) slope=(0.380324923,0.182168955)
54SkOpSpan::sortableTop [2] valid=1 operand=0 span=1 ccw=0 seg=1 {{{{494.348663f, 224.583771f}, {494.365143f, 224.633194f}, {494.376404f, 224.684067f}}}, 0.998645842f} t=0.494228767 pt=(494.363678,224.63298) slope=(0.0138909232,0.050105697)
55SkOpSegment::markWinding id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 [3] (494.376404,224.684067) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
56SkOpSegment::markWinding id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 [5] (492.952789,224.005585) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
57SkOpSegment::markWinding id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 [3] (494.376404,224.684067) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
58SkOpSegment::markWinding id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0.988457533 [13] (494.376129,224.682892) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
59SkOpSegment::markWinding id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0 [1] (494.348663,224.583771) tEnd=0.988457533 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
60SkOpSegment::markWinding id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0 [1] (494.348663,224.583771) tEnd=0.988457533 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
61SkOpSegment::markWinding id=6 (494.895874,225.840698 494.348663,224.583771) t=0 [11] (494.895874,225.840698) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
62SkOpSegment::markWinding id=5 (494.37619,224.68309 494.634338,225.414886 494.895874,225.840698) t=0 [9] (494.37619,224.68309) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
63SkOpSegment::findNextWinding simple
64SkOpSegment::markDone id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0 [1] (494.348663,224.583771) tEnd=0.988457533 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
65bridgeWinding current id=1 from=(494.376129,224.682892) to=(494.348663,224.583771)
66path.moveTo(494.376129,224.682892);
67path.conicTo(494.36496,224.632629, 494.348663,224.583771, 0.998676896);
68SkOpSegment::findNextWinding simple
69SkOpSegment::markDone id=6 (494.895874,225.840698 494.348663,224.583771) t=0 [11] (494.895874,225.840698) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
70bridgeWinding current id=6 from=(494.348663,224.583771) to=(494.895874,225.840698)
71SkOpSegment::markDone id=5 (494.37619,224.68309 494.634338,225.414886 494.895874,225.840698) t=0 [9] (494.37619,224.68309) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
72path.lineTo(494.895874,225.840698);
73SkOpSegment::debugShowActiveSpans id=1 (494.376129,224.682892 494.376274,224.68348 494.376404,224.684067 0.999999821f) t=0.988457533 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
74SkOpSegment::debugShowActiveSpans id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
75SkOpSegment::debugShowActiveSpans id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
76SkOpSegment::findNextWinding
77SkOpAngle::dumpOne [1/2] next=1/1 sect=25/25 s=0.988457533 [13] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
78SkOpAngle::dumpOne [1/1] next=3/3 sect=9/9 s=0.988457533 [13] e=0 [1] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done
79SkOpAngle::dumpOne [3/3] next=1/2 sect=13/13 s=1 [6] e=0 [5] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0
80SkOpSegment::markDone id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 [5] (492.952789,224.005585) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
81SkOpSegment::markDone id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 [3] (494.376404,224.684067) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
82SkOpSegment::markDone id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0.988457533 [13] (494.376129,224.682892) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
83SkOpSegment::findNextWinding from:[1] to:[1] start=13259432 end=18937312
84bridgeWinding current id=1 from=(494.376404,224.684067) to=(494.376129,224.682892)
85path.moveTo(494.376404,224.684067);
86path.lineTo(494.376129,224.682892);
caryclarkdac1d172014-06-17 05:15:38 -070087</div>
caryclark26ad22a2015-10-16 09:03:38 -070088
caryclarkdac1d172014-06-17 05:15:38 -070089</div>
90
91<script type="text/javascript">
92
caryclark55888e42016-07-18 10:01:36 -070093 var testDivs = [
caryclark81a478c2016-09-09 09:37:57 -070094 tiger8b_h_1,
caryclark30b9fdd2016-08-31 14:36:29 -070095 ];
caryclarkdac1d172014-06-17 05:15:38 -070096
97var decimal_places = 3; // make this 3 to show more precision
98
99var tests = [];
100var testLines = [];
101var testTitles = [];
102var testIndex = 0;
103var ctx;
104
105var xmin, xmax, focusXmin, focusXmax;
106var ymin, ymax, focusYmin, focusYmax;
107var scale;
108var mouseX, mouseY;
109var srcLeft, srcTop;
110var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700111var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700112var curveT = 0;
113
114var pt_labels = 2;
115var collect_bounds = false;
116var control_lines = 0;
117var curve_t = false;
118var debug_xy = 1;
119var focus_enabled = false;
120var focus_on_selection = false;
121var step_limit = 0;
122var draw_active = false;
123var draw_add = false;
124var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700125var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700126var draw_deriviatives = 0;
127var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700128var draw_id = false;
129var draw_intersection = 0;
130var draw_intersectT = false;
131var draw_legend = true;
132var draw_log = false;
133var draw_mark = false;
134var draw_midpoint = false;
135var draw_op = 0;
136var draw_sequence = false;
137var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700138var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700139var draw_path = 3;
140var draw_computed = 0;
141var retina_scale = !!window.devicePixelRatio;
142
143var activeCount = 0;
144var addCount = 0;
145var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700146var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700147var opCount = 0;
148var sectCount = 0;
149var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700150var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700151var markCount = 0;
152var activeMax = 0;
153var addMax = 0;
154var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700155var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700156var sectMax = 0;
157var sectMax2 = 0;
158var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700159var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700160var markMax = 0;
161var opMax = 0;
162var stepMax = 0;
163var lastIndex = 0;
164var hasPath = false;
caryclark26ad22a2015-10-16 09:03:38 -0700165var hasAlignedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700166var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700167var angleBetween = false;
168var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700169
170var firstActiveSpan = -1;
171var logStart = -1;
172var logRange = 0;
173
174var SPAN_ID = 0;
175var SPAN_X1 = SPAN_ID + 1;
176var SPAN_Y1 = SPAN_X1 + 1;
177var SPAN_X2 = SPAN_Y1 + 1;
178var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700179
caryclark55888e42016-07-18 10:01:36 -0700180var SPAN_L_TX = SPAN_Y2 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700181var SPAN_L_TY = SPAN_L_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700182var SPAN_L_OTHER = SPAN_L_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700183var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
184var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
185var SPAN_L_SUM = SPAN_L_OTHERI + 1;
186var SPAN_L_VAL = SPAN_L_SUM + 1;
187var SPAN_L_OPP = SPAN_L_VAL + 1;
188
189var SPAN_X3 = SPAN_Y2 + 1;
190var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700191
caryclark55888e42016-07-18 10:01:36 -0700192var SPAN_Q_TX = SPAN_Y3 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700193var SPAN_Q_TY = SPAN_Q_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700194var SPAN_Q_OTHER = SPAN_Q_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700195var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
196var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
197var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
198var SPAN_Q_VAL = SPAN_Q_SUM + 1;
199var SPAN_Q_OPP = SPAN_Q_VAL + 1;
200
caryclark1049f122015-04-20 08:31:59 -0700201var SPAN_K_W = SPAN_Y3 + 1;
caryclark55888e42016-07-18 10:01:36 -0700202var SPAN_K_TX = SPAN_K_W + 1;
caryclark1049f122015-04-20 08:31:59 -0700203var SPAN_K_TY = SPAN_K_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700204var SPAN_K_OTHER = SPAN_K_TY + 1;
caryclark1049f122015-04-20 08:31:59 -0700205var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
206var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
207var SPAN_K_SUM = SPAN_K_OTHERI + 1;
208var SPAN_K_VAL = SPAN_K_SUM + 1;
209var SPAN_K_OPP = SPAN_K_VAL + 1;
210
caryclarkdac1d172014-06-17 05:15:38 -0700211var SPAN_X4 = SPAN_Y3 + 1;
212var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700213
caryclark55888e42016-07-18 10:01:36 -0700214var SPAN_C_TX = SPAN_Y4 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700215var SPAN_C_TY = SPAN_C_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700216var SPAN_C_OTHER = SPAN_C_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700217var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
218var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
219var SPAN_C_SUM = SPAN_C_OTHERI + 1;
220var SPAN_C_VAL = SPAN_C_SUM + 1;
221var SPAN_C_OPP = SPAN_C_VAL + 1;
222
223var ACTIVE_LINE_SPAN = 1;
224var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700225var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
226var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700227
228var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
229var ADD_LINETO = ADD_MOVETO + 1;
230var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700231var ADD_CONICTO = ADD_QUADTO + 1;
232var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700233var ADD_CLOSE = ADD_CUBICTO + 1;
234var ADD_FILL = ADD_CLOSE + 1;
235
236var PATH_LINE = ADD_FILL + 1;
237var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700238var PATH_CONIC = PATH_QUAD + 1;
239var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700240
241var INTERSECT_LINE = PATH_CUBIC + 1;
242var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
243var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
244var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
245var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
246var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
247var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
248var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
249var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700250var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
251var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
252var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
caryclark55888e42016-07-18 10:01:36 -0700253var INTERSECT_CONIC_QUAD = INTERSECT_CONIC_LINE_NO + 1;
254var INTERSECT_CONIC_QUAD_2 = INTERSECT_CONIC_QUAD + 1;
255var INTERSECT_CONIC_QUAD_NO = INTERSECT_CONIC_QUAD_2 + 1;
256var INTERSECT_CONIC = INTERSECT_CONIC_QUAD_NO + 1;
caryclark1049f122015-04-20 08:31:59 -0700257var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
258var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
259var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700260var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
261var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
262var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
263var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
264var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
265var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
266var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
267var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
268var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
269var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
270var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
271var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
272var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
273var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
274// FIXME: add cubic 5- 9
275var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
276
277var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
278var SORT_BINARY = SORT_UNARY + 1;
279
280var OP_DIFFERENCE = SORT_BINARY + 1;
281var OP_INTERSECT = OP_DIFFERENCE + 1;
282var OP_UNION = OP_INTERSECT + 1;
283var OP_XOR = OP_UNION + 1;
284
285var MARK_LINE = OP_XOR + 1;
286var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700287var MARK_CONIC = MARK_QUAD + 1;
288var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700289var MARK_DONE_LINE = MARK_CUBIC + 1;
290var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700291var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
292var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700293var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
294var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700295var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
296var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700297var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
298var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700299var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
300var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700301var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
302var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700303var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
304var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700305var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
306var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700307var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
308var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700309var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
310
311var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
312var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
313
caryclark624637c2015-05-11 07:21:27 -0700314var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700315var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700316
caryclark54359292015-03-26 07:52:43 -0700317var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700318
caryclark624637c2015-05-11 07:21:27 -0700319var COIN_MAIN_SPAN = ACTIVE_OP + 1;
320var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
321
322var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700323
324var REC_TYPE_UNKNOWN = -1;
325var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700326var REC_TYPE_PATH2 = 1;
327var REC_TYPE_SECT = 2;
328var REC_TYPE_ACTIVE = 3;
329var REC_TYPE_ADD = 4;
330var REC_TYPE_SORT = 5;
331var REC_TYPE_OP = 6;
332var REC_TYPE_MARK = 7;
333var REC_TYPE_COMPUTED = 8;
334var REC_TYPE_COIN = 9;
335var REC_TYPE_ANGLE = 10;
336var REC_TYPE_ACTIVE_OP = 11;
337var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700338var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700339var REC_TYPE_COINCIDENCE = 14;
caryclark26ad22a2015-10-16 09:03:38 -0700340var REC_TYPE_ALIGNED = 15;
341var REC_TYPE_LAST = REC_TYPE_ALIGNED;
caryclarkdac1d172014-06-17 05:15:38 -0700342
343function strs_to_nums(strs) {
344 var result = [];
345 for (var idx = 1; idx < strs.length; ++idx) {
346 var str = strs[idx];
347 var num = parseFloat(str);
348 if (isNaN(num)) {
349 result.push(str);
350 } else {
351 result.push(num);
352 }
353 }
354 return result;
355}
356
357function filter_str_by(id, str, regex, array) {
358 if (regex.test(str)) {
359 var strs = regex.exec(str);
360 var result = strs_to_nums(strs);
361 array.push(id);
362 array.push(result);
363 return true;
364 }
365 return false;
366}
367
368function construct_regexp2(pattern) {
369 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
370 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
371 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700372 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700373 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
374 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
375 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700376 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700377 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
378 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
379 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700380 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700381 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700382 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700383 escape = escape.replace(/NUM/g, "(-?\\d+)");
384 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
385 return new RegExp(escape, 'i');
386}
387
388function construct_regexp2c(pattern) {
389 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
390 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700391 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700392 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700393 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
394 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700395 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700396 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700397 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700398 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 -0700399 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700400 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700401 escape = escape.replace(/OPER/g, "[a-z]+");
402 escape = escape.replace(/PATH/g, "pathB?");
403 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700404 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700405 escape = escape.replace(/NUM/g, "(-?\\d+)");
406 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
407 return new RegExp(escape, 'i');
408}
409
410function match_regexp(str, lineNo, array, id, pattern) {
411 var regex = construct_regexp2(pattern);
412 if (filter_str_by(id, str, regex, array)) {
413 return true;
414 }
415 regex = construct_regexp2c(pattern);
416 return filter_str_by(id, str, regex, array);
417}
418
419function endsWith(str, suffix) {
420 return str.indexOf(suffix, str.length - suffix.length) !== -1;
421}
422
423function parse_all(test) {
424 var lines = test.match(/[^\r\n]+/g);
425 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
426 var record = [];
427 var recType = REC_TYPE_UNKNOWN;
428 var lastLineNo;
429 var moveX, moveY;
430 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
431 var line = lines[lineNo];
432 if (line.length == 0) {
433 continue;
434 }
435 var opStart = "SkOpSegment::";
436 if (line.lastIndexOf(opStart, 0) === 0) {
437 line = line.substr(opStart.length);
438 }
439 var angleStart = "SkOpAngle::";
440 if (line.lastIndexOf(angleStart, 0) === 0) {
441 line = line.substr(angleStart.length);
442 }
caryclark624637c2015-05-11 07:21:27 -0700443 var coinStart = "SkOpCoincidence::";
444 if (line.lastIndexOf(coinStart, 0) === 0) {
445 line = line.substr(coinStart.length);
446 }
caryclark54359292015-03-26 07:52:43 -0700447 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700448 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700449 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclark55888e42016-07-18 10:01:36 -0700450 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700451 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700452 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
453 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
454 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
455 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
caryclark26ad22a2015-10-16 09:03:38 -0700456 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
caryclarkdac1d172014-06-17 05:15:38 -0700457 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700458 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700459 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
460 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
461 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
462 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
463 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700464 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700465 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
466 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
467 : REC_TYPE_UNKNOWN;
468 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
469 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
470 if (recType != REC_TYPE_UNKNOWN) {
471 records.push(recType);
472 records.push(lastLineNo);
473 records.push(record);
474 }
475 record = [];
476 recType = type;
477 lastLineNo = lineNo;
478 }
479 var found = false;
480 switch (recType) {
481 case REC_TYPE_ACTIVE:
482 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700483" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700484 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700485" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700486 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700487" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700488 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700489" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark624637c2015-05-11 07:21:27 -0700490 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700491" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700492 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700493" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700494 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700495" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700496 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700497" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700498 );
499 break;
500 case REC_TYPE_ACTIVE_OP:
501 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
502" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
503 );
504 break;
505 case REC_TYPE_ADD:
506 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
507 moveX = record[1][0];
508 moveY = record[1][1];
509 found = true;
510 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
511 record[1].unshift(moveY);
512 record[1].unshift(moveX);
513 moveX = record[1][2];
514 moveY = record[1][3];
515 found = true;
516 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
517 record[1].unshift(moveY);
518 record[1].unshift(moveX);
519 moveX = record[1][4];
520 moveY = record[1][5];
521 found = true;
caryclark1049f122015-04-20 08:31:59 -0700522 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
523 record[1].unshift(moveY);
524 record[1].unshift(moveX);
525 moveX = record[1][4];
526 moveY = record[1][5];
527 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700528 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
529 record[1].unshift(moveY);
530 record[1].unshift(moveX);
531 moveX = record[1][6];
532 moveY = record[1][7];
533 found = true;
534 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
535 found = true;
536 } else {
537 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
538 }
539 break;
caryclark54359292015-03-26 07:52:43 -0700540 case REC_TYPE_AFTERPART:
541 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL")
542 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL")
caryclark1049f122015-04-20 08:31:59 -0700543 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL")
caryclark54359292015-03-26 07:52:43 -0700544 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL")
545 break;
caryclark26ad22a2015-10-16 09:03:38 -0700546 case REC_TYPE_ALIGNED:
547 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL"
548 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL"
549 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL"
550 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL"
551 );
552 break;
caryclarkdac1d172014-06-17 05:15:38 -0700553 case REC_TYPE_ANGLE:
554 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700555"[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");
556 break;
557 case REC_TYPE_COIN:
558 found = true;
559 break;
caryclark624637c2015-05-11 07:21:27 -0700560 case REC_TYPE_COINCIDENCE:
561 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
562" + id=IDX t=T_VAL tEnd=T_VAL"
563 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
564" - id=IDX t=T_VAL tEnd=T_VAL"
565 );
566 break;
caryclarkdac1d172014-06-17 05:15:38 -0700567 case REC_TYPE_COMPUTED:
568 found = line == "computed quadratics given"
569 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
570 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
571 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700572 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700573 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
574 );
575 break;
576 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700577 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
578 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700579 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700580 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
581 );
582 break;
583 case REC_TYPE_PATH2:
584 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
585 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700586 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700587 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700588 );
589 break;
590 case REC_TYPE_SECT:
591 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
592" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
593 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
594" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
595 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
596" no intersect LINE_VAL LINE_VAL"
597 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
598" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
599 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
600" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
601 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
602" no intersect QUAD_VAL LINE_VAL"
603 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
604" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
605 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
606" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
607 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
608" no intersect QUAD_VAL QUAD_VAL"
caryclark55888e42016-07-18 10:01:36 -0700609
caryclark1049f122015-04-20 08:31:59 -0700610 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
611" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
612 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
613" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
614 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
615" no intersect CONIC_VAL LINE_VAL"
caryclark55888e42016-07-18 10:01:36 -0700616
617 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD, "debugShowConicQuadIntersection" +
618" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
619 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_2, "debugShowConicQuadIntersection" +
620" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
621 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" +
622" no intersect CONIC_VAL QUAD_VAL"
623
caryclark1049f122015-04-20 08:31:59 -0700624 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
625" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
626 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
627" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
628 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
629" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700630 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
631" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
632 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
633" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
634 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
635" 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"
636 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
637" no intersect CUBIC_VAL LINE_VAL"
638 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
639" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
640 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
641" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
642 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
643" 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"
644 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
645" 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"
646 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
647" no intersect CUBIC_VAL QUAD_VAL"
648 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
649" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
650 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
651" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
652 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
653" 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"
654 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
655" 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"
656 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
657" no intersect CUBIC_VAL CUBIC_VAL"
658 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
659" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
660 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
661" no self intersect CUBIC_VAL"
662 );
663 break;
664 case REC_TYPE_SORT:
665 var hasDone = / done/.test(line);
666 var hasUnorderable = / unorderable/.test(line);
667 var hasSmall = / small/.test(line);
668 var hasTiny = / tiny/.test(line);
669 var hasOperand = / operand/.test(line);
670 var hasStop = / stop/.test(line);
671 line.replace(/[ a-z]+$/, "");
672 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
673" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
674 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
675" [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"
676 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
677" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
678 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
679" [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"
680 );
681 if (found) {
682 record[1].push(hasDone);
683 record[1].push(hasUnorderable);
684 record[1].push(hasSmall);
685 record[1].push(hasTiny);
686 record[1].push(hasOperand);
687 record[1].push(hasStop);
688 }
689 break;
caryclark03b03ca2015-04-23 09:13:37 -0700690 case REC_TYPE_TOP:
691 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
692" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
693 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
694" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
695 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
696" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
697 );
698 break;
caryclarkdac1d172014-06-17 05:15:38 -0700699 case REC_TYPE_MARK:
700 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700701" 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 -0700702 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700703" 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 -0700704 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
705" 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 -0700706 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700707" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
708 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
709" 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"
710 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
711" 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 -0700712 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
713" 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 -0700714 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
715" 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 -0700716 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
717" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
718 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
719" 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 -0700720 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
721" 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 -0700722 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
723" 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 -0700724 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700725" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700726 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark55888e42016-07-18 10:01:36 -0700727" last seg=IDX span=IDX"
728 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
729" last segment=IDX span=IDX windSum=OPT"
730 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
731" last seg=IDX span=IDX windSum=OPT"
732 );
caryclarkdac1d172014-06-17 05:15:38 -0700733 break;
734 case REC_TYPE_OP:
735 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
736 || line.lastIndexOf("operator<", 0) === 0) {
737 found = true;
738 break;
739 }
caryclark54359292015-03-26 07:52:43 -0700740 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700741 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700742 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700743 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
744 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
745 );
746 break;
747 case REC_TYPE_UNKNOWN:
748 found = true;
749 break;
750 }
751 if (!found) {
752 console.log(line + " [" + lineNo + "] of type " + type + " not found");
753 }
754 }
755 if (recType != REC_TYPE_UNKNOWN) {
756 records.push(recType);
757 records.push(lastLineNo);
758 records.push(record);
759 }
760 if (records.length >= 1) {
761 tests[testIndex] = records;
762 testLines[testIndex] = lines;
763 }
764}
765
766function init(test) {
767 var canvas = document.getElementById('canvas');
768 if (!canvas.getContext) return;
769 ctx = canvas.getContext('2d');
770 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
771 var unscaledWidth = window.innerWidth - 20;
772 var unscaledHeight = window.innerHeight - 20;
773 screenWidth = unscaledWidth;
774 screenHeight = unscaledHeight;
775 canvas.width = unscaledWidth * resScale;
776 canvas.height = unscaledHeight * resScale;
777 canvas.style.width = unscaledWidth + 'px';
778 canvas.style.height = unscaledHeight + 'px';
779 if (resScale != 1) {
780 ctx.scale(resScale, resScale);
781 }
782 xmin = Infinity;
783 xmax = -Infinity;
784 ymin = Infinity;
785 ymax = -Infinity;
caryclark26ad22a2015-10-16 09:03:38 -0700786 hasPath = hasAlignedPath = hasComputedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700787 firstActiveSpan = -1;
788 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
789 var recType = test[tIndex];
790 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
791 console.log("unknown rec type: " + recType);
792 throw "stop execution";
793 }
794 var records = test[tIndex + 2];
795 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
796 var fragType = records[recordIndex];
797 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
798 console.log("unknown in range frag type: " + fragType);
799 throw "stop execution";
800 }
801 var frags = records[recordIndex + 1];
802 var first = 0;
803 var last = -1;
804 var first2 = 0;
805 var last2 = 0;
806 switch (recType) {
caryclark26ad22a2015-10-16 09:03:38 -0700807 case REC_TYPE_ALIGNED:
808 hasAlignedPath = true;
caryclarkdac1d172014-06-17 05:15:38 -0700809 case REC_TYPE_COMPUTED:
810 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
811 break;
812 }
caryclark26ad22a2015-10-16 09:03:38 -0700813 if (REC_TYPE_COMPUTED == recType) {
814 hasComputedPath = true;
815 }
caryclarkdac1d172014-06-17 05:15:38 -0700816 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700817 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700818 switch (fragType) {
819 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700820 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700821 break;
caryclark1049f122015-04-20 08:31:59 -0700822 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700823 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700824 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700825 break;
826 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700827 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700828 break;
829 default:
caryclark55888e42016-07-18 10:01:36 -0700830 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
caryclarkdac1d172014-06-17 05:15:38 -0700831 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
832 throw "stop execution";
833 }
834 if (recType == REC_TYPE_PATH) {
835 hasPath = true;
836 }
837 break;
caryclark54359292015-03-26 07:52:43 -0700838 case REC_TYPE_PATH2:
839 first = 1;
840 switch (fragType) {
841 case PATH_LINE:
842 last = 5;
843 break;
caryclark1049f122015-04-20 08:31:59 -0700844 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700845 case PATH_QUAD:
846 last = 7;
847 break;
848 case PATH_CUBIC:
849 last = 9;
850 break;
851 default:
caryclark55888e42016-07-18 10:01:36 -0700852 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
caryclark54359292015-03-26 07:52:43 -0700853 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
854 throw "stop execution";
855 }
856 if (recType == REC_TYPE_PATH2) {
857 hasPath = true;
858 }
859 break;
caryclarkdac1d172014-06-17 05:15:38 -0700860 case REC_TYPE_ACTIVE:
861 if (firstActiveSpan < 0) {
862 firstActiveSpan = tIndex;
863 }
864 first = 1;
865 switch (fragType) {
866 case ACTIVE_LINE_SPAN:
867 last = 5;
868 break;
caryclark1049f122015-04-20 08:31:59 -0700869 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -0700870 case ACTIVE_QUAD_SPAN:
871 last = 7;
872 break;
873 case ACTIVE_CUBIC_SPAN:
874 last = 9;
875 break;
876 default:
877 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
878 throw "stop execution";
879 }
880 break;
881 case REC_TYPE_ADD:
882 switch (fragType) {
883 case ADD_MOVETO:
884 break;
885 case ADD_LINETO:
886 last = 4;
887 break;
caryclark1049f122015-04-20 08:31:59 -0700888 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -0700889 case ADD_QUADTO:
890 last = 6;
891 break;
892 case ADD_CUBICTO:
893 last = 8;
894 break;
895 case ADD_CLOSE:
896 case ADD_FILL:
897 break;
898 default:
899 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
900 throw "stop execution";
901 }
902 break;
caryclark54359292015-03-26 07:52:43 -0700903 case REC_TYPE_AFTERPART:
904 switch (fragType) {
905 case PATH_LINE:
906 last = 4;
907 break;
caryclark1049f122015-04-20 08:31:59 -0700908 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700909 case PATH_QUAD:
910 last = 6;
911 break;
912 case PATH_CUBIC:
913 last = 8;
914 break;
915 default:
916 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
917 throw "stop execution";
918 }
919 break;
caryclarkdac1d172014-06-17 05:15:38 -0700920 case REC_TYPE_SECT:
921 switch (fragType) {
922 case INTERSECT_LINE:
923 first = 1; last = 5; first2 = 8; last2 = 12;
924 break;
925 case INTERSECT_LINE_2:
926 first = 1; last = 5; first2 = 11; last2 = 15;
927 break;
928 case INTERSECT_LINE_NO:
929 first = 0; last = 4; first2 = 4; last2 = 8;
930 break;
caryclark1049f122015-04-20 08:31:59 -0700931 case INTERSECT_CONIC_LINE:
932 first = 1; last = 7; first2 = 11; last2 = 15;
933 break;
caryclarkdac1d172014-06-17 05:15:38 -0700934 case INTERSECT_QUAD_LINE:
935 first = 1; last = 7; first2 = 10; last2 = 14;
936 break;
caryclark1049f122015-04-20 08:31:59 -0700937 case INTERSECT_CONIC_LINE_2:
938 first = 1; last = 7; first2 = 14; last2 = 18;
939 break;
caryclarkdac1d172014-06-17 05:15:38 -0700940 case INTERSECT_QUAD_LINE_2:
941 first = 1; last = 7; first2 = 13; last2 = 17;
942 break;
caryclark1049f122015-04-20 08:31:59 -0700943 case INTERSECT_CONIC_LINE_NO:
944 first = 0; last = 6; first2 = 7; last2 = 11;
945 break;
caryclarkdac1d172014-06-17 05:15:38 -0700946 case INTERSECT_QUAD_LINE_NO:
947 first = 0; last = 6; first2 = 6; last2 = 10;
948 break;
caryclark1049f122015-04-20 08:31:59 -0700949 case INTERSECT_CONIC:
950 first = 1; last = 7; first2 = 11; last2 = 17;
951 break;
caryclarkdac1d172014-06-17 05:15:38 -0700952 case INTERSECT_QUAD:
953 first = 1; last = 7; first2 = 10; last2 = 16;
954 break;
caryclark1049f122015-04-20 08:31:59 -0700955 case INTERSECT_CONIC_2:
956 first = 1; last = 7; first2 = 14; last2 = 20;
957 break;
caryclarkdac1d172014-06-17 05:15:38 -0700958 case INTERSECT_QUAD_2:
959 first = 1; last = 7; first2 = 13; last2 = 19;
960 break;
caryclark1049f122015-04-20 08:31:59 -0700961 case INTERSECT_CONIC_NO:
962 first = 0; last = 6; first2 = 7; last2 = 13;
963 break;
caryclarkdac1d172014-06-17 05:15:38 -0700964 case INTERSECT_QUAD_NO:
965 first = 0; last = 6; first2 = 6; last2 = 12;
966 break;
967 case INTERSECT_SELF_CUBIC:
968 first = 1; last = 9;
969 break;
970 case INTERSECT_SELF_CUBIC_NO:
971 first = 0; last = 8;
972 break;
973 case INTERSECT_CUBIC_LINE:
974 first = 1; last = 9; first2 = 12; last2 = 16;
975 break;
976 case INTERSECT_CUBIC_LINE_2:
977 first = 1; last = 9; first2 = 15; last2 = 19;
978 break;
979 case INTERSECT_CUBIC_LINE_3:
980 first = 1; last = 9; first2 = 18; last2 = 22;
981 break;
982 case INTERSECT_CUBIC_LINE_NO:
983 first = 0; last = 8; first2 = 8; last2 = 12;
984 break;
caryclark55888e42016-07-18 10:01:36 -0700985 case INTERSECT_CONIC_QUAD:
986 first = 1; last = 7; first2 = 11; last2 = 17;
987 break;
988 case INTERSECT_CONIC_QUAD_2:
989 first = 1; last = 7; first2 = 14; last2 = 20;
990 break;
991 case INTERSECT_CONIC_QUAD_NO:
992 first = 0; last = 6; first2 = 7; last2 = 13;
993 break;
caryclarkdac1d172014-06-17 05:15:38 -0700994 case INTERSECT_CUBIC_QUAD:
995 first = 1; last = 9; first2 = 12; last2 = 18;
996 break;
997 case INTERSECT_CUBIC_QUAD_2:
998 first = 1; last = 9; first2 = 15; last2 = 21;
999 break;
1000 case INTERSECT_CUBIC_QUAD_3:
1001 first = 1; last = 9; first2 = 18; last2 = 24;
1002 break;
1003 case INTERSECT_CUBIC_QUAD_4:
1004 first = 1; last = 9; first2 = 21; last2 = 27;
1005 break;
1006 case INTERSECT_CUBIC_QUAD_NO:
1007 first = 0; last = 8; first2 = 8; last2 = 14;
1008 break;
1009 case INTERSECT_CUBIC:
1010 first = 1; last = 9; first2 = 12; last2 = 20;
1011 break;
1012 case INTERSECT_CUBIC_2:
1013 first = 1; last = 9; first2 = 15; last2 = 23;
1014 break;
1015 case INTERSECT_CUBIC_3:
1016 first = 1; last = 9; first2 = 18; last2 = 26;
1017 break;
1018 case INTERSECT_CUBIC_4:
1019 first = 1; last = 9; first2 = 21; last2 = 29;
1020 break;
1021 case INTERSECT_CUBIC_NO:
1022 first = 0; last = 8; first2 = 8; last2 = 16;
1023 break;
1024 default:
1025 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1026 throw "stop execution";
1027 }
1028 break;
1029 default:
1030 continue;
1031 }
1032 for (var idx = first; idx < last; idx += 2) {
1033 xmin = Math.min(xmin, frags[idx]);
1034 xmax = Math.max(xmax, frags[idx]);
1035 ymin = Math.min(ymin, frags[idx + 1]);
1036 ymax = Math.max(ymax, frags[idx + 1]);
1037 }
1038 for (var idx = first2; idx < last2; idx += 2) {
1039 xmin = Math.min(xmin, frags[idx]);
1040 xmax = Math.max(xmax, frags[idx]);
1041 ymin = Math.min(ymin, frags[idx + 1]);
1042 ymax = Math.max(ymax, frags[idx + 1]);
1043 }
1044 }
1045 }
1046 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1047 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1048 var recType = test[tIndex];
1049 var records = test[tIndex + 2];
1050 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1051 var fragType = records[recordIndex];
1052 var frags = records[recordIndex + 1];
1053 switch (recType) {
1054 case REC_TYPE_ACTIVE_OP:
1055 if (!draw_op) {
1056 break;
1057 }
1058 {
1059 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1060 curve_extremes(curve, angleBounds);
1061 }
1062 break;
1063 case REC_TYPE_ANGLE:
1064 if (!draw_angle) {
1065 break;
1066 }
caryclark54359292015-03-26 07:52:43 -07001067 {
caryclarkdac1d172014-06-17 05:15:38 -07001068 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1069 curve_extremes(curve, angleBounds);
1070 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1071 curve_extremes(curve, angleBounds);
1072 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1073 }
1074 break;
caryclark624637c2015-05-11 07:21:27 -07001075 case REC_TYPE_COINCIDENCE:
1076 if (!draw_coincidence) {
1077 break;
1078 }
1079 {
1080 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1081 curve_extremes(curve, angleBounds);
1082 }
1083 break;
caryclarkdac1d172014-06-17 05:15:38 -07001084 case REC_TYPE_SORT:
1085 if (!draw_sort) {
1086 break;
1087 }
1088 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1089 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1090 curve_extremes(curve, angleBounds);
1091 }
1092 break;
caryclark03b03ca2015-04-23 09:13:37 -07001093 case REC_TYPE_TOP:
1094 if (!draw_top) {
1095 break;
1096 }
1097 {
1098 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1099 curve_extremes(curve, angleBounds);
1100 }
1101 break;
caryclarkdac1d172014-06-17 05:15:38 -07001102 }
1103 }
1104 }
1105 xmin = Math.min(xmin, angleBounds[0]);
1106 ymin = Math.min(ymin, angleBounds[1]);
1107 xmax = Math.max(xmax, angleBounds[2]);
1108 ymax = Math.max(ymax, angleBounds[3]);
1109 setScale(xmin, xmax, ymin, ymax);
1110 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001111 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001112 }
1113 if (hasPath == true && hasComputedPath == false && draw_computed) {
1114 draw_computed = 0;
1115 }
1116}
1117
caryclark26ad22a2015-10-16 09:03:38 -07001118function curveByIDMatch(test, id, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001119 var tIndex = -3;
1120 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001121 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001122 if (recType == REC_TYPE_OP) {
1123 continue;
1124 }
caryclark26ad22a2015-10-16 09:03:38 -07001125 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001126 return [];
1127 }
1128 var records = test[tIndex + 2];
1129 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1130 var fragType = records[recordIndex];
1131 var frags = records[recordIndex + 1];
1132 if (frags[0] == id) {
1133 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001134 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001135 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001136 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001137 return [frags[1], frags[2], frags[3], frags[4],
1138 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001139 case PATH_CONIC:
1140 return [frags[1], frags[2], frags[3], frags[4],
1141 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001142 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001143 return [frags[1], frags[2], frags[3], frags[4],
1144 frags[5], frags[6], frags[7], frags[8]];
1145 }
1146 }
1147 }
caryclarkdac1d172014-06-17 05:15:38 -07001148 }
1149 return [];
1150}
1151
caryclark26ad22a2015-10-16 09:03:38 -07001152function curveByID(test, id) {
1153 var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : [];
1154 if (!result.length) {
1155 result = curveByIDMatch(test, id, REC_TYPE_PATH);
1156 }
1157 return result;
1158}
1159
1160function curvePartialByIDMatch(test, id, t0, t1, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001161 var tIndex = -3;
1162 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001163 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001164 if (recType == REC_TYPE_OP) {
1165 continue;
1166 }
caryclark26ad22a2015-10-16 09:03:38 -07001167 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001168 return [];
1169 }
1170 var records = test[tIndex + 2];
1171 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1172 var fragType = records[recordIndex];
1173 var frags = records[recordIndex + 1];
1174 if (frags[0] == id) {
1175 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001176 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001177 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001178 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001179 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1180 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001181 case PATH_CONIC:
1182 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1183 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001184 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001185 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1186 frags[5], frags[6], frags[7], frags[8], t0, t1);
1187 }
1188 }
1189 }
caryclarkdac1d172014-06-17 05:15:38 -07001190 }
1191 return [];
1192}
1193
caryclark26ad22a2015-10-16 09:03:38 -07001194function curvePartialByID(test, id, t0, t1) {
1195 var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : [];
1196 if (!result.length) {
1197 result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH);
1198 }
1199 return result;
1200}
1201
1202function idByCurveIDMatch(test, frag, type, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001203 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001204 while (tIndex < test.length) {
1205 var recType = test[tIndex];
caryclark26ad22a2015-10-16 09:03:38 -07001206 if (recType != recMatch) {
caryclark54359292015-03-26 07:52:43 -07001207 ++tIndex;
1208 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001209 }
1210 var records = test[tIndex + 2];
1211 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1212 var fragType = records[recordIndex];
1213 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001214 if (frag.length != frags.length - 1) {
1215 continue;
1216 }
caryclarkdac1d172014-06-17 05:15:38 -07001217 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001218 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001219 if (frag[0] != frags[1] || frag[1] != frags[2]
1220 || frag[2] != frags[3] || frag[3] != frags[4]) {
1221 continue;
1222 }
1223 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001224 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001225 if (frag[0] != frags[1] || frag[1] != frags[2]
1226 || frag[2] != frags[3] || frag[3] != frags[4]
1227 || frag[4] != frags[5] || frag[5] != frags[6]) {
1228 continue;
1229 }
1230 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001231 case PATH_CONIC:
1232 if (frag[0] != frags[1] || frag[1] != frags[2]
1233 || frag[2] != frags[3] || frag[3] != frags[4]
1234 || frag[4] != frags[5] || frag[5] != frags[6]
1235 || frag[6] != frags[7]) {
1236 continue;
1237 }
1238 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001239 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001240 if (frag[0] != frags[1] || frag[1] != frags[2]
1241 || frag[2] != frags[3] || frag[3] != frags[4]
1242 || frag[4] != frags[5] || frag[5] != frags[6]
1243 || frag[6] != frags[7] || frag[7] != frags[8]) {
1244 continue;
1245 }
1246 return frags[0];
1247 }
1248 }
1249 ++tIndex;
1250 }
1251 return -1;
1252}
1253
caryclark26ad22a2015-10-16 09:03:38 -07001254function idByCurve(test, frag, type) {
1255 var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : [];
1256 if (!result.length) {
1257 result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH);
1258 }
1259 return result;
1260}
1261
caryclarkdac1d172014-06-17 05:15:38 -07001262function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001263 var length = curve.length == 7 ? 6 : curve.length;
caryclarked0935a2015-10-22 07:23:52 -07001264 for (var index = 0; index < length; index += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001265 var x = curve[index];
1266 var y = curve[index + 1];
1267 bounds[0] = Math.min(bounds[0], x);
1268 bounds[1] = Math.min(bounds[1], y);
1269 bounds[2] = Math.max(bounds[2], x);
1270 bounds[3] = Math.max(bounds[3], y);
1271 }
1272}
1273
1274function setScale(x0, x1, y0, y1) {
1275 var srcWidth = x1 - x0;
1276 var srcHeight = y1 - y0;
1277 var usableWidth = screenWidth;
1278 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1279 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1280 usableWidth -= (xDigits + yDigits) * 10;
1281 usableWidth -= decimal_places * 10;
1282 if (draw_legend) {
1283 usableWidth -= 40;
1284 }
1285 var hscale = usableWidth / srcWidth;
1286 var vscale = screenHeight / srcHeight;
1287 scale = Math.min(hscale, vscale);
1288 var invScale = 1 / scale;
1289 var sxmin = x0 - invScale * 5;
1290 var symin = y0 - invScale * 10;
1291 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1292 var symax = y1 + invScale * 10;
1293 srcWidth = sxmax - sxmin;
1294 srcHeight = symax - symin;
1295 hscale = usableWidth / srcWidth;
1296 vscale = screenHeight / srcHeight;
1297 scale = Math.min(hscale, vscale);
1298 srcLeft = sxmin;
1299 srcTop = symin;
1300}
1301
1302function drawArc(curve, op, from, to) {
1303 var type = PATH_LINE + (curve.length / 2 - 2);
1304 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1305 var dy = pt.y - curve[1];
1306 var dx = pt.x - curve[0];
1307 var dist = Math.sqrt(dy * dy + dx * dx);
1308 var _dist = dist * scale;
1309 var angle = Math.atan2(dy, dx);
1310 var _px = (curve[0] - srcLeft) * scale;
1311 var _py = (curve[1] - srcTop) * scale;
1312 var divisor = 4;
1313 var endDist;
1314 do {
1315 var ends = [];
1316 for (var index = -1; index <= 1; index += 2) {
1317 var px = Math.cos(index * Math.PI / divisor);
1318 var py = Math.sin(index * Math.PI / divisor);
1319 ends.push(px);
1320 ends.push(py);
1321 }
1322 var endDx = (ends[2] - ends[0]) * scale * dist;
1323 var endDy = (ends[3] - ends[1]) * scale * dist;
1324 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1325 if (endDist < 100) {
1326 break;
1327 }
1328 divisor *= 2;
1329 } while (true);
1330 if (endDist < 30) {
1331 return;
1332 }
1333 if (op) {
1334 divisor *= 2;
1335 }
1336 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1337 ctx.beginPath();
1338 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1339 ctx.stroke();
1340 var saveAlign = ctx.textAlign;
1341 var saveStyle = ctx.fillStyle;
1342 var saveFont = ctx.font;
1343 ctx.textAlign = "center";
1344 ctx.fillStyle = "black";
1345 ctx.font = "normal 24px Arial";
1346 divisor *= 0.8;
1347 for (var index = -1; index <= 1; index += 2) {
1348 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1349 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1350 var _px = (px - srcLeft) * scale;
1351 var _py = (py - srcTop) * scale;
1352 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1353 }
1354 ctx.textAlign = saveAlign;
1355 ctx.fillStyle = saveStyle;
1356 ctx.font = saveFont;
1357}
1358
1359function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001360 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1361 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001362 var x = drawnPts[pts];
1363 var y = drawnPts[pts + 1];
1364 if (px == x && py == y) {
1365 return;
1366 }
1367 }
1368 drawnPts.push(px);
1369 drawnPts.push(py);
1370 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1371 var _px = (px - srcLeft) * scale;
1372 var _py = (py - srcTop) * scale;
1373 ctx.beginPath();
1374 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1375 ctx.closePath();
1376 if (end) {
1377 ctx.fill();
1378 } else {
1379 ctx.stroke();
1380 }
1381 if (debug_xy) {
1382 ctx.textAlign = "left";
1383 ctx.fillText(label, _px + 5, _py);
1384 }
1385}
1386
caryclark1049f122015-04-20 08:31:59 -07001387function coordCount(curveType) {
1388 switch (curveType) {
1389 case PATH_LINE:
1390 return 4;
1391 case PATH_QUAD:
1392 return 6;
1393 case PATH_CONIC:
1394 return 6;
1395 case PATH_CUBIC:
1396 return 8;
1397 }
1398 return -1;
1399}
1400
caryclarkdac1d172014-06-17 05:15:38 -07001401function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001402 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001403 for (var idx = 0; idx < count; idx += 2) {
1404 if (!drawControls && idx != 0 && idx != count - 2) {
1405 continue;
1406 }
1407 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1408 }
1409}
1410
1411function drawControlLines(curve, curveType, drawEnd) {
1412 if (curveType == PATH_LINE) {
1413 return;
1414 }
1415 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1416 drawLine(curve[0], curve[1], curve[2], curve[3]);
1417 drawLine(curve[2], curve[3], curve[4], curve[5]);
1418 if (curveType == PATH_CUBIC) {
1419 drawLine(curve[4], curve[5], curve[6], curve[7]);
1420 if (drawEnd > 1) {
1421 drawLine(curve[6], curve[7], curve[0], curve[1]);
1422 if (drawEnd > 2) {
1423 drawLine(curve[0], curve[1], curve[4], curve[5]);
1424 drawLine(curve[6], curve[7], curve[2], curve[3]);
1425 }
1426 }
1427 } else if (drawEnd > 1) {
1428 drawLine(curve[4], curve[5], curve[0], curve[1]);
1429 }
1430}
1431
1432function pointAtT(curve, curveType, t) {
1433 var xy = {};
1434 switch (curveType) {
1435 case PATH_LINE:
1436 var a = 1 - t;
1437 var b = t;
1438 xy.x = a * curve[0] + b * curve[2];
1439 xy.y = a * curve[1] + b * curve[3];
1440 break;
1441 case PATH_QUAD:
1442 var one_t = 1 - t;
1443 var a = one_t * one_t;
1444 var b = 2 * one_t * t;
1445 var c = t * t;
1446 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1447 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1448 break;
caryclark1049f122015-04-20 08:31:59 -07001449 case PATH_CONIC:
1450 var one_t = 1 - t;
1451 var a = one_t * one_t;
1452 var b = 2 * one_t * t;
1453 var c = t * t;
1454 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1455 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1456 var d = a + b * curve[6] + c;
1457 xy.x /= d;
1458 xy.y /= d;
1459 break;
caryclarkdac1d172014-06-17 05:15:38 -07001460 case PATH_CUBIC:
1461 var one_t = 1 - t;
1462 var one_t2 = one_t * one_t;
1463 var a = one_t2 * one_t;
1464 var b = 3 * one_t2 * t;
1465 var t2 = t * t;
1466 var c = 3 * one_t * t2;
1467 var d = t2 * t;
1468 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1469 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1470 break;
1471 }
1472 return xy;
1473}
caryclark55888e42016-07-18 10:01:36 -07001474
caryclarkdac1d172014-06-17 05:15:38 -07001475function drawPointAtT(curve, curveType) {
1476 var x, y;
1477 var xy = pointAtT(curve, curveType, curveT);
1478 drawPoint(xy.x, xy.y, true);
1479 if (!draw_intersectT) {
1480 return;
1481 }
1482 ctx.fillStyle = "red";
1483 drawTAtPointUp(xy.x, xy.y, curveT);
1484}
1485
1486function drawTAtPointUp(px, py, t) {
1487 var label = t.toFixed(decimal_places);
1488 var _px = (px - srcLeft)* scale;
1489 var _py = (py - srcTop) * scale;
1490 ctx.fillText(label, _px + 5, _py - 10);
1491}
1492
1493function drawTAtPointDown(px, py, t) {
1494 var label = t.toFixed(decimal_places);
1495 var _px = (px - srcLeft)* scale;
1496 var _py = (py - srcTop) * scale;
1497 ctx.fillText(label, _px + 5, _py + 10);
1498}
1499
1500function alreadyDrawnLine(x1, y1, x2, y2) {
1501 if (collect_bounds) {
1502 if (focus_enabled) {
1503 focusXmin = Math.min(focusXmin, x1, x2);
1504 focusYmin = Math.min(focusYmin, y1, y2);
1505 focusXmax = Math.max(focusXmax, x1, x2);
1506 focusYmax = Math.max(focusYmax, y1, y2);
1507 }
1508 return true;
1509 }
1510 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1511 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1512 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1513 return true;
1514 }
1515 }
1516 drawnLines.push(x1);
1517 drawnLines.push(y1);
1518 drawnLines.push(x2);
1519 drawnLines.push(y2);
1520 return false;
1521}
1522
1523function drawLine(x1, y1, x2, y2) {
1524 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1525 return;
1526 }
1527 ctx.beginPath();
1528 ctx.moveTo((x1 - srcLeft) * scale,
1529 (y1 - srcTop) * scale);
1530 ctx.lineTo((x2 - srcLeft) * scale,
1531 (y2 - srcTop) * scale);
1532 ctx.stroke();
1533}
1534
1535function linePartial(x1, y1, x2, y2, t1, t2) {
1536 var dx = x1 - x2;
1537 var dy = y1 - y2;
1538 var array = [
1539 x1 - t1 * dx,
1540 y1 - t1 * dy,
1541 x1 - t2 * dx,
1542 y1 - t2 * dy
1543 ];
1544 return array;
1545}
1546
1547function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1548 var a = linePartial(x1, y1, x2, y2, t1, t2);
1549 var ax = a[0];
1550 var ay = a[1];
1551 var bx = a[2];
1552 var by = a[3];
1553 if (alreadyDrawnLine(ax, ay, bx, by)) {
1554 return;
1555 }
1556 ctx.beginPath();
1557 ctx.moveTo((ax - srcLeft) * scale,
1558 (ay - srcTop) * scale);
1559 ctx.lineTo((bx - srcLeft) * scale,
1560 (by - srcTop) * scale);
1561 ctx.stroke();
1562}
1563
1564function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1565 if (collect_bounds) {
1566 if (focus_enabled) {
1567 focusXmin = Math.min(focusXmin, x1, x2, x3);
1568 focusYmin = Math.min(focusYmin, y1, y2, y3);
1569 focusXmax = Math.max(focusXmax, x1, x2, x3);
1570 focusYmax = Math.max(focusYmax, y1, y2, y3);
1571 }
1572 return true;
1573 }
1574 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1575 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1576 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1577 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1578 return true;
1579 }
1580 }
1581 drawnQuads.push(x1);
1582 drawnQuads.push(y1);
1583 drawnQuads.push(x2);
1584 drawnQuads.push(y2);
1585 drawnQuads.push(x3);
1586 drawnQuads.push(y3);
1587 return false;
1588}
1589
1590function drawQuad(x1, y1, x2, y2, x3, y3) {
1591 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1592 return;
1593 }
1594 ctx.beginPath();
1595 ctx.moveTo((x1 - srcLeft) * scale,
1596 (y1 - srcTop) * scale);
1597 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1598 (y2 - srcTop) * scale,
1599 (x3 - srcLeft) * scale,
1600 (y3 - srcTop) * scale);
1601 ctx.stroke();
1602}
1603
1604function interp(A, B, t) {
1605 return A + (B - A) * t;
1606}
1607
1608function interp_quad_coords(x1, x2, x3, t)
1609{
1610 var ab = interp(x1, x2, t);
1611 var bc = interp(x2, x3, t);
1612 var abc = interp(ab, bc, t);
1613 return abc;
1614}
1615
1616function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1617 var ax = interp_quad_coords(x1, x2, x3, t1);
1618 var ay = interp_quad_coords(y1, y2, y3, t1);
1619 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1620 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1621 var cx = interp_quad_coords(x1, x2, x3, t2);
1622 var cy = interp_quad_coords(y1, y2, y3, t2);
1623 var bx = 2*dx - (ax + cx)/2;
1624 var by = 2*dy - (ay + cy)/2;
1625 var array = [
1626 ax, ay, bx, by, cx, cy
1627 ];
1628 return array;
1629}
1630
1631function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1632 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1633 var ax = a[0];
1634 var ay = a[1];
1635 var bx = a[2];
1636 var by = a[3];
1637 var cx = a[4];
1638 var cy = a[5];
1639 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1640 return;
1641 }
1642 ctx.beginPath();
1643 ctx.moveTo((ax - srcLeft) * scale,
1644 (ay - srcTop) * scale);
1645 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1646 (by - srcTop) * scale,
1647 (cx - srcLeft) * scale,
1648 (cy - srcTop) * scale);
1649 ctx.stroke();
1650}
1651
caryclark1049f122015-04-20 08:31:59 -07001652function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1653 if (collect_bounds) {
1654 if (focus_enabled) {
1655 focusXmin = Math.min(focusXmin, x1, x2, x3);
1656 focusYmin = Math.min(focusYmin, y1, y2, y3);
1657 focusXmax = Math.max(focusXmax, x1, x2, x3);
1658 focusYmax = Math.max(focusYmax, y1, y2, y3);
1659 }
1660 return true;
1661 }
1662 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1663 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001664 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1665 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclark1049f122015-04-20 08:31:59 -07001666 && w == drawnCubics[pts + 6]) {
1667 return true;
1668 }
1669 }
1670 drawnConics.push(x1);
1671 drawnConics.push(y1);
1672 drawnConics.push(x2);
1673 drawnConics.push(y2);
1674 drawnConics.push(x3);
1675 drawnConics.push(y3);
1676 drawnCubics.push(w);
1677 return false;
1678}
1679
1680var kMaxConicToQuadPOW2 = 5;
1681
1682function computeQuadPOW2(curve, tol) {
1683 var a = curve[6] - 1;
1684 var k = a / (4 * (2 + a));
1685 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1686 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1687
1688 var error = Math.sqrt(x * x + y * y);
1689 var pow2;
1690 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1691 if (error <= tol) {
1692 break;
1693 }
1694 error *= 0.25;
1695 }
1696 return pow2;
1697}
1698
1699function subdivide_w_value(w) {
1700 return Math.sqrt(0.5 + w * 0.5);
1701}
1702
1703function chop(curve, part1, part2) {
1704 var w = curve[6];
1705 var scale = 1 / (1 + w);
1706 part1[0] = curve[0];
1707 part1[1] = curve[1];
1708 part1[2] = (curve[0] + curve[2] * w) * scale;
1709 part1[3] = (curve[1] + curve[3] * w) * scale;
1710 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1711 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1712 part2[2] = (curve[2] * w + curve[4]) * scale;
1713 part2[3] = (curve[3] * w + curve[5]) * scale;
1714 part2[4] = curve[4];
1715 part2[5] = curve[5];
1716 part1[6] = part2[6] = subdivide_w_value(w);
1717}
1718
1719function subdivide(curve, level, pts) {
1720 if (0 == level) {
1721 pts.push(curve[2]);
1722 pts.push(curve[3]);
1723 pts.push(curve[4]);
1724 pts.push(curve[5]);
1725 } else {
1726 var part1 = [], part2 = [];
1727 chop(curve, part1, part2);
1728 --level;
1729 subdivide(part1, level, pts);
1730 subdivide(part2, level, pts);
1731 }
1732}
1733
1734function chopIntoQuadsPOW2(curve, pow2, pts) {
1735 subdivide(curve, pow2, pts);
1736 return 1 << pow2;
1737}
1738
1739function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1740 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1741 return;
1742 }
1743 ctx.beginPath();
1744 ctx.moveTo((x1 - srcLeft) * scale,
1745 (y1 - srcTop) * scale);
1746 var tol = 1 / scale;
1747 var curve = [x1, y1, x2, y2, x3, y3, w];
1748 var pow2 = computeQuadPOW2(curve, tol);
1749 var pts = [];
1750 chopIntoQuadsPOW2(curve, pow2, pts);
1751 for (var i = 0; i < pts.length; i += 4) {
1752 ctx.quadraticCurveTo(
1753 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1754 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1755 }
1756 ctx.stroke();
1757}
1758
1759function conic_eval_numerator(x1, x2, x3, w, t) {
1760 var src2w = x2 * w;
1761 var C = x1;
1762 var A = x3 - 2 * src2w + C;
1763 var B = 2 * (src2w - C);
1764 return (A * t + B) * t + C;
1765}
1766
1767
1768function conic_eval_denominator(w, t) {
1769 var B = 2 * (w - 1);
1770 var C = 1;
1771 var A = -B;
1772 return (A * t + B) * t + C;
1773}
1774
1775function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1776 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1777 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1778 var az = conic_eval_denominator(w, t1);
1779 var midT = (t1 + t2) / 2;
1780 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1781 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1782 var dz = conic_eval_denominator(w, midT);
1783 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1784 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1785 var cz = conic_eval_denominator(w, t2);
1786 var bx = 2 * dx - (ax + cx) / 2;
1787 var by = 2 * dy - (ay + cy) / 2;
1788 var bz = 2 * dz - (az + cz) / 2;
1789 var dt = t2 - t1;
1790 var dt_1 = 1 - dt;
caryclark1049f122015-04-20 08:31:59 -07001791 var array = [
caryclarked0935a2015-10-22 07:23:52 -07001792 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
caryclark1049f122015-04-20 08:31:59 -07001793 ];
caryclarked0935a2015-10-22 07:23:52 -07001794 var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 };
1795 var dMid = { x:dx / dz, y:dy / dz };
1796 var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y };
1797 var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] };
1798 var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y)
1799 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y);
1800 array[6] = partW;
caryclark1049f122015-04-20 08:31:59 -07001801 return array;
1802}
caryclark55888e42016-07-18 10:01:36 -07001803
caryclark1049f122015-04-20 08:31:59 -07001804function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1805 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1806 var ax = a[0];
1807 var ay = a[1];
1808 var bx = a[2];
1809 var by = a[3];
1810 var cx = a[4];
1811 var cy = a[5];
1812 var w_ = a[6];
1813 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1814}
1815
caryclarkdac1d172014-06-17 05:15:38 -07001816function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1817 if (collect_bounds) {
1818 if (focus_enabled) {
1819 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1820 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1821 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1822 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1823 }
1824 return true;
1825 }
1826 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1827 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001828 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1829 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclarkdac1d172014-06-17 05:15:38 -07001830 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1831 return true;
1832 }
1833 }
1834 drawnCubics.push(x1);
1835 drawnCubics.push(y1);
1836 drawnCubics.push(x2);
1837 drawnCubics.push(y2);
1838 drawnCubics.push(x3);
1839 drawnCubics.push(y3);
1840 drawnCubics.push(x4);
1841 drawnCubics.push(y4);
1842 return false;
1843}
1844
1845function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1846 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1847 return;
1848 }
1849 ctx.beginPath();
1850 ctx.moveTo((x1 - srcLeft) * scale,
1851 (y1 - srcTop) * scale);
1852 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1853 (y2 - srcTop) * scale,
1854 (x3 - srcLeft) * scale,
1855 (y3 - srcTop) * scale,
1856 (x4 - srcLeft) * scale,
1857 (y4 - srcTop) * scale);
1858 ctx.stroke();
1859}
1860
1861function interp_cubic_coords(x1, x2, x3, x4, t)
1862{
1863 var ab = interp(x1, x2, t);
1864 var bc = interp(x2, x3, t);
1865 var cd = interp(x3, x4, t);
1866 var abc = interp(ab, bc, t);
1867 var bcd = interp(bc, cd, t);
1868 var abcd = interp(abc, bcd, t);
1869 return abcd;
1870}
1871
1872function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1873 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1874 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1875 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1876 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1877 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1878 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1879 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1880 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1881 var mx = ex * 27 - ax * 8 - dx;
1882 var my = ey * 27 - ay * 8 - dy;
1883 var nx = fx * 27 - ax - dx * 8;
1884 var ny = fy * 27 - ay - dy * 8;
1885 var bx = (mx * 2 - nx) / 18;
1886 var by = (my * 2 - ny) / 18;
1887 var cx = (nx * 2 - mx) / 18;
1888 var cy = (ny * 2 - my) / 18;
1889 var array = [
1890 ax, ay, bx, by, cx, cy, dx, dy
1891 ];
1892 return array;
1893}
caryclark55888e42016-07-18 10:01:36 -07001894
caryclarkdac1d172014-06-17 05:15:38 -07001895function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1896 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
1897 var ax = a[0];
1898 var ay = a[1];
1899 var bx = a[2];
1900 var by = a[3];
1901 var cx = a[4];
1902 var cy = a[5];
1903 var dx = a[6];
1904 var dy = a[7];
1905 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
1906 return;
1907 }
1908 ctx.beginPath();
1909 ctx.moveTo((ax - srcLeft) * scale,
1910 (ay - srcTop) * scale);
1911 ctx.bezierCurveTo((bx - srcLeft) * scale,
1912 (by - srcTop) * scale,
1913 (cx - srcLeft) * scale,
1914 (cy - srcTop) * scale,
1915 (dx - srcLeft) * scale,
1916 (dy - srcTop) * scale);
1917 ctx.stroke();
1918}
1919
1920function drawCurve(c) {
1921 switch (c.length) {
1922 case 4:
1923 drawLine(c[0], c[1], c[2], c[3]);
1924 break;
1925 case 6:
1926 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
1927 break;
caryclark1049f122015-04-20 08:31:59 -07001928 case 7:
1929 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
1930 break;
caryclarkdac1d172014-06-17 05:15:38 -07001931 case 8:
1932 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1933 break;
1934 }
1935}
1936
1937function boundsWidth(pts) {
1938 var min = pts[0];
1939 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07001940 var length = pts.length == 7 ? 6 : pts.length;
1941 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001942 min = Math.min(min, pts[idx]);
1943 max = Math.max(max, pts[idx]);
1944 }
1945 return max - min;
1946}
1947
1948function boundsHeight(pts) {
1949 var min = pts[1];
1950 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07001951 var length = pts.length == 7 ? 6 : pts.length;
1952 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001953 min = Math.min(min, pts[idx]);
1954 max = Math.max(max, pts[idx]);
1955 }
1956 return max - min;
1957}
1958
1959function tangent(pts) {
1960 var dx = pts[2] - pts[0];
1961 var dy = pts[3] - pts[1];
1962 if (dx == 0 && dy == 0 && pts.length > 4) {
1963 dx = pts[4] - pts[0];
1964 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07001965 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07001966 dx = pts[6] - pts[0];
1967 dy = pts[7] - pts[1];
1968 }
1969 }
1970 return Math.atan2(-dy, dx);
1971}
1972
1973function hodograph(cubic) {
1974 var hodo = [];
1975 hodo[0] = 3 * (cubic[2] - cubic[0]);
1976 hodo[1] = 3 * (cubic[3] - cubic[1]);
1977 hodo[2] = 3 * (cubic[4] - cubic[2]);
1978 hodo[3] = 3 * (cubic[5] - cubic[3]);
1979 hodo[4] = 3 * (cubic[6] - cubic[4]);
1980 hodo[5] = 3 * (cubic[7] - cubic[5]);
1981 return hodo;
1982}
1983
1984function hodograph2(cubic) {
1985 var quad = hodograph(cubic);
1986 var hodo = [];
1987 hodo[0] = 2 * (quad[2] - quad[0]);
1988 hodo[1] = 2 * (quad[3] - quad[1]);
1989 hodo[2] = 2 * (quad[4] - quad[2]);
1990 hodo[3] = 2 * (quad[5] - quad[3]);
1991 return hodo;
1992}
1993
1994function quadraticRootsReal(A, B, C, s) {
1995 if (A == 0) {
1996 if (B == 0) {
1997 s[0] = 0;
1998 return C == 0;
1999 }
2000 s[0] = -C / B;
2001 return 1;
2002 }
2003 /* normal form: x^2 + px + q = 0 */
2004 var p = B / (2 * A);
2005 var q = C / A;
2006 var p2 = p * p;
2007 if (p2 < q) {
2008 return 0;
2009 }
2010 var sqrt_D = 0;
2011 if (p2 > q) {
2012 sqrt_D = sqrt(p2 - q);
2013 }
2014 s[0] = sqrt_D - p;
2015 s[1] = -sqrt_D - p;
2016 return 1 + s[0] != s[1];
2017}
2018
2019function add_valid_ts(s, realRoots, t) {
2020 var foundRoots = 0;
2021 for (var index = 0; index < realRoots; ++index) {
2022 var tValue = s[index];
2023 if (tValue >= 0 && tValue <= 1) {
2024 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2025 if (t[idx2] != tValue) {
2026 t[foundRoots++] = tValue;
2027 }
2028 }
2029 }
2030 }
2031 return foundRoots;
2032}
2033
2034function quadraticRootsValidT(a, b, c, t) {
2035 var s = [];
2036 var realRoots = quadraticRootsReal(A, B, C, s);
2037 var foundRoots = add_valid_ts(s, realRoots, t);
2038 return foundRoots != 0;
2039}
2040
2041function find_cubic_inflections(cubic, tValues) {
2042 var Ax = src[2] - src[0];
2043 var Ay = src[3] - src[1];
2044 var Bx = src[4] - 2 * src[2] + src[0];
2045 var By = src[5] - 2 * src[3] + src[1];
2046 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2047 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2048 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2049 Ax * By - Ay * Bx, tValues);
2050}
2051
2052function dxy_at_t(curve, type, t) {
2053 var dxy = {};
2054 if (type == PATH_QUAD) {
2055 var a = t - 1;
2056 var b = 1 - 2 * t;
2057 var c = t;
2058 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2059 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002060 } else if (type == PATH_CONIC) {
2061 var p20x = curve[4] - curve[0];
2062 var p20y = curve[5] - curve[1];
2063 var p10xw = (curve[2] - curve[0]) * curve[6];
2064 var p10yw = (curve[3] - curve[1]) * curve[6];
2065 var coeff0x = curve[6] * p20x - p20x;
2066 var coeff0y = curve[6] * p20y - p20y;
2067 var coeff1x = p20x - 2 * p10xw;
2068 var coeff1y = p20y - 2 * p10yw;
2069 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2070 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002071 } else if (type == PATH_CUBIC) {
2072 var one_t = 1 - t;
2073 var a = curve[0];
2074 var b = curve[2];
2075 var c = curve[4];
2076 var d = curve[6];
2077 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2078 a = curve[1];
2079 b = curve[3];
2080 c = curve[5];
2081 d = curve[7];
2082 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2083 }
2084 return dxy;
2085}
2086
2087function drawLabel(num, px, py) {
2088 ctx.beginPath();
2089 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2090 ctx.closePath();
2091 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2092 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2093 ctx.stroke();
2094 ctx.fillStyle = "black";
2095 ctx.font = "normal 10px Arial";
2096 // ctx.rotate(0.001);
2097 ctx.fillText(num, px - 2, py + 3);
2098 // ctx.rotate(-0.001);
2099}
2100
2101function drawLabelX(ymin, num, loc) {
2102 var px = (loc - srcLeft) * scale;
2103 var py = (ymin - srcTop) * scale - 20;
2104 drawLabel(num, px, py);
2105}
2106
2107function drawLabelY(xmin, num, loc) {
2108 var px = (xmin - srcLeft) * scale - 20;
2109 var py = (loc - srcTop) * scale;
2110 drawLabel(num, px, py);
2111}
2112
2113function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2114 ctx.beginPath();
2115 ctx.moveTo(hx, hy - 100);
2116 ctx.lineTo(hx, hy);
2117 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2118 ctx.stroke();
2119 ctx.beginPath();
2120 ctx.moveTo(hx, hy);
2121 ctx.lineTo(hx, hy + 100);
2122 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2123 ctx.stroke();
2124 ctx.beginPath();
2125 ctx.moveTo(hx - 100, hy);
2126 ctx.lineTo(hx, hy);
2127 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2128 ctx.stroke();
2129 ctx.beginPath();
2130 ctx.moveTo(hx, hy);
2131 ctx.lineTo(hx + 100, hy);
2132 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2133 ctx.stroke();
2134}
2135
2136function scalexy(x, y, mag) {
2137 var length = Math.sqrt(x * x + y * y);
2138 return mag / length;
2139}
2140
caryclark03b03ca2015-04-23 09:13:37 -07002141function drawArrow(x, y, dx, dy, s) {
2142 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002143 dx *= dscale;
2144 dy *= dscale;
2145 ctx.beginPath();
2146 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2147 x += dx;
2148 y += dy;
2149 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2150 dx /= 10;
2151 dy /= 10;
2152 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2153 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2154 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2155 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2156 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2157 ctx.stroke();
2158}
2159
2160function x_at_t(curve, t) {
2161 var one_t = 1 - t;
2162 if (curve.length == 4) {
2163 return one_t * curve[0] + t * curve[2];
2164 }
2165 var one_t2 = one_t * one_t;
2166 var t2 = t * t;
2167 if (curve.length == 6) {
2168 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2169 }
caryclark1049f122015-04-20 08:31:59 -07002170 if (curve.length == 7) {
2171 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2172 / (one_t2 +2 * one_t * t * curve[6] + t2);
2173 }
caryclarkdac1d172014-06-17 05:15:38 -07002174 var a = one_t2 * one_t;
2175 var b = 3 * one_t2 * t;
2176 var c = 3 * one_t * t2;
2177 var d = t2 * t;
2178 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2179}
2180
2181function y_at_t(curve, t) {
2182 var one_t = 1 - t;
2183 if (curve.length == 4) {
2184 return one_t * curve[1] + t * curve[3];
2185 }
2186 var one_t2 = one_t * one_t;
2187 var t2 = t * t;
2188 if (curve.length == 6) {
2189 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2190 }
caryclark1049f122015-04-20 08:31:59 -07002191 if (curve.length == 7) {
2192 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2193 / (one_t2 +2 * one_t * t * curve[6] + t2);
2194 }
caryclarkdac1d172014-06-17 05:15:38 -07002195 var a = one_t2 * one_t;
2196 var b = 3 * one_t2 * t;
2197 var c = 3 * one_t * t2;
2198 var d = t2 * t;
2199 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2200}
2201
2202function drawOrder(curve, label) {
2203 var px = x_at_t(curve, 0.75);
2204 var py = y_at_t(curve, 0.75);
2205 var _px = (px - srcLeft) * scale;
2206 var _py = (py - srcTop) * scale;
2207 ctx.beginPath();
2208 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2209 ctx.closePath();
2210 ctx.fillStyle = "white";
2211 ctx.fill();
2212 if (label == 'L') {
2213 ctx.strokeStyle = "rgba(255,0,0, 1)";
2214 ctx.fillStyle = "rgba(255,0,0, 1)";
2215 } else {
2216 ctx.strokeStyle = "rgba(0,0,255, 1)";
2217 ctx.fillStyle = "rgba(0,0,255, 1)";
2218 }
2219 ctx.stroke();
2220 ctx.font = "normal 16px Arial";
2221 ctx.textAlign = "center";
2222 ctx.fillText(label, _px, _py + 5);
2223 ctx.font = "normal 10px Arial";
2224}
2225
2226function drawID(curve, id) {
2227 var px = x_at_t(curve, 0.5);
2228 var py = y_at_t(curve, 0.5);
2229 var _px = (px - srcLeft) * scale;
2230 var _py = (py - srcTop) * scale;
2231 draw_id_at(id, _px, _py);
2232}
2233
2234function draw_id_at(id, _px, _py) {
2235 ctx.beginPath();
2236 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2237 ctx.closePath();
2238 ctx.fillStyle = "white";
2239 ctx.fill();
2240 ctx.strokeStyle = "rgba(127,127,0, 1)";
2241 ctx.fillStyle = "rgba(127,127,0, 1)";
2242 ctx.stroke();
2243 ctx.font = "normal 16px Arial";
2244 ctx.textAlign = "center";
2245 ctx.fillText(id, _px, _py + 5);
2246 ctx.font = "normal 10px Arial";
2247}
2248
2249function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2250 var curve = [x1, y1, x2, y2];
2251 drawCurvePartialID(id, curve, t1, t2);
2252}
2253
caryclark55888e42016-07-18 10:01:36 -07002254function drawLineID(id, x1, y1, x2, y2) {
2255 drawLinePartialID(id, x1, y1, x2, y2, 0, 1);
2256}
2257
caryclarkdac1d172014-06-17 05:15:38 -07002258function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2259 var curve = [x1, y1, x2, y2, x3, y3];
2260 drawCurvePartialID(id, curve, t1, t2);
2261}
2262
caryclark55888e42016-07-18 10:01:36 -07002263function drawQuadID(id, x1, y1, x2, y2, x3, y3) {
2264 drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1);
2265}
2266
caryclark1049f122015-04-20 08:31:59 -07002267function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2268 var curve = [x1, y1, x2, y2, x3, y3, w];
2269 drawCurvePartialID(id, curve, t1, t2);
2270}
2271
caryclark55888e42016-07-18 10:01:36 -07002272function drawConicID(id, x1, y1, x2, y2, x3, y3, w) {
2273 drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1);
2274}
2275
caryclarkdac1d172014-06-17 05:15:38 -07002276function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2277 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2278 drawCurvePartialID(id, curve, t1, t2);
2279}
2280
caryclark55888e42016-07-18 10:01:36 -07002281function drawCubicID(id, x1, y1, x2, y2, x3, y3, x4, y4) {
2282 drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, 0, 1);
2283}
2284
caryclarkdac1d172014-06-17 05:15:38 -07002285function drawCurvePartialID(id, curve, t1, t2) {
2286 var px = x_at_t(curve, (t1 + t2) / 2);
2287 var py = y_at_t(curve, (t1 + t2) / 2);
2288 var _px = (px - srcLeft) * scale;
2289 var _py = (py - srcTop) * scale;
2290 draw_id_at(id, _px, _py);
2291}
2292
2293function drawCurveSpecials(test, curve, type) {
2294 if (pt_labels) {
2295 drawPoints(curve, type, pt_labels == 2);
2296 }
2297 if (control_lines != 0) {
2298 drawControlLines(curve, type, control_lines);
2299 }
2300 if (curve_t) {
2301 drawPointAtT(curve, type);
2302 }
2303 if (draw_midpoint) {
2304 var mid = pointAtT(curve, type, 0.5);
2305 drawPoint(mid.x, mid.y, true);
2306 }
2307 if (draw_id) {
2308 var id = idByCurve(test, curve, type);
2309 if (id >= 0) {
2310 drawID(curve, id);
2311 }
2312 }
2313 if (type == PATH_LINE) {
2314 return;
2315 }
2316 if (draw_deriviatives > 0) {
2317 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002318 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002319 if (draw_deriviatives == 2) {
2320 d = dxy_at_t(curve, type, 1);
2321 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002322 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002323 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002324 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002325 }
2326 }
2327 if (draw_midpoint) {
2328 var mid = pointAtT(curve, type, 0.5);
2329 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002330 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002331 }
2332 }
2333 if (type != PATH_CUBIC) {
2334 return;
2335 }
caryclarkdac1d172014-06-17 05:15:38 -07002336 if (draw_sequence) {
2337 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2338 for (var i = 0; i < 8; i+= 2) {
2339 drawLabelX(ymin, i >> 1, curve[i]);
2340 }
2341 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2342 for (var i = 1; i < 8; i+= 2) {
2343 drawLabelY(xmin, i >> 1, curve[i]);
2344 }
2345 }
2346}
2347
2348function logCurves(test) {
2349 for (curves in test) {
2350 var curve = test[curves];
2351 dumpCurve(curve);
2352 }
2353}
2354
2355function curveToString(curve) {
2356 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002357 var length = curve.length == 7 ? 6 : curve.length;
2358 if (curve.length == 7) {
2359 str += "{";
2360 }
2361 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002362 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2363 if (i < curve.length - 2) {
2364 str += "}, {";
2365 }
2366 }
caryclark1049f122015-04-20 08:31:59 -07002367 str += "}";
2368 if (curve.length == 7) {
2369 str += "}, " + curve[6].toFixed(decimal_places);
2370 }
2371 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002372 return str;
2373}
2374
2375function dumpCurve(curve) {
2376 console.log(curveToString(curve));
2377}
2378
2379function draw(test, lines, title) {
2380 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2381 ctx.font = "normal 50px Arial";
2382 ctx.textAlign = "left";
2383 ctx.fillText(title, 50, 50);
2384 ctx.font = "normal 10px Arial";
2385 ctx.lineWidth = "1.001"; "0.999";
2386 var secondPath = test.length;
2387 var closeCount = 0;
2388 logStart = -1;
2389 logRange = 0;
2390 // find last active rec type at this step
2391 var curType = test[0];
2392 var curStep = 0;
2393 var hasOp = false;
2394 var lastActive = 0;
2395 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002396 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002397 var lastSect = 0;
2398 var lastSort = 0;
2399 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002400 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002401 activeCount = 0;
2402 addCount = 0;
2403 angleCount = 0;
2404 opCount = 0;
2405 sectCount = 0;
2406 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002407 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002408 markCount = 0;
2409 activeMax = 0;
2410 addMax = 0;
2411 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002412 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002413 opMax = 0;
2414 sectMax = 0;
2415 sectMax2 = 0;
2416 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002417 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002418 markMax = 0;
2419 lastIndex = test.length - 3;
2420 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2421 var recType = test[tIndex];
2422 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2423 console.log("unknown rec type: " + recType);
2424 throw "stop execution";
2425 }
2426 // if (curType == recType && curType != REC_TYPE_ADD) {
2427 // continue;
2428 // }
2429 var inStepRange = step_limit == 0 || curStep < step_limit;
2430 curType = recType;
2431 if (recType == REC_TYPE_OP) {
2432 hasOp = true;
2433 continue;
2434 }
2435 if (recType == REC_TYPE_UNKNOWN) {
2436 // these types do not advance step
2437 continue;
2438 }
2439 var bumpStep = false;
2440 var records = test[tIndex + 2];
2441 var fragType = records[0];
2442 if (recType == REC_TYPE_ADD) {
2443 if (records.length != 2) {
2444 console.log("expect only two elements: " + records.length);
2445 throw "stop execution";
2446 }
2447 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2448 continue;
2449 }
2450 ++addMax;
2451 if (!draw_add || !inStepRange) {
2452 continue;
2453 }
2454 lastAdd = tIndex;
2455 ++addCount;
2456 bumpStep = true;
2457 }
2458 if (recType == REC_TYPE_PATH && hasOp) {
2459 secondPath = tIndex;
2460 }
caryclark54359292015-03-26 07:52:43 -07002461 if (recType == REC_TYPE_PATH2 && hasOp) {
2462 secondPath = tIndex;
2463 }
caryclarkdac1d172014-06-17 05:15:38 -07002464 if (recType == REC_TYPE_ACTIVE) {
2465 ++activeMax;
2466 if (!draw_active || !inStepRange) {
2467 continue;
2468 }
2469 lastActive = tIndex;
2470 ++activeCount;
2471 bumpStep = true;
2472 }
2473 if (recType == REC_TYPE_ACTIVE_OP) {
2474 ++opMax;
2475 if (!draw_op || !inStepRange) {
2476 continue;
2477 }
2478 lastOp = tIndex;
2479 ++opCount;
2480 bumpStep = true;
2481 }
caryclark54359292015-03-26 07:52:43 -07002482 if (recType == REC_TYPE_AFTERPART) {
2483 if (draw_angle != 3 || !inStepRange) {
2484 continue;
2485 }
2486 lastAngle = tIndex;
2487 ++angleCount;
2488 bumpStep = true;
2489 }
caryclarkdac1d172014-06-17 05:15:38 -07002490 if (recType == REC_TYPE_ANGLE) {
2491 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002492 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002493 continue;
2494 }
2495 lastAngle = tIndex;
2496 ++angleCount;
2497 bumpStep = true;
2498 }
caryclark624637c2015-05-11 07:21:27 -07002499 if (recType == REC_TYPE_COINCIDENCE) {
2500 ++coinMax;
2501 if (!draw_coincidence || !inStepRange) {
2502 continue;
2503 }
2504 lastCoin = tIndex;
2505 ++coinCount;
2506 bumpStep = true;
2507 }
caryclarkdac1d172014-06-17 05:15:38 -07002508 if (recType == REC_TYPE_SECT) {
2509 if (records.length != 2) {
2510 console.log("expect only two elements: " + records.length);
2511 throw "stop execution";
2512 }
2513 ++sectMax;
2514 var sectBump = 1;
2515 switch (fragType) {
2516 case INTERSECT_LINE:
2517 case INTERSECT_QUAD_LINE:
2518 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002519 case INTERSECT_CONIC_LINE:
caryclark55888e42016-07-18 10:01:36 -07002520 case INTERSECT_CONIC_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002521 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002522 case INTERSECT_SELF_CUBIC:
2523 case INTERSECT_CUBIC_LINE:
2524 case INTERSECT_CUBIC_QUAD:
2525 case INTERSECT_CUBIC:
2526 sectBump = 1;
2527 break;
2528 case INTERSECT_LINE_2:
2529 case INTERSECT_QUAD_LINE_2:
2530 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002531 case INTERSECT_CONIC_LINE_2:
caryclark55888e42016-07-18 10:01:36 -07002532 case INTERSECT_CONIC_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002533 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002534 case INTERSECT_CUBIC_LINE_2:
2535 case INTERSECT_CUBIC_QUAD_2:
2536 case INTERSECT_CUBIC_2:
2537 sectBump = 2;
2538 break;
2539 case INTERSECT_LINE_NO:
2540 case INTERSECT_QUAD_LINE_NO:
2541 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002542 case INTERSECT_CONIC_LINE_NO:
caryclark55888e42016-07-18 10:01:36 -07002543 case INTERSECT_CONIC_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002544 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002545 case INTERSECT_SELF_CUBIC_NO:
2546 case INTERSECT_CUBIC_LINE_NO:
2547 case INTERSECT_CUBIC_QUAD_NO:
2548 case INTERSECT_CUBIC_NO:
2549 sectBump = 0;
2550 break;
2551 case INTERSECT_CUBIC_LINE_3:
2552 case INTERSECT_CUBIC_QUAD_3:
2553 case INTERSECT_CUBIC_3:
2554 sectBump = 3;
2555 break;
2556 case INTERSECT_CUBIC_QUAD_4:
2557 case INTERSECT_CUBIC_4:
2558 sectBump = 4;
2559 break;
2560 default:
2561 console.log("missing case " + records.length);
2562 throw "stop execution";
2563 }
2564 sectMax2 += sectBump;
2565 if (draw_intersection <= 1 || !inStepRange) {
2566 continue;
2567 }
2568 lastSect = tIndex;
2569 sectCount += sectBump;
2570 bumpStep = true;
2571 }
2572 if (recType == REC_TYPE_SORT) {
2573 ++sortMax;
2574 if (!draw_sort || !inStepRange) {
2575 continue;
2576 }
2577 lastSort = tIndex;
2578 ++sortCount;
2579 bumpStep = true;
2580 }
caryclark03b03ca2015-04-23 09:13:37 -07002581 if (recType == REC_TYPE_TOP) {
2582 ++topMax;
2583 if (!draw_top || !inStepRange) {
2584 continue;
2585 }
2586 lastTop = tIndex;
2587 ++topCount;
2588 bumpStep = true;
2589 }
caryclarkdac1d172014-06-17 05:15:38 -07002590 if (recType == REC_TYPE_MARK) {
2591 ++markMax;
2592 if (!draw_mark || !inStepRange) {
2593 continue;
2594 }
2595 lastMark = tIndex;
2596 ++markCount;
2597 bumpStep = true;
2598 }
2599 if (bumpStep) {
2600 lastIndex = tIndex;
2601 logStart = test[tIndex + 1];
2602 logRange = records.length / 2;
2603 ++curStep;
2604 }
2605 }
2606 stepMax = (draw_add ? addMax : 0)
2607 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002608 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002609 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002610 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002611 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002612 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002613 + (draw_mark ? markMax : 0)
2614 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2615 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002616 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002617 }
2618 drawnPts = [];
2619 drawnLines = [];
2620 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002621 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002622 drawnCubics = [];
2623 focusXmin = focusYmin = Infinity;
2624 focusXmax = focusYmax = -Infinity;
2625 var pathIndex = 0;
2626 var opLetter = 'S';
2627 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2628 var recType = test[tIndex];
2629 var records = test[tIndex + 2];
2630 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2631 var fragType = records[recordIndex];
2632 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2633 console.log("unknown in range frag type: " + fragType);
2634 throw "stop execution";
2635 }
2636 var frags = records[recordIndex + 1];
2637 focus_enabled = false;
2638 switch (recType) {
2639 case REC_TYPE_COMPUTED:
2640 if (draw_computed == 0) {
2641 continue;
2642 }
2643 ctx.lineWidth = 1;
2644 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2645 ctx.fillStyle = "blue";
2646 var drawThis = false;
2647 switch (fragType) {
2648 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002649 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2650 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002651 drawQuad(frags[0], frags[1], frags[2], frags[3],
2652 frags[4], frags[5]);
2653 drawThis = true;
2654 }
2655 break;
caryclark1049f122015-04-20 08:31:59 -07002656 case PATH_CONIC:
2657 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2658 && (draw_computed & 7) == pathIndex)) {
2659 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2660 frags[4], frags[5], frags[6]);
2661 drawThis = true;
2662 }
2663 break;
caryclarkdac1d172014-06-17 05:15:38 -07002664 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002665 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2666 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002667 drawCubic(frags[0], frags[1], frags[2], frags[3],
2668 frags[4], frags[5], frags[6], frags[7]);
2669 drawThis = true;
2670 }
2671 ++pathIndex;
2672 break;
2673 case COMPUTED_SET_1:
2674 pathIndex = 0;
2675 break;
2676 case COMPUTED_SET_2:
2677 pathIndex = 1;
2678 break;
2679 default:
2680 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2681 throw "stop execution";
2682 }
2683 if (!drawThis || collect_bounds) {
2684 break;
2685 }
2686 drawCurveSpecials(test, frags, fragType);
2687 break;
caryclark26ad22a2015-10-16 09:03:38 -07002688 case REC_TYPE_ALIGNED:
2689 if (draw_path < 4) {
2690 continue;
2691 }
caryclarkdac1d172014-06-17 05:15:38 -07002692 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002693 case REC_TYPE_PATH2:
caryclark26ad22a2015-10-16 09:03:38 -07002694 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
2695 continue;
2696 }
caryclarkdac1d172014-06-17 05:15:38 -07002697 if (!draw_path) {
2698 continue;
2699 }
2700 var firstPath = tIndex < secondPath;
2701 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2702 continue;
2703 }
2704 ctx.lineWidth = 1;
2705 ctx.strokeStyle = firstPath ? "black" : "red";
2706 ctx.fillStyle = "blue";
caryclark55888e42016-07-18 10:01:36 -07002707 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002708 switch (fragType) {
2709 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002710 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2711 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002712 break;
2713 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002714 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2715 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2716 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002717 break;
caryclark1049f122015-04-20 08:31:59 -07002718 case PATH_CONIC:
2719 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
2720 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
2721 frags2[4], frags2[5], frags2[6]);
2722 break;
caryclarkdac1d172014-06-17 05:15:38 -07002723 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07002724 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
2725 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
2726 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07002727 break;
2728 default:
caryclark26ad22a2015-10-16 09:03:38 -07002729 console.log("unknown " + recType + " frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002730 throw "stop execution";
2731 }
2732 if (collect_bounds) {
2733 break;
2734 }
caryclark54359292015-03-26 07:52:43 -07002735 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002736 break;
2737 case REC_TYPE_OP:
2738 switch (fragType) {
2739 case OP_INTERSECT: opLetter = 'I'; break;
2740 case OP_DIFFERENCE: opLetter = 'D'; break;
2741 case OP_UNION: opLetter = 'U'; break;
2742 case OP_XOR: opLetter = 'X'; break;
2743 default:
2744 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2745 throw "stop execution";
2746 }
2747 break;
2748 case REC_TYPE_ACTIVE:
2749 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
2750 continue;
2751 }
2752 var x1 = frags[SPAN_X1];
2753 var y1 = frags[SPAN_Y1];
2754 var x2 = frags[SPAN_X2];
2755 var y2 = frags[SPAN_Y2];
caryclark55888e42016-07-18 10:01:36 -07002756 var x3, y3, x3, y4, w;
caryclarkdac1d172014-06-17 05:15:38 -07002757 ctx.lineWidth = 3;
2758 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2759 focus_enabled = true;
2760 switch (fragType) {
2761 case ACTIVE_LINE_SPAN:
caryclark55888e42016-07-18 10:01:36 -07002762 drawLine(x1, y1, x2, y2);
caryclarkdac1d172014-06-17 05:15:38 -07002763 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07002764 drawLineID(frags[0], x1, y1, x2, y2);
2765 }
2766 if (pt_labels) {
2767 var curve = [x1, y1, x2, y2];
2768 ctx.fillStyle = "blue";
2769 drawPoints(curve, PATH_LINE, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07002770 }
2771 break;
2772 case ACTIVE_QUAD_SPAN:
2773 x3 = frags[SPAN_X3];
2774 y3 = frags[SPAN_Y3];
caryclark55888e42016-07-18 10:01:36 -07002775 drawQuad(x1, y1, x2, y2, x3, y3);
caryclarkdac1d172014-06-17 05:15:38 -07002776 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07002777 drawQuadID(frags[0], x1, y1, x2, y2, x3, y3);
2778 }
2779 if (pt_labels) {
2780 var curve = [x1, y1, x2, y2, x3, y3];
2781 ctx.fillStyle = "blue";
2782 drawPoints(curve, PATH_QUAD, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07002783 }
2784 break;
caryclark1049f122015-04-20 08:31:59 -07002785 case ACTIVE_CONIC_SPAN:
2786 x3 = frags[SPAN_X3];
2787 y3 = frags[SPAN_Y3];
caryclark1049f122015-04-20 08:31:59 -07002788 w = frags[SPAN_K_W];
caryclark55888e42016-07-18 10:01:36 -07002789 drawConicWithQuads(x1, y1, x2, y2, x3, y3, w);
caryclark1049f122015-04-20 08:31:59 -07002790 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07002791 drawConicID(frags[0], x1, y1, x2, y2, x3, y3, w);
2792 }
2793 if (pt_labels) {
2794 var curve = [x1, y1, x2, y2, x3, y3, w];
2795 ctx.fillStyle = "blue";
2796 drawPoints(curve, PATH_CONIC, pt_labels == 2);
caryclark1049f122015-04-20 08:31:59 -07002797 }
2798 break;
caryclarkdac1d172014-06-17 05:15:38 -07002799 case ACTIVE_CUBIC_SPAN:
2800 x3 = frags[SPAN_X3];
2801 y3 = frags[SPAN_Y3];
2802 x4 = frags[SPAN_X4];
2803 y4 = frags[SPAN_Y4];
caryclark55888e42016-07-18 10:01:36 -07002804 drawCubic(x1, y1, x2, y2, x3, y3, x4, y4);
caryclarkdac1d172014-06-17 05:15:38 -07002805 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07002806 drawCubicID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4);
2807 }
2808 if (pt_labels) {
2809 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2810 ctx.fillStyle = "blue";
2811 drawPoints(curve, PATH_CUBIC, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07002812 }
2813 break;
2814 default:
2815 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2816 throw "stop execution";
2817 }
2818 break;
2819 case REC_TYPE_ACTIVE_OP:
2820 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2821 continue;
2822 }
2823 focus_enabled = true;
2824 ctx.lineWidth = 3;
2825 var activeSpan = frags[7] == "1";
2826 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
2827 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2828 drawCurve(curve);
2829 if (draw_op > 1) {
2830 drawArc(curve, false, frags[3], frags[4]);
2831 drawArc(curve, true, frags[5], frags[6]);
2832 }
2833 break;
2834 case REC_TYPE_ADD:
2835 if (!draw_add) {
2836 continue;
2837 }
2838 ctx.lineWidth = 3;
2839 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
2840 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
2841 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
2842 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
2843 : "rgba(127,0,127, 0.3)";
2844 focus_enabled = true;
2845 switch (fragType) {
2846 case ADD_MOVETO:
2847 break;
2848 case ADD_LINETO:
2849 if (step_limit == 0 || tIndex >= lastAdd) {
2850 drawLine(frags[0], frags[1], frags[2], frags[3]);
2851 }
2852 break;
2853 case ADD_QUADTO:
2854 if (step_limit == 0 || tIndex >= lastAdd) {
2855 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
2856 }
2857 break;
caryclark1049f122015-04-20 08:31:59 -07002858 case ADD_CONICTO:
2859 if (step_limit == 0 || tIndex >= lastAdd) {
2860 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2861 frags[4], frags[5], frags[6]);
2862 }
2863 break;
caryclarkdac1d172014-06-17 05:15:38 -07002864 case ADD_CUBICTO:
2865 if (step_limit == 0 || tIndex >= lastAdd) {
2866 drawCubic(frags[0], frags[1], frags[2], frags[3],
2867 frags[4], frags[5], frags[6], frags[7]);
2868 }
2869 break;
2870 case ADD_CLOSE:
2871 ++closeCount;
2872 break;
2873 case ADD_FILL:
2874 break;
2875 default:
2876 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2877 throw "stop execution";
2878 }
2879 break;
2880 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07002881 angleBetween = frags[18] == "T";
2882 afterIndex = 0;
2883 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07002884 continue;
2885 }
2886 focus_enabled = true;
2887 ctx.lineWidth = 3;
2888 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07002889 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
2890 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
2891 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07002892 drawCurve(leftCurve);
2893 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07002894 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07002895 drawCurve(midCurve);
2896 if (draw_angle > 1) {
2897 drawOrder(leftCurve, 'L');
2898 drawOrder(rightCurve, 'R');
2899 }
2900 break;
caryclark54359292015-03-26 07:52:43 -07002901 case REC_TYPE_AFTERPART:
2902 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
2903 continue;
2904 }
2905 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
2906 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
2907 : "rgba(0,0,255, 1.0)";
2908 switch (fragType) {
2909 case PATH_LINE:
2910 drawLine(frags[0], frags[1], frags[2], frags[3]);
2911 break;
2912 case PATH_QUAD:
2913 drawQuad(frags[0], frags[1], frags[2], frags[3],
2914 frags[4], frags[5]);
2915 break;
caryclark1049f122015-04-20 08:31:59 -07002916 case PATH_CONIC:
2917 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2918 frags[4], frags[5], frags[6]);
2919 break;
caryclark54359292015-03-26 07:52:43 -07002920 case PATH_CUBIC:
2921 drawCubic(frags[0], frags[1], frags[2], frags[3],
caryclark1049f122015-04-20 08:31:59 -07002922 frags[4], frags[5], frags[6], frags[7]);
caryclark54359292015-03-26 07:52:43 -07002923 break;
2924 default:
2925 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
2926 throw "stop execution";
2927 }
2928 ++afterIndex;
2929 break;
caryclark624637c2015-05-11 07:21:27 -07002930 case REC_TYPE_COINCIDENCE:
2931 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
2932 continue;
2933 }
2934 focus_enabled = true;
2935 ctx.lineWidth = 3;
2936 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
2937 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2938 drawCurve(curve);
2939 break;
caryclarkdac1d172014-06-17 05:15:38 -07002940 case REC_TYPE_SECT:
2941 if (!draw_intersection) {
2942 continue;
2943 }
2944 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
2945 continue;
2946 }
2947 // draw_intersection == 1 : show all
2948 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
2949 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
2950 ctx.lineWidth = 1;
2951 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2952 ctx.fillStyle = "blue";
2953 focus_enabled = true;
2954 var f = [];
2955 var c1s;
2956 var c1l;
2957 var c2s;
2958 var c2l;
2959 switch (fragType) {
2960 case INTERSECT_LINE:
2961 f.push(5, 6, 0, 7);
2962 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
2963 break;
2964 case INTERSECT_LINE_2:
2965 f.push(5, 6, 0, 10);
2966 f.push(8, 9, 7, 15);
2967 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
2968 break;
2969 case INTERSECT_LINE_NO:
2970 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
2971 break;
2972 case INTERSECT_QUAD_LINE:
2973 f.push(7, 8, 0, 9);
2974 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
2975 break;
2976 case INTERSECT_QUAD_LINE_2:
2977 f.push(7, 8, 0, 12);
2978 f.push(10, 11, 9, 17);
2979 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
2980 break;
2981 case INTERSECT_QUAD_LINE_NO:
2982 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
2983 break;
2984 case INTERSECT_QUAD:
2985 f.push(7, 8, 0, 9);
2986 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
2987 break;
2988 case INTERSECT_QUAD_2:
2989 f.push(7, 8, 0, 12);
2990 f.push(10, 11, 9, 19);
2991 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
2992 break;
2993 case INTERSECT_QUAD_NO:
2994 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
2995 break;
caryclark1049f122015-04-20 08:31:59 -07002996 case INTERSECT_CONIC_LINE:
2997 f.push(8, 9, 0, 10);
2998 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
2999 break;
3000 case INTERSECT_CONIC_LINE_2:
3001 f.push(8, 9, 0, 12);
3002 f.push(11, 12, 10, 18);
3003 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
3004 break;
3005 case INTERSECT_CONIC_LINE_NO:
3006 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
3007 break;
caryclark55888e42016-07-18 10:01:36 -07003008 case INTERSECT_CONIC_QUAD:
3009 f.push(8, 9, 0, 10);
3010 c1s = 1; c1l = 7; c2s = 11; c2l = 6;
3011 break;
3012 case INTERSECT_CONIC_QUAD_2:
3013 f.push(8, 9, 0, 12);
3014 f.push(11, 12, 10, 18);
3015 c1s = 1; c1l = 7; c2s = 14; c2l = 6;
3016 break;
3017 case INTERSECT_CONIC_QUAD_NO:
3018 c1s = 0; c1l = 7; c2s = 7; c2l = 6;
3019 break;
caryclark1049f122015-04-20 08:31:59 -07003020 case INTERSECT_CONIC:
3021 f.push(8, 9, 0, 10);
3022 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
3023 break;
3024 case INTERSECT_CONIC_2:
3025 f.push(8, 9, 0, 13);
3026 f.push(11, 12, 10, 21);
3027 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
3028 break;
3029 case INTERSECT_CONIC_NO:
3030 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
3031 break;
caryclarkdac1d172014-06-17 05:15:38 -07003032 case INTERSECT_SELF_CUBIC:
3033 f.push(9, 10, 0, 11);
3034 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3035 break;
3036 case INTERSECT_SELF_CUBIC_NO:
3037 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3038 break;
3039 case INTERSECT_CUBIC_LINE:
3040 f.push(9, 10, 0, 11);
3041 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3042 break;
3043 case INTERSECT_CUBIC_LINE_2:
3044 f.push(9, 10, 0, 14);
3045 f.push(12, 13, 11, 19);
3046 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3047 break;
3048 case INTERSECT_CUBIC_LINE_3:
3049 f.push(9, 10, 0, 17);
3050 f.push(12, 13, 11, 22);
3051 f.push(15, 16, 14, 23);
3052 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3053 break;
3054 case INTERSECT_CUBIC_QUAD_NO:
3055 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3056 break;
3057 case INTERSECT_CUBIC_QUAD:
3058 f.push(9, 10, 0, 11);
3059 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3060 break;
3061 case INTERSECT_CUBIC_QUAD_2:
3062 f.push(9, 10, 0, 14);
3063 f.push(12, 13, 11, 21);
3064 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3065 break;
3066 case INTERSECT_CUBIC_QUAD_3:
3067 f.push(9, 10, 0, 17);
3068 f.push(12, 13, 11, 24);
3069 f.push(15, 16, 14, 25);
3070 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3071 break;
3072 case INTERSECT_CUBIC_QUAD_4:
3073 f.push(9, 10, 0, 20);
3074 f.push(12, 13, 11, 27);
3075 f.push(15, 16, 14, 28);
3076 f.push(18, 19, 17, 29);
3077 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3078 break;
3079 case INTERSECT_CUBIC_LINE_NO:
3080 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3081 break;
3082 case INTERSECT_CUBIC:
3083 f.push(9, 10, 0, 11);
3084 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3085 break;
3086 case INTERSECT_CUBIC_2:
3087 f.push(9, 10, 0, 14);
3088 f.push(12, 13, 11, 23);
3089 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3090 break;
3091 case INTERSECT_CUBIC_3:
3092 f.push(9, 10, 0, 17);
3093 f.push(12, 13, 11, 26);
3094 f.push(15, 16, 14, 27);
3095 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3096 break;
3097 case INTERSECT_CUBIC_4:
3098 f.push(9, 10, 0, 20);
3099 f.push(12, 13, 11, 29);
3100 f.push(15, 16, 14, 30);
3101 f.push(18, 19, 17, 31);
3102 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3103 break;
3104 case INTERSECT_CUBIC_NO:
3105 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3106 break;
3107 default:
3108 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3109 throw "stop execution";
3110 }
3111 if (draw_intersection != 1) {
3112 var id = -1;
3113 var curve;
3114 switch (c1l) {
caryclark55888e42016-07-18 10:01:36 -07003115 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003116 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3117 if (draw_id) {
3118 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3119 id = idByCurve(test, curve, PATH_LINE);
3120 }
3121 break;
3122 case 6:
3123 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3124 frags[c1s + 4], frags[c1s + 5]);
3125 if (draw_id) {
3126 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3127 frags[c1s + 4], frags[c1s + 5]];
3128 id = idByCurve(test, curve, PATH_QUAD);
3129 }
3130 break;
caryclark1049f122015-04-20 08:31:59 -07003131 case 7:
3132 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3133 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3134 if (draw_id) {
3135 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3136 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3137 id = idByCurve(test, curve, PATH_CONIC);
3138 }
3139 break;
caryclarkdac1d172014-06-17 05:15:38 -07003140 case 8:
3141 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3142 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3143 if (draw_id) {
3144 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3145 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3146 id = idByCurve(test, curve, PATH_CUBIC);
3147 }
3148 break;
3149 }
3150 if (id >= 0) {
3151 drawID(curve, id);
3152 }
3153 id = -1;
3154 switch (c2l) {
3155 case 0:
3156 break;
caryclark55888e42016-07-18 10:01:36 -07003157 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003158 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3159 if (draw_id) {
3160 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3161 id = idByCurve(test, curve, PATH_LINE);
3162 }
3163 break;
3164 case 6:
3165 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3166 frags[c2s + 4], frags[c2s + 5]);
3167 if (draw_id) {
3168 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3169 frags[c2s + 4], frags[c2s + 5]];
3170 id = idByCurve(test, curve, PATH_QUAD);
3171 }
3172 break;
caryclark1049f122015-04-20 08:31:59 -07003173 case 7:
3174 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3175 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3176 if (draw_id) {
3177 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3178 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3179 id = idByCurve(test, curve, PATH_CONIC);
3180 }
3181 break;
caryclarkdac1d172014-06-17 05:15:38 -07003182 case 8:
3183 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3184 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3185 if (draw_id) {
3186 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3187 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3188 id = idByCurve(test, curve, PATH_CUBIC);
3189 }
3190 break;
3191 }
3192 if (id >= 0) {
3193 drawID(curve, id);
3194 }
3195 }
3196 if (collect_bounds) {
3197 break;
3198 }
caryclark54359292015-03-26 07:52:43 -07003199 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3200 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003201 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3202 }
3203 }
3204 if (!draw_intersectT) {
3205 break;
3206 }
3207 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003208 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3209 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003210 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3211 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3212 }
3213 }
3214 break;
3215 case REC_TYPE_SORT:
3216 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3217 continue;
3218 }
3219 ctx.lineWidth = 3;
3220 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3221 focus_enabled = true;
3222 switch (fragType) {
3223 case SORT_UNARY:
3224 case SORT_BINARY:
3225 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3226 drawCurve(curve);
3227 break;
3228 default:
3229 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3230 throw "stop execution";
3231 }
3232 break;
caryclark03b03ca2015-04-23 09:13:37 -07003233 case REC_TYPE_TOP:
3234 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3235 continue;
3236 }
3237 ctx.lineWidth = 3;
3238 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3239 focus_enabled = true;
3240 {
3241 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3242 drawCurve(curve);
3243 var type = PATH_LINE + (curve.length / 2 - 2);
3244 var mid = pointAtT(curve, type, 0.5);
3245 var d = dxy_at_t(curve, type, 0.5);
3246 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3247 }
3248 break;
caryclarkdac1d172014-06-17 05:15:38 -07003249 case REC_TYPE_MARK:
3250 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3251 continue;
3252 }
3253 ctx.lineWidth = 3;
3254 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3255 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3256 focus_enabled = true;
3257 switch (fragType) {
3258 case MARK_LINE:
3259 case MARK_DONE_LINE:
3260 case MARK_UNSORTABLE_LINE:
3261 case MARK_SIMPLE_LINE:
3262 case MARK_SIMPLE_DONE_LINE:
3263 case MARK_DONE_UNARY_LINE:
3264 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3265 frags[5], frags[9]);
3266 if (draw_id) {
3267 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3268 frags[5], frags[9]);
3269 }
3270 break;
3271 case MARK_QUAD:
3272 case MARK_DONE_QUAD:
3273 case MARK_UNSORTABLE_QUAD:
3274 case MARK_SIMPLE_QUAD:
3275 case MARK_SIMPLE_DONE_QUAD:
3276 case MARK_DONE_UNARY_QUAD:
3277 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3278 frags[5], frags[6], frags[7], frags[11]);
3279 if (draw_id) {
3280 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3281 frags[5], frags[6], frags[7], frags[11]);
3282 }
3283 break;
3284 case MARK_CUBIC:
3285 case MARK_DONE_CUBIC:
3286 case MARK_UNSORTABLE_CUBIC:
3287 case MARK_SIMPLE_CUBIC:
3288 case MARK_SIMPLE_DONE_CUBIC:
3289 case MARK_DONE_UNARY_CUBIC:
3290 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3291 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3292 if (draw_id) {
3293 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3294 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3295 }
3296 break;
3297 case MARK_ANGLE_LAST:
3298 // FIXME: ignored for now
3299 break;
3300 default:
3301 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3302 throw "stop execution";
3303 }
3304 break;
3305 default:
3306 continue;
3307 }
3308 }
3309 switch (recType) {
3310 case REC_TYPE_SORT:
3311 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3312 break;
3313 }
3314 var angles = []; // use tangent lines to describe arcs
3315 var windFrom = [];
3316 var windTo = [];
3317 var opp = [];
3318 var minXY = Number.MAX_VALUE;
3319 var partial;
3320 focus_enabled = true;
3321 var someUnsortable = false;
3322 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3323 var fragType = records[recordIndex];
3324 var frags = records[recordIndex + 1];
3325 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3326 (fragType == SORT_BINARY && frags[16]);
3327 someUnsortable |= unsortable;
3328 switch (fragType) {
3329 case SORT_UNARY:
3330 case SORT_BINARY:
3331 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3332 break;
3333 default:
3334 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3335 throw "stop execution";
3336 }
3337 var dx = boundsWidth(partial);
3338 var dy = boundsHeight(partial);
3339 minXY = Math.min(minXY, dx * dx + dy * dy);
3340 if (collect_bounds) {
3341 continue;
3342 }
3343 angles.push(tangent(partial));
3344 var from = frags[12];
3345 var to = frags[12];
3346 var sgn = frags[10];
3347 if (sgn < 0) {
3348 from -= frags[11];
3349 } else if (sgn > 0) {
3350 to -= frags[11];
3351 }
3352 windFrom.push(from + (unsortable ? "!" : ""));
3353 windTo.push(to + (unsortable ? "!" : ""));
3354 opp.push(fragType == SORT_BINARY);
3355 if (draw_sort == 1) {
3356 drawOrder(partial, frags[12]);
3357 } else {
3358 drawOrder(partial, (recordIndex / 2) + 1);
3359 }
3360 }
3361 var radius = Math.sqrt(minXY) / 2 * scale;
3362 radius = Math.min(50, radius);
3363 var scaledRadius = radius / scale;
3364 var centerX = partial[0];
3365 var centerY = partial[1];
3366 if (collect_bounds) {
3367 if (focus_enabled) {
3368 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3369 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3370 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3371 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3372 }
3373 break;
3374 }
3375 break;
3376 default:
3377 break;
3378 }
3379 }
3380 if (collect_bounds) {
3381 return;
3382 }
3383 if (draw_log && logStart >= 0) {
3384 ctx.font = "normal 10px Arial";
3385 ctx.textAlign = "left";
3386 ctx.beginPath();
3387 var top = screenHeight - 20 - (logRange + 2) * 10;
3388 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3389 ctx.fillStyle = "white";
3390 ctx.fill();
3391 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3392 if (logStart > 0) {
3393 ctx.fillText(lines[logStart - 1], 50, top + 8);
3394 }
3395 ctx.fillStyle = "black";
3396 for (var idx = 0; idx < logRange; ++idx) {
3397 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3398 }
3399 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3400 if (logStart + logRange < lines.length) {
3401 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3402 }
3403 }
3404 if (draw_legend) {
3405 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003406 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003407 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3408 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3409 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3410 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3411 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003412 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003413 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3414 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003415 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003416 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
caryclark55888e42016-07-18 10:01:36 -07003417 drawBox(pos++, "black", "white",
caryclark26ad22a2015-10-16 09:03:38 -07003418 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
caryclarkdac1d172014-06-17 05:15:38 -07003419 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3420 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3421 draw_computed != 0, computedKey);
3422 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3423 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3424 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3425 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3426 if (curve_t) {
3427 drawCurveTControl();
3428 }
3429 ctx.font = "normal 20px Arial";
3430 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3431 ctx.textAlign = "right";
3432 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3433 }
3434 if (draw_hints) {
3435 ctx.font = "normal 10px Arial";
3436 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3437 ctx.textAlign = "right";
3438 var y = 4;
3439 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3440 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3441 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3442 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003443 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3444 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3445 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3446 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3447 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3448 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3449 }
3450}
3451
3452function drawBox(y, backC, foreC, str, enable, label) {
3453 ctx.beginPath();
3454 ctx.fillStyle = backC;
3455 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3456 ctx.fill();
3457 ctx.font = "normal 16px Arial";
3458 ctx.fillStyle = foreC;
3459 ctx.textAlign = "center";
3460 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3461 if (!enable) {
3462 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3463 ctx.fill();
3464 }
3465 if (label != '') {
3466 ctx.font = "normal 9px Arial";
3467 ctx.fillStyle = "black";
3468 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3469 }
3470}
3471
3472function drawCurveTControl() {
3473 ctx.lineWidth = 2;
3474 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3475 ctx.beginPath();
3476 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3477 ctx.stroke();
3478 var ty = 40 + curveT * (screenHeight - 80);
3479 ctx.beginPath();
3480 ctx.moveTo(screenWidth - 80, ty);
3481 ctx.lineTo(screenWidth - 85, ty - 5);
3482 ctx.lineTo(screenWidth - 85, ty + 5);
3483 ctx.lineTo(screenWidth - 80, ty);
3484 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3485 ctx.fill();
3486 var num = curveT.toFixed(decimal_places);
3487 ctx.font = "normal 10px Arial";
3488 ctx.textAlign = "left";
3489 ctx.fillText(num, screenWidth - 78, ty);
3490}
3491
3492function ptInTControl() {
3493 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07003494 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07003495 var left = tgt.offsetLeft;
3496 var top = tgt.offsetTop;
3497 var x = (e.clientX - left);
3498 var y = (e.clientY - top);
3499 if (x < screenWidth - 80 || x > screenWidth - 50) {
3500 return false;
3501 }
3502 if (y < 40 || y > screenHeight - 80) {
3503 return false;
3504 }
3505 curveT = (y - 40) / (screenHeight - 120);
3506 if (curveT < 0 || curveT > 1) {
3507 throw "stop execution";
3508 }
3509 return true;
3510}
3511
3512function drawTop() {
3513 if (tests[testIndex] == null) {
3514 var str = testDivs[testIndex].textContent;
3515 parse_all(str);
3516 var title = testDivs[testIndex].id.toString();
3517 testTitles[testIndex] = title;
3518 }
3519 init(tests[testIndex]);
3520 redraw();
3521}
3522
3523function redraw() {
3524 if (focus_on_selection) {
3525 collect_bounds = true;
3526 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3527 collect_bounds = false;
3528 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3529 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3530 }
3531 }
3532 ctx.beginPath();
3533 ctx.fillStyle = "white";
3534 ctx.rect(0, 0, screenWidth, screenHeight);
3535 ctx.fill();
3536 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3537}
3538
3539function dumpCurvePartial(test, id, t0, t1) {
3540 var curve = curveByID(test, id);
3541 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3542 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3543 + " t0=" + t0 + " t1=" + t1
3544 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3545}
3546
3547function dumpAngleTest(test, id, t0, t1) {
3548 var curve = curveByID(test, id);
caryclark55888e42016-07-18 10:01:36 -07003549 console.log(" { {" + curveToString(curve) + "}, "
caryclarkdac1d172014-06-17 05:15:38 -07003550 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3551}
3552
3553function dumpLogToConsole() {
3554 if (logStart < 0) {
3555 return;
3556 }
3557 var test = tests[testIndex];
3558 var recType = REC_TYPE_UNKNOWN;
3559 var records;
3560 for (var index = 0; index < test.length; index += 3) {
3561 var lastLineNo = test[index + 1];
3562 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3563 recType = test[index];
3564 records = test[index + 2];
3565 break;
3566 }
3567 }
3568 if (recType == REC_TYPE_UNKNOWN) {
3569 return;
3570 }
3571 var lines = testLines[testIndex];
3572 for (var idx = 0; idx < logRange; ++idx) {
3573 var line = lines[logStart + idx];
3574 console.log(line);
3575 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3576 var fragType = records[recordIndex];
3577 var frags = records[recordIndex + 1];
3578 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003579 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3580 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3581 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3582 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3583 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3584 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3585 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3586 console.log("}; //");
3587 }
3588 }
3589 }
3590}
3591
3592var activeKey = 'a';
3593var pathKey = 'b';
3594var pathBackKey = 'B';
3595var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07003596var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003597var addKey = 'd';
3598var deriviativesKey = 'f';
3599var angleKey = 'g';
3600var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003601var intersectionKey = 'i';
3602var intersectionBackKey = 'I';
3603var sequenceKey = 'j';
3604var midpointKey = 'k';
3605var logKey = 'l';
3606var logToConsoleKey = 'L';
3607var markKey = 'm';
3608var sortKey = 'o';
3609var opKey = 'p';
3610var opBackKey = 'P';
3611var computedKey = 'q';
3612var computedBackKey = 'Q';
3613var stepKey = 's';
3614var stepBackKey = 'S';
3615var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003616var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003617var curveTKey = 'u';
3618var controlLinesBackKey = 'V';
3619var controlLinesKey = 'v';
3620var ptsKey = 'x';
3621var xyKey = 'y';
3622var logCurvesKey = 'z';
3623var focusKey = '`';
3624var idKey = '.';
3625var retinaKey = '\\';
3626
3627function doKeyPress(evt) {
3628 var char = String.fromCharCode(evt.charCode);
3629 var focusWasOn = false;
3630 switch (char) {
3631 case '0':
3632 case '1':
3633 case '2':
3634 case '3':
3635 case '4':
3636 case '5':
3637 case '6':
3638 case '7':
3639 case '8':
3640 case '9':
3641 decimal_places = char - '0';
3642 redraw();
3643 break;
3644 case activeKey:
3645 draw_active ^= true;
caryclark55888e42016-07-18 10:01:36 -07003646 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003647 break;
3648 case addKey:
3649 draw_add ^= true;
caryclark55888e42016-07-18 10:01:36 -07003650 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003651 break;
3652 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003653 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003654 redraw();
3655 break;
3656 case angleBackKey:
3657 draw_angle = (draw_angle + 2) % 3;
3658 redraw();
3659 break;
3660 case centerKey:
3661 setScale(xmin, xmax, ymin, ymax);
caryclark55888e42016-07-18 10:01:36 -07003662 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003663 break;
caryclark624637c2015-05-11 07:21:27 -07003664 case coincidenceKey:
3665 draw_coincidence ^= true;
3666 redraw();
3667 break;
caryclarkdac1d172014-06-17 05:15:38 -07003668 case controlLinesBackKey:
3669 control_lines = (control_lines + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07003670 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003671 break;
3672 case controlLinesKey:
3673 control_lines = (control_lines + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07003674 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003675 break;
3676 case computedBackKey:
3677 draw_computed = (draw_computed + 5) % 6;
caryclark55888e42016-07-18 10:01:36 -07003678 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003679 break;
3680 case computedKey:
3681 draw_computed = (draw_computed + 1) % 6;
caryclark55888e42016-07-18 10:01:36 -07003682 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003683 break;
3684 case curveTKey:
3685 curve_t ^= true;
3686 if (curve_t) {
3687 draw_legend = true;
3688 }
3689 redraw();
3690 break;
3691 case deriviativesKey:
3692 draw_deriviatives = (draw_deriviatives + 1) % 3;
3693 redraw();
3694 break;
3695 case focusKey:
3696 focus_on_selection ^= true;
3697 setScale(xmin, xmax, ymin, ymax);
3698 redraw();
3699 break;
caryclarkdac1d172014-06-17 05:15:38 -07003700 case idKey:
3701 draw_id ^= true;
3702 redraw();
3703 break;
3704 case intersectionBackKey:
3705 draw_intersection = (draw_intersection + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07003706 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003707 break;
3708 case intersectionKey:
3709 draw_intersection = (draw_intersection + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07003710 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003711 break;
3712 case intersectTKey:
3713 draw_intersectT ^= true;
3714 redraw();
3715 break;
3716 case logCurvesKey:
3717 logCurves(tests[testIndex]);
3718 break;
3719 case logKey:
3720 draw_log ^= true;
3721 redraw();
3722 break;
3723 case logToConsoleKey:
3724 if (draw_log) {
3725 dumpLogToConsole();
3726 }
3727 break;
3728 case markKey:
3729 draw_mark ^= true;
3730 redraw();
3731 break;
3732 case midpointKey:
3733 draw_midpoint ^= true;
3734 redraw();
3735 break;
3736 case opKey:
3737 draw_op = (draw_op + 1) % 3;
3738 redraw();
3739 break;
3740 case opBackKey:
3741 draw_op = (draw_op + 2) % 3;
3742 redraw();
3743 break;
3744 case pathKey:
caryclark26ad22a2015-10-16 09:03:38 -07003745 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07003746 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003747 break;
3748 case pathBackKey:
caryclark26ad22a2015-10-16 09:03:38 -07003749 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07003750 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003751 break;
3752 case ptsKey:
3753 pt_labels = (pt_labels + 1) % 3;
3754 redraw();
3755 break;
3756 case retinaKey:
3757 retina_scale ^= true;
3758 drawTop();
3759 break;
3760 case sequenceKey:
3761 draw_sequence ^= true;
3762 redraw();
3763 break;
3764 case sortKey:
3765 draw_sort = (draw_sort + 1) % 3;
3766 drawTop();
3767 break;
3768 case stepKey:
3769 step_limit++;
3770 if (step_limit > stepMax) {
3771 step_limit = stepMax;
3772 }
3773 redraw();
3774 break;
3775 case stepBackKey:
3776 step_limit--;
3777 if (step_limit < 0) {
3778 step_limit = 0;
3779 }
3780 redraw();
3781 break;
caryclark03b03ca2015-04-23 09:13:37 -07003782 case topKey:
3783 draw_top ^= true;
3784 redraw();
3785 break;
caryclarkdac1d172014-06-17 05:15:38 -07003786 case xyKey:
3787 debug_xy = (debug_xy + 1) % 3;
3788 redraw();
3789 break;
3790 case '-':
3791 focusWasOn = focus_on_selection;
3792 if (focusWasOn) {
3793 focus_on_selection = false;
3794 scale /= 1.2;
3795 } else {
3796 scale /= 2;
3797 calcLeftTop();
3798 }
3799 redraw();
3800 focus_on_selection = focusWasOn;
3801 break;
3802 case '=':
3803 case '+':
3804 focusWasOn = focus_on_selection;
3805 if (focusWasOn) {
3806 focus_on_selection = false;
3807 scale *= 1.2;
3808 } else {
3809 scale *= 2;
3810 calcLeftTop();
3811 }
3812 redraw();
3813 focus_on_selection = focusWasOn;
3814 break;
3815 case '?':
3816 draw_hints ^= true;
3817 if (draw_hints && !draw_legend) {
3818 draw_legend = true;
3819 }
3820 redraw();
3821 break;
3822 case '/':
3823 draw_legend ^= true;
3824 redraw();
3825 break;
3826 }
3827}
3828
3829function doKeyDown(evt) {
3830 var char = evt.keyCode;
3831 var preventDefault = false;
3832 switch (char) {
3833 case 37: // left arrow
3834 if (evt.shiftKey) {
3835 testIndex -= 9;
3836 }
3837 if (--testIndex < 0)
3838 testIndex = tests.length - 1;
3839 drawTop();
3840 preventDefault = true;
3841 break;
3842 case 39: // right arrow
3843 if (evt.shiftKey) {
3844 testIndex += 9;
3845 }
3846 if (++testIndex >= tests.length)
3847 testIndex = 0;
3848 drawTop();
3849 preventDefault = true;
3850 break;
3851 }
3852 if (preventDefault) {
3853 evt.preventDefault();
3854 return false;
3855 }
3856 return true;
3857}
3858
3859(function() {
3860 var hidden = "hidden";
3861
3862 // Standards:
3863 if (hidden in document)
3864 document.addEventListener("visibilitychange", onchange);
3865 else if ((hidden = "mozHidden") in document)
3866 document.addEventListener("mozvisibilitychange", onchange);
3867 else if ((hidden = "webkitHidden") in document)
3868 document.addEventListener("webkitvisibilitychange", onchange);
3869 else if ((hidden = "msHidden") in document)
3870 document.addEventListener("msvisibilitychange", onchange);
3871 // IE 9 and lower:
3872 else if ('onfocusin' in document)
3873 document.onfocusin = document.onfocusout = onchange;
3874 // All others:
3875 else
caryclark55888e42016-07-18 10:01:36 -07003876 window.onpageshow = window.onpagehide
caryclarkdac1d172014-06-17 05:15:38 -07003877 = window.onfocus = window.onblur = onchange;
3878
3879 function onchange (evt) {
3880 var v = 'visible', h = 'hidden',
caryclark55888e42016-07-18 10:01:36 -07003881 evtMap = {
3882 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
caryclarkdac1d172014-06-17 05:15:38 -07003883 };
3884
3885 evt = evt || window.event;
3886 if (evt.type in evtMap)
3887 document.body.className = evtMap[evt.type];
caryclark55888e42016-07-18 10:01:36 -07003888 else
caryclarkdac1d172014-06-17 05:15:38 -07003889 document.body.className = this[hidden] ? "hidden" : "visible";
3890 }
3891})();
3892
3893function calcXY() {
3894 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07003895 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07003896 var left = tgt.offsetLeft;
3897 var top = tgt.offsetTop;
3898 mouseX = (e.clientX - left) / scale + srcLeft;
3899 mouseY = (e.clientY - top) / scale + srcTop;
3900}
3901
3902function calcLeftTop() {
3903 srcLeft = mouseX - screenWidth / 2 / scale;
3904 srcTop = mouseY - screenHeight / 2 / scale;
3905}
3906
3907var disableClick = false;
3908
3909function handleMouseClick() {
3910 if (disableClick) {
3911 return;
3912 }
3913 if (!curve_t || !ptInTControl()) {
3914 calcXY();
3915 calcLeftTop();
3916 }
3917 redraw();
3918// if (!curve_t || !ptInTControl()) {
3919// mouseX = screenWidth / 2 / scale + srcLeft;
3920// mouseY = screenHeight / 2 / scale + srcTop;
3921// }
3922}
3923
3924function handleMouseOver() {
3925 calcXY();
3926 if (debug_xy != 2) {
3927 return;
3928 }
3929 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
3930 ctx.beginPath();
3931 ctx.rect(300,100,num.length * 6,10);
3932 ctx.fillStyle="white";
3933 ctx.fill();
3934 ctx.font = "normal 10px Arial";
3935 ctx.fillStyle="black";
3936 ctx.textAlign = "left";
3937 ctx.fillText(num, 300, 108);
3938}
3939
3940function start() {
3941 for (var i = 0; i < testDivs.length; ++i) {
3942 tests[i] = null;
3943 }
3944 testIndex = 0;
3945 drawTop();
3946 window.addEventListener('keypress', doKeyPress, true);
3947 window.addEventListener('keydown', doKeyDown, true);
3948 window.onresize = function() {
3949 drawTop();
3950 }
3951 /*
3952 window.onpagehide = function() {
3953 disableClick = true;
3954 }
3955 */
3956 window.onpageshow = function () {
3957 disableClick = false;
3958 }
3959}
3960
3961</script>
3962</head>
3963
3964<body onLoad="start();">
3965<canvas id="canvas" width="750" height="500"
3966 onmousemove="handleMouseOver()"
3967 onclick="handleMouseClick()"
3968 ></canvas >
3969</body>
3970</html>