1 <html> 2 <head> 3 <div height="0" hidden="true"> 4 5 <div id="skpwww_argus_presse_fr_41"> 6 RunTestSet [skpwww_argus_presse_fr_41] 7 8 {{1000,343}, {165,343}}, 9 {{165,343}, {165,364.869873}}, 10 {{165,364.869873}, {1000,364.869873}}, 11 {{1000,364.869873}, {1000,343}}, 12 op intersect 13 {{165,343.000031}, {1000,343.000031}}, 14 {{1000,343.000031}, {1000,364.869904}}, 15 {{1000,364.869904}, {165,364.869904}}, 16 {{165,364.869904}, {165,343.000031}}, 17 debugShowLineIntersection wtTs[0]=0 {{165,343}, {165,364.869873}} {{165,343}} wnTs[0]=1 {{1000,343}, {165,343}} 18 debugShowLineIntersection wtTs[0]=1 {{1000,364.869873}, {1000,343}} {{1000,343}} wnTs[0]=0 {{1000,343}, {165,343}} 19 debugShowLineIntersection wtTs[0]=0 {{165,364.869873}, {1000,364.869873}} {{165,364.869873}} wnTs[0]=1 {{165,343}, {165,364.869873}} 20 debugShowLineIntersection wtTs[0]=0 {{1000,364.869873}, {1000,343}} {{1000,364.869873}} wnTs[0]=1 {{165,364.869873}, {1000,364.869873}} 21 debugShowLineIntersection wtTs[0]=0 {{165,343.000031}, {1000,343.000031}} {{165,343}} wtTs[1]=1 {{1000,343}} wnTs[0]=1 {{1000,343}, {165,343}} wnTs[1]=0 22 debugShowLineIntersection wtTs[0]=0 {{1000,343.000031}, {1000,364.869904}} {{1000,343.000031}} wnTs[0]=0 {{1000,343}, {165,343}} 23 debugShowLineIntersection wtTs[0]=1 {{165,364.869904}, {165,343.000031}} {{165,343.000031}} wnTs[0]=1 {{1000,343}, {165,343}} 24 debugShowLineIntersection wtTs[0]=0 {{165,343.000031}, {1000,343.000031}} {{165,343}} wnTs[0]=0 {{165,343}, {165,364.869873}} 25 debugShowLineIntersection wtTs[0]=1 {{1000,364.869904}, {165,364.869904}} {{165,364.869873}} wnTs[0]=1 {{165,343}, {165,364.869873}} 26 debugShowLineIntersection wtTs[0]=0 {{165,364.869904}, {165,343.000031}} {{165,364.869904}} wtTs[1]=1 {{165,343.000031}} wnTs[0]=1 {{165,343}, {165,364.869873}} wnTs[1]=1.39541634e-006 27 debugShowLineIntersection wtTs[0]=1 {{1000,343.000031}, {1000,364.869904}} {{1000,364.869904}} wnTs[0]=1 {{165,364.869873}, {1000,364.869873}} 28 debugShowLineIntersection wtTs[0]=0 {{1000,364.869904}, {165,364.869904}} {{1000,364.869873}} wtTs[1]=1 {{165,364.869873}} wnTs[0]=1 {{165,364.869873}, {1000,364.869873}} wnTs[1]=0 29 debugShowLineIntersection wtTs[0]=0 {{165,364.869904}, {165,343.000031}} {{165,364.869904}} wnTs[0]=0 {{165,364.869873}, {1000,364.869873}} 30 debugShowLineIntersection wtTs[0]=1 {{165,343.000031}, {1000,343.000031}} {{1000,343}} wnTs[0]=1 {{1000,364.869873}, {1000,343}} 31 debugShowLineIntersection wtTs[0]=0 {{1000,343.000031}, {1000,364.869904}} {{1000,343.000031}} wtTs[1]=1 {{1000,364.869904}} wnTs[0]=0.999999 {{1000,364.869873}, {1000,343}} wnTs[1]=0 32 debugShowLineIntersection wtTs[0]=0 {{1000,364.869904}, {165,364.869904}} {{1000,364.869873}} wnTs[0]=0 {{1000,364.869873}, {1000,343}} 33 debugShowLineIntersection wtTs[0]=0 {{1000,343.000031}, {1000,364.869904}} {{1000,343.000031}} wnTs[0]=1 {{165,343.000031}, {1000,343.000031}} 34 debugShowLineIntersection wtTs[0]=1 {{165,364.869904}, {165,343.000031}} {{165,343.000031}} wnTs[0]=0 {{165,343.000031}, {1000,343.000031}} 35 debugShowLineIntersection wtTs[0]=0 {{1000,364.869904}, {165,364.869904}} {{1000,364.869904}} wnTs[0]=1 {{1000,343.000031}, {1000,364.869904}} 36 debugShowLineIntersection wtTs[0]=0 {{165,364.869904}, {165,343.000031}} {{165,364.869904}} wnTs[0]=1 {{1000,364.869904}, {165,364.869904}} 37 SkOpSegment::debugShowTs - id=0 [o=3,5 t=0 1000,343.000031 w=1 o=0] [o=7,1 t=1 165,343 w=1 o=0] 38 SkOpSegment::debugShowTs o id=4 [o=7,1 t=0 165,343 w=1 o=0] [o=3,5 t=1 1000,343.000031 w=1 o=0] operand 39 SkOpSegment::debugShowTs + id=0 [o=3,5 t=0 1000,343.000031 w=1 o=0] [o=7,1 t=1 165,343 w=1 o=0] 40 SkOpSegment::debugShowTs o id=4 [o=7,1 t=0 165,343 w=1 o=0] [o=3,5 t=1 1000,343.000031 w=1 o=0] operand 41 SkOpSegment::debugShowTs - id=1 [o=4,0 t=0 165,343 w=1 o=0] [o=6,2 t=1 165,364.869873 w=1 o=0] 42 SkOpSegment::debugShowTs o id=7 [o=6,2 t=0 165,364.869904 w=1 o=0] [o=4,0 t=1 165,343.000031 w=1 o=0] operand 43 SkOpSegment::addTPair addTPair this=1 1.39541634e-006 other=7 1 44 SkOpSegment::addTPair addTPair this=7 0 other=1 1 45 SkOpSegment::debugShowTs + id=1 [o=4,0 t=0 165,343 w=1 o=0] [o=7 t=1.4e-006 165,343.000031 w=1 o=0] [o=7,6,2 t=1 165,364.869873 w=1 o=0] 46 SkOpSegment::debugShowTs o id=7 [o=1,6,2 t=0 165,364.869904 w=1 o=0] [o=1,4,0 t=1 165,343.000031 w=1 o=0] operand 47 SkOpSegment::debugShowTs - id=2 [o=1,7 t=0 165,364.869904 w=1 o=0] [o=5,3 t=1 1000,364.869873 w=1 o=0] 48 SkOpSegment::debugShowTs o id=6 [o=5,3 t=0 1000,364.869873 w=1 o=0] [o=1,7 t=1 165,364.869904 w=1 o=0] operand 49 SkOpSegment::debugShowTs + id=2 [o=1,7 t=0 165,364.869904 w=1 o=0] [o=5,3 t=1 1000,364.869873 w=1 o=0] 50 SkOpSegment::debugShowTs o id=6 [o=5,3 t=0 1000,364.869873 w=1 o=0] [o=1,7 t=1 165,364.869904 w=1 o=0] operand 51 SkOpSegment::debugShowTs - id=3 [o=6,2 t=0 1000,364.869873 w=1 o=0] [o=4,0 t=1 1000,343 w=1 o=0] 52 SkOpSegment::debugShowTs o id=5 [o=4,0 t=0 1000,343.000031 w=1 o=0] [o=6,2 t=1 1000,364.869904 w=1 o=0] operand 53 SkOpSegment::addTPair addTPair this=3 0 other=5 1 54 SkOpSegment::addTPair addTPair this=5 0 other=3 0.999998605 55 SkOpSegment::debugShowTs + id=3 [o=6,2,5 t=0 1000,364.869904 w=1 o=0] [o=5 t=1 1000,343.000031 w=1 o=0] [o=4,0 t=1 1000,343 w=1 o=0] 56 SkOpSegment::debugShowTs o id=5 [o=3,4,0 t=0 1000,343.000031 w=1 o=0] [o=3,6,2 t=1 1000,364.869904 w=1 o=0] operand 57 SkOpContour::calcCoincidentWinding count=4 58 SkOpSegment::debugShowTs p id=0 [o=3,5 t=0 1000,343.000031 w=1 o=-1] [o=7,1 t=1 165,343 w=1 o=0] 59 SkOpSegment::debugShowTs o id=4 [o=7,1 t=0 165,343 w=0 o=0] [o=3,5 t=1 1000,343.000031 w=1 o=0] operand done 60 SkOpSegment::debugShowTs p id=1 [o=4,0 t=0 165,343 w=1 o=0] [o=7 t=1.4e-006 165,343.000031 w=1 o=-1] [o=7,6,2 t=1 165,364.869873 w=1 o=0] 61 SkOpSegment::debugShowTs o id=7 [o=1,6,2 t=0 165,364.869904 w=0 o=0] [o=1,4,0 t=1 165,343.000031 w=1 o=0] operand done 62 SkOpSegment::debugShowTs p id=2 [o=1,7 t=0 165,364.869904 w=1 o=-1] [o=5,3 t=1 1000,364.869873 w=1 o=0] 63 SkOpSegment::debugShowTs o id=6 [o=5,3 t=0 1000,364.869873 w=0 o=0] [o=1,7 t=1 165,364.869904 w=1 o=0] operand done 64 SkOpSegment::debugShowTs p id=3 [o=6,2,5 t=0 1000,364.869904 w=1 o=-1] [o=5 t=1 1000,343.000031 w=1 o=0] [o=4,0 t=1 1000,343 w=1 o=0] 65 SkOpSegment::debugShowTs o id=5 [o=3,4,0 t=0 1000,343.000031 w=0 o=0] [o=3,6,2 t=1 1000,364.869904 w=1 o=0] operand done 66 SkOpSegment::addTPair addTPair this=0 0 other=4 1 67 SkOpSegment::addTPair addTPair this=0 1 other=4 0 68 SkOpSegment::addTPair addTPair this=6 1 other=2 0 69 SkOpSegment::addTPair addTPair duplicate this=2 0 other=6 1 70 SkOpSegment::addTPair addTPair this=2 1 other=6 0 71 SkOpContour::joinCoincidence count=4 72 SkOpSegment::sortAngles [0] tStart=0 [0] 73 SkOpSegment::sortAngles [0] tStart=1 [5] 74 SkOpSegment::sortAngles [1] tStart=1.39541634e-006 [2] 75 SkOpSegment::sortAngles [1] tStart=1 [5] 76 SkOpSegment::sortAngles [2] tStart=1 [5] 77 SkOpSegment::sortAngles [3] tStart=0.999998605 [3] 78 SkOpSegment::debugShowActiveSpans id=0 (1000,343 165,343) t=0 (1000,343) tEnd=1 other=3 otherT=1 otherIndex=5 windSum=? windValue=1 oppValue=-1 79 SkOpSegment::debugShowActiveSpans id=1 (165,343 165,364.869873) t=1.39541634e-006 (165,343.000031) tEnd=1 other=7 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=-1 80 SkOpSegment::debugShowActiveSpans id=2 (165,364.869873 1000,364.869873) t=0 (165,364.869873) tEnd=1 other=6 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=-1 81 SkOpSegment::debugShowActiveSpans id=3 (1000,364.869873 1000,343) t=0 (1000,364.869873) tEnd=0.999998605 other=6 otherT=0 otherIndex=2 windSum=? windValue=1 oppValue=-1 82 Assemble 83 84 </div> 85 86 </div> 87 88 <script type="text/javascript"> 89 90 var testDivs = [ 91 skpwww_argus_presse_fr_41, 92 ]; 93 94 var decimal_places = 3; // make this 3 to show more precision 95 96 var tests = []; 97 var testLines = []; 98 var testTitles = []; 99 var testIndex = 0; 100 var ctx; 101 102 var xmin, xmax, focusXmin, focusXmax; 103 var ymin, ymax, focusYmin, focusYmax; 104 var scale; 105 var mouseX, mouseY; 106 var srcLeft, srcTop; 107 var screenWidth, screenHeight; 108 var drawnPts, drawnLines, drawnQuads, drawnCubics; 109 var curveT = 0; 110 111 var pt_labels = 2; 112 var collect_bounds = false; 113 var control_lines = 0; 114 var curve_t = false; 115 var debug_xy = 1; 116 var focus_enabled = false; 117 var focus_on_selection = false; 118 var step_limit = 0; 119 var draw_active = false; 120 var draw_add = false; 121 var draw_angle = 0; 122 var draw_deriviatives = 0; 123 var draw_hints = false; 124 var draw_hodo = 0; 125 var draw_id = false; 126 var draw_intersection = 0; 127 var draw_intersectT = false; 128 var draw_legend = true; 129 var draw_log = false; 130 var draw_mark = false; 131 var draw_midpoint = false; 132 var draw_op = 0; 133 var draw_sequence = false; 134 var draw_sort = 0; 135 var draw_path = 3; 136 var draw_computed = 0; 137 var retina_scale = !!window.devicePixelRatio; 138 139 var activeCount = 0; 140 var addCount = 0; 141 var angleCount = 0; 142 var opCount = 0; 143 var sectCount = 0; 144 var sortCount = 0; 145 var markCount = 0; 146 var activeMax = 0; 147 var addMax = 0; 148 var angleMax = 0; 149 var sectMax = 0; 150 var sectMax2 = 0; 151 var sortMax = 0; 152 var markMax = 0; 153 var opMax = 0; 154 var stepMax = 0; 155 var lastIndex = 0; 156 var hasPath = false; 157 var hasComputedPath = false; 158 159 var firstActiveSpan = -1; 160 var logStart = -1; 161 var logRange = 0; 162 163 var SPAN_ID = 0; 164 var SPAN_X1 = SPAN_ID + 1; 165 var SPAN_Y1 = SPAN_X1 + 1; 166 var SPAN_X2 = SPAN_Y1 + 1; 167 var SPAN_Y2 = SPAN_X2 + 1; 168 var SPAN_L_T = SPAN_Y2 + 1; 169 var SPAN_L_TX = SPAN_L_T + 1; 170 var SPAN_L_TY = SPAN_L_TX + 1; 171 var SPAN_L_TEND = SPAN_L_TY + 1; 172 var SPAN_L_OTHER = SPAN_L_TEND + 1; 173 var SPAN_L_OTHERT = SPAN_L_OTHER + 1; 174 var SPAN_L_OTHERI = SPAN_L_OTHERT + 1; 175 var SPAN_L_SUM = SPAN_L_OTHERI + 1; 176 var SPAN_L_VAL = SPAN_L_SUM + 1; 177 var SPAN_L_OPP = SPAN_L_VAL + 1; 178 179 var SPAN_X3 = SPAN_Y2 + 1; 180 var SPAN_Y3 = SPAN_X3 + 1; 181 var SPAN_Q_T = SPAN_Y3 + 1; 182 var SPAN_Q_TX = SPAN_Q_T + 1; 183 var SPAN_Q_TY = SPAN_Q_TX + 1; 184 var SPAN_Q_TEND = SPAN_Q_TY + 1; 185 var SPAN_Q_OTHER = SPAN_Q_TEND + 1; 186 var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1; 187 var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1; 188 var SPAN_Q_SUM = SPAN_Q_OTHERI + 1; 189 var SPAN_Q_VAL = SPAN_Q_SUM + 1; 190 var SPAN_Q_OPP = SPAN_Q_VAL + 1; 191 192 var SPAN_X4 = SPAN_Y3 + 1; 193 var SPAN_Y4 = SPAN_X4 + 1; 194 var SPAN_C_T = SPAN_Y4 + 1; 195 var SPAN_C_TX = SPAN_C_T + 1; 196 var SPAN_C_TY = SPAN_C_TX + 1; 197 var SPAN_C_TEND = SPAN_C_TY + 1; 198 var SPAN_C_OTHER = SPAN_C_TEND + 1; 199 var SPAN_C_OTHERT = SPAN_C_OTHER + 1; 200 var SPAN_C_OTHERI = SPAN_C_OTHERT + 1; 201 var SPAN_C_SUM = SPAN_C_OTHERI + 1; 202 var SPAN_C_VAL = SPAN_C_SUM + 1; 203 var SPAN_C_OPP = SPAN_C_VAL + 1; 204 205 var ACTIVE_LINE_SPAN = 1; 206 var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1; 207 var ACTIVE_CUBIC_SPAN = ACTIVE_QUAD_SPAN + 1; 208 209 var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1; 210 var ADD_LINETO = ADD_MOVETO + 1; 211 var ADD_QUADTO = ADD_LINETO + 1; 212 var ADD_CUBICTO = ADD_QUADTO + 1; 213 var ADD_CLOSE = ADD_CUBICTO + 1; 214 var ADD_FILL = ADD_CLOSE + 1; 215 216 var PATH_LINE = ADD_FILL + 1; 217 var PATH_QUAD = PATH_LINE + 1; 218 var PATH_CUBIC = PATH_QUAD + 1; 219 220 var INTERSECT_LINE = PATH_CUBIC + 1; 221 var INTERSECT_LINE_2 = INTERSECT_LINE + 1; 222 var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1; 223 var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1; 224 var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1; 225 var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1; 226 var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1; 227 var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1; 228 var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1; 229 var INTERSECT_SELF_CUBIC = INTERSECT_QUAD_NO + 1; 230 var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1; 231 var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1; 232 var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1; 233 var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1; 234 var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1; 235 var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1; 236 var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1; 237 var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1; 238 var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1; 239 var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1; 240 var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1; 241 var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1; 242 var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1; 243 var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1; 244 // FIXME: add cubic 5- 9 245 var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1; 246 247 var SORT_UNARY = INTERSECT_CUBIC_NO + 1; 248 var SORT_BINARY = SORT_UNARY + 1; 249 250 var OP_DIFFERENCE = SORT_BINARY + 1; 251 var OP_INTERSECT = OP_DIFFERENCE + 1; 252 var OP_UNION = OP_INTERSECT + 1; 253 var OP_XOR = OP_UNION + 1; 254 255 var MARK_LINE = OP_XOR + 1; 256 var MARK_QUAD = MARK_LINE + 1; 257 var MARK_CUBIC = MARK_QUAD + 1; 258 var MARK_DONE_LINE = MARK_CUBIC + 1; 259 var MARK_DONE_QUAD = MARK_DONE_LINE + 1; 260 var MARK_DONE_CUBIC = MARK_DONE_QUAD + 1; 261 var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1; 262 var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1; 263 var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_QUAD + 1; 264 var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1; 265 var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1; 266 var MARK_SIMPLE_CUBIC = MARK_SIMPLE_QUAD + 1; 267 var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1; 268 var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1; 269 var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_QUAD + 1; 270 var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1; 271 var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1; 272 var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_QUAD + 1; 273 var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1; 274 275 var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1; 276 var COMPUTED_SET_2 = COMPUTED_SET_1 + 1; 277 278 var ANGLE_AFTER = COMPUTED_SET_2; 279 var ANGLE_AFTER2 = ANGLE_AFTER + 1; 280 281 var ACTIVE_OP = ANGLE_AFTER2 + 1; 282 283 var FRAG_TYPE_LAST = ACTIVE_OP; 284 285 var REC_TYPE_UNKNOWN = -1; 286 var REC_TYPE_PATH = 0; 287 var REC_TYPE_SECT = 1; 288 var REC_TYPE_ACTIVE = 2; 289 var REC_TYPE_ADD = 3; 290 var REC_TYPE_SORT = 4; 291 var REC_TYPE_OP = 5; 292 var REC_TYPE_MARK = 6; 293 var REC_TYPE_COMPUTED = 7; 294 var REC_TYPE_COIN = 8; 295 var REC_TYPE_ANGLE = 9; 296 var REC_TYPE_ACTIVE_OP = 10; 297 var REC_TYPE_LAST = REC_TYPE_ACTIVE_OP; 298 299 function strs_to_nums(strs) { 300 var result = []; 301 for (var idx = 1; idx < strs.length; ++idx) { 302 var str = strs[idx]; 303 var num = parseFloat(str); 304 if (isNaN(num)) { 305 result.push(str); 306 } else { 307 result.push(num); 308 } 309 } 310 return result; 311 } 312 313 function filter_str_by(id, str, regex, array) { 314 if (regex.test(str)) { 315 var strs = regex.exec(str); 316 var result = strs_to_nums(strs); 317 array.push(id); 318 array.push(result); 319 return true; 320 } 321 return false; 322 } 323 324 function construct_regexp2(pattern) { 325 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); 326 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*"); 327 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)"); 328 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)"); 329 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)"); 330 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType"); 331 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)"); 332 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?"); 333 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)"); 334 escape = escape.replace(/PATH/g, "pathB?"); 335 escape = escape.replace(/IDX/g, "(\\d+)"); 336 escape = escape.replace(/NUM/g, "(-?\\d+)"); 337 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)"); 338 return new RegExp(escape, 'i'); 339 } 340 341 function construct_regexp2c(pattern) { 342 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); 343 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*"); 344 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}"); 345 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}"); 346 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{P_VAL\\}, \\{P_VAL\\}\\}"); 347 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType"); 348 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}"); 349 escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?,(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?"); 350 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)"); 351 escape = escape.replace(/OPER/g, "[a-z]+"); 352 escape = escape.replace(/PATH/g, "pathB?"); 353 escape = escape.replace(/T_F/g, "([TF])"); 354 escape = escape.replace(/IDX/g, "(\\d+)"); 355 escape = escape.replace(/NUM/g, "(-?\\d+)"); 356 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)"); 357 return new RegExp(escape, 'i'); 358 } 359 360 function match_regexp(str, lineNo, array, id, pattern) { 361 var regex = construct_regexp2(pattern); 362 if (filter_str_by(id, str, regex, array)) { 363 return true; 364 } 365 regex = construct_regexp2c(pattern); 366 return filter_str_by(id, str, regex, array); 367 } 368 369 function endsWith(str, suffix) { 370 return str.indexOf(suffix, str.length - suffix.length) !== -1; 371 } 372 373 function parse_all(test) { 374 var lines = test.match(/[^\r\n]+/g); 375 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add 376 var record = []; 377 var recType = REC_TYPE_UNKNOWN; 378 var lastLineNo; 379 var moveX, moveY; 380 for (var lineNo = 0; lineNo < lines.length; ++lineNo) { 381 var line = lines[lineNo]; 382 if (line.length == 0) { 383 continue; 384 } 385 var opStart = "SkOpSegment::"; 386 if (line.lastIndexOf(opStart, 0) === 0) { 387 line = line.substr(opStart.length); 388 } 389 var angleStart = "SkOpAngle::"; 390 if (line.lastIndexOf(angleStart, 0) === 0) { 391 line = line.substr(angleStart.length); 392 } 393 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE 394 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN 395 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT 396 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP 397 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED 398 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT 399 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT 400 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD 401 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD 402 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE 403 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK 404 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED 405 : line.lastIndexOf("{{", 0) === 0 ? REC_TYPE_PATH 406 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP 407 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH 408 : REC_TYPE_UNKNOWN; 409 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT 410 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) { 411 if (recType != REC_TYPE_UNKNOWN) { 412 records.push(recType); 413 records.push(lastLineNo); 414 records.push(record); 415 } 416 record = []; 417 recType = type; 418 lastLineNo = lineNo; 419 } 420 var found = false; 421 switch (recType) { 422 case REC_TYPE_ACTIVE: 423 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" + 424 " id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=NUM" 425 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" + 426 " id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=NUM" 427 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" + 428 " id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=NUM" 429 ); 430 break; 431 case REC_TYPE_ACTIVE_OP: 432 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" + 433 " id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX" 434 ); 435 break; 436 case REC_TYPE_ADD: 437 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) { 438 moveX = record[1][0]; 439 moveY = record[1][1]; 440 found = true; 441 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) { 442 record[1].unshift(moveY); 443 record[1].unshift(moveX); 444 moveX = record[1][2]; 445 moveY = record[1][3]; 446 found = true; 447 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) { 448 record[1].unshift(moveY); 449 record[1].unshift(moveX); 450 moveX = record[1][4]; 451 moveY = record[1][5]; 452 found = true; 453 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) { 454 record[1].unshift(moveY); 455 record[1].unshift(moveX); 456 moveX = record[1][6]; 457 moveY = record[1][7]; 458 found = true; 459 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) { 460 found = true; 461 } else { 462 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();"); 463 } 464 break; 465 case REC_TYPE_ANGLE: 466 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " + 467 "id=IDX IDX/IDX tStart=T_VAL tEnd=T_VAL < id=IDX IDX/IDX tStart=T_VAL tEnd=T_VAL < id=IDX IDX/IDX tStart=T_VAL tEnd=T_VAL T_F IDX"); 468 if (found) { 469 break; 470 } 471 found = match_regexp(line, lineNo, record, ANGLE_AFTER2, "after " + 472 "[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"); 473 break; 474 case REC_TYPE_COIN: 475 found = true; 476 break; 477 case REC_TYPE_COMPUTED: 478 found = line == "computed quadratics given" 479 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1" 480 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2" 481 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL," 482 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL," 483 ); 484 break; 485 case REC_TYPE_PATH: 486 found = match_regexp(line, lineNo, record, PATH_LINE, "LINE_VAL" 487 ) || match_regexp(line, lineNo, record, PATH_QUAD, "QUAD_VAL" 488 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "CUBIC_VAL" 489 ); 490 break; 491 case REC_TYPE_SECT: 492 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" + 493 " wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 494 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" + 495 " wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 496 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" + 497 " no intersect LINE_VAL LINE_VAL" 498 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" + 499 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 500 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" + 501 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 502 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" + 503 " no intersect QUAD_VAL LINE_VAL" 504 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" + 505 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL" 506 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" + 507 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL" 508 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" + 509 " no intersect QUAD_VAL QUAD_VAL" 510 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" + 511 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 512 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" + 513 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 514 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" + 515 " 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" 516 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" + 517 " no intersect CUBIC_VAL LINE_VAL" 518 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" + 519 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL" 520 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" + 521 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL" 522 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" + 523 " 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" 524 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" + 525 " 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" 526 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" + 527 " no intersect CUBIC_VAL QUAD_VAL" 528 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" + 529 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL" 530 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" + 531 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL" 532 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" + 533 " 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" 534 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" + 535 " 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" 536 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" + 537 " no intersect CUBIC_VAL CUBIC_VAL" 538 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" + 539 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL" 540 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" + 541 " no self intersect CUBIC_VAL" 542 ); 543 break; 544 case REC_TYPE_SORT: 545 var hasDone = / done/.test(line); 546 var hasUnorderable = / unorderable/.test(line); 547 var hasSmall = / small/.test(line); 548 var hasTiny = / tiny/.test(line); 549 var hasOperand = / operand/.test(line); 550 var hasStop = / stop/.test(line); 551 line.replace(/[ a-z]+$/, ""); 552 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" + 553 " [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT" 554 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" + 555 " [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" 556 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" + 557 " [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT" 558 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" + 559 " [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" 560 ); 561 if (found) { 562 record[1].push(hasDone); 563 record[1].push(hasUnorderable); 564 record[1].push(hasSmall); 565 record[1].push(hasTiny); 566 record[1].push(hasOperand); 567 record[1].push(hasStop); 568 } 569 break; 570 case REC_TYPE_MARK: 571 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" + 572 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX" 573 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" + 574 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX" 575 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" + 576 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX" 577 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDoneBinary" + 578 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX" 579 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDoneBinary" + 580 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX" 581 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDoneBinary" + 582 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX" 583 ) || match_regexp(line, lineNo, record, MARK_UNSORTABLE_LINE, "markUnsortable" + 584 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 585 ) || match_regexp(line, lineNo, record, MARK_UNSORTABLE_QUAD, "markUnsortable" + 586 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 587 ) || match_regexp(line, lineNo, record, MARK_UNSORTABLE_CUBIC, "markUnsortable" + 588 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 589 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" + 590 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 591 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" + 592 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 593 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" + 594 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 595 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_DONE_LINE, "markDone" + 596 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 597 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_DONE_QUAD, "markDone" + 598 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 599 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_DONE_CUBIC, "markDone" + 600 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 601 ) || match_regexp(line, lineNo, record, MARK_DONE_UNARY_LINE, "markDoneUnary" + 602 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 603 ) || match_regexp(line, lineNo, record, MARK_DONE_UNARY_QUAD, "markDoneUnary" + 604 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 605 ) || match_regexp(line, lineNo, record, MARK_DONE_UNARY_CUBIC, "markDoneUnary" + 606 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 607 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" + 608 " last id=IDX windSum=OPT small=IDX"); 609 break; 610 case REC_TYPE_OP: 611 if (line.lastIndexOf("oppSign oppSign=", 0) === 0 612 || line.lastIndexOf("operator<", 0) === 0) { 613 found = true; 614 break; 615 } 616 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op difference" 617 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect" 618 ) || match_regexp(line, lineNo, record, OP_UNION, "op union" 619 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor" 620 ); 621 break; 622 case REC_TYPE_UNKNOWN: 623 found = true; 624 break; 625 } 626 if (!found) { 627 console.log(line + " [" + lineNo + "] of type " + type + " not found"); 628 } 629 } 630 if (recType != REC_TYPE_UNKNOWN) { 631 records.push(recType); 632 records.push(lastLineNo); 633 records.push(record); 634 } 635 if (records.length >= 1) { 636 tests[testIndex] = records; 637 testLines[testIndex] = lines; 638 } 639 } 640 641 function init(test) { 642 var canvas = document.getElementById('canvas'); 643 if (!canvas.getContext) return; 644 ctx = canvas.getContext('2d'); 645 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1; 646 var unscaledWidth = window.innerWidth - 20; 647 var unscaledHeight = window.innerHeight - 20; 648 screenWidth = unscaledWidth; 649 screenHeight = unscaledHeight; 650 canvas.width = unscaledWidth * resScale; 651 canvas.height = unscaledHeight * resScale; 652 canvas.style.width = unscaledWidth + 'px'; 653 canvas.style.height = unscaledHeight + 'px'; 654 if (resScale != 1) { 655 ctx.scale(resScale, resScale); 656 } 657 xmin = Infinity; 658 xmax = -Infinity; 659 ymin = Infinity; 660 ymax = -Infinity; 661 hasPath = hasComputedPath = false; 662 firstActiveSpan = -1; 663 for (var tIndex = 0; tIndex < test.length; tIndex += 3) { 664 var recType = test[tIndex]; 665 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) { 666 console.log("unknown rec type: " + recType); 667 throw "stop execution"; 668 } 669 var records = test[tIndex + 2]; 670 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 671 var fragType = records[recordIndex]; 672 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) { 673 console.log("unknown in range frag type: " + fragType); 674 throw "stop execution"; 675 } 676 var frags = records[recordIndex + 1]; 677 var first = 0; 678 var last = -1; 679 var first2 = 0; 680 var last2 = 0; 681 switch (recType) { 682 case REC_TYPE_COMPUTED: 683 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) { 684 break; 685 } 686 hasComputedPath = true; 687 case REC_TYPE_PATH: 688 switch (fragType) { 689 case PATH_LINE: 690 last = 4; 691 break; 692 case PATH_QUAD: 693 last = 6; 694 break; 695 case PATH_CUBIC: 696 last = 8; 697 break; 698 default: 699 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH" 700 : "REC_TYPE_COMPUTED") + " frag type:" + fragType); 701 throw "stop execution"; 702 } 703 if (recType == REC_TYPE_PATH) { 704 hasPath = true; 705 } 706 break; 707 case REC_TYPE_ACTIVE: 708 if (firstActiveSpan < 0) { 709 firstActiveSpan = tIndex; 710 } 711 first = 1; 712 switch (fragType) { 713 case ACTIVE_LINE_SPAN: 714 last = 5; 715 break; 716 case ACTIVE_QUAD_SPAN: 717 last = 7; 718 break; 719 case ACTIVE_CUBIC_SPAN: 720 last = 9; 721 break; 722 default: 723 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType); 724 throw "stop execution"; 725 } 726 break; 727 case REC_TYPE_ADD: 728 switch (fragType) { 729 case ADD_MOVETO: 730 break; 731 case ADD_LINETO: 732 last = 4; 733 break; 734 case ADD_QUADTO: 735 last = 6; 736 break; 737 case ADD_CUBICTO: 738 last = 8; 739 break; 740 case ADD_CLOSE: 741 case ADD_FILL: 742 break; 743 default: 744 console.log("unknown REC_TYPE_ADD frag type: " + fragType); 745 throw "stop execution"; 746 } 747 break; 748 case REC_TYPE_SECT: 749 switch (fragType) { 750 case INTERSECT_LINE: 751 first = 1; last = 5; first2 = 8; last2 = 12; 752 break; 753 case INTERSECT_LINE_2: 754 first = 1; last = 5; first2 = 11; last2 = 15; 755 break; 756 case INTERSECT_LINE_NO: 757 first = 0; last = 4; first2 = 4; last2 = 8; 758 break; 759 case INTERSECT_QUAD_LINE: 760 first = 1; last = 7; first2 = 10; last2 = 14; 761 break; 762 case INTERSECT_QUAD_LINE_2: 763 first = 1; last = 7; first2 = 13; last2 = 17; 764 break; 765 case INTERSECT_QUAD_LINE_NO: 766 first = 0; last = 6; first2 = 6; last2 = 10; 767 break; 768 case INTERSECT_QUAD: 769 first = 1; last = 7; first2 = 10; last2 = 16; 770 break; 771 case INTERSECT_QUAD_2: 772 first = 1; last = 7; first2 = 13; last2 = 19; 773 break; 774 case INTERSECT_QUAD_NO: 775 first = 0; last = 6; first2 = 6; last2 = 12; 776 break; 777 case INTERSECT_SELF_CUBIC: 778 first = 1; last = 9; 779 break; 780 case INTERSECT_SELF_CUBIC_NO: 781 first = 0; last = 8; 782 break; 783 case INTERSECT_CUBIC_LINE: 784 first = 1; last = 9; first2 = 12; last2 = 16; 785 break; 786 case INTERSECT_CUBIC_LINE_2: 787 first = 1; last = 9; first2 = 15; last2 = 19; 788 break; 789 case INTERSECT_CUBIC_LINE_3: 790 first = 1; last = 9; first2 = 18; last2 = 22; 791 break; 792 case INTERSECT_CUBIC_LINE_NO: 793 first = 0; last = 8; first2 = 8; last2 = 12; 794 break; 795 case INTERSECT_CUBIC_QUAD: 796 first = 1; last = 9; first2 = 12; last2 = 18; 797 break; 798 case INTERSECT_CUBIC_QUAD_2: 799 first = 1; last = 9; first2 = 15; last2 = 21; 800 break; 801 case INTERSECT_CUBIC_QUAD_3: 802 first = 1; last = 9; first2 = 18; last2 = 24; 803 break; 804 case INTERSECT_CUBIC_QUAD_4: 805 first = 1; last = 9; first2 = 21; last2 = 27; 806 break; 807 case INTERSECT_CUBIC_QUAD_NO: 808 first = 0; last = 8; first2 = 8; last2 = 14; 809 break; 810 case INTERSECT_CUBIC: 811 first = 1; last = 9; first2 = 12; last2 = 20; 812 break; 813 case INTERSECT_CUBIC_2: 814 first = 1; last = 9; first2 = 15; last2 = 23; 815 break; 816 case INTERSECT_CUBIC_3: 817 first = 1; last = 9; first2 = 18; last2 = 26; 818 break; 819 case INTERSECT_CUBIC_4: 820 first = 1; last = 9; first2 = 21; last2 = 29; 821 break; 822 case INTERSECT_CUBIC_NO: 823 first = 0; last = 8; first2 = 8; last2 = 16; 824 break; 825 default: 826 console.log("unknown REC_TYPE_SECT frag type: " + fragType); 827 throw "stop execution"; 828 } 829 break; 830 default: 831 continue; 832 } 833 for (var idx = first; idx < last; idx += 2) { 834 xmin = Math.min(xmin, frags[idx]); 835 xmax = Math.max(xmax, frags[idx]); 836 ymin = Math.min(ymin, frags[idx + 1]); 837 ymax = Math.max(ymax, frags[idx + 1]); 838 } 839 for (var idx = first2; idx < last2; idx += 2) { 840 xmin = Math.min(xmin, frags[idx]); 841 xmax = Math.max(xmax, frags[idx]); 842 ymin = Math.min(ymin, frags[idx + 1]); 843 ymax = Math.max(ymax, frags[idx + 1]); 844 } 845 } 846 } 847 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity]; 848 for (var tIndex = 0; tIndex < test.length; tIndex += 3) { 849 var recType = test[tIndex]; 850 var records = test[tIndex + 2]; 851 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 852 var fragType = records[recordIndex]; 853 var frags = records[recordIndex + 1]; 854 switch (recType) { 855 case REC_TYPE_ACTIVE_OP: 856 if (!draw_op) { 857 break; 858 } 859 { 860 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 861 curve_extremes(curve, angleBounds); 862 } 863 break; 864 case REC_TYPE_ANGLE: 865 if (!draw_angle) { 866 break; 867 } 868 if (fragType == ANGLE_AFTER) { 869 var curve = curvePartialByID(test, frags[0], frags[3], frags[4]); 870 curve_extremes(curve, angleBounds); 871 curve = curvePartialByID(test, frags[5], frags[8], frags[9]); 872 curve_extremes(curve, angleBounds); 873 curve = curvePartialByID(test, frags[10], frags[13], frags[14]); 874 } else if (fragType == ANGLE_AFTER2) { 875 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]); 876 curve_extremes(curve, angleBounds); 877 curve = curvePartialByID(test, frags[6], frags[10], frags[11]); 878 curve_extremes(curve, angleBounds); 879 curve = curvePartialByID(test, frags[12], frags[16], frags[17]); 880 } 881 break; 882 case REC_TYPE_SORT: 883 if (!draw_sort) { 884 break; 885 } 886 if (fragType == SORT_UNARY || fragType == SORT_BINARY) { 887 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]); 888 curve_extremes(curve, angleBounds); 889 } 890 break; 891 } 892 } 893 } 894 xmin = Math.min(xmin, angleBounds[0]); 895 ymin = Math.min(ymin, angleBounds[1]); 896 xmax = Math.max(xmax, angleBounds[2]); 897 ymax = Math.max(ymax, angleBounds[3]); 898 setScale(xmin, xmax, ymin, ymax); 899 if (hasPath == false && hasComputedPath == true && !draw_computed) { 900 draw_computed = 3; // show both quadratics and cubics 901 } 902 if (hasPath == true && hasComputedPath == false && draw_computed) { 903 draw_computed = 0; 904 } 905 } 906 907 function curveByID(test, id) { 908 var tIndex = firstActiveSpan; 909 if (tIndex < 0) { 910 return []; 911 } 912 while (tIndex < test.length) { 913 var recType = test[tIndex]; 914 if (recType != REC_TYPE_ACTIVE) { 915 return []; 916 } 917 var records = test[tIndex + 2]; 918 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 919 var fragType = records[recordIndex]; 920 var frags = records[recordIndex + 1]; 921 if (frags[0] == id) { 922 switch (fragType) { 923 case ACTIVE_LINE_SPAN: 924 return [frags[1], frags[2], frags[3], frags[4]]; 925 case ACTIVE_QUAD_SPAN: 926 return [frags[1], frags[2], frags[3], frags[4], 927 frags[5], frags[6]]; 928 case ACTIVE_CUBIC_SPAN: 929 return [frags[1], frags[2], frags[3], frags[4], 930 frags[5], frags[6], frags[7], frags[8]]; 931 } 932 } 933 } 934 tIndex += 3; 935 } 936 return []; 937 } 938 939 function curvePartialByID(test, id, t0, t1) { 940 var tIndex = firstActiveSpan; 941 if (tIndex < 0) { 942 return []; 943 } 944 while (tIndex < test.length) { 945 var recType = test[tIndex]; 946 if (recType != REC_TYPE_ACTIVE) { 947 return []; 948 } 949 var records = test[tIndex + 2]; 950 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 951 var fragType = records[recordIndex]; 952 var frags = records[recordIndex + 1]; 953 if (frags[0] == id) { 954 switch (fragType) { 955 case ACTIVE_LINE_SPAN: 956 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1); 957 case ACTIVE_QUAD_SPAN: 958 return quadPartial(frags[1], frags[2], frags[3], frags[4], 959 frags[5], frags[6], t0, t1); 960 case ACTIVE_CUBIC_SPAN: 961 return cubicPartial(frags[1], frags[2], frags[3], frags[4], 962 frags[5], frags[6], frags[7], frags[8], t0, t1); 963 } 964 } 965 } 966 tIndex += 3; 967 } 968 return []; 969 } 970 971 function idByCurve(test, frag, type) { 972 var tIndex = firstActiveSpan; 973 if (tIndex < 0) { 974 return -1; 975 } 976 while (tIndex < test.length) { 977 var recType = test[tIndex]; 978 if (recType != REC_TYPE_ACTIVE) { 979 return -1; 980 } 981 var records = test[tIndex + 2]; 982 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 983 var fragType = records[recordIndex]; 984 var frags = records[recordIndex + 1]; 985 switch (fragType) { 986 case ACTIVE_LINE_SPAN: 987 if (type != PATH_LINE) { 988 continue; 989 } 990 if (frag[0] != frags[1] || frag[1] != frags[2] 991 || frag[2] != frags[3] || frag[3] != frags[4]) { 992 continue; 993 } 994 return frags[0]; 995 case ACTIVE_QUAD_SPAN: 996 if (type != PATH_QUAD) { 997 continue; 998 } 999 if (frag[0] != frags[1] || frag[1] != frags[2] 1000 || frag[2] != frags[3] || frag[3] != frags[4] 1001 || frag[4] != frags[5] || frag[5] != frags[6]) { 1002 continue; 1003 } 1004 return frags[0]; 1005 case ACTIVE_CUBIC_SPAN: 1006 if (type != PATH_CUBIC) { 1007 continue; 1008 } 1009 if (frag[0] != frags[1] || frag[1] != frags[2] 1010 || frag[2] != frags[3] || frag[3] != frags[4] 1011 || frag[4] != frags[5] || frag[5] != frags[6] 1012 || frag[6] != frags[7] || frag[7] != frags[8]) { 1013 continue; 1014 } 1015 return frags[0]; 1016 } 1017 } 1018 ++tIndex; 1019 } 1020 return -1; 1021 } 1022 1023 function curve_extremes(curve, bounds) { 1024 for (var index = 0; index < curve.length; index += 2) { 1025 var x = curve[index]; 1026 var y = curve[index + 1]; 1027 bounds[0] = Math.min(bounds[0], x); 1028 bounds[1] = Math.min(bounds[1], y); 1029 bounds[2] = Math.max(bounds[2], x); 1030 bounds[3] = Math.max(bounds[3], y); 1031 } 1032 } 1033 1034 function setScale(x0, x1, y0, y1) { 1035 var srcWidth = x1 - x0; 1036 var srcHeight = y1 - y0; 1037 var usableWidth = screenWidth; 1038 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10)); 1039 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10)); 1040 usableWidth -= (xDigits + yDigits) * 10; 1041 usableWidth -= decimal_places * 10; 1042 if (draw_legend) { 1043 usableWidth -= 40; 1044 } 1045 var hscale = usableWidth / srcWidth; 1046 var vscale = screenHeight / srcHeight; 1047 scale = Math.min(hscale, vscale); 1048 var invScale = 1 / scale; 1049 var sxmin = x0 - invScale * 5; 1050 var symin = y0 - invScale * 10; 1051 var sxmax = x1 + invScale * (6 * decimal_places + 10); 1052 var symax = y1 + invScale * 10; 1053 srcWidth = sxmax - sxmin; 1054 srcHeight = symax - symin; 1055 hscale = usableWidth / srcWidth; 1056 vscale = screenHeight / srcHeight; 1057 scale = Math.min(hscale, vscale); 1058 srcLeft = sxmin; 1059 srcTop = symin; 1060 } 1061 1062 function drawArc(curve, op, from, to) { 1063 var type = PATH_LINE + (curve.length / 2 - 2); 1064 var pt = pointAtT(curve, type, op ? 0.4 : 0.6); 1065 var dy = pt.y - curve[1]; 1066 var dx = pt.x - curve[0]; 1067 var dist = Math.sqrt(dy * dy + dx * dx); 1068 var _dist = dist * scale; 1069 var angle = Math.atan2(dy, dx); 1070 var _px = (curve[0] - srcLeft) * scale; 1071 var _py = (curve[1] - srcTop) * scale; 1072 var divisor = 4; 1073 var endDist; 1074 do { 1075 var ends = []; 1076 for (var index = -1; index <= 1; index += 2) { 1077 var px = Math.cos(index * Math.PI / divisor); 1078 var py = Math.sin(index * Math.PI / divisor); 1079 ends.push(px); 1080 ends.push(py); 1081 } 1082 var endDx = (ends[2] - ends[0]) * scale * dist; 1083 var endDy = (ends[3] - ends[1]) * scale * dist; 1084 endDist = Math.sqrt(endDx * endDx + endDy * endDy); 1085 if (endDist < 100) { 1086 break; 1087 } 1088 divisor *= 2; 1089 } while (true); 1090 if (endDist < 30) { 1091 return; 1092 } 1093 if (op) { 1094 divisor *= 2; 1095 } 1096 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)"; 1097 ctx.beginPath(); 1098 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false); 1099 ctx.stroke(); 1100 var saveAlign = ctx.textAlign; 1101 var saveStyle = ctx.fillStyle; 1102 var saveFont = ctx.font; 1103 ctx.textAlign = "center"; 1104 ctx.fillStyle = "black"; 1105 ctx.font = "normal 24px Arial"; 1106 divisor *= 0.8; 1107 for (var index = -1; index <= 1; index += 2) { 1108 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist; 1109 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist; 1110 var _px = (px - srcLeft) * scale; 1111 var _py = (py - srcTop) * scale; 1112 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8); 1113 } 1114 ctx.textAlign = saveAlign; 1115 ctx.fillStyle = saveStyle; 1116 ctx.font = saveFont; 1117 } 1118 1119 function drawPoint(px, py, end) { 1120 for (var pts = 0; pts < drawnPts.length; pts += 2) { 1121 var x = drawnPts[pts]; 1122 var y = drawnPts[pts + 1]; 1123 if (px == x && py == y) { 1124 return; 1125 } 1126 } 1127 drawnPts.push(px); 1128 drawnPts.push(py); 1129 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places); 1130 var _px = (px - srcLeft) * scale; 1131 var _py = (py - srcTop) * scale; 1132 ctx.beginPath(); 1133 ctx.arc(_px, _py, 3, 0, Math.PI*2, true); 1134 ctx.closePath(); 1135 if (end) { 1136 ctx.fill(); 1137 } else { 1138 ctx.stroke(); 1139 } 1140 if (debug_xy) { 1141 ctx.textAlign = "left"; 1142 ctx.fillText(label, _px + 5, _py); 1143 } 1144 } 1145 1146 function drawPoints(ptArray, curveType, drawControls) { 1147 var count = (curveType - PATH_LINE + 2) * 2; 1148 for (var idx = 0; idx < count; idx += 2) { 1149 if (!drawControls && idx != 0 && idx != count - 2) { 1150 continue; 1151 } 1152 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2); 1153 } 1154 } 1155 1156 function drawControlLines(curve, curveType, drawEnd) { 1157 if (curveType == PATH_LINE) { 1158 return; 1159 } 1160 ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 1161 drawLine(curve[0], curve[1], curve[2], curve[3]); 1162 drawLine(curve[2], curve[3], curve[4], curve[5]); 1163 if (curveType == PATH_CUBIC) { 1164 drawLine(curve[4], curve[5], curve[6], curve[7]); 1165 if (drawEnd > 1) { 1166 drawLine(curve[6], curve[7], curve[0], curve[1]); 1167 if (drawEnd > 2) { 1168 drawLine(curve[0], curve[1], curve[4], curve[5]); 1169 drawLine(curve[6], curve[7], curve[2], curve[3]); 1170 } 1171 } 1172 } else if (drawEnd > 1) { 1173 drawLine(curve[4], curve[5], curve[0], curve[1]); 1174 } 1175 } 1176 1177 function pointAtT(curve, curveType, t) { 1178 var xy = {}; 1179 switch (curveType) { 1180 case PATH_LINE: 1181 var a = 1 - t; 1182 var b = t; 1183 xy.x = a * curve[0] + b * curve[2]; 1184 xy.y = a * curve[1] + b * curve[3]; 1185 break; 1186 case PATH_QUAD: 1187 var one_t = 1 - t; 1188 var a = one_t * one_t; 1189 var b = 2 * one_t * t; 1190 var c = t * t; 1191 xy.x = a * curve[0] + b * curve[2] + c * curve[4]; 1192 xy.y = a * curve[1] + b * curve[3] + c * curve[5]; 1193 break; 1194 case PATH_CUBIC: 1195 var one_t = 1 - t; 1196 var one_t2 = one_t * one_t; 1197 var a = one_t2 * one_t; 1198 var b = 3 * one_t2 * t; 1199 var t2 = t * t; 1200 var c = 3 * one_t * t2; 1201 var d = t2 * t; 1202 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6]; 1203 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7]; 1204 break; 1205 } 1206 return xy; 1207 } 1208 1209 function drawPointAtT(curve, curveType) { 1210 var x, y; 1211 var xy = pointAtT(curve, curveType, curveT); 1212 drawPoint(xy.x, xy.y, true); 1213 if (!draw_intersectT) { 1214 return; 1215 } 1216 ctx.fillStyle = "red"; 1217 drawTAtPointUp(xy.x, xy.y, curveT); 1218 } 1219 1220 function drawTAtPointUp(px, py, t) { 1221 var label = t.toFixed(decimal_places); 1222 var _px = (px - srcLeft)* scale; 1223 var _py = (py - srcTop) * scale; 1224 ctx.fillText(label, _px + 5, _py - 10); 1225 } 1226 1227 function drawTAtPointDown(px, py, t) { 1228 var label = t.toFixed(decimal_places); 1229 var _px = (px - srcLeft)* scale; 1230 var _py = (py - srcTop) * scale; 1231 ctx.fillText(label, _px + 5, _py + 10); 1232 } 1233 1234 function alreadyDrawnLine(x1, y1, x2, y2) { 1235 if (collect_bounds) { 1236 if (focus_enabled) { 1237 focusXmin = Math.min(focusXmin, x1, x2); 1238 focusYmin = Math.min(focusYmin, y1, y2); 1239 focusXmax = Math.max(focusXmax, x1, x2); 1240 focusYmax = Math.max(focusYmax, y1, y2); 1241 } 1242 return true; 1243 } 1244 for (var pts = 0; pts < drawnLines.length; pts += 4) { 1245 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1] 1246 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) { 1247 return true; 1248 } 1249 } 1250 drawnLines.push(x1); 1251 drawnLines.push(y1); 1252 drawnLines.push(x2); 1253 drawnLines.push(y2); 1254 return false; 1255 } 1256 1257 function drawLine(x1, y1, x2, y2) { 1258 if (alreadyDrawnLine(x1, y1, x2, y2)) { 1259 return; 1260 } 1261 ctx.beginPath(); 1262 ctx.moveTo((x1 - srcLeft) * scale, 1263 (y1 - srcTop) * scale); 1264 ctx.lineTo((x2 - srcLeft) * scale, 1265 (y2 - srcTop) * scale); 1266 ctx.stroke(); 1267 } 1268 1269 function linePartial(x1, y1, x2, y2, t1, t2) { 1270 var dx = x1 - x2; 1271 var dy = y1 - y2; 1272 var array = [ 1273 x1 - t1 * dx, 1274 y1 - t1 * dy, 1275 x1 - t2 * dx, 1276 y1 - t2 * dy 1277 ]; 1278 return array; 1279 } 1280 1281 function drawLinePartial(x1, y1, x2, y2, t1, t2) { 1282 var a = linePartial(x1, y1, x2, y2, t1, t2); 1283 var ax = a[0]; 1284 var ay = a[1]; 1285 var bx = a[2]; 1286 var by = a[3]; 1287 if (alreadyDrawnLine(ax, ay, bx, by)) { 1288 return; 1289 } 1290 ctx.beginPath(); 1291 ctx.moveTo((ax - srcLeft) * scale, 1292 (ay - srcTop) * scale); 1293 ctx.lineTo((bx - srcLeft) * scale, 1294 (by - srcTop) * scale); 1295 ctx.stroke(); 1296 } 1297 1298 function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) { 1299 if (collect_bounds) { 1300 if (focus_enabled) { 1301 focusXmin = Math.min(focusXmin, x1, x2, x3); 1302 focusYmin = Math.min(focusYmin, y1, y2, y3); 1303 focusXmax = Math.max(focusXmax, x1, x2, x3); 1304 focusYmax = Math.max(focusYmax, y1, y2, y3); 1305 } 1306 return true; 1307 } 1308 for (var pts = 0; pts < drawnQuads.length; pts += 6) { 1309 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1] 1310 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3] 1311 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) { 1312 return true; 1313 } 1314 } 1315 drawnQuads.push(x1); 1316 drawnQuads.push(y1); 1317 drawnQuads.push(x2); 1318 drawnQuads.push(y2); 1319 drawnQuads.push(x3); 1320 drawnQuads.push(y3); 1321 return false; 1322 } 1323 1324 function drawQuad(x1, y1, x2, y2, x3, y3) { 1325 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) { 1326 return; 1327 } 1328 ctx.beginPath(); 1329 ctx.moveTo((x1 - srcLeft) * scale, 1330 (y1 - srcTop) * scale); 1331 ctx.quadraticCurveTo((x2 - srcLeft) * scale, 1332 (y2 - srcTop) * scale, 1333 (x3 - srcLeft) * scale, 1334 (y3 - srcTop) * scale); 1335 ctx.stroke(); 1336 } 1337 1338 function interp(A, B, t) { 1339 return A + (B - A) * t; 1340 } 1341 1342 function interp_quad_coords(x1, x2, x3, t) 1343 { 1344 var ab = interp(x1, x2, t); 1345 var bc = interp(x2, x3, t); 1346 var abc = interp(ab, bc, t); 1347 return abc; 1348 } 1349 1350 function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) { 1351 var ax = interp_quad_coords(x1, x2, x3, t1); 1352 var ay = interp_quad_coords(y1, y2, y3, t1); 1353 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2); 1354 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2); 1355 var cx = interp_quad_coords(x1, x2, x3, t2); 1356 var cy = interp_quad_coords(y1, y2, y3, t2); 1357 var bx = 2*dx - (ax + cx)/2; 1358 var by = 2*dy - (ay + cy)/2; 1359 var array = [ 1360 ax, ay, bx, by, cx, cy 1361 ]; 1362 return array; 1363 } 1364 1365 function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) { 1366 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2); 1367 var ax = a[0]; 1368 var ay = a[1]; 1369 var bx = a[2]; 1370 var by = a[3]; 1371 var cx = a[4]; 1372 var cy = a[5]; 1373 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) { 1374 return; 1375 } 1376 ctx.beginPath(); 1377 ctx.moveTo((ax - srcLeft) * scale, 1378 (ay - srcTop) * scale); 1379 ctx.quadraticCurveTo((bx - srcLeft) * scale, 1380 (by - srcTop) * scale, 1381 (cx - srcLeft) * scale, 1382 (cy - srcTop) * scale); 1383 ctx.stroke(); 1384 } 1385 1386 function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) { 1387 if (collect_bounds) { 1388 if (focus_enabled) { 1389 focusXmin = Math.min(focusXmin, x1, x2, x3, x4); 1390 focusYmin = Math.min(focusYmin, y1, y2, y3, y4); 1391 focusXmax = Math.max(focusXmax, x1, x2, x3, x4); 1392 focusYmax = Math.max(focusYmax, y1, y2, y3, y4); 1393 } 1394 return true; 1395 } 1396 for (var pts = 0; pts < drawnCubics.length; pts += 8) { 1397 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1] 1398 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3] 1399 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5] 1400 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) { 1401 return true; 1402 } 1403 } 1404 drawnCubics.push(x1); 1405 drawnCubics.push(y1); 1406 drawnCubics.push(x2); 1407 drawnCubics.push(y2); 1408 drawnCubics.push(x3); 1409 drawnCubics.push(y3); 1410 drawnCubics.push(x4); 1411 drawnCubics.push(y4); 1412 return false; 1413 } 1414 1415 function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) { 1416 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) { 1417 return; 1418 } 1419 ctx.beginPath(); 1420 ctx.moveTo((x1 - srcLeft) * scale, 1421 (y1 - srcTop) * scale); 1422 ctx.bezierCurveTo((x2 - srcLeft) * scale, 1423 (y2 - srcTop) * scale, 1424 (x3 - srcLeft) * scale, 1425 (y3 - srcTop) * scale, 1426 (x4 - srcLeft) * scale, 1427 (y4 - srcTop) * scale); 1428 ctx.stroke(); 1429 } 1430 1431 function interp_cubic_coords(x1, x2, x3, x4, t) 1432 { 1433 var ab = interp(x1, x2, t); 1434 var bc = interp(x2, x3, t); 1435 var cd = interp(x3, x4, t); 1436 var abc = interp(ab, bc, t); 1437 var bcd = interp(bc, cd, t); 1438 var abcd = interp(abc, bcd, t); 1439 return abcd; 1440 } 1441 1442 function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) { 1443 var ax = interp_cubic_coords(x1, x2, x3, x4, t1); 1444 var ay = interp_cubic_coords(y1, y2, y3, y4, t1); 1445 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3); 1446 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3); 1447 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3); 1448 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3); 1449 var dx = interp_cubic_coords(x1, x2, x3, x4, t2); 1450 var dy = interp_cubic_coords(y1, y2, y3, y4, t2); 1451 var mx = ex * 27 - ax * 8 - dx; 1452 var my = ey * 27 - ay * 8 - dy; 1453 var nx = fx * 27 - ax - dx * 8; 1454 var ny = fy * 27 - ay - dy * 8; 1455 var bx = (mx * 2 - nx) / 18; 1456 var by = (my * 2 - ny) / 18; 1457 var cx = (nx * 2 - mx) / 18; 1458 var cy = (ny * 2 - my) / 18; 1459 var array = [ 1460 ax, ay, bx, by, cx, cy, dx, dy 1461 ]; 1462 return array; 1463 } 1464 1465 function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) { 1466 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2); 1467 var ax = a[0]; 1468 var ay = a[1]; 1469 var bx = a[2]; 1470 var by = a[3]; 1471 var cx = a[4]; 1472 var cy = a[5]; 1473 var dx = a[6]; 1474 var dy = a[7]; 1475 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) { 1476 return; 1477 } 1478 ctx.beginPath(); 1479 ctx.moveTo((ax - srcLeft) * scale, 1480 (ay - srcTop) * scale); 1481 ctx.bezierCurveTo((bx - srcLeft) * scale, 1482 (by - srcTop) * scale, 1483 (cx - srcLeft) * scale, 1484 (cy - srcTop) * scale, 1485 (dx - srcLeft) * scale, 1486 (dy - srcTop) * scale); 1487 ctx.stroke(); 1488 } 1489 1490 function drawCurve(c) { 1491 switch (c.length) { 1492 case 4: 1493 drawLine(c[0], c[1], c[2], c[3]); 1494 break; 1495 case 6: 1496 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]); 1497 break; 1498 case 8: 1499 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); 1500 break; 1501 } 1502 } 1503 1504 function boundsWidth(pts) { 1505 var min = pts[0]; 1506 var max = pts[0]; 1507 for (var idx = 2; idx < pts.length; idx += 2) { 1508 min = Math.min(min, pts[idx]); 1509 max = Math.max(max, pts[idx]); 1510 } 1511 return max - min; 1512 } 1513 1514 function boundsHeight(pts) { 1515 var min = pts[1]; 1516 var max = pts[1]; 1517 for (var idx = 3; idx < pts.length; idx += 2) { 1518 min = Math.min(min, pts[idx]); 1519 max = Math.max(max, pts[idx]); 1520 } 1521 return max - min; 1522 } 1523 1524 function tangent(pts) { 1525 var dx = pts[2] - pts[0]; 1526 var dy = pts[3] - pts[1]; 1527 if (dx == 0 && dy == 0 && pts.length > 4) { 1528 dx = pts[4] - pts[0]; 1529 dy = pts[5] - pts[1]; 1530 if (dx == 0 && dy == 0 && pts.length > 6) { 1531 dx = pts[6] - pts[0]; 1532 dy = pts[7] - pts[1]; 1533 } 1534 } 1535 return Math.atan2(-dy, dx); 1536 } 1537 1538 function hodograph(cubic) { 1539 var hodo = []; 1540 hodo[0] = 3 * (cubic[2] - cubic[0]); 1541 hodo[1] = 3 * (cubic[3] - cubic[1]); 1542 hodo[2] = 3 * (cubic[4] - cubic[2]); 1543 hodo[3] = 3 * (cubic[5] - cubic[3]); 1544 hodo[4] = 3 * (cubic[6] - cubic[4]); 1545 hodo[5] = 3 * (cubic[7] - cubic[5]); 1546 return hodo; 1547 } 1548 1549 function hodograph2(cubic) { 1550 var quad = hodograph(cubic); 1551 var hodo = []; 1552 hodo[0] = 2 * (quad[2] - quad[0]); 1553 hodo[1] = 2 * (quad[3] - quad[1]); 1554 hodo[2] = 2 * (quad[4] - quad[2]); 1555 hodo[3] = 2 * (quad[5] - quad[3]); 1556 return hodo; 1557 } 1558 1559 function quadraticRootsReal(A, B, C, s) { 1560 if (A == 0) { 1561 if (B == 0) { 1562 s[0] = 0; 1563 return C == 0; 1564 } 1565 s[0] = -C / B; 1566 return 1; 1567 } 1568 /* normal form: x^2 + px + q = 0 */ 1569 var p = B / (2 * A); 1570 var q = C / A; 1571 var p2 = p * p; 1572 if (p2 < q) { 1573 return 0; 1574 } 1575 var sqrt_D = 0; 1576 if (p2 > q) { 1577 sqrt_D = sqrt(p2 - q); 1578 } 1579 s[0] = sqrt_D - p; 1580 s[1] = -sqrt_D - p; 1581 return 1 + s[0] != s[1]; 1582 } 1583 1584 function add_valid_ts(s, realRoots, t) { 1585 var foundRoots = 0; 1586 for (var index = 0; index < realRoots; ++index) { 1587 var tValue = s[index]; 1588 if (tValue >= 0 && tValue <= 1) { 1589 for (var idx2 = 0; idx2 < foundRoots; ++idx2) { 1590 if (t[idx2] != tValue) { 1591 t[foundRoots++] = tValue; 1592 } 1593 } 1594 } 1595 } 1596 return foundRoots; 1597 } 1598 1599 function quadraticRootsValidT(a, b, c, t) { 1600 var s = []; 1601 var realRoots = quadraticRootsReal(A, B, C, s); 1602 var foundRoots = add_valid_ts(s, realRoots, t); 1603 return foundRoots != 0; 1604 } 1605 1606 function find_cubic_inflections(cubic, tValues) { 1607 var Ax = src[2] - src[0]; 1608 var Ay = src[3] - src[1]; 1609 var Bx = src[4] - 2 * src[2] + src[0]; 1610 var By = src[5] - 2 * src[3] + src[1]; 1611 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0]; 1612 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1]; 1613 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx), 1614 Ax * By - Ay * Bx, tValues); 1615 } 1616 1617 function dxy_at_t(curve, type, t) { 1618 var dxy = {}; 1619 if (type == PATH_QUAD) { 1620 var a = t - 1; 1621 var b = 1 - 2 * t; 1622 var c = t; 1623 dxy.x = a * curve[0] + b * curve[2] + c * curve[4]; 1624 dxy.y = a * curve[1] + b * curve[3] + c * curve[5]; 1625 } else if (type == PATH_CUBIC) { 1626 var one_t = 1 - t; 1627 var a = curve[0]; 1628 var b = curve[2]; 1629 var c = curve[4]; 1630 var d = curve[6]; 1631 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); 1632 a = curve[1]; 1633 b = curve[3]; 1634 c = curve[5]; 1635 d = curve[7]; 1636 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); 1637 } 1638 return dxy; 1639 } 1640 1641 function drawLabel(num, px, py) { 1642 ctx.beginPath(); 1643 ctx.arc(px, py, 8, 0, Math.PI*2, true); 1644 ctx.closePath(); 1645 ctx.strokeStyle = "rgba(0,0,0, 0.4)"; 1646 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1; 1647 ctx.stroke(); 1648 ctx.fillStyle = "black"; 1649 ctx.font = "normal 10px Arial"; 1650 // ctx.rotate(0.001); 1651 ctx.fillText(num, px - 2, py + 3); 1652 // ctx.rotate(-0.001); 1653 } 1654 1655 function drawLabelX(ymin, num, loc) { 1656 var px = (loc - srcLeft) * scale; 1657 var py = (ymin - srcTop) * scale - 20; 1658 drawLabel(num, px, py); 1659 } 1660 1661 function drawLabelY(xmin, num, loc) { 1662 var px = (xmin - srcLeft) * scale - 20; 1663 var py = (loc - srcTop) * scale; 1664 drawLabel(num, px, py); 1665 } 1666 1667 function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) { 1668 ctx.beginPath(); 1669 ctx.moveTo(hx, hy - 100); 1670 ctx.lineTo(hx, hy); 1671 ctx.strokeStyle = hMinY < 0 ? "green" : "blue"; 1672 ctx.stroke(); 1673 ctx.beginPath(); 1674 ctx.moveTo(hx, hy); 1675 ctx.lineTo(hx, hy + 100); 1676 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue"; 1677 ctx.stroke(); 1678 ctx.beginPath(); 1679 ctx.moveTo(hx - 100, hy); 1680 ctx.lineTo(hx, hy); 1681 ctx.strokeStyle = hMinX < 0 ? "green" : "blue"; 1682 ctx.stroke(); 1683 ctx.beginPath(); 1684 ctx.moveTo(hx, hy); 1685 ctx.lineTo(hx + 100, hy); 1686 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue"; 1687 ctx.stroke(); 1688 } 1689 1690 function scalexy(x, y, mag) { 1691 var length = Math.sqrt(x * x + y * y); 1692 return mag / length; 1693 } 1694 1695 function drawArrow(x, y, dx, dy) { 1696 var dscale = scalexy(dx, dy, 1 / scale * 100); 1697 dx *= dscale; 1698 dy *= dscale; 1699 ctx.beginPath(); 1700 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale); 1701 x += dx; 1702 y += dy; 1703 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale); 1704 dx /= 10; 1705 dy /= 10; 1706 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale); 1707 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale); 1708 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale); 1709 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale); 1710 ctx.strokeStyle = "rgba(0,75,0, 0.4)"; 1711 ctx.stroke(); 1712 } 1713 1714 function x_at_t(curve, t) { 1715 var one_t = 1 - t; 1716 if (curve.length == 4) { 1717 return one_t * curve[0] + t * curve[2]; 1718 } 1719 var one_t2 = one_t * one_t; 1720 var t2 = t * t; 1721 if (curve.length == 6) { 1722 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4]; 1723 } 1724 var a = one_t2 * one_t; 1725 var b = 3 * one_t2 * t; 1726 var c = 3 * one_t * t2; 1727 var d = t2 * t; 1728 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6]; 1729 } 1730 1731 function y_at_t(curve, t) { 1732 var one_t = 1 - t; 1733 if (curve.length == 4) { 1734 return one_t * curve[1] + t * curve[3]; 1735 } 1736 var one_t2 = one_t * one_t; 1737 var t2 = t * t; 1738 if (curve.length == 6) { 1739 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5]; 1740 } 1741 var a = one_t2 * one_t; 1742 var b = 3 * one_t2 * t; 1743 var c = 3 * one_t * t2; 1744 var d = t2 * t; 1745 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7]; 1746 } 1747 1748 function drawOrder(curve, label) { 1749 var px = x_at_t(curve, 0.75); 1750 var py = y_at_t(curve, 0.75); 1751 var _px = (px - srcLeft) * scale; 1752 var _py = (py - srcTop) * scale; 1753 ctx.beginPath(); 1754 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true); 1755 ctx.closePath(); 1756 ctx.fillStyle = "white"; 1757 ctx.fill(); 1758 if (label == 'L') { 1759 ctx.strokeStyle = "rgba(255,0,0, 1)"; 1760 ctx.fillStyle = "rgba(255,0,0, 1)"; 1761 } else { 1762 ctx.strokeStyle = "rgba(0,0,255, 1)"; 1763 ctx.fillStyle = "rgba(0,0,255, 1)"; 1764 } 1765 ctx.stroke(); 1766 ctx.font = "normal 16px Arial"; 1767 ctx.textAlign = "center"; 1768 ctx.fillText(label, _px, _py + 5); 1769 ctx.font = "normal 10px Arial"; 1770 } 1771 1772 function drawID(curve, id) { 1773 var px = x_at_t(curve, 0.5); 1774 var py = y_at_t(curve, 0.5); 1775 var _px = (px - srcLeft) * scale; 1776 var _py = (py - srcTop) * scale; 1777 draw_id_at(id, _px, _py); 1778 } 1779 1780 function draw_id_at(id, _px, _py) { 1781 ctx.beginPath(); 1782 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true); 1783 ctx.closePath(); 1784 ctx.fillStyle = "white"; 1785 ctx.fill(); 1786 ctx.strokeStyle = "rgba(127,127,0, 1)"; 1787 ctx.fillStyle = "rgba(127,127,0, 1)"; 1788 ctx.stroke(); 1789 ctx.font = "normal 16px Arial"; 1790 ctx.textAlign = "center"; 1791 ctx.fillText(id, _px, _py + 5); 1792 ctx.font = "normal 10px Arial"; 1793 } 1794 1795 function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) { 1796 var curve = [x1, y1, x2, y2]; 1797 drawCurvePartialID(id, curve, t1, t2); 1798 } 1799 1800 function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) { 1801 var curve = [x1, y1, x2, y2, x3, y3]; 1802 drawCurvePartialID(id, curve, t1, t2); 1803 } 1804 1805 function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) { 1806 var curve = [x1, y1, x2, y2, x3, y3, x4, y4]; 1807 drawCurvePartialID(id, curve, t1, t2); 1808 } 1809 1810 function drawCurvePartialID(id, curve, t1, t2) { 1811 var px = x_at_t(curve, (t1 + t2) / 2); 1812 var py = y_at_t(curve, (t1 + t2) / 2); 1813 var _px = (px - srcLeft) * scale; 1814 var _py = (py - srcTop) * scale; 1815 draw_id_at(id, _px, _py); 1816 } 1817 1818 function drawCurveSpecials(test, curve, type) { 1819 if (pt_labels) { 1820 drawPoints(curve, type, pt_labels == 2); 1821 } 1822 if (control_lines != 0) { 1823 drawControlLines(curve, type, control_lines); 1824 } 1825 if (curve_t) { 1826 drawPointAtT(curve, type); 1827 } 1828 if (draw_midpoint) { 1829 var mid = pointAtT(curve, type, 0.5); 1830 drawPoint(mid.x, mid.y, true); 1831 } 1832 if (draw_id) { 1833 var id = idByCurve(test, curve, type); 1834 if (id >= 0) { 1835 drawID(curve, id); 1836 } 1837 } 1838 if (type == PATH_LINE) { 1839 return; 1840 } 1841 if (draw_deriviatives > 0) { 1842 var d = dxy_at_t(curve, type, 0); 1843 drawArrow(curve[0], curve[1], d.x, d.y); 1844 if (draw_deriviatives == 2) { 1845 d = dxy_at_t(curve, type, 1); 1846 if (type == PATH_CUBIC) { 1847 drawArrow(curve[6], curve[7], d.x, d.y); 1848 } else { 1849 drawArrow(curve[4], curve[5], d.x, d.y); 1850 } 1851 } 1852 if (draw_midpoint) { 1853 var mid = pointAtT(curve, type, 0.5); 1854 d = dxy_at_t(curve, type, 0.5); 1855 drawArrow(mid.x, mid.y, d.x, d.y); 1856 } 1857 } 1858 if (type != PATH_CUBIC) { 1859 return; 1860 } 1861 if (draw_hodo == 1 || draw_hodo == 2) { 1862 var hodo = hodograph(curve); 1863 var hMinX = Math.min(0, hodo[0], hodo[2], hodo[4]); 1864 var hMinY = Math.min(0, hodo[1], hodo[3], hodo[5]); 1865 var hMaxX = Math.max(0, hodo[0], hodo[2], hodo[4]); 1866 var hMaxY = Math.max(0, hodo[1], hodo[3], hodo[5]); 1867 var hScaleX = hMaxX - hMinX > 0 ? screenWidth / (hMaxX - hMinX) : 1; 1868 var hScaleY = hMaxY - hMinY > 0 ? screenHeight / (hMaxY - hMinY) : 1; 1869 var hUnit = Math.min(hScaleX, hScaleY); 1870 hUnit /= 2; 1871 var hx = xoffset - hMinX * hUnit; 1872 var hy = yoffset - hMinY * hUnit; 1873 ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit); 1874 ctx.quadraticCurveTo( 1875 hx + hodo[2] * hUnit, hy + hodo[3] * hUnit, 1876 hx + hodo[4] * hUnit, hy + hodo[5] * hUnit); 1877 ctx.strokeStyle = "red"; 1878 ctx.stroke(); 1879 if (draw_hodo == 1) { 1880 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY); 1881 } 1882 } 1883 if (draw_hodo == 3) { 1884 var hodo = hodograph2(curve); 1885 var hMinX = Math.min(0, hodo[0], hodo[2]); 1886 var hMinY = Math.min(0, hodo[1], hodo[3]); 1887 var hMaxX = Math.max(0, hodo[0], hodo[2]); 1888 var hMaxY = Math.max(0, hodo[1], hodo[3]); 1889 var hScaleX = hMaxX - hMinX > 0 ? screenWidth / (hMaxX - hMinX) : 1; 1890 var hScaleY = hMaxY - hMinY > 0 ? screenHeight / (hMaxY - hMinY) : 1; 1891 var hUnit = Math.min(hScaleX, hScaleY); 1892 hUnit /= 2; 1893 var hx = xoffset - hMinX * hUnit; 1894 var hy = yoffset - hMinY * hUnit; 1895 ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit); 1896 ctx.lineTo(hx + hodo[2] * hUnit, hy + hodo[3] * hUnit); 1897 ctx.strokeStyle = "red"; 1898 ctx.stroke(); 1899 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY); 1900 } 1901 if (draw_sequence) { 1902 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]); 1903 for (var i = 0; i < 8; i+= 2) { 1904 drawLabelX(ymin, i >> 1, curve[i]); 1905 } 1906 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]); 1907 for (var i = 1; i < 8; i+= 2) { 1908 drawLabelY(xmin, i >> 1, curve[i]); 1909 } 1910 } 1911 } 1912 1913 function logCurves(test) { 1914 for (curves in test) { 1915 var curve = test[curves]; 1916 dumpCurve(curve); 1917 } 1918 } 1919 1920 function curveToString(curve) { 1921 var str = "{{"; 1922 for (i = 0; i < curve.length; i += 2) { 1923 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places); 1924 if (i < curve.length - 2) { 1925 str += "}, {"; 1926 } 1927 } 1928 str += "}}"; 1929 return str; 1930 } 1931 1932 function dumpCurve(curve) { 1933 console.log(curveToString(curve)); 1934 } 1935 1936 function draw(test, lines, title) { 1937 ctx.fillStyle = "rgba(0,0,0, 0.1)"; 1938 ctx.font = "normal 50px Arial"; 1939 ctx.textAlign = "left"; 1940 ctx.fillText(title, 50, 50); 1941 ctx.font = "normal 10px Arial"; 1942 ctx.lineWidth = "1.001"; "0.999"; 1943 var secondPath = test.length; 1944 var closeCount = 0; 1945 logStart = -1; 1946 logRange = 0; 1947 // find last active rec type at this step 1948 var curType = test[0]; 1949 var curStep = 0; 1950 var hasOp = false; 1951 var lastActive = 0; 1952 var lastAdd = 0; 1953 var lastSect = 0; 1954 var lastSort = 0; 1955 var lastMark = 0; 1956 activeCount = 0; 1957 addCount = 0; 1958 angleCount = 0; 1959 opCount = 0; 1960 sectCount = 0; 1961 sortCount = 0; 1962 markCount = 0; 1963 activeMax = 0; 1964 addMax = 0; 1965 angleMax = 0; 1966 opMax = 0; 1967 sectMax = 0; 1968 sectMax2 = 0; 1969 sortMax = 0; 1970 markMax = 0; 1971 lastIndex = test.length - 3; 1972 for (var tIndex = 0; tIndex < test.length; tIndex += 3) { 1973 var recType = test[tIndex]; 1974 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) { 1975 console.log("unknown rec type: " + recType); 1976 throw "stop execution"; 1977 } 1978 // if (curType == recType && curType != REC_TYPE_ADD) { 1979 // continue; 1980 // } 1981 var inStepRange = step_limit == 0 || curStep < step_limit; 1982 curType = recType; 1983 if (recType == REC_TYPE_OP) { 1984 hasOp = true; 1985 continue; 1986 } 1987 if (recType == REC_TYPE_UNKNOWN) { 1988 // these types do not advance step 1989 continue; 1990 } 1991 var bumpStep = false; 1992 var records = test[tIndex + 2]; 1993 var fragType = records[0]; 1994 if (recType == REC_TYPE_ADD) { 1995 if (records.length != 2) { 1996 console.log("expect only two elements: " + records.length); 1997 throw "stop execution"; 1998 } 1999 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) { 2000 continue; 2001 } 2002 ++addMax; 2003 if (!draw_add || !inStepRange) { 2004 continue; 2005 } 2006 lastAdd = tIndex; 2007 ++addCount; 2008 bumpStep = true; 2009 } 2010 if (recType == REC_TYPE_PATH && hasOp) { 2011 secondPath = tIndex; 2012 } 2013 if (recType == REC_TYPE_ACTIVE) { 2014 ++activeMax; 2015 if (!draw_active || !inStepRange) { 2016 continue; 2017 } 2018 lastActive = tIndex; 2019 ++activeCount; 2020 bumpStep = true; 2021 } 2022 if (recType == REC_TYPE_ACTIVE_OP) { 2023 ++opMax; 2024 if (!draw_op || !inStepRange) { 2025 continue; 2026 } 2027 lastOp = tIndex; 2028 ++opCount; 2029 bumpStep = true; 2030 } 2031 if (recType == REC_TYPE_ANGLE) { 2032 ++angleMax; 2033 if (!draw_angle || !inStepRange) { 2034 continue; 2035 } 2036 lastAngle = tIndex; 2037 ++angleCount; 2038 bumpStep = true; 2039 } 2040 if (recType == REC_TYPE_SECT) { 2041 if (records.length != 2) { 2042 console.log("expect only two elements: " + records.length); 2043 throw "stop execution"; 2044 } 2045 ++sectMax; 2046 var sectBump = 1; 2047 switch (fragType) { 2048 case INTERSECT_LINE: 2049 case INTERSECT_QUAD_LINE: 2050 case INTERSECT_QUAD: 2051 case INTERSECT_SELF_CUBIC: 2052 case INTERSECT_CUBIC_LINE: 2053 case INTERSECT_CUBIC_QUAD: 2054 case INTERSECT_CUBIC: 2055 sectBump = 1; 2056 break; 2057 case INTERSECT_LINE_2: 2058 case INTERSECT_QUAD_LINE_2: 2059 case INTERSECT_QUAD_2: 2060 case INTERSECT_CUBIC_LINE_2: 2061 case INTERSECT_CUBIC_QUAD_2: 2062 case INTERSECT_CUBIC_2: 2063 sectBump = 2; 2064 break; 2065 case INTERSECT_LINE_NO: 2066 case INTERSECT_QUAD_LINE_NO: 2067 case INTERSECT_QUAD_NO: 2068 case INTERSECT_SELF_CUBIC_NO: 2069 case INTERSECT_CUBIC_LINE_NO: 2070 case INTERSECT_CUBIC_QUAD_NO: 2071 case INTERSECT_CUBIC_NO: 2072 sectBump = 0; 2073 break; 2074 case INTERSECT_CUBIC_LINE_3: 2075 case INTERSECT_CUBIC_QUAD_3: 2076 case INTERSECT_CUBIC_3: 2077 sectBump = 3; 2078 break; 2079 case INTERSECT_CUBIC_QUAD_4: 2080 case INTERSECT_CUBIC_4: 2081 sectBump = 4; 2082 break; 2083 default: 2084 console.log("missing case " + records.length); 2085 throw "stop execution"; 2086 } 2087 sectMax2 += sectBump; 2088 if (draw_intersection <= 1 || !inStepRange) { 2089 continue; 2090 } 2091 lastSect = tIndex; 2092 sectCount += sectBump; 2093 bumpStep = true; 2094 } 2095 if (recType == REC_TYPE_SORT) { 2096 ++sortMax; 2097 if (!draw_sort || !inStepRange) { 2098 continue; 2099 } 2100 lastSort = tIndex; 2101 ++sortCount; 2102 bumpStep = true; 2103 } 2104 if (recType == REC_TYPE_MARK) { 2105 ++markMax; 2106 if (!draw_mark || !inStepRange) { 2107 continue; 2108 } 2109 lastMark = tIndex; 2110 ++markCount; 2111 bumpStep = true; 2112 } 2113 if (bumpStep) { 2114 lastIndex = tIndex; 2115 logStart = test[tIndex + 1]; 2116 logRange = records.length / 2; 2117 ++curStep; 2118 } 2119 } 2120 stepMax = (draw_add ? addMax : 0) 2121 + (draw_active ? activeMax : 0) 2122 + (draw_op ? opMax : 0) 2123 + (draw_angle ? angleMax : 0) 2124 + (draw_sort ? sortMax : 0) 2125 + (draw_mark ? markMax : 0) 2126 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0); 2127 if (stepMax == 0) { 2128 stepMax = addMax + activeMax + angleMax + opMax + sortMax + markMax; 2129 } 2130 drawnPts = []; 2131 drawnLines = []; 2132 drawnQuads = []; 2133 drawnCubics = []; 2134 focusXmin = focusYmin = Infinity; 2135 focusXmax = focusYmax = -Infinity; 2136 var pathIndex = 0; 2137 var opLetter = 'S'; 2138 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) { 2139 var recType = test[tIndex]; 2140 var records = test[tIndex + 2]; 2141 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 2142 var fragType = records[recordIndex]; 2143 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) { 2144 console.log("unknown in range frag type: " + fragType); 2145 throw "stop execution"; 2146 } 2147 var frags = records[recordIndex + 1]; 2148 focus_enabled = false; 2149 switch (recType) { 2150 case REC_TYPE_COMPUTED: 2151 if (draw_computed == 0) { 2152 continue; 2153 } 2154 ctx.lineWidth = 1; 2155 ctx.strokeStyle = pathIndex == 0 ? "black" : "red"; 2156 ctx.fillStyle = "blue"; 2157 var drawThis = false; 2158 switch (fragType) { 2159 case PATH_QUAD: 2160 if ((draw_computed & 5) == 1 || ((draw_computed & 4) != 0 2161 && (draw_computed & 1) == pathIndex)) { 2162 drawQuad(frags[0], frags[1], frags[2], frags[3], 2163 frags[4], frags[5]); 2164 drawThis = true; 2165 } 2166 break; 2167 case PATH_CUBIC: 2168 if ((draw_computed & 6) == 2 || ((draw_computed & 4) != 0 2169 && (draw_computed & 1) != pathIndex)) { 2170 drawCubic(frags[0], frags[1], frags[2], frags[3], 2171 frags[4], frags[5], frags[6], frags[7]); 2172 drawThis = true; 2173 } 2174 ++pathIndex; 2175 break; 2176 case COMPUTED_SET_1: 2177 pathIndex = 0; 2178 break; 2179 case COMPUTED_SET_2: 2180 pathIndex = 1; 2181 break; 2182 default: 2183 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType); 2184 throw "stop execution"; 2185 } 2186 if (!drawThis || collect_bounds) { 2187 break; 2188 } 2189 drawCurveSpecials(test, frags, fragType); 2190 break; 2191 case REC_TYPE_PATH: 2192 if (!draw_path) { 2193 continue; 2194 } 2195 var firstPath = tIndex < secondPath; 2196 if ((draw_path & (firstPath ? 1 : 2)) == 0) { 2197 continue; 2198 } 2199 ctx.lineWidth = 1; 2200 ctx.strokeStyle = firstPath ? "black" : "red"; 2201 ctx.fillStyle = "blue"; 2202 switch (fragType) { 2203 case PATH_LINE: 2204 drawLine(frags[0], frags[1], frags[2], frags[3]); 2205 break; 2206 case PATH_QUAD: 2207 drawQuad(frags[0], frags[1], frags[2], frags[3], 2208 frags[4], frags[5]); 2209 break; 2210 case PATH_CUBIC: 2211 drawCubic(frags[0], frags[1], frags[2], frags[3], 2212 frags[4], frags[5], frags[6], frags[7]); 2213 break; 2214 default: 2215 console.log("unknown REC_TYPE_PATH frag type: " + fragType); 2216 throw "stop execution"; 2217 } 2218 if (collect_bounds) { 2219 break; 2220 } 2221 drawCurveSpecials(test, frags, fragType); 2222 break; 2223 case REC_TYPE_OP: 2224 switch (fragType) { 2225 case OP_INTERSECT: opLetter = 'I'; break; 2226 case OP_DIFFERENCE: opLetter = 'D'; break; 2227 case OP_UNION: opLetter = 'U'; break; 2228 case OP_XOR: opLetter = 'X'; break; 2229 default: 2230 console.log("unknown REC_TYPE_OP frag type: " + fragType); 2231 throw "stop execution"; 2232 } 2233 break; 2234 case REC_TYPE_ACTIVE: 2235 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) { 2236 continue; 2237 } 2238 var x1 = frags[SPAN_X1]; 2239 var y1 = frags[SPAN_Y1]; 2240 var x2 = frags[SPAN_X2]; 2241 var y2 = frags[SPAN_Y2]; 2242 var x3, y3, x3, y4, t1, t2; 2243 ctx.lineWidth = 3; 2244 ctx.strokeStyle = "rgba(0,0,255, 0.3)"; 2245 focus_enabled = true; 2246 switch (fragType) { 2247 case ACTIVE_LINE_SPAN: 2248 t1 = frags[SPAN_L_T]; 2249 t2 = frags[SPAN_L_TEND]; 2250 drawLinePartial(x1, y1, x2, y2, t1, t2); 2251 if (draw_id) { 2252 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2); 2253 } 2254 break; 2255 case ACTIVE_QUAD_SPAN: 2256 x3 = frags[SPAN_X3]; 2257 y3 = frags[SPAN_Y3]; 2258 t1 = frags[SPAN_Q_T]; 2259 t2 = frags[SPAN_Q_TEND]; 2260 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2); 2261 if (draw_id) { 2262 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2); 2263 } 2264 break; 2265 case ACTIVE_CUBIC_SPAN: 2266 x3 = frags[SPAN_X3]; 2267 y3 = frags[SPAN_Y3]; 2268 x4 = frags[SPAN_X4]; 2269 y4 = frags[SPAN_Y4]; 2270 t1 = frags[SPAN_C_T]; 2271 t2 = frags[SPAN_C_TEND]; 2272 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2); 2273 if (draw_id) { 2274 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2); 2275 } 2276 break; 2277 default: 2278 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType); 2279 throw "stop execution"; 2280 } 2281 break; 2282 case REC_TYPE_ACTIVE_OP: 2283 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) { 2284 continue; 2285 } 2286 focus_enabled = true; 2287 ctx.lineWidth = 3; 2288 var activeSpan = frags[7] == "1"; 2289 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)"; 2290 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 2291 drawCurve(curve); 2292 if (draw_op > 1) { 2293 drawArc(curve, false, frags[3], frags[4]); 2294 drawArc(curve, true, frags[5], frags[6]); 2295 } 2296 break; 2297 case REC_TYPE_ADD: 2298 if (!draw_add) { 2299 continue; 2300 } 2301 ctx.lineWidth = 3; 2302 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)" 2303 : closeCount == 1 ? "rgba(0,127,0, 0.3)" 2304 : closeCount == 2 ? "rgba(0,127,127, 0.3)" 2305 : closeCount == 3 ? "rgba(127,127,0, 0.3)" 2306 : "rgba(127,0,127, 0.3)"; 2307 focus_enabled = true; 2308 switch (fragType) { 2309 case ADD_MOVETO: 2310 break; 2311 case ADD_LINETO: 2312 if (step_limit == 0 || tIndex >= lastAdd) { 2313 drawLine(frags[0], frags[1], frags[2], frags[3]); 2314 } 2315 break; 2316 case ADD_QUADTO: 2317 if (step_limit == 0 || tIndex >= lastAdd) { 2318 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]); 2319 } 2320 break; 2321 case ADD_CUBICTO: 2322 if (step_limit == 0 || tIndex >= lastAdd) { 2323 drawCubic(frags[0], frags[1], frags[2], frags[3], 2324 frags[4], frags[5], frags[6], frags[7]); 2325 } 2326 break; 2327 case ADD_CLOSE: 2328 ++closeCount; 2329 break; 2330 case ADD_FILL: 2331 break; 2332 default: 2333 console.log("unknown REC_TYPE_ADD frag type: " + fragType); 2334 throw "stop execution"; 2335 } 2336 break; 2337 case REC_TYPE_ANGLE: 2338 if (!draw_angle || (step_limit > 0 && tIndex < lastAngle)) { 2339 continue; 2340 } 2341 if (fragType != ANGLE_AFTER && fragType != ANGLE_AFTER2) { 2342 continue; 2343 } 2344 focus_enabled = true; 2345 ctx.lineWidth = 3; 2346 ctx.strokeStyle = "rgba(127,45,127, 0.3)"; 2347 var leftCurve, midCurve, rightCurve; 2348 if (fragType == ANGLE_AFTER) { 2349 leftCurve = curvePartialByID(test, frags[0], frags[3], frags[4]); 2350 midCurve = curvePartialByID(test, frags[5], frags[8], frags[9]); 2351 rightCurve = curvePartialByID(test, frags[10], frags[13], frags[14]); 2352 } else { 2353 leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]); 2354 midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]); 2355 rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]); 2356 } 2357 drawCurve(leftCurve); 2358 drawCurve(rightCurve); 2359 var inBetween = frags[fragType == ANGLE_AFTER ? 15 : 18] == "T"; 2360 ctx.strokeStyle = inBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)"; 2361 drawCurve(midCurve); 2362 if (draw_angle > 1) { 2363 drawOrder(leftCurve, 'L'); 2364 drawOrder(rightCurve, 'R'); 2365 } 2366 break; 2367 case REC_TYPE_SECT: 2368 if (!draw_intersection) { 2369 continue; 2370 } 2371 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) { 2372 continue; 2373 } 2374 // draw_intersection == 1 : show all 2375 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step 2376 // draw_intersection == 3 : step == 0 ? show all : show intersection #step 2377 ctx.lineWidth = 1; 2378 ctx.strokeStyle = "rgba(0,0,255, 0.3)"; 2379 ctx.fillStyle = "blue"; 2380 focus_enabled = true; 2381 var f = []; 2382 var c1s; 2383 var c1l; 2384 var c2s; 2385 var c2l; 2386 switch (fragType) { 2387 case INTERSECT_LINE: 2388 f.push(5, 6, 0, 7); 2389 c1s = 1; c1l = 4; c2s = 8; c2l = 4; 2390 break; 2391 case INTERSECT_LINE_2: 2392 f.push(5, 6, 0, 10); 2393 f.push(8, 9, 7, 15); 2394 c1s = 1; c1l = 4; c2s = 11; c2l = 4; 2395 break; 2396 case INTERSECT_LINE_NO: 2397 c1s = 0; c1l = 4; c2s = 4; c2l = 4; 2398 break; 2399 case INTERSECT_QUAD_LINE: 2400 f.push(7, 8, 0, 9); 2401 c1s = 1; c1l = 6; c2s = 10; c2l = 4; 2402 break; 2403 case INTERSECT_QUAD_LINE_2: 2404 f.push(7, 8, 0, 12); 2405 f.push(10, 11, 9, 17); 2406 c1s = 1; c1l = 6; c2s = 13; c2l = 4; 2407 break; 2408 case INTERSECT_QUAD_LINE_NO: 2409 c1s = 0; c1l = 6; c2s = 6; c2l = 4; 2410 break; 2411 case INTERSECT_QUAD: 2412 f.push(7, 8, 0, 9); 2413 c1s = 1; c1l = 6; c2s = 10; c2l = 6; 2414 break; 2415 case INTERSECT_QUAD_2: 2416 f.push(7, 8, 0, 12); 2417 f.push(10, 11, 9, 19); 2418 c1s = 1; c1l = 6; c2s = 13; c2l = 6; 2419 break; 2420 case INTERSECT_QUAD_NO: 2421 c1s = 0; c1l = 6; c2s = 6; c2l = 6; 2422 break; 2423 case INTERSECT_SELF_CUBIC: 2424 f.push(9, 10, 0, 11); 2425 c1s = 1; c1l = 8; c2s = 0; c2l = 0; 2426 break; 2427 case INTERSECT_SELF_CUBIC_NO: 2428 c1s = 0; c1l = 8; c2s = 0; c2l = 0; 2429 break; 2430 case INTERSECT_CUBIC_LINE: 2431 f.push(9, 10, 0, 11); 2432 c1s = 1; c1l = 8; c2s = 12; c2l = 4; 2433 break; 2434 case INTERSECT_CUBIC_LINE_2: 2435 f.push(9, 10, 0, 14); 2436 f.push(12, 13, 11, 19); 2437 c1s = 1; c1l = 8; c2s = 15; c2l = 4; 2438 break; 2439 case INTERSECT_CUBIC_LINE_3: 2440 f.push(9, 10, 0, 17); 2441 f.push(12, 13, 11, 22); 2442 f.push(15, 16, 14, 23); 2443 c1s = 1; c1l = 8; c2s = 18; c2l = 4; 2444 break; 2445 case INTERSECT_CUBIC_QUAD_NO: 2446 c1s = 0; c1l = 8; c2s = 8; c2l = 6; 2447 break; 2448 case INTERSECT_CUBIC_QUAD: 2449 f.push(9, 10, 0, 11); 2450 c1s = 1; c1l = 8; c2s = 12; c2l = 6; 2451 break; 2452 case INTERSECT_CUBIC_QUAD_2: 2453 f.push(9, 10, 0, 14); 2454 f.push(12, 13, 11, 21); 2455 c1s = 1; c1l = 8; c2s = 15; c2l = 6; 2456 break; 2457 case INTERSECT_CUBIC_QUAD_3: 2458 f.push(9, 10, 0, 17); 2459 f.push(12, 13, 11, 24); 2460 f.push(15, 16, 14, 25); 2461 c1s = 1; c1l = 8; c2s = 18; c2l = 6; 2462 break; 2463 case INTERSECT_CUBIC_QUAD_4: 2464 f.push(9, 10, 0, 20); 2465 f.push(12, 13, 11, 27); 2466 f.push(15, 16, 14, 28); 2467 f.push(18, 19, 17, 29); 2468 c1s = 1; c1l = 8; c2s = 21; c2l = 6; 2469 break; 2470 case INTERSECT_CUBIC_LINE_NO: 2471 c1s = 0; c1l = 8; c2s = 8; c2l = 4; 2472 break; 2473 case INTERSECT_CUBIC: 2474 f.push(9, 10, 0, 11); 2475 c1s = 1; c1l = 8; c2s = 12; c2l = 8; 2476 break; 2477 case INTERSECT_CUBIC_2: 2478 f.push(9, 10, 0, 14); 2479 f.push(12, 13, 11, 23); 2480 c1s = 1; c1l = 8; c2s = 15; c2l = 8; 2481 break; 2482 case INTERSECT_CUBIC_3: 2483 f.push(9, 10, 0, 17); 2484 f.push(12, 13, 11, 26); 2485 f.push(15, 16, 14, 27); 2486 c1s = 1; c1l = 8; c2s = 18; c2l = 8; 2487 break; 2488 case INTERSECT_CUBIC_4: 2489 f.push(9, 10, 0, 20); 2490 f.push(12, 13, 11, 29); 2491 f.push(15, 16, 14, 30); 2492 f.push(18, 19, 17, 31); 2493 c1s = 1; c1l = 8; c2s = 21; c2l = 8; 2494 break; 2495 case INTERSECT_CUBIC_NO: 2496 c1s = 0; c1l = 8; c2s = 8; c2l = 8; 2497 break; 2498 default: 2499 console.log("unknown REC_TYPE_SECT frag type: " + fragType); 2500 throw "stop execution"; 2501 } 2502 if (draw_intersection != 1) { 2503 var id = -1; 2504 var curve; 2505 switch (c1l) { 2506 case 4: 2507 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]); 2508 if (draw_id) { 2509 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]]; 2510 id = idByCurve(test, curve, PATH_LINE); 2511 } 2512 break; 2513 case 6: 2514 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 2515 frags[c1s + 4], frags[c1s + 5]); 2516 if (draw_id) { 2517 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 2518 frags[c1s + 4], frags[c1s + 5]]; 2519 id = idByCurve(test, curve, PATH_QUAD); 2520 } 2521 break; 2522 case 8: 2523 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 2524 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]); 2525 if (draw_id) { 2526 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 2527 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]]; 2528 id = idByCurve(test, curve, PATH_CUBIC); 2529 } 2530 break; 2531 } 2532 if (id >= 0) { 2533 drawID(curve, id); 2534 } 2535 id = -1; 2536 switch (c2l) { 2537 case 0: 2538 break; 2539 case 4: 2540 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]); 2541 if (draw_id) { 2542 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]]; 2543 id = idByCurve(test, curve, PATH_LINE); 2544 } 2545 break; 2546 case 6: 2547 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 2548 frags[c2s + 4], frags[c2s + 5]); 2549 if (draw_id) { 2550 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 2551 frags[c2s + 4], frags[c2s + 5]]; 2552 id = idByCurve(test, curve, PATH_QUAD); 2553 } 2554 break; 2555 case 8: 2556 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 2557 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]); 2558 if (draw_id) { 2559 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 2560 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]]; 2561 id = idByCurve(test, curve, PATH_CUBIC); 2562 } 2563 break; 2564 } 2565 if (id >= 0) { 2566 drawID(curve, id); 2567 } 2568 } 2569 if (collect_bounds) { 2570 break; 2571 } 2572 for (var idx = 0; idx < f.length; idx += 4) { 2573 if (draw_intersection != 3 || idx == lastSect - tIndex) { 2574 drawPoint(frags[f[idx]], frags[f[idx + 1]], true); 2575 } 2576 } 2577 if (!draw_intersectT) { 2578 break; 2579 } 2580 ctx.fillStyle = "red"; 2581 for (var idx = 0; idx < f.length; idx += 4) { 2582 if (draw_intersection != 3 || idx == lastSect - tIndex) { 2583 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]); 2584 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]); 2585 } 2586 } 2587 break; 2588 case REC_TYPE_SORT: 2589 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) { 2590 continue; 2591 } 2592 ctx.lineWidth = 3; 2593 ctx.strokeStyle = "rgba(127,127,0, 0.5)"; 2594 focus_enabled = true; 2595 switch (fragType) { 2596 case SORT_UNARY: 2597 case SORT_BINARY: 2598 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]); 2599 drawCurve(curve); 2600 break; 2601 default: 2602 console.log("unknown REC_TYPE_SORT frag type: " + fragType); 2603 throw "stop execution"; 2604 } 2605 break; 2606 case REC_TYPE_MARK: 2607 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) { 2608 continue; 2609 } 2610 ctx.lineWidth = 3; 2611 ctx.strokeStyle = fragType >= MARK_DONE_LINE ? 2612 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)"; 2613 focus_enabled = true; 2614 switch (fragType) { 2615 case MARK_LINE: 2616 case MARK_DONE_LINE: 2617 case MARK_UNSORTABLE_LINE: 2618 case MARK_SIMPLE_LINE: 2619 case MARK_SIMPLE_DONE_LINE: 2620 case MARK_DONE_UNARY_LINE: 2621 drawLinePartial(frags[1], frags[2], frags[3], frags[4], 2622 frags[5], frags[9]); 2623 if (draw_id) { 2624 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4], 2625 frags[5], frags[9]); 2626 } 2627 break; 2628 case MARK_QUAD: 2629 case MARK_DONE_QUAD: 2630 case MARK_UNSORTABLE_QUAD: 2631 case MARK_SIMPLE_QUAD: 2632 case MARK_SIMPLE_DONE_QUAD: 2633 case MARK_DONE_UNARY_QUAD: 2634 drawQuadPartial(frags[1], frags[2], frags[3], frags[4], 2635 frags[5], frags[6], frags[7], frags[11]); 2636 if (draw_id) { 2637 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4], 2638 frags[5], frags[6], frags[7], frags[11]); 2639 } 2640 break; 2641 case MARK_CUBIC: 2642 case MARK_DONE_CUBIC: 2643 case MARK_UNSORTABLE_CUBIC: 2644 case MARK_SIMPLE_CUBIC: 2645 case MARK_SIMPLE_DONE_CUBIC: 2646 case MARK_DONE_UNARY_CUBIC: 2647 drawCubicPartial(frags[1], frags[2], frags[3], frags[4], 2648 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]); 2649 if (draw_id) { 2650 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4], 2651 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]); 2652 } 2653 break; 2654 case MARK_ANGLE_LAST: 2655 // FIXME: ignored for now 2656 break; 2657 default: 2658 console.log("unknown REC_TYPE_MARK frag type: " + fragType); 2659 throw "stop execution"; 2660 } 2661 break; 2662 default: 2663 continue; 2664 } 2665 } 2666 switch (recType) { 2667 case REC_TYPE_SORT: 2668 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) { 2669 break; 2670 } 2671 var angles = []; // use tangent lines to describe arcs 2672 var windFrom = []; 2673 var windTo = []; 2674 var opp = []; 2675 var minXY = Number.MAX_VALUE; 2676 var partial; 2677 focus_enabled = true; 2678 var someUnsortable = false; 2679 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 2680 var fragType = records[recordIndex]; 2681 var frags = records[recordIndex + 1]; 2682 var unsortable = (fragType == SORT_UNARY && frags[14]) || 2683 (fragType == SORT_BINARY && frags[16]); 2684 someUnsortable |= unsortable; 2685 switch (fragType) { 2686 case SORT_UNARY: 2687 case SORT_BINARY: 2688 partial = curvePartialByID(test, frags[0], frags[6], frags[8]); 2689 break; 2690 default: 2691 console.log("unknown REC_TYPE_SORT frag type: " + fragType); 2692 throw "stop execution"; 2693 } 2694 var dx = boundsWidth(partial); 2695 var dy = boundsHeight(partial); 2696 minXY = Math.min(minXY, dx * dx + dy * dy); 2697 if (collect_bounds) { 2698 continue; 2699 } 2700 angles.push(tangent(partial)); 2701 var from = frags[12]; 2702 var to = frags[12]; 2703 var sgn = frags[10]; 2704 if (sgn < 0) { 2705 from -= frags[11]; 2706 } else if (sgn > 0) { 2707 to -= frags[11]; 2708 } 2709 windFrom.push(from + (unsortable ? "!" : "")); 2710 windTo.push(to + (unsortable ? "!" : "")); 2711 opp.push(fragType == SORT_BINARY); 2712 if (draw_sort == 1) { 2713 drawOrder(partial, frags[12]); 2714 } else { 2715 drawOrder(partial, (recordIndex / 2) + 1); 2716 } 2717 } 2718 var radius = Math.sqrt(minXY) / 2 * scale; 2719 radius = Math.min(50, radius); 2720 var scaledRadius = radius / scale; 2721 var centerX = partial[0]; 2722 var centerY = partial[1]; 2723 if (collect_bounds) { 2724 if (focus_enabled) { 2725 focusXmin = Math.min(focusXmin, centerX - scaledRadius); 2726 focusYmin = Math.min(focusYmin, centerY - scaledRadius); 2727 focusXmax = Math.max(focusXmax, centerX + scaledRadius); 2728 focusYmax = Math.max(focusYmax, centerY + scaledRadius); 2729 } 2730 break; 2731 } 2732 break; 2733 default: 2734 break; 2735 } 2736 } 2737 if (collect_bounds) { 2738 return; 2739 } 2740 if (draw_log && logStart >= 0) { 2741 ctx.font = "normal 10px Arial"; 2742 ctx.textAlign = "left"; 2743 ctx.beginPath(); 2744 var top = screenHeight - 20 - (logRange + 2) * 10; 2745 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10); 2746 ctx.fillStyle = "white"; 2747 ctx.fill(); 2748 ctx.fillStyle = "rgba(0,0,0, 0.5)"; 2749 if (logStart > 0) { 2750 ctx.fillText(lines[logStart - 1], 50, top + 8); 2751 } 2752 ctx.fillStyle = "black"; 2753 for (var idx = 0; idx < logRange; ++idx) { 2754 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx); 2755 } 2756 ctx.fillStyle = "rgba(0,0,0, 0.5)"; 2757 if (logStart + logRange < lines.length) { 2758 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange); 2759 } 2760 } 2761 if (draw_legend) { 2762 var pos = 0; 2763 var drawSomething = draw_add | draw_active | draw_sort | draw_mark; 2764 // drawBox(pos++, "yellow", "black", opLetter, true, ''); 2765 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey); 2766 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey); 2767 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey); 2768 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey); 2769 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey); 2770 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey); 2771 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey); 2772 drawBox(pos++, "black", "white", 2773 (new Array('P', 'P1', 'P2', 'P'))[draw_path], draw_path != 0, pathKey); 2774 drawBox(pos++, "rgba(0,63,0, 0.7)", "white", 2775 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed], 2776 draw_computed != 0, computedKey); 2777 drawBox(pos++, "green", "black", step_limit, drawSomething, ''); 2778 drawBox(pos++, "green", "black", stepMax, drawSomething, ''); 2779 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, ''); 2780 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, ''); 2781 if (curve_t) { 2782 drawCurveTControl(); 2783 } 2784 ctx.font = "normal 20px Arial"; 2785 ctx.fillStyle = "rgba(0,0,0, 0.3)"; 2786 ctx.textAlign = "right"; 2787 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5); 2788 } 2789 if (draw_hints) { 2790 ctx.font = "normal 10px Arial"; 2791 ctx.fillStyle = "rgba(0,0,0, 0.5)"; 2792 ctx.textAlign = "right"; 2793 var y = 4; 2794 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10); 2795 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10); 2796 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10); 2797 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10); 2798 ctx.fillText("hodo : " + hodoKey, screenWidth - 10, pos * 50 + y++ * 10); 2799 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10); 2800 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10); 2801 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10); 2802 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10); 2803 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10); 2804 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10); 2805 } 2806 } 2807 2808 function drawBox(y, backC, foreC, str, enable, label) { 2809 ctx.beginPath(); 2810 ctx.fillStyle = backC; 2811 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30); 2812 ctx.fill(); 2813 ctx.font = "normal 16px Arial"; 2814 ctx.fillStyle = foreC; 2815 ctx.textAlign = "center"; 2816 ctx.fillText(str, screenWidth - 20, y * 50 + 32); 2817 if (!enable) { 2818 ctx.fillStyle = "rgba(255,255,255, 0.5)"; 2819 ctx.fill(); 2820 } 2821 if (label != '') { 2822 ctx.font = "normal 9px Arial"; 2823 ctx.fillStyle = "black"; 2824 ctx.fillText(label, screenWidth - 47, y * 50 + 40); 2825 } 2826 } 2827 2828 function drawCurveTControl() { 2829 ctx.lineWidth = 2; 2830 ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 2831 ctx.beginPath(); 2832 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80); 2833 ctx.stroke(); 2834 var ty = 40 + curveT * (screenHeight - 80); 2835 ctx.beginPath(); 2836 ctx.moveTo(screenWidth - 80, ty); 2837 ctx.lineTo(screenWidth - 85, ty - 5); 2838 ctx.lineTo(screenWidth - 85, ty + 5); 2839 ctx.lineTo(screenWidth - 80, ty); 2840 ctx.fillStyle = "rgba(0,0,0, 0.6)"; 2841 ctx.fill(); 2842 var num = curveT.toFixed(decimal_places); 2843 ctx.font = "normal 10px Arial"; 2844 ctx.textAlign = "left"; 2845 ctx.fillText(num, screenWidth - 78, ty); 2846 } 2847 2848 function ptInTControl() { 2849 var e = window.event; 2850 var tgt = e.target || e.srcElement; 2851 var left = tgt.offsetLeft; 2852 var top = tgt.offsetTop; 2853 var x = (e.clientX - left); 2854 var y = (e.clientY - top); 2855 if (x < screenWidth - 80 || x > screenWidth - 50) { 2856 return false; 2857 } 2858 if (y < 40 || y > screenHeight - 80) { 2859 return false; 2860 } 2861 curveT = (y - 40) / (screenHeight - 120); 2862 if (curveT < 0 || curveT > 1) { 2863 throw "stop execution"; 2864 } 2865 return true; 2866 } 2867 2868 function drawTop() { 2869 if (tests[testIndex] == null) { 2870 var str = testDivs[testIndex].textContent; 2871 parse_all(str); 2872 var title = testDivs[testIndex].id.toString(); 2873 testTitles[testIndex] = title; 2874 } 2875 init(tests[testIndex]); 2876 redraw(); 2877 } 2878 2879 function redraw() { 2880 if (focus_on_selection) { 2881 collect_bounds = true; 2882 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]); 2883 collect_bounds = false; 2884 if (focusXmin < focusXmax && focusYmin < focusYmax) { 2885 setScale(focusXmin, focusXmax, focusYmin, focusYmax); 2886 } 2887 } 2888 ctx.beginPath(); 2889 ctx.fillStyle = "white"; 2890 ctx.rect(0, 0, screenWidth, screenHeight); 2891 ctx.fill(); 2892 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]); 2893 } 2894 2895 function dumpCurvePartial(test, id, t0, t1) { 2896 var curve = curveByID(test, id); 2897 var name = ["line", "quad", "cubic"][curve.length / 2 - 2]; 2898 console.log("id=" + id + " " + name + "=" + curveToString(curve) 2899 + " t0=" + t0 + " t1=" + t1 2900 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1))); 2901 } 2902 2903 function dumpAngleTest(test, id, t0, t1) { 2904 var curve = curveByID(test, id); 2905 console.log(" { {" + curveToString(curve) + "}, " 2906 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //"); 2907 } 2908 2909 function dumpLogToConsole() { 2910 if (logStart < 0) { 2911 return; 2912 } 2913 var test = tests[testIndex]; 2914 var recType = REC_TYPE_UNKNOWN; 2915 var records; 2916 for (var index = 0; index < test.length; index += 3) { 2917 var lastLineNo = test[index + 1]; 2918 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) { 2919 recType = test[index]; 2920 records = test[index + 2]; 2921 break; 2922 } 2923 } 2924 if (recType == REC_TYPE_UNKNOWN) { 2925 return; 2926 } 2927 var lines = testLines[testIndex]; 2928 for (var idx = 0; idx < logRange; ++idx) { 2929 var line = lines[logStart + idx]; 2930 console.log(line); 2931 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 2932 var fragType = records[recordIndex]; 2933 var frags = records[recordIndex + 1]; 2934 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) { 2935 dumpCurvePartial(test, frags[0], frags[3], frags[4]); 2936 dumpCurvePartial(test, frags[5], frags[8], frags[9]); 2937 dumpCurvePartial(test, frags[10], frags[13], frags[14]); 2938 console.log("\nstatic IntersectData intersectDataSet[] = {"); 2939 dumpAngleTest(test, frags[0], frags[3], frags[4]); 2940 dumpAngleTest(test, frags[5], frags[8], frags[9]); 2941 dumpAngleTest(test, frags[10], frags[13], frags[14]); 2942 console.log("};"); 2943 } else if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER2) { 2944 dumpCurvePartial(test, frags[0], frags[4], frags[5]); 2945 dumpCurvePartial(test, frags[6], frags[10], frags[11]); 2946 dumpCurvePartial(test, frags[12], frags[16], frags[17]); 2947 console.log("\nstatic IntersectData intersectDataSet[] = { //"); 2948 dumpAngleTest(test, frags[0], frags[4], frags[5]); 2949 dumpAngleTest(test, frags[6], frags[10], frags[11]); 2950 dumpAngleTest(test, frags[12], frags[16], frags[17]); 2951 console.log("}; //"); 2952 } 2953 } 2954 } 2955 } 2956 2957 var activeKey = 'a'; 2958 var pathKey = 'b'; 2959 var pathBackKey = 'B'; 2960 var centerKey = 'c'; 2961 var addKey = 'd'; 2962 var deriviativesKey = 'f'; 2963 var angleKey = 'g'; 2964 var angleBackKey = 'G'; 2965 var hodoKey = 'h'; 2966 var intersectionKey = 'i'; 2967 var intersectionBackKey = 'I'; 2968 var sequenceKey = 'j'; 2969 var midpointKey = 'k'; 2970 var logKey = 'l'; 2971 var logToConsoleKey = 'L'; 2972 var markKey = 'm'; 2973 var sortKey = 'o'; 2974 var opKey = 'p'; 2975 var opBackKey = 'P'; 2976 var computedKey = 'q'; 2977 var computedBackKey = 'Q'; 2978 var stepKey = 's'; 2979 var stepBackKey = 'S'; 2980 var intersectTKey = 't'; 2981 var curveTKey = 'u'; 2982 var controlLinesBackKey = 'V'; 2983 var controlLinesKey = 'v'; 2984 var ptsKey = 'x'; 2985 var xyKey = 'y'; 2986 var logCurvesKey = 'z'; 2987 var focusKey = '`'; 2988 var idKey = '.'; 2989 var retinaKey = '\\'; 2990 2991 function doKeyPress(evt) { 2992 var char = String.fromCharCode(evt.charCode); 2993 var focusWasOn = false; 2994 switch (char) { 2995 case '0': 2996 case '1': 2997 case '2': 2998 case '3': 2999 case '4': 3000 case '5': 3001 case '6': 3002 case '7': 3003 case '8': 3004 case '9': 3005 decimal_places = char - '0'; 3006 redraw(); 3007 break; 3008 case activeKey: 3009 draw_active ^= true; 3010 redraw(); 3011 break; 3012 case addKey: 3013 draw_add ^= true; 3014 redraw(); 3015 break; 3016 case angleKey: 3017 draw_angle = (draw_angle + 1) % 3; 3018 redraw(); 3019 break; 3020 case angleBackKey: 3021 draw_angle = (draw_angle + 2) % 3; 3022 redraw(); 3023 break; 3024 case centerKey: 3025 setScale(xmin, xmax, ymin, ymax); 3026 redraw(); 3027 break; 3028 case controlLinesBackKey: 3029 control_lines = (control_lines + 3) % 4; 3030 redraw(); 3031 break; 3032 case controlLinesKey: 3033 control_lines = (control_lines + 1) % 4; 3034 redraw(); 3035 break; 3036 case computedBackKey: 3037 draw_computed = (draw_computed + 5) % 6; 3038 redraw(); 3039 break; 3040 case computedKey: 3041 draw_computed = (draw_computed + 1) % 6; 3042 redraw(); 3043 break; 3044 case curveTKey: 3045 curve_t ^= true; 3046 if (curve_t) { 3047 draw_legend = true; 3048 } 3049 redraw(); 3050 break; 3051 case deriviativesKey: 3052 draw_deriviatives = (draw_deriviatives + 1) % 3; 3053 redraw(); 3054 break; 3055 case focusKey: 3056 focus_on_selection ^= true; 3057 setScale(xmin, xmax, ymin, ymax); 3058 redraw(); 3059 break; 3060 case hodoKey: 3061 draw_hodo = (draw_hodo + 1) % 4; 3062 redraw(); 3063 break; 3064 case idKey: 3065 draw_id ^= true; 3066 redraw(); 3067 break; 3068 case intersectionBackKey: 3069 draw_intersection = (draw_intersection + 3) % 4; 3070 redraw(); 3071 break; 3072 case intersectionKey: 3073 draw_intersection = (draw_intersection + 1) % 4; 3074 redraw(); 3075 break; 3076 case intersectTKey: 3077 draw_intersectT ^= true; 3078 redraw(); 3079 break; 3080 case logCurvesKey: 3081 logCurves(tests[testIndex]); 3082 break; 3083 case logKey: 3084 draw_log ^= true; 3085 redraw(); 3086 break; 3087 case logToConsoleKey: 3088 if (draw_log) { 3089 dumpLogToConsole(); 3090 } 3091 break; 3092 case markKey: 3093 draw_mark ^= true; 3094 redraw(); 3095 break; 3096 case midpointKey: 3097 draw_midpoint ^= true; 3098 redraw(); 3099 break; 3100 case opKey: 3101 draw_op = (draw_op + 1) % 3; 3102 redraw(); 3103 break; 3104 case opBackKey: 3105 draw_op = (draw_op + 2) % 3; 3106 redraw(); 3107 break; 3108 case pathKey: 3109 draw_path = (draw_path + 1) % 4; 3110 redraw(); 3111 break; 3112 case pathBackKey: 3113 draw_path = (draw_path + 3) % 4; 3114 redraw(); 3115 break; 3116 case ptsKey: 3117 pt_labels = (pt_labels + 1) % 3; 3118 redraw(); 3119 break; 3120 case retinaKey: 3121 retina_scale ^= true; 3122 drawTop(); 3123 break; 3124 case sequenceKey: 3125 draw_sequence ^= true; 3126 redraw(); 3127 break; 3128 case sortKey: 3129 draw_sort = (draw_sort + 1) % 3; 3130 drawTop(); 3131 break; 3132 case stepKey: 3133 step_limit++; 3134 if (step_limit > stepMax) { 3135 step_limit = stepMax; 3136 } 3137 redraw(); 3138 break; 3139 case stepBackKey: 3140 step_limit--; 3141 if (step_limit < 0) { 3142 step_limit = 0; 3143 } 3144 redraw(); 3145 break; 3146 case xyKey: 3147 debug_xy = (debug_xy + 1) % 3; 3148 redraw(); 3149 break; 3150 case '-': 3151 focusWasOn = focus_on_selection; 3152 if (focusWasOn) { 3153 focus_on_selection = false; 3154 scale /= 1.2; 3155 } else { 3156 scale /= 2; 3157 calcLeftTop(); 3158 } 3159 redraw(); 3160 focus_on_selection = focusWasOn; 3161 break; 3162 case '=': 3163 case '+': 3164 focusWasOn = focus_on_selection; 3165 if (focusWasOn) { 3166 focus_on_selection = false; 3167 scale *= 1.2; 3168 } else { 3169 scale *= 2; 3170 calcLeftTop(); 3171 } 3172 redraw(); 3173 focus_on_selection = focusWasOn; 3174 break; 3175 case '?': 3176 draw_hints ^= true; 3177 if (draw_hints && !draw_legend) { 3178 draw_legend = true; 3179 } 3180 redraw(); 3181 break; 3182 case '/': 3183 draw_legend ^= true; 3184 redraw(); 3185 break; 3186 } 3187 } 3188 3189 function doKeyDown(evt) { 3190 var char = evt.keyCode; 3191 var preventDefault = false; 3192 switch (char) { 3193 case 37: // left arrow 3194 if (evt.shiftKey) { 3195 testIndex -= 9; 3196 } 3197 if (--testIndex < 0) 3198 testIndex = tests.length - 1; 3199 drawTop(); 3200 preventDefault = true; 3201 break; 3202 case 39: // right arrow 3203 if (evt.shiftKey) { 3204 testIndex += 9; 3205 } 3206 if (++testIndex >= tests.length) 3207 testIndex = 0; 3208 drawTop(); 3209 preventDefault = true; 3210 break; 3211 } 3212 if (preventDefault) { 3213 evt.preventDefault(); 3214 return false; 3215 } 3216 return true; 3217 } 3218 3219 (function() { 3220 var hidden = "hidden"; 3221 3222 // Standards: 3223 if (hidden in document) 3224 document.addEventListener("visibilitychange", onchange); 3225 else if ((hidden = "mozHidden") in document) 3226 document.addEventListener("mozvisibilitychange", onchange); 3227 else if ((hidden = "webkitHidden") in document) 3228 document.addEventListener("webkitvisibilitychange", onchange); 3229 else if ((hidden = "msHidden") in document) 3230 document.addEventListener("msvisibilitychange", onchange); 3231 // IE 9 and lower: 3232 else if ('onfocusin' in document) 3233 document.onfocusin = document.onfocusout = onchange; 3234 // All others: 3235 else 3236 window.onpageshow = window.onpagehide 3237 = window.onfocus = window.onblur = onchange; 3238 3239 function onchange (evt) { 3240 var v = 'visible', h = 'hidden', 3241 evtMap = { 3242 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h 3243 }; 3244 3245 evt = evt || window.event; 3246 if (evt.type in evtMap) 3247 document.body.className = evtMap[evt.type]; 3248 else 3249 document.body.className = this[hidden] ? "hidden" : "visible"; 3250 } 3251 })(); 3252 3253 function calcXY() { 3254 var e = window.event; 3255 var tgt = e.target || e.srcElement; 3256 var left = tgt.offsetLeft; 3257 var top = tgt.offsetTop; 3258 mouseX = (e.clientX - left) / scale + srcLeft; 3259 mouseY = (e.clientY - top) / scale + srcTop; 3260 } 3261 3262 function calcLeftTop() { 3263 srcLeft = mouseX - screenWidth / 2 / scale; 3264 srcTop = mouseY - screenHeight / 2 / scale; 3265 } 3266 3267 var disableClick = false; 3268 3269 function handleMouseClick() { 3270 if (disableClick) { 3271 return; 3272 } 3273 if (!curve_t || !ptInTControl()) { 3274 calcXY(); 3275 calcLeftTop(); 3276 } 3277 redraw(); 3278 // if (!curve_t || !ptInTControl()) { 3279 // mouseX = screenWidth / 2 / scale + srcLeft; 3280 // mouseY = screenHeight / 2 / scale + srcTop; 3281 // } 3282 } 3283 3284 function handleMouseOver() { 3285 calcXY(); 3286 if (debug_xy != 2) { 3287 return; 3288 } 3289 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places); 3290 ctx.beginPath(); 3291 ctx.rect(300,100,num.length * 6,10); 3292 ctx.fillStyle="white"; 3293 ctx.fill(); 3294 ctx.font = "normal 10px Arial"; 3295 ctx.fillStyle="black"; 3296 ctx.textAlign = "left"; 3297 ctx.fillText(num, 300, 108); 3298 } 3299 3300 function start() { 3301 for (var i = 0; i < testDivs.length; ++i) { 3302 tests[i] = null; 3303 } 3304 testIndex = 0; 3305 drawTop(); 3306 window.addEventListener('keypress', doKeyPress, true); 3307 window.addEventListener('keydown', doKeyDown, true); 3308 window.onresize = function() { 3309 drawTop(); 3310 } 3311 /* 3312 window.onpagehide = function() { 3313 disableClick = true; 3314 } 3315 */ 3316 window.onpageshow = function () { 3317 disableClick = false; 3318 } 3319 } 3320 3321 </script> 3322 </head> 3323 3324 <body onLoad="start();"> 3325 <canvas id="canvas" width="750" height="500" 3326 onmousemove="handleMouseOver()" 3327 onclick="handleMouseClick()" 3328 ></canvas > 3329 </body> 3330 </html> 3331