Home | History | Annotate | Download | only in tools
      1 <html>
      2 <head>
      3 <div height="0" hidden="true">
      4 <div id="bug8380">
      5 SkDCubic::ComplexBreak
      6 {{{126, 9.396100044250488281}, {125.6320571899414063, 9.295844078063964844}, {125.1227340698242188, 9.337338447570800781}, {124.6031646728515625, 9.379667282104492188}}},
      7 inflectionsTs[0]=0.999997776 {{{126.1618761931709827, 9.252680507258252973}, {123.04446008475567, 9.506653492188940291}}},
      8 SkDCubic::ComplexBreak
      9 {{{124.6031646728515625, 9.379667282104492188}, {124.1427383422851563, 9.417178153991699219}, {123.6742630004882813, 9.45534515380859375}, {123.28900146484375, 9.396100044250488281}}},
     10 inflectionsTs[0]=4.14921088e-06 {{{125.984438133710114, 9.267135117035042668}, {123.2218797495565639, 9.492200381017113386}}},
     11 maxCurvature[0]=0.0817322831 {{{125.8735553329735666, 9.277935394706121386}, {123.1067608854740314, 9.499713475347833835}}},
     12 SkDCubic::ComplexBreak
     13 {{{126, 9.396200180053710938}, {125.305999755859375, 9.206999778747558594}, {124.1090011596679688, 9.522199630737304688}, {123.28900146484375, 9.396200180053710938}}},
     14 inflectionsTs[0]=0.530286644 {{{127.5428560571536707, 9.140180090182106198}, {121.6628069847287179, 9.619260454379688241}}},
     15 maxCurvature[0]=0.568563182 {{{127.4346914043237859, 9.15278490094694952}, {121.5456828946143446, 9.624913158409162506}}},
     16 seg=1 {{{0, 353.891998f}, {126, 9.39610004f}}}
     17 seg=2 {{{126, 9.39610004f}, {125.632057f, 9.29584408f}, {125.122734f, 9.33733845f}, {124.603165f, 9.37966728f}}}
     18 seg=3 {{{124.603165f, 9.37966728f}, {124.142731f, 9.41717815f}, {123.674263f, 9.45534515f}, {123.289001f, 9.39610004f}}}
     19 seg=4 {{{123.289001f, 9.39610004f}, {118.119003f, 8.07219982f}}}
     20 seg=5 {{{118.119003f, 8.07219982f}, {8.17210007f, 104.212997f}}}
     21 seg=6 {{{8.17210007f, 104.212997f}, {0, 259.298737f}}}
     22 seg=7 {{{0, 259.298737f}, {0, 353.891998f}}}
     23 op sect
     24 seg=8 {{{8.17210007f, 104.212997f}, {-5.82350016f, 369.813995f}}}
     25 seg=9 {{{-5.82350016f, 369.813995f}, {126, 9.39620018f}}}
     26 seg=10 {{{126, 9.39620018f}, {125.631981f, 9.29586983f}, {125.12252f, 9.3373785f}, {124.602829f, 9.37972069f}}}
     27 seg=11 {{{124.602829f, 9.37972069f}, {124.142509f, 9.41722488f}, {123.674164f, 9.45538425f}, {123.289001f, 9.39620018f}}}
     28 seg=12 {{{123.289001f, 9.39620018f}, {118.119003f, 8.07219982f}}}
     29 seg=13 {{{118.119003f, 8.07219982f}, {8.17210007f, 104.212997f}}}
     30 debugShowLineIntersection wtTs[0]=1 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{-5.82350016,369.813995}} wnTs[0]=0 {{{-5.82350016,369.813995}, {126,9.39620018}}}
     31 debugShowLineIntersection wtTs[0]=0 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{8.17210007,104.212997}} wnTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
     32 debugShowCubicLineIntersection wtTs[0]=0 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{126,9.39620018}} wnTs[0]=1 {{{-5.82350016,369.813995}, {126,9.39620018}}}
     33 debugShowCubicLineIntersection no intersect {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{{-5.82350016,369.813995}, {126,9.39620018}}}
     34 debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{123.289001,9.39620018}, {118.119003,8.07219982}}}
     35 debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
     36 debugShowCubicIntersection wtTs[0]=1 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{124.602829,9.37972069}} wnTs[0]=0 {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}}
     37 debugShowCubicLineIntersection wtTs[0]=1 {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{123.289001,9.39620018}} wnTs[0]=0 {{{123.289001,9.39620018}, {118.119003,8.07219982}}}
     38 debugShowLineIntersection wtTs[0]=1 {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{118.119003,8.07219982}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
     39 debugShowLineIntersection no intersect {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{{0,353.891998}, {126,9.39610004}}}
     40 debugShowLineIntersection wtTs[0]=0 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{8.17210007,104.212997}} wnTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
     41 debugShowLineIntersection wtTs[0]=0 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{8.17210007,104.212997}} wtTs[1]=0.583904956 {{0,259.298737}} wnTs[0]=0 {{{8.17210007,104.212997}, {0,259.298737}}} wnTs[1]=1
     42 SkOpSegment::addT insert t=0.583904956 segID=8 spanID=27
     43 debugShowLineIntersection wtTs[0]=0.583904956 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{0,259.298737}} wnTs[0]=0 {{{0,259.298737}, {0,353.891998}}}
     44 debugShowLineIntersection wtTs[0]=0.0441765002 {{{-5.82350016,369.813995}, {126,9.39620018}}} {{0,353.891998}} wtTs[1]=1 {{126,9.39620018}} wnTs[0]=0 {{{0,353.891998}, {126,9.39610004}}} wnTs[1]=0.999999744
     45 SkOpSegment::addT insert t=0.0441765002 segID=9 spanID=28
     46 debugShowCubicLineIntersection no intersect {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{{-5.82350016,369.813995}, {126,9.39620018}}}
     47 debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
     48 debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{8.17210007,104.212997}, {0,259.298737}}}
     49 debugShowLineIntersection wtTs[0]=0.0441765002 {{{-5.82350016,369.813995}, {126,9.39620018}}} {{0,353.891998}} wnTs[0]=1 {{{0,259.298737}, {0,353.891998}}}
     50 debugShowCubicLineIntersection wtTs[0]=0 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{126,9.39620018}} wnTs[0]=1 {{{0,353.891998}, {126,9.39610004}}}
     51 -1=(0.375,0.5) [-1]
     52 SkTSect::addForPerp addBounded span=-1 opp=-1
     53 -1=(0.5,0.625) [-1]
     54 SkTSect::addForPerp addBounded span=-1 opp=-1
     55 -1=(0.625,0.75) [-1]
     56 SkTSect::addForPerp addBounded span=-1 opp=-1
     57 -1=(0.75,0.8125) [-1]
     58 SkTSect::addForPerp addBounded span=-1 opp=-1
     59 -1=(0.8125,0.875) [-1]
     60 SkTSect::addForPerp addBounded span=-1 opp=-1
     61 -1=(0.875,0.9375) [-1]
     62 SkTSect::addForPerp addBounded span=-1 opp=-1
     63 SkTSect::addForPerp priorSpan=-1 t=0.937702598 opp=-1
     64 -1=(0.9375,1) []
     65 SkTSect::addForPerp addBounded span=-1 opp=-1
     66 debugShowCubicIntersection wtTs[0]=0.307128906 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{125.624687,9.33981037}} wtTs[1]=0.9375 {{124.700119,9.37182617}} wnTs[0]=0.307191 {{{126,9.39610004}, {125.632057,9.29584408}, {125.122734,9.33733845}, {124.603165,9.37966728}}} wnTs[1]=0.937702598
     67 SkOpSegment::addT insert t=0.307128906 segID=10 spanID=29
     68 SkOpSegment::addT insert t=0.307190555 segID=2 spanID=30
     69 SkOpSegment::addT insert t=0.9375 segID=10 spanID=31
     70 SkOpSegment::addT insert t=0.937702598 segID=2 spanID=32
     71 debugShowCubicIntersection no intersect {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}}
     72 debugShowCubicLineIntersection no intersect {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{{0,353.891998}, {126,9.39610004}}}
     73 -1=(0.125,0.1875) [-1]
     74 SkTSect::addForPerp addBounded span=-1 opp=-1
     75 -1=(0.1875,0.25) [-1]
     76 SkTSect::addForPerp addBounded span=-1 opp=-1
     77 -1=(0.25,0.375) [-1]
     78 SkTSect::addForPerp addBounded span=-1 opp=-1
     79 -1=(0.375,0.5) [-1]
     80 SkTSect::addForPerp addBounded span=-1 opp=-1
     81 -1=(0.5,0.625) [-1]
     82 SkTSect::addForPerp addBounded span=-1 opp=-1
     83 -1=(0.625,0.75) [-1]
     84 SkTSect::addForPerp addBounded span=-1 opp=-1
     85 debugShowCubicIntersection wtTs[0]=0.0625 {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{124.516449,9.38673687}} wtTs[1]=0.625 {{123.752594,9.4268837}} wnTs[0]=0.0627287 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} wnTs[1]=0.625091708
     86 SkOpSegment::addT insert t=0.0625 segID=11 spanID=33
     87 SkOpSegment::addT insert t=0.0627286673 segID=3 spanID=34
     88 SkOpSegment::addT insert t=0.625 segID=11 spanID=35
     89 SkOpSegment::addT insert t=0.625091708 segID=3 spanID=36
     90 debugShowCubicLineIntersection no intersect {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{{123.289001,9.39610004}, {118.119003,8.07219982}}}
     91 debugShowLineIntersection no intersect {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{{0,353.891998}, {126,9.39610004}}}
     92 debugShowCubicLineIntersection wtTs[0]=0.999978653 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{123.289001,9.39620018}} wnTs[0]=0 {{{123.289001,9.39620018}, {118.119003,8.07219982}}}
     93 debugShowLineIntersection wtTs[0]=4.65488731e-06 {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{123.289001,9.39610004}} wtTs[1]=1 {{118.119003,8.07219982}} wnTs[0]=0 {{{123.289001,9.39610004}, {118.119003,8.07219982}}} wnTs[1]=1
     94 debugShowLineIntersection wtTs[0]=1 {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{118.119003,8.07219982}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
     95 debugShowLineIntersection no intersect {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{{0,353.891998}, {126,9.39610004}}}
     96 debugShowLineIntersection wtTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{118.119003,8.07219982}} wnTs[0]=1 {{{123.289001,9.39610004}, {118.119003,8.07219982}}}
     97 debugShowLineIntersection wtTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{118.119003,8.07219982}} wtTs[1]=1 {{8.17210007,104.212997}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} wnTs[1]=1
     98 debugShowLineIntersection wtTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{8.17210007,104.212997}} wnTs[0]=0 {{{8.17210007,104.212997}, {0,259.298737}}}
     99 debugShowCubicLineIntersection wtTs[0]=0 {{{126,9.39610004}, {125.632057,9.29584408}, {125.122734,9.33733845}, {124.603165,9.37966728}}} {{126,9.39610004}} wnTs[0]=1 {{{0,353.891998}, {126,9.39610004}}}
    100 debugShowCubicLineIntersection no intersect {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{{0,353.891998}, {126,9.39610004}}}
    101 debugShowLineIntersection no intersect {{{0,353.891998}, {126,9.39610004}}} {{{123.289001,9.39610004}, {118.119003,8.07219982}}}
    102 debugShowLineIntersection no intersect {{{0,353.891998}, {126,9.39610004}}} {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
    103 debugShowLineIntersection no intersect {{{0,353.891998}, {126,9.39610004}}} {{{8.17210007,104.212997}, {0,259.298737}}}
    104 debugShowLineIntersection wtTs[0]=0 {{{0,353.891998}, {126,9.39610004}}} {{0,353.891998}} wnTs[0]=1 {{{0,259.298737}, {0,353.891998}}}
    105 debugShowCubicIntersection wtTs[0]=1 {{{126,9.39610004}, {125.632057,9.29584408}, {125.122734,9.33733845}, {124.603165,9.37966728}}} {{124.603165,9.37966728}} wnTs[0]=0 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}}
    106 debugShowCubicLineIntersection wtTs[0]=1 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{123.289001,9.39610004}} wnTs[0]=0 {{{123.289001,9.39610004}, {118.119003,8.07219982}}}
    107 debugShowLineIntersection wtTs[0]=1 {{{123.289001,9.39610004}, {118.119003,8.07219982}}} {{118.119003,8.07219982}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}
    108 debugShowLineIntersection wtTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{8.17210007,104.212997}} wnTs[0]=0 {{{8.17210007,104.212997}, {0,259.298737}}}
    109 debugShowLineIntersection wtTs[0]=1 {{{8.17210007,104.212997}, {0,259.298737}}} {{0,259.298737}} wnTs[0]=0 {{{0,259.298737}, {0,353.891998}}}
    110 ----------------x-x--x-x-------------- addExpanded
    111 00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    112 01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    113 02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    114 03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    115 04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    116 05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    117 06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    118 07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    119 08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    120 09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    121 10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin
    122 11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin
    123 12:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    124 13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    125 14:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    126 15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    127 16:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    128 17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd
    129 18:  seg/base=2/30 seg/base=10/29 MarkCoinStart
    130 19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    131 20:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    132 21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    133 22:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    134 23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    135 SkOpSegment::debugShowActiveSpans id=8 (8.17210007,104.212997 -2.71619996e-07,259.298737) t=0 tEnd=0.583904956 windSum=? windValue=1
    136 SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=? windValue=1
    137 SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=? windValue=1
    138 SkOpSegment::debugShowActiveSpans id=9 (7.26031715e-07,353.891998 126,9.39620018) t=0.0441765002 tEnd=1 windSum=? windValue=1
    139 SkOpSegment::debugShowActiveSpans id=10 (126,9.39620018 125.886971,9.36538583 125.760599,9.34795095 125.624687,9.33981037) t=0 tEnd=0.307128906 windSum=? windValue=1
    140 SkOpSegment::debugShowActiveSpans id=10 (125.624687,9.33981037 125.345733,9.32310212 125.026588,9.34554777 124.700119,9.37182617) t=0.307128906 tEnd=0.9375 windSum=? windValue=1
    141 SkOpSegment::debugShowActiveSpans id=10 (124.700119,9.37182617 124.66775,9.37443162 124.63531,9.3770743 124.602829,9.37972069) t=0.9375 tEnd=1 windSum=? windValue=1
    142 SkOpSegment::debugShowActiveSpans id=11 (124.602829,9.37972069 124.574059,9.3820647 124.545259,9.38441166 124.516449,9.38673687) t=0 tEnd=0.0625 windSum=? windValue=1
    143 SkOpSegment::debugShowActiveSpans id=11 (124.516449,9.38673687 124.257155,9.40766372 123.997126,9.42685982 123.752594,9.4268837) t=0.0625 tEnd=0.625 windSum=? windValue=1
    144 SkOpSegment::debugShowActiveSpans id=11 (123.752594,9.4268837 123.589573,9.42689962 123.433437,9.41839421 123.289001,9.39620018) t=0.625 tEnd=1 windSum=? windValue=1
    145 SkOpSegment::debugShowActiveSpans id=12 (123.289001,9.39620018 118.119003,8.07219982) t=0 tEnd=1 windSum=? windValue=1
    146 SkOpSegment::debugShowActiveSpans id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 tEnd=1 windSum=? windValue=1
    147 SkOpSegment::debugShowActiveSpans id=1 (0,353.891998 126,9.39610004) t=0 tEnd=1 windSum=? windValue=1
    148 SkOpSegment::debugShowActiveSpans id=2 (126,9.39610004 125.886971,9.36530236 125.760605,9.34788101 125.624695,9.33975124) t=0 tEnd=0.307190555 windSum=? windValue=1
    149 SkOpSegment::debugShowActiveSpans id=2 (125.624695,9.33975124 125.345738,9.3230648 125.026588,9.34552196 124.700119,9.37180042) t=0.307190555 tEnd=0.937702598 windSum=? windValue=1
    150 SkOpSegment::debugShowActiveSpans id=2 (124.700119,9.37180042 124.667862,9.37439685 124.635532,9.37703031 124.603165,9.37966728) t=0.937702598 tEnd=1 windSum=? windValue=1
    151 SkOpSegment::debugShowActiveSpans id=3 (124.603165,9.37966728 124.574282,9.38202029 124.545364,9.3843762 124.516441,9.38671017) t=0 tEnd=0.0627286673 windSum=? windValue=1
    152 SkOpSegment::debugShowActiveSpans id=3 (124.516441,9.38671017 124.257145,9.40763418 123.997124,9.42681973 123.752594,9.42682648) t=0.0627286673 tEnd=0.625091708 windSum=? windValue=1
    153 SkOpSegment::debugShowActiveSpans id=3 (123.752594,9.42682648 123.589574,9.42683098 123.433439,9.41831153 123.289001,9.39610004) t=0.625091708 tEnd=1 windSum=? windValue=1
    154 SkOpSegment::debugShowActiveSpans id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 tEnd=1 windSum=? windValue=1
    155 SkOpSegment::debugShowActiveSpans id=5 (118.119003,8.07219982 8.17210007,104.212997) t=0 tEnd=1 windSum=? windValue=1
    156 SkOpSegment::debugShowActiveSpans id=6 (8.17210007,104.212997 0,259.298737) t=0 tEnd=1 windSum=? windValue=1
    157 SkOpSegment::debugShowActiveSpans id=7 (0,259.298737 0,353.891998) t=0 tEnd=1 windSum=? windValue=1
    158 ----------------x-x--x-x-------------- move_multiples
    159 00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    160 01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    161 02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    162 03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    163 04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    164 05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    165 06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    166 07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    167 08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    168 09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    169 10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin
    170 11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin
    171 12:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    172 13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    173 14:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    174 15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    175 16:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    176 17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd
    177 18:  seg/base=2/30 seg/base=10/29 MarkCoinStart
    178 19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    179 20:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    180 21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    181 22:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    182 23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    183 ----------------x-x--x-x-------------- move_nearby
    184 00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    185 01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    186 02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    187 03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    188 04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    189 05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    190 06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    191 07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    192 08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    193 09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    194 10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin
    195 11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin
    196 12:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    197 13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    198 14:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    199 15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    200 16:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    201 17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd
    202 18:  seg/base=2/30 seg/base=10/29 MarkCoinStart
    203 19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    204 20:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    205 21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    206 22:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    207 23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    208 ----------------x-x--x-x-------------- correctEnds
    209 00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    210 01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    211 02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    212 03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    213 04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    214 05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    215 06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    216 07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    217 08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    218 09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    219 10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin
    220 11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin
    221 12:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    222 13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    223 14:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    224 15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    225 16:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    226 17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd
    227 18:  seg/base=2/30 seg/base=10/29 MarkCoinStart
    228 19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    229 20:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    230 21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    231 22:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    232 23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    233 ----------------x-x--x-x-------------- addEndMovedSpans
    234 00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    235 01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    236 02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    237 03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    238 04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    239 05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    240 06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    241 07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    242 08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    243 09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    244 10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin
    245 11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin
    246 12:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    247 13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    248 14:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    249 15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    250 16:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    251 17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd
    252 18:  seg/base=2/30 seg/base=10/29 MarkCoinStart
    253 19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    254 20:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    255 21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    256 22:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    257 23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    258 ----------------x-x--x-x-------------- expand
    259 00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    260 01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    261 02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    262 03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin
    263 04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin
    264 05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    265 06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    266 07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    267 08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin
    268 09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin
    269 10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin
    270 11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin
    271 12:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    272 13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    273 14:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    274 15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    275 16:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    276 17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd
    277 18:  seg/base=2/30 seg/base=10/29 MarkCoinStart
    278 19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    279 20:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    280 21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    281 22:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    282 23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    283 ------------------xx-x-x-------------- addExpanded
    284 00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    285 01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    286 02:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    287 03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    288 04:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    289 05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    290 06:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    291 07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd
    292 08:  seg/base=3/36 MarkCoinInsert
    293 09:  seg/base=11/35 MarkCoinInsert
    294 10:  seg/base=2/3 seg/base=10/19 MarkCoinStart
    295 11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    296 12:  seg/base=10/29 MarkCoinInsert
    297 13:  seg/base=2/30 MarkCoinInsert
    298 14:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    299 15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    300 16:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    301 17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    302 ------------------xx-x-x-------------- move_multiples
    303 00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    304 01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    305 02:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    306 03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    307 04:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    308 05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    309 06:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    310 07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd
    311 08:  seg/base=3/36 MarkCoinInsert
    312 09:  seg/base=11/35 MarkCoinInsert
    313 10:  seg/base=2/3 seg/base=10/19 MarkCoinStart
    314 11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    315 12:  seg/base=10/29 MarkCoinInsert
    316 13:  seg/base=2/30 MarkCoinInsert
    317 14:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    318 15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    319 16:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    320 17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    321 ------------------xx-x-x-------------- move_nearby
    322 00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    323 01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    324 02:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    325 03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    326 04:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    327 05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    328 06:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    329 07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd
    330 08:  seg/base=3/36 MarkCoinInsert
    331 09:  seg/base=11/35 MarkCoinInsert
    332 10:  seg/base=2/3 seg/base=10/19 MarkCoinStart
    333 11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    334 12:  seg/base=10/29 MarkCoinInsert
    335 13:  seg/base=2/30 MarkCoinInsert
    336 14:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    337 15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    338 16:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    339 17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    340 ------------------xx-x-x-------------- addExpanded
    341 00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    342 01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    343 02:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    344 03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    345 04:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    346 05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    347 06:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    348 07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd
    349 08:  seg/base=3/36 MarkCoinInsert
    350 09:  seg/base=11/35 MarkCoinInsert
    351 10:  seg/base=2/3 seg/base=10/19 MarkCoinStart
    352 11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    353 12:  seg/base=10/29 MarkCoinInsert
    354 13:  seg/base=2/30 MarkCoinInsert
    355 14:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    356 15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    357 16:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    358 17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    359 ------------------xx-x-x-------------- mark
    360 00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    361 01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin
    362 02:  seg/base=13/25 seg/base=5/9 MarkCoinStart
    363 03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd
    364 04:  seg/base=4/7 seg/base=12/23 MarkCoinStart
    365 05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd
    366 06:  seg/base=11/33 seg/base=3/34 MarkCoinStart
    367 07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd
    368 08:  seg/base=3/36 MarkCoinInsert
    369 09:  seg/base=11/35 MarkCoinInsert
    370 10:  seg/base=2/3 seg/base=10/19 MarkCoinStart
    371 11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd
    372 12:  seg/base=10/29 MarkCoinInsert
    373 13:  seg/base=2/30 MarkCoinInsert
    374 14:  seg/base=9/28 seg/base=1/1 MarkCoinStart
    375 15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd
    376 16:  seg/base=8/15 seg/base=6/11 MarkCoinStart
    377 17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd
    378 -------------------------------------- missing_coincidence
    379 -------------------------------------- expand
    380 -------------------------------------- expand
    381 -------------------------------------- apply
    382 SkOpSegment::markDone id=5 (118.119003,8.07219982 8.17210007,104.212997) t=0 [9] (118.119003,8.07219982) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    383 SkOpSegment::markDone id=12 (123.289001,9.39620018 118.119003,8.07219982) t=0 [23] (123.289001,9.39620018) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    384 SkOpSegment::markDone id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0.0627286673 [34] (124.516441,9.38671017) tEnd=0.625091708 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    385 SkOpSegment::markDone id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0.625091708 [36] (123.752594,9.42682648) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    386 SkOpSegment::markDone id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0 [19] (126,9.39620018) tEnd=0.307128906 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    387 SkOpSegment::markDone id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0.307128906 [29] (125.624687,9.33981037) tEnd=0.9375 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    388 SkOpSegment::markDone id=1 (0,353.891998 126,9.39610004) t=0 [1] (0,353.891998) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    389 SkOpSegment::markDone id=6 (8.17210007,104.212997 0,259.298737) t=0 [11] (8.17210007,104.212997) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
    390 -------------------------------------- findOverlaps
    391 SkOpSegment::debugShowActiveSpans id=8 (8.17210007,104.212997 -2.71619996e-07,259.298737) t=0 tEnd=0.583904956 windSum=? oppSum=? windValue=1 oppValue=1
    392 SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=? windValue=1
    393 SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=? windValue=1
    394 SkOpSegment::debugShowActiveSpans id=9 (7.26031715e-07,353.891998 126,9.39620018) t=0.0441765002 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
    395 SkOpSegment::debugShowActiveSpans id=10 (124.700119,9.37182617 124.66775,9.37443162 124.63531,9.3770743 124.602829,9.37972069) t=0.9375 tEnd=1 windSum=? windValue=1
    396 SkOpSegment::debugShowActiveSpans id=11 (124.602829,9.37972069 124.574059,9.3820647 124.545259,9.38441166 124.516449,9.38673687) t=0 tEnd=0.0625 windSum=? windValue=1
    397 SkOpSegment::debugShowActiveSpans id=11 (124.516449,9.38673687 124.257155,9.40766372 123.997126,9.42685982 123.752594,9.4268837) t=0.0625 tEnd=0.625 windSum=? oppSum=? windValue=1 oppValue=1
    398 SkOpSegment::debugShowActiveSpans id=11 (123.752594,9.4268837 123.589573,9.42689962 123.433437,9.41839421 123.289001,9.39620018) t=0.625 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
    399 SkOpSegment::debugShowActiveSpans id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
    400 SkOpSegment::debugShowActiveSpans id=2 (126,9.39610004 125.886971,9.36530236 125.760605,9.34788101 125.624695,9.33975124) t=0 tEnd=0.307190555 windSum=? oppSum=? windValue=1 oppValue=1
    401 SkOpSegment::debugShowActiveSpans id=2 (125.624695,9.33975124 125.345738,9.3230648 125.026588,9.34552196 124.700119,9.37180042) t=0.307190555 tEnd=0.937702598 windSum=? oppSum=? windValue=1 oppValue=1
    402 SkOpSegment::debugShowActiveSpans id=2 (124.700119,9.37180042 124.667862,9.37439685 124.635532,9.37703031 124.603165,9.37966728) t=0.937702598 tEnd=1 windSum=? windValue=1
    403 SkOpSegment::debugShowActiveSpans id=3 (124.603165,9.37966728 124.574282,9.38202029 124.545364,9.3843762 124.516441,9.38671017) t=0 tEnd=0.0627286673 windSum=? windValue=1
    404 SkOpSegment::debugShowActiveSpans id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
    405 SkOpSegment::debugShowActiveSpans id=7 (0,259.298737 0,353.891998) t=0 tEnd=1 windSum=? windValue=1
    406 -------------------------------------- calc_angles
    407 SkOpSegment::sortAngles [8] tStart=0 [15]
    408 SkOpSegment::sortAngles [8] tStart=0.583904956 [27]
    409 SkOpAngle::after [8/2] 5/5 tStart=0.583904956 tEnd=0 < [7/23] 23/23 tStart=0 tEnd=1 < [8/3] 21/21 tStart=0.583904956 tEnd=1  F 4
    410 SkOpAngle::afterPart {{{0,259.298737}, {8.17210034,104.212997}}} id=8
    411 SkOpAngle::afterPart {{{0,259.298737}, {0,353.891998}}} id=7
    412 SkOpAngle::afterPart {{{0,259.298737}, {-5.82349988,369.813995}}} id=8
    413 SkOpSegment::sortAngles [9] tStart=0.0441765002 [28]
    414 SkOpAngle::after [9/4] 21/21 tStart=0.0441765002 tEnd=0 < [7/24] 7/7 tStart=1 tEnd=0 < [9/5] 5/5 tStart=0.0441765002 tEnd=1  F 4
    415 SkOpAngle::afterPart {{{0,353.891998}, {-5.82350088,369.813995}}} id=9
    416 SkOpAngle::afterPart {{{0,353.891998}, {0,259.298737}}} id=7
    417 SkOpAngle::afterPart {{{0,353.891998}, {125.999999,9.39620018}}} id=9
    418 SkOpSegment::sortAngles [9] tStart=1 [18]
    419 SkOpSegment::sortAngles [10] tStart=0.9375 [31]
    420 SkOpAngle::after [10/7] 17/17 tStart=0.9375 tEnd=1 < [2/19] 17/17 tStart=0.937702598 tEnd=1 < [2/18] 1/1 tStart=0.937702598 tEnd=0.307190555  T 12
    421 SkOpAngle::afterPart {{{124.700119,9.37180042}, {124.66775,9.37440587}, {124.63531,9.37704855}, {124.602829,9.37969494}}} id=10
    422 SkOpAngle::afterPart {{{124.700119,9.37180042}, {124.667862,9.37439685}, {124.635532,9.37703031}, {124.603165,9.37966728}}} id=2
    423 SkOpAngle::afterPart {{{124.700119,9.37180042}, {125.026588,9.34552196}, {125.345738,9.3230648}, {125.624695,9.33975124}}} id=2
    424 SkOpSegment::sortAngles [11] tStart=0.0625 [33]
    425 SkOpAngle::after [11/8] 1/1 tStart=0.0625 tEnd=0 < [3/20] 1/1 tStart=0.0627286673 tEnd=0 < [11/9] 17/17 tStart=0.0625 tEnd=0.625  T 12
    426 SkOpAngle::afterPart {{{124.516441,9.38671017}, {124.545252,9.38438496}, {124.574051,9.382038}, {124.602821,9.37969398}}} id=11
    427 SkOpAngle::afterPart {{{124.516441,9.38671017}, {124.545364,9.3843762}, {124.574282,9.38202029}, {124.603165,9.37966728}}} id=3
    428 SkOpAngle::afterPart {{{124.516441,9.38671017}, {124.257148,9.40763702}, {123.997118,9.42683311}, {123.752586,9.42685699}}} id=11
    429 SkOpSegment::sortAngles [11] tStart=0.625 [35]
    430 SkOpSegment::sortAngles [11] tStart=1 [22]
    431 SkOpSegment::sortAngles [13] tStart=0 [25]
    432 SkOpSegment::sortAngles [13] tStart=1 [26]
    433 SkOpSegment::sortAngles [2] tStart=0 [3]
    434 SkOpSegment::sortAngles [2] tStart=0.307190555 [30]
    435 SkOpSegment::sortAngles [2] tStart=0.937702598 [32]
    436 SkOpSegment::sortAngles [3] tStart=0.0627286673 [34]
    437 SkOpSegment::sortAngles [4] tStart=0 [7]
    438 SkOpSegment::sortAngles [4] tStart=1 [8]
    439 SkOpSegment::sortAngles [7] tStart=0 [13]
    440 SkOpSegment::sortAngles [7] tStart=1 [14]
    441 coinSpan - id=13 t=0 tEnd=1
    442 coinSpan + id=5 t=0 tEnd=1
    443 coinSpan - id=4 t=0 tEnd=1
    444 coinSpan + id=12 t=0 tEnd=1
    445 coinSpan - id=11 t=0.0625 tEnd=1
    446 coinSpan + id=3 t=0.0627286673 tEnd=1
    447 coinSpan - id=2 t=0 tEnd=0.937702598
    448 coinSpan + id=10 t=0 tEnd=0.9375
    449 coinSpan - id=9 t=0.0441765002 tEnd=1
    450 coinSpan + id=1 t=0 tEnd=1
    451 coinSpan - id=8 t=0 tEnd=0.583904956
    452 coinSpan + id=6 t=0 tEnd=1
    453 SkOpSpan::sortableTop dir=kLeft seg=8 t=0.291952478 pt=(4.08605003,181.755859)
    454 SkOpSpan::sortableTop [0] valid=1 operand=1 span=15 ccw=0 seg=8 {{{8.17210007f, 104.212997f}, {-5.82350016f, 369.813995f}}} t=0.291952478 pt=(4.08605003,181.755859) slope=(-13.9956002,265.600998)
    455 SkOpSegment::markWinding id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0 [15] (8.17210007,104.212997) tEnd=0.583904956 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    456 SkOpSegment::markWinding id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0 [15] (8.17210007,104.212997) tEnd=0.583904956 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    457 SkOpSegment::markWinding id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 [25] (118.119003,8.07219982) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1
    458 SkOpSegment::markWinding id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 [7] (123.289001,9.39610004) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1
    459 SkOpSegment::markWinding id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.625 [35] (123.752594,9.4268837) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1
    460 SkOpSegment::markWinding id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.0625 [33] (124.516449,9.38673687) tEnd=0.625 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1
    461 SkOpSegment::activeOp id=8 t=0.583904956 tEnd=0 op=sect miFrom=1 miTo=0 suFrom=1 suTo=0 result=1
    462 SkOpSegment::findNextOp simple
    463 SkOpSegment::markDone id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0 [15] (8.17210007,104.212997) tEnd=0.583904956 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    464 bridgeOp current id=8 from=(-2.71619996e-07,259.298737) to=(8.17210007,104.212997)
    465 SkOpSegment::findNextOp simple
    466 SkOpSegment::markDone id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 [25] (118.119003,8.07219982) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    467 bridgeOp current id=13 from=(8.17210007,104.212997) to=(118.119003,8.07219982)
    468 path.moveTo(-2.71619996e-07,259.298737);
    469 path.lineTo(8.17210007,104.212997);
    470 SkOpSegment::findNextOp simple
    471 SkOpSegment::markDone id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 [7] (123.289001,9.39610004) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    472 bridgeOp current id=4 from=(118.119003,8.07219982) to=(123.289001,9.39610004)
    473 path.lineTo(118.119003,8.07219982);
    474 SkOpSegment::findNextOp simple
    475 SkOpSegment::markDone id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.625 [35] (123.752594,9.4268837) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    476 bridgeOp current id=11 from=(123.289001,9.39620018) to=(123.752594,9.4268837)
    477 path.lineTo(123.289001,9.39610004);
    478 path.cubicTo(123.433441,9.41839409, 123.589569,9.42689991, 123.752594,9.4268837);
    479 SkOpSegment::markWinding id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0 [21] (124.602829,9.37972069) tEnd=0.0625 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
    480 SkOpSegment::markWinding id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0.9375 [31] (124.700119,9.37182617) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
    481 SkOpSegment::markAngle last segment=10 span=31 windSum=1
    482 SkOpSegment::markWinding id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0 [5] (124.603165,9.37966728) tEnd=0.0627286673 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
    483 SkOpSegment::markWinding id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.937702598 [32] (124.700119,9.37180042) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
    484 SkOpSegment::markAngle last segment=2 span=32 windSum=1
    485 SkOpSegment::findNextOp
    486 SkOpAngle::dumpOne [11/9] next=11/8 sect=17/17  s=0.0625 [33] e=0.625 [35] sgn=-1 windVal=1 windSum=1 oppVal=1 oppSum=1 operand
    487 SkOpAngle::dumpOne [11/8] next=3/20 sect=1/1  s=0.0625 [33] e=0 [21] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
    488 SkOpAngle::dumpOne [3/20] next=11/9 sect=1/1  s=0.0627286673 [34] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0
    489 SkOpSegment::activeOp id=11 t=0.0625 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
    490 SkOpSegment::findNextOp chase.append segment=10 span=31 windSum=1
    491 SkOpSegment::activeOp id=3 t=0.0627286673 tEnd=0 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
    492 SkOpSegment::markDone id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0 [5] (124.603165,9.37966728) tEnd=0.0627286673 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
    493 SkOpSegment::markDone id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.937702598 [32] (124.700119,9.37180042) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
    494 SkOpSegment::findNextOp chase.append segment=2 span=32 windSum=1
    495 SkOpSegment::markDone id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.0625 [33] (124.516449,9.38673687) tEnd=0.625 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1
    496 SkOpSegment::findNextOp from:[11] to:[11] start=-1132576784 end=-1353716568
    497 bridgeOp current id=11 from=(123.752594,9.4268837) to=(124.516449,9.38673687)
    498 path.cubicTo(123.997124,9.42685986, 124.257156,9.40766335, 124.516449,9.38673687);
    499 SkOpSegment::findNextOp simple
    500 SkOpSegment::markDone id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0 [21] (124.602829,9.37972069) tEnd=0.0625 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
    501 bridgeOp current id=11 from=(124.516449,9.38673687) to=(124.602829,9.37972069)
    502 path.cubicTo(124.545258,9.38441181, 124.574059,9.38206482, 124.602829,9.37972069);
    503 SkOpSegment::markWinding id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.307190555 [30] (125.624695,9.33975124) tEnd=0.937702598 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1
    504 SkOpSegment::markWinding id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0 [3] (126,9.39610004) tEnd=0.307190555 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1
    505 SkOpSegment::markWinding id=9 (-5.82350016,369.813995 126,9.39620018) t=0.0441765002 [28] (7.26031715e-07,353.891998) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1
    506 SkOpSegment::markAngle last segment=9 span=28 windSum=-1
    507 SkOpSegment::findNextOp
    508 SkOpAngle::dumpOne [10/7] next=2/19 sect=17/17  s=0.9375 [31] e=1 [20] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
    509 SkOpAngle::dumpOne [2/19] next=2/18 sect=17/17  s=0.937702598 [32] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done
    510 SkOpAngle::dumpOne [2/18] next=10/7 sect=1/1  s=0.937702598 [32] e=0.307190555 [30] sgn=1 windVal=1 windSum=1 oppVal=1 oppSum=-1
    511 SkOpSegment::activeOp id=2 t=0.937702598 tEnd=1 op=sect = result=1
    512 SkOpSegment::activeOp id=2 t=0.937702598 tEnd=0.307190555 op=sect miFrom=0 miTo=1 suFrom=1 suTo=0 result=0
    513 SkOpSegment::markDone id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.307190555 [30] (125.624695,9.33975124) tEnd=0.937702598 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=1
    514 SkOpSegment::markDone id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0 [3] (126,9.39610004) tEnd=0.307190555 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=1
    515 SkOpSegment::markDone id=9 (-5.82350016,369.813995 126,9.39620018) t=0.0441765002 [28] (7.26031715e-07,353.891998) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=1
    516 SkOpSegment::findNextOp chase.append segment=9 span=28 windSum=-1
    517 SkOpSegment::markDone id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0.9375 [31] (124.700119,9.37182617) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
    518 SkOpSegment::findNextOp from:[10] to:[2] start=-1132576976 end=-1353719496
    519 bridgeOp current id=10 from=(124.602829,9.37972069) to=(124.700119,9.37182617)
    520 path.cubicTo(124.635307,9.37707424, 124.667747,9.37443161, 124.700119,9.37182617);
    521 SkOpSegment::markWinding id=7 (0,259.298737 0,353.891998) t=0 [13] (0,259.298737) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
    522 SkOpSegment::markWinding id=9 (-5.82350016,369.813995 126,9.39620018) t=0 [17] (-5.82350016,369.813995) tEnd=0.0441765002 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
    523 SkOpSegment::markWinding id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0.583904956 [27] (-2.71619996e-07,259.298737) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
    524 SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
    525 SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=-1 oppSum=0 windValue=1 oppValue=0
    526 SkOpSegment::debugShowActiveSpans id=7 (0,259.298737 0,353.891998) t=0 tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
    527 SkOpSegment::activeOp id=7 t=1 tEnd=0 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
    528 SkOpSegment::markDone id=7 (0,259.298737 0,353.891998) t=0 [13] (0,259.298737) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
    529 bridgeOp chase.append id=7 windSum=1
    530 SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
    531 SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=-1 oppSum=0 windValue=1 oppValue=0
    532 SkOpSegment::activeOp id=8 t=0.583904956 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
    533 SkOpSegment::markDone id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0.583904956 [27] (-2.71619996e-07,259.298737) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
    534 SkOpSegment::markDone id=9 (-5.82350016,369.813995 126,9.39620018) t=0 [17] (-5.82350016,369.813995) tEnd=0.0441765002 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
    535 </div>
    536 
    537 
    538 
    539     </div>
    540 
    541 <script type="text/javascript">
    542 
    543     var testDivs = [
    544         bug8380,
    545     ];
    546 
    547 var decimal_places = 3; // make this 3 to show more precision
    548 
    549 var tests = [];
    550 var testLines = [];
    551 var testTitles = [];
    552 var testIndex = 0;
    553 var ctx;
    554 
    555 var xmin, xmax, focusXmin, focusXmax;
    556 var ymin, ymax, focusYmin, focusYmax;
    557 var scale;
    558 var mouseX, mouseY;
    559 var srcLeft, srcTop;
    560 var screenWidth, screenHeight;
    561 var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
    562 var curveT = 0;
    563 
    564 var pt_labels = 2;
    565 var collect_bounds = false;
    566 var control_lines = 0;
    567 var curve_t = false;
    568 var debug_xy = 1;
    569 var focus_enabled = false;
    570 var focus_on_selection = false;
    571 var step_limit = 0;
    572 var draw_active = false;
    573 var draw_add = false;
    574 var draw_angle = 0;
    575 var draw_coincidence = false;
    576 var draw_deriviatives = 0;
    577 var draw_direction = false;
    578 var draw_hints = false;
    579 var draw_id = false;
    580 var draw_intersection = 0;
    581 var draw_intersectT = false;
    582 var draw_legend = true;
    583 var draw_log = false;
    584 var draw_mark = false;
    585 var draw_midpoint = false;
    586 var draw_op = 0;
    587 var draw_sequence = false;
    588 var draw_sort = 0;
    589 var draw_top = false;
    590 var draw_path = 3;
    591 var draw_computed = 0;
    592 var retina_scale = !!window.devicePixelRatio;
    593 
    594 var activeCount = 0;
    595 var addCount = 0;
    596 var angleCount = 0;
    597 var coinCount = 0;
    598 var opCount = 0;
    599 var sectCount = 0;
    600 var sortCount = 0;
    601 var topCount = 0;
    602 var markCount = 0;
    603 var activeMax = 0;
    604 var addMax = 0;
    605 var angleMax = 0;
    606 var coinMax = 0;
    607 var sectMax = 0;
    608 var sectMax2 = 0;
    609 var sortMax = 0;
    610 var topMax = 0;
    611 var markMax = 0;
    612 var opMax = 0;
    613 var stepMax = 0;
    614 var lastIndex = 0;
    615 var hasPath = false;
    616 var hasAlignedPath = false;
    617 var hasComputedPath = false;
    618 var angleBetween = false;
    619 var afterIndex = 0;
    620 
    621 var firstActiveSpan = -1;
    622 var logStart = -1;
    623 var logRange = 0;
    624 
    625 var SPAN_ID = 0;
    626 var SPAN_X1 = SPAN_ID + 1;
    627 var SPAN_Y1 = SPAN_X1 + 1;
    628 var SPAN_X2 = SPAN_Y1 + 1;
    629 var SPAN_Y2 = SPAN_X2 + 1;
    630 
    631 var SPAN_L_TX = SPAN_Y2 + 1;
    632 var SPAN_L_TY = SPAN_L_TX + 1;
    633 var SPAN_L_OTHER = SPAN_L_TY + 1;
    634 var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
    635 var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
    636 var SPAN_L_SUM = SPAN_L_OTHERI + 1;
    637 var SPAN_L_VAL = SPAN_L_SUM + 1;
    638 var SPAN_L_OPP = SPAN_L_VAL + 1;
    639 
    640 var SPAN_X3 = SPAN_Y2 + 1;
    641 var SPAN_Y3 = SPAN_X3 + 1;
    642 
    643 var SPAN_Q_TX = SPAN_Y3 + 1;
    644 var SPAN_Q_TY = SPAN_Q_TX + 1;
    645 var SPAN_Q_OTHER = SPAN_Q_TY + 1;
    646 var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
    647 var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
    648 var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
    649 var SPAN_Q_VAL = SPAN_Q_SUM + 1;
    650 var SPAN_Q_OPP = SPAN_Q_VAL + 1;
    651 
    652 var SPAN_K_W = SPAN_Y3 + 1;
    653 var SPAN_K_TX = SPAN_K_W + 1;
    654 var SPAN_K_TY = SPAN_K_TX + 1;
    655 var SPAN_K_OTHER = SPAN_K_TY + 1;
    656 var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
    657 var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
    658 var SPAN_K_SUM = SPAN_K_OTHERI + 1;
    659 var SPAN_K_VAL = SPAN_K_SUM + 1;
    660 var SPAN_K_OPP = SPAN_K_VAL + 1;
    661 
    662 var SPAN_X4 = SPAN_Y3 + 1;
    663 var SPAN_Y4 = SPAN_X4 + 1;
    664 
    665 var SPAN_C_TX = SPAN_Y4 + 1;
    666 var SPAN_C_TY = SPAN_C_TX + 1;
    667 var SPAN_C_OTHER = SPAN_C_TY + 1;
    668 var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
    669 var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
    670 var SPAN_C_SUM = SPAN_C_OTHERI + 1;
    671 var SPAN_C_VAL = SPAN_C_SUM + 1;
    672 var SPAN_C_OPP = SPAN_C_VAL + 1;
    673 
    674 var ACTIVE_LINE_SPAN =        1;
    675 var ACTIVE_QUAD_SPAN =        ACTIVE_LINE_SPAN + 1;
    676 var ACTIVE_CONIC_SPAN =       ACTIVE_QUAD_SPAN + 1;
    677 var ACTIVE_CUBIC_SPAN =       ACTIVE_CONIC_SPAN + 1;
    678 
    679 var ADD_MOVETO =              ACTIVE_CUBIC_SPAN + 1;
    680 var ADD_LINETO =              ADD_MOVETO + 1;
    681 var ADD_QUADTO =              ADD_LINETO + 1;
    682 var ADD_CONICTO =             ADD_QUADTO + 1;
    683 var ADD_CUBICTO =             ADD_CONICTO + 1;
    684 var ADD_CLOSE =               ADD_CUBICTO + 1;
    685 var ADD_FILL =                ADD_CLOSE + 1;
    686 
    687 var PATH_LINE =               ADD_FILL + 1;
    688 var PATH_QUAD =               PATH_LINE + 1;
    689 var PATH_CONIC =              PATH_QUAD + 1;
    690 var PATH_CUBIC =              PATH_CONIC + 1;
    691 
    692 var INTERSECT_LINE =          PATH_CUBIC + 1;
    693 var INTERSECT_LINE_2 =        INTERSECT_LINE + 1;
    694 var INTERSECT_LINE_NO =       INTERSECT_LINE_2 + 1;
    695 var INTERSECT_QUAD_LINE =     INTERSECT_LINE_NO + 1;
    696 var INTERSECT_QUAD_LINE_2 =   INTERSECT_QUAD_LINE + 1;
    697 var INTERSECT_QUAD_LINE_NO =  INTERSECT_QUAD_LINE_2 + 1;
    698 var INTERSECT_QUAD =          INTERSECT_QUAD_LINE_NO + 1;
    699 var INTERSECT_QUAD_2 =        INTERSECT_QUAD + 1;
    700 var INTERSECT_QUAD_NO =       INTERSECT_QUAD_2 + 1;
    701 var INTERSECT_CONIC_LINE =    INTERSECT_QUAD_NO + 1;
    702 var INTERSECT_CONIC_LINE_2 =  INTERSECT_CONIC_LINE + 1;
    703 var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
    704 var INTERSECT_CONIC_QUAD =    INTERSECT_CONIC_LINE_NO + 1;
    705 var INTERSECT_CONIC_QUAD_2 =  INTERSECT_CONIC_QUAD + 1;
    706 var INTERSECT_CONIC_QUAD_3 =  INTERSECT_CONIC_QUAD_2 + 1;
    707 var INTERSECT_CONIC_QUAD_4 =  INTERSECT_CONIC_QUAD_3 + 1;
    708 var INTERSECT_CONIC_QUAD_NO = INTERSECT_CONIC_QUAD_4 + 1;
    709 var INTERSECT_CONIC =         INTERSECT_CONIC_QUAD_NO + 1;
    710 var INTERSECT_CONIC_2 =       INTERSECT_CONIC + 1;
    711 var INTERSECT_CONIC_NO =      INTERSECT_CONIC_2 + 1;
    712 var INTERSECT_SELF_CUBIC =    INTERSECT_CONIC_NO + 1;
    713 var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
    714 var INTERSECT_CUBIC_LINE =    INTERSECT_SELF_CUBIC_NO + 1;
    715 var INTERSECT_CUBIC_LINE_2 =  INTERSECT_CUBIC_LINE + 1;
    716 var INTERSECT_CUBIC_LINE_3 =  INTERSECT_CUBIC_LINE_2 + 1;
    717 var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
    718 var INTERSECT_CUBIC_QUAD =    INTERSECT_CUBIC_LINE_NO + 1;
    719 var INTERSECT_CUBIC_QUAD_2 =  INTERSECT_CUBIC_QUAD + 1;
    720 var INTERSECT_CUBIC_QUAD_3 =  INTERSECT_CUBIC_QUAD_2 + 1;
    721 var INTERSECT_CUBIC_QUAD_4 =  INTERSECT_CUBIC_QUAD_3 + 1;
    722 var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
    723 var INTERSECT_CUBIC =         INTERSECT_CUBIC_QUAD_NO + 1;
    724 var INTERSECT_CUBIC_2 =       INTERSECT_CUBIC + 1;
    725 var INTERSECT_CUBIC_3 =       INTERSECT_CUBIC_2 + 1;
    726 var INTERSECT_CUBIC_4 =       INTERSECT_CUBIC_3 + 1;
    727 // FIXME: add cubic 5- 9
    728 var INTERSECT_CUBIC_NO =      INTERSECT_CUBIC_4 + 1;
    729 
    730 var SORT_UNARY =              INTERSECT_CUBIC_NO + 1;
    731 var SORT_BINARY =             SORT_UNARY + 1;
    732 
    733 var OP_DIFFERENCE =           SORT_BINARY + 1;
    734 var OP_INTERSECT =            OP_DIFFERENCE + 1;
    735 var OP_UNION =                OP_INTERSECT + 1;
    736 var OP_XOR =                  OP_UNION + 1;
    737 
    738 var MARK_LINE =               OP_XOR + 1;
    739 var MARK_QUAD =               MARK_LINE + 1;
    740 var MARK_CONIC =              MARK_QUAD + 1;
    741 var MARK_CUBIC =              MARK_CONIC + 1;
    742 var MARK_DONE_LINE =          MARK_CUBIC + 1;
    743 var MARK_DONE_QUAD =          MARK_DONE_LINE + 1;
    744 var MARK_DONE_CONIC =         MARK_DONE_QUAD + 1;
    745 var MARK_DONE_CUBIC =         MARK_DONE_CONIC + 1;
    746 var MARK_UNSORTABLE_LINE =    MARK_DONE_CUBIC + 1;
    747 var MARK_UNSORTABLE_QUAD =    MARK_UNSORTABLE_LINE + 1;
    748 var MARK_UNSORTABLE_CONIC =   MARK_UNSORTABLE_QUAD + 1;
    749 var MARK_UNSORTABLE_CUBIC =   MARK_UNSORTABLE_CONIC + 1;
    750 var MARK_SIMPLE_LINE =        MARK_UNSORTABLE_CUBIC + 1;
    751 var MARK_SIMPLE_QUAD =        MARK_SIMPLE_LINE + 1;
    752 var MARK_SIMPLE_CONIC =       MARK_SIMPLE_QUAD + 1;
    753 var MARK_SIMPLE_CUBIC =       MARK_SIMPLE_CONIC + 1;
    754 var MARK_SIMPLE_DONE_LINE =   MARK_SIMPLE_CUBIC + 1;
    755 var MARK_SIMPLE_DONE_QUAD =   MARK_SIMPLE_DONE_LINE + 1;
    756 var MARK_SIMPLE_DONE_CONIC =  MARK_SIMPLE_DONE_QUAD + 1;
    757 var MARK_SIMPLE_DONE_CUBIC =  MARK_SIMPLE_DONE_CONIC + 1;
    758 var MARK_DONE_UNARY_LINE =    MARK_SIMPLE_DONE_CUBIC + 1;
    759 var MARK_DONE_UNARY_QUAD =    MARK_DONE_UNARY_LINE + 1;
    760 var MARK_DONE_UNARY_CONIC =   MARK_DONE_UNARY_QUAD + 1;
    761 var MARK_DONE_UNARY_CUBIC =   MARK_DONE_UNARY_CONIC + 1;
    762 var MARK_ANGLE_LAST =         MARK_DONE_UNARY_CUBIC + 1;
    763 
    764 var COMPUTED_SET_1 =          MARK_ANGLE_LAST + 1;
    765 var COMPUTED_SET_2 =          COMPUTED_SET_1 + 1;
    766 
    767 var ANGLE_AFTER =             COMPUTED_SET_2 + 1;
    768 var ANGLE_AFTERPART =         ANGLE_AFTER + 1;
    769 
    770 var ACTIVE_OP =               ANGLE_AFTERPART + 1;
    771 
    772 var COIN_MAIN_SPAN =          ACTIVE_OP + 1;
    773 var COIN_OPP_SPAN =           COIN_MAIN_SPAN + 1;
    774 
    775 var FRAG_TYPE_LAST =          COIN_OPP_SPAN;
    776 
    777 var REC_TYPE_UNKNOWN = -1;
    778 var REC_TYPE_PATH = 0;
    779 var REC_TYPE_PATH2 = 1;
    780 var REC_TYPE_SECT = 2;
    781 var REC_TYPE_ACTIVE = 3;
    782 var REC_TYPE_ADD = 4;
    783 var REC_TYPE_SORT = 5;
    784 var REC_TYPE_OP = 6;
    785 var REC_TYPE_MARK = 7;
    786 var REC_TYPE_COMPUTED = 8;
    787 var REC_TYPE_COIN = 9;
    788 var REC_TYPE_ANGLE = 10;
    789 var REC_TYPE_ACTIVE_OP = 11;
    790 var REC_TYPE_AFTERPART = 12;
    791 var REC_TYPE_TOP = 13;
    792 var REC_TYPE_COINCIDENCE = 14;
    793 var REC_TYPE_ALIGNED = 15;
    794 var REC_TYPE_LAST = REC_TYPE_ALIGNED;
    795 
    796 function strs_to_nums(strs) {
    797     var result = [];
    798     for (var idx = 1; idx < strs.length; ++idx) {
    799         var str = strs[idx];
    800         var num = parseFloat(str);
    801         if (isNaN(num)) {
    802             result.push(str);
    803         } else {
    804             result.push(num);
    805         }
    806     }
    807     return result;
    808 }
    809 
    810 function filter_str_by(id, str, regex, array) {
    811     if (regex.test(str)) {
    812         var strs = regex.exec(str);
    813         var result = strs_to_nums(strs);
    814         array.push(id);
    815         array.push(result);
    816         return true;
    817     }
    818     return false;
    819 }
    820 
    821 function construct_regexp2(pattern) {
    822     var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
    823     escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
    824     escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
    825     escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
    826     escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
    827     escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
    828     escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
    829     escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
    830     escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
    831     escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
    832     escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)");
    833     escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
    834     escape = escape.replace(/PATH/g, "pathB?");
    835     escape = escape.replace(/IDX/g, "(-?\\d+)");
    836     escape = escape.replace(/NUM/g, "(-?\\d+)");
    837     escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
    838     return new RegExp(escape, 'i');
    839 }
    840 
    841 function construct_regexp2c(pattern) {
    842     var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
    843     escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
    844     escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
    845     escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
    846     escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
    847     escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
    848     escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
    849     escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
    850     escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
    851     escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
    852     escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)");
    853     escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
    854     escape = escape.replace(/OPER/g, "[a-z]+");
    855     escape = escape.replace(/PATH/g, "pathB?");
    856     escape = escape.replace(/T_F/g, "([TF])");
    857     escape = escape.replace(/IDX/g, "(-?\\d+)");
    858     escape = escape.replace(/NUM/g, "(-?\\d+)");
    859     escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
    860     return new RegExp(escape, 'i');
    861 }
    862 
    863 function match_regexp(str, lineNo, array, id, pattern) {
    864     var regex = construct_regexp2(pattern);
    865     if (filter_str_by(id, str, regex, array)) {
    866         return true;
    867     }
    868     regex = construct_regexp2c(pattern);
    869     return filter_str_by(id, str, regex, array);
    870 }
    871 
    872 function endsWith(str, suffix) {
    873     return str.indexOf(suffix, str.length - suffix.length) !== -1;
    874 }
    875 
    876 function parse_all(test) {
    877     var lines = test.match(/[^\r\n]+/g);
    878     var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
    879     var record = [];
    880     var recType = REC_TYPE_UNKNOWN;
    881     var lastLineNo;
    882     var moveX, moveY;
    883     for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
    884         var line = lines[lineNo];
    885         if (line.length == 0) {
    886             continue;
    887         }
    888         var opStart = "SkOpSegment::";
    889         if (line.lastIndexOf(opStart, 0) === 0) {
    890             line = line.substr(opStart.length);
    891         }
    892         var angleStart = "SkOpAngle::";
    893         if (line.lastIndexOf(angleStart, 0) === 0) {
    894             line = line.substr(angleStart.length);
    895         }
    896         var coinStart = "SkOpCoincidence::";
    897         if (line.lastIndexOf(coinStart, 0) === 0) {
    898             line = line.substr(coinStart.length);
    899         }
    900         var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
    901                 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
    902                 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
    903                 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
    904                 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
    905                 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
    906                 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
    907                 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
    908                 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
    909                 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
    910                 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
    911                 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
    912                 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
    913                 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
    914                 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
    915                 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
    916                 : line.lastIndexOf("  {{", 0) === 0 ? REC_TYPE_COMPUTED
    917                 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
    918                 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
    919                 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
    920                 : REC_TYPE_UNKNOWN;
    921         if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
    922                 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
    923             if (recType != REC_TYPE_UNKNOWN) {
    924                 records.push(recType);
    925                 records.push(lastLineNo);
    926                 records.push(record);
    927             }
    928             record = [];
    929             recType = type;
    930             lastLineNo = lineNo;
    931         }
    932         var found = false;
    933         switch (recType) {
    934             case REC_TYPE_ACTIVE:
    935                 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
    936 " id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
    937                 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
    938 " id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
    939                 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
    940 " id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
    941                 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
    942 " id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
    943                 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
    944 " id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
    945                 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
    946 " id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
    947                 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
    948 " id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
    949                 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
    950 " id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
    951                 );
    952                 break;
    953             case REC_TYPE_ACTIVE_OP:
    954                 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
    955 " id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
    956                 );
    957                 break;
    958             case REC_TYPE_ADD:
    959                 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
    960                     moveX = record[1][0];
    961                     moveY = record[1][1];
    962                     found = true;
    963                 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
    964                     record[1].unshift(moveY);
    965                     record[1].unshift(moveX);
    966                     moveX = record[1][2];
    967                     moveY = record[1][3];
    968                     found = true;
    969                 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
    970                     record[1].unshift(moveY);
    971                     record[1].unshift(moveX);
    972                     moveX = record[1][4];
    973                     moveY = record[1][5];
    974                     found = true;
    975                 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
    976                     record[1].unshift(moveY);
    977                     record[1].unshift(moveX);
    978                     moveX = record[1][4];
    979                     moveY = record[1][5];
    980                     found = true;
    981                 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
    982                     record[1].unshift(moveY);
    983                     record[1].unshift(moveX);
    984                     moveX = record[1][6];
    985                     moveY = record[1][7];
    986                     found = true;
    987                 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
    988                     found = true;
    989                 } else {
    990                     found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
    991                 }
    992                 break;
    993             case REC_TYPE_AFTERPART:
    994                 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL id=IDX")
    995                     || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL id=IDX")
    996                     || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL id=IDX")
    997                     || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL id=IDX")
    998                 break;
    999             case REC_TYPE_ALIGNED:
   1000                 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL"
   1001                 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL"
   1002                 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL"
   1003                 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL"
   1004                 );
   1005                 break;
   1006             case REC_TYPE_ANGLE:
   1007                 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
   1008 "[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");
   1009                 break;
   1010             case REC_TYPE_COIN:
   1011                 found = true;
   1012                 break;
   1013             case REC_TYPE_COINCIDENCE:
   1014                 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
   1015 " + id=IDX t=T_VAL tEnd=T_VAL"
   1016                 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
   1017 " - id=IDX t=T_VAL tEnd=T_VAL"
   1018                 );
   1019                 break;
   1020             case REC_TYPE_COMPUTED:
   1021                 found = line ==  "computed quadratics given"
   1022                   || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
   1023                 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
   1024                 ) || match_regexp(line, lineNo, record, PATH_QUAD, "  QUAD_VAL,"
   1025                 ) || match_regexp(line, lineNo, record, PATH_CONIC, "  CONIC_VAL,"
   1026                 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "  CUBIC_VAL,"
   1027                 );
   1028                 break;
   1029             case REC_TYPE_PATH:
   1030                 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
   1031                 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
   1032                 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
   1033                 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
   1034                 );
   1035                 break;
   1036             case REC_TYPE_PATH2:
   1037                 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
   1038                 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
   1039                 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
   1040                 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
   1041                 );
   1042                 break;
   1043             case REC_TYPE_SECT:
   1044                 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
   1045 " wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
   1046                 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
   1047 " wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
   1048                 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
   1049 " no intersect LINE_VAL LINE_VAL"
   1050                 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
   1051 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
   1052                 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
   1053 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
   1054                 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
   1055 " no intersect QUAD_VAL LINE_VAL"
   1056                 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
   1057 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
   1058                 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
   1059 " wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
   1060                 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
   1061 " no intersect QUAD_VAL QUAD_VAL"
   1062 
   1063                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
   1064 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
   1065                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
   1066 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
   1067                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
   1068 " no intersect CONIC_VAL LINE_VAL"
   1069 
   1070                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD, "debugShowConicQuadIntersection" +
   1071 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
   1072                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_2, "debugShowConicQuadIntersection" +
   1073 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
   1074                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_3, "debugShowConicQuadIntersection" +
   1075 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
   1076                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_4, "debugShowConicQuadIntersection" +
   1077 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL"
   1078                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" +
   1079 " no intersect CONIC_VAL QUAD_VAL"
   1080 
   1081                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
   1082 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
   1083                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
   1084 " wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
   1085                 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
   1086 " no intersect CONIC_VAL CONIC_VAL"
   1087                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
   1088 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
   1089                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
   1090 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
   1091                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
   1092 " 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"
   1093                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
   1094 " no intersect CUBIC_VAL LINE_VAL"
   1095                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
   1096 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
   1097                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
   1098 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
   1099                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
   1100 " 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"
   1101                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
   1102 " 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"
   1103                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
   1104 " no intersect CUBIC_VAL QUAD_VAL"
   1105                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
   1106 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
   1107                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
   1108 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
   1109                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
   1110 " 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"
   1111                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
   1112 " 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"
   1113                 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
   1114 " no intersect CUBIC_VAL CUBIC_VAL"
   1115                 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
   1116 " wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
   1117                 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
   1118 " no self intersect CUBIC_VAL"
   1119                 );
   1120                 break;
   1121             case REC_TYPE_SORT:
   1122                 var hasDone = / done/.test(line);
   1123                 var hasUnorderable = / unorderable/.test(line);
   1124                 var hasSmall = / small/.test(line);
   1125                 var hasTiny = / tiny/.test(line);
   1126                 var hasOperand = / operand/.test(line);
   1127                 var hasStop = / stop/.test(line);
   1128                 line.replace(/[ a-z]+$/, "");
   1129                 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
   1130 " [IDX/IDX] next=IDX/IDX sect=IDX/IDX  s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
   1131                 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
   1132 " [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"
   1133                 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
   1134 " [IDX/IDX] next=IDX/IDX sect=NUM/NUM  s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
   1135                 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
   1136 " [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"
   1137                 );
   1138                 if (found) {
   1139                     record[1].push(hasDone);
   1140                     record[1].push(hasUnorderable);
   1141                     record[1].push(hasSmall);
   1142                     record[1].push(hasTiny);
   1143                     record[1].push(hasOperand);
   1144                     record[1].push(hasStop);
   1145                 }
   1146                 break;
   1147             case REC_TYPE_TOP:
   1148                 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
   1149 " id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
   1150                 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
   1151 " id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
   1152                 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
   1153 " id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
   1154                 );
   1155                 break;
   1156             case REC_TYPE_MARK:
   1157                 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
   1158 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
   1159                 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
   1160 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
   1161                 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
   1162 " id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
   1163                 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
   1164 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
   1165                 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
   1166 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
   1167                 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
   1168 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
   1169                 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
   1170 " id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
   1171                 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
   1172 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
   1173                 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
   1174 " id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
   1175                 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
   1176 " id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
   1177                 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
   1178 " id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
   1179                 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
   1180 " id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
   1181                 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
   1182 " last segment=IDX span=IDX"
   1183                 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
   1184 " last seg=IDX span=IDX"
   1185                 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
   1186 " last segment=IDX span=IDX windSum=OPT"
   1187                 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
   1188 " last seg=IDX span=IDX windSum=OPT"
   1189                 );
   1190                 break;
   1191             case REC_TYPE_OP:
   1192                 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
   1193                         || line.lastIndexOf("operator<", 0) === 0) {
   1194                     found = true;
   1195                     break;
   1196                 }
   1197                 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
   1198                 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
   1199                 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
   1200                 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
   1201                 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
   1202                 );
   1203                 break;
   1204             case REC_TYPE_UNKNOWN:
   1205                 found = true;
   1206                 break;
   1207         }
   1208         if (!found) {
   1209             console.log(line + " [" + lineNo + "] of type " + type + " not found");
   1210         }
   1211     }
   1212     if (recType != REC_TYPE_UNKNOWN) {
   1213         records.push(recType);
   1214         records.push(lastLineNo);
   1215         records.push(record);
   1216     }
   1217     if (records.length >= 1) {
   1218         tests[testIndex] = records;
   1219         testLines[testIndex] = lines;
   1220     }
   1221 }
   1222 
   1223 function init(test) {
   1224     var canvas = document.getElementById('canvas');
   1225     if (!canvas.getContext) return;
   1226     ctx = canvas.getContext('2d');
   1227     var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
   1228     var unscaledWidth = window.innerWidth - 20;
   1229     var unscaledHeight = window.innerHeight - 20;
   1230     screenWidth = unscaledWidth;
   1231     screenHeight = unscaledHeight;
   1232     canvas.width = unscaledWidth * resScale;
   1233     canvas.height = unscaledHeight * resScale;
   1234     canvas.style.width = unscaledWidth + 'px';
   1235     canvas.style.height = unscaledHeight + 'px';
   1236     if (resScale != 1) {
   1237         ctx.scale(resScale, resScale);
   1238     }
   1239     xmin = Infinity;
   1240     xmax = -Infinity;
   1241     ymin = Infinity;
   1242     ymax = -Infinity;
   1243     hasPath = hasAlignedPath = hasComputedPath = false;
   1244     firstActiveSpan = -1;
   1245     for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
   1246         var recType = test[tIndex];
   1247         if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
   1248             console.log("unknown rec type: " + recType);
   1249             throw "stop execution";
   1250         }
   1251         var records = test[tIndex + 2];
   1252         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   1253             var fragType = records[recordIndex];
   1254             if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
   1255                 console.log("unknown in range frag type: " + fragType);
   1256                 throw "stop execution";
   1257             }
   1258             var frags = records[recordIndex + 1];
   1259             var first = 0;
   1260             var last = -1;
   1261             var first2 = 0;
   1262             var last2 = 0;
   1263             switch (recType) {
   1264                 case REC_TYPE_ALIGNED:
   1265                     hasAlignedPath = true;
   1266                 case REC_TYPE_COMPUTED:
   1267                     if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
   1268                         break;
   1269                     }
   1270                     if (REC_TYPE_COMPUTED == recType) {
   1271                         hasComputedPath = true;
   1272                     }
   1273                 case REC_TYPE_PATH:
   1274                     first = 1;
   1275                     switch (fragType) {
   1276                         case PATH_LINE:
   1277                             last = 5;
   1278                             break;
   1279                         case PATH_CONIC:
   1280                         case PATH_QUAD:
   1281                             last = 7;
   1282                             break;
   1283                         case PATH_CUBIC:
   1284                             last = 9;
   1285                             break;
   1286                         default:
   1287                             console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
   1288                                     : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
   1289                             throw "stop execution";
   1290                     }
   1291                     if (recType == REC_TYPE_PATH) {
   1292                         hasPath = true;
   1293                     }
   1294                     break;
   1295                 case REC_TYPE_PATH2:
   1296                     first = 1;
   1297                     switch (fragType) {
   1298                         case PATH_LINE:
   1299                             last = 5;
   1300                             break;
   1301                         case PATH_CONIC:
   1302                         case PATH_QUAD:
   1303                             last = 7;
   1304                             break;
   1305                         case PATH_CUBIC:
   1306                             last = 9;
   1307                             break;
   1308                         default:
   1309                             console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
   1310                                     : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
   1311                             throw "stop execution";
   1312                     }
   1313                     if (recType == REC_TYPE_PATH2) {
   1314                         hasPath = true;
   1315                     }
   1316                     break;
   1317                 case REC_TYPE_ACTIVE:
   1318                     if (firstActiveSpan < 0) {
   1319                         firstActiveSpan = tIndex;
   1320                     }
   1321                     first = 1;
   1322                     switch (fragType) {
   1323                         case ACTIVE_LINE_SPAN:
   1324                             last = 5;
   1325                             break;
   1326                         case ACTIVE_CONIC_SPAN:
   1327                         case ACTIVE_QUAD_SPAN:
   1328                             last = 7;
   1329                             break;
   1330                         case ACTIVE_CUBIC_SPAN:
   1331                             last = 9;
   1332                             break;
   1333                         default:
   1334                             console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
   1335                             throw "stop execution";
   1336                     }
   1337                     break;
   1338                 case REC_TYPE_ADD:
   1339                     switch (fragType) {
   1340                         case ADD_MOVETO:
   1341                             break;
   1342                         case ADD_LINETO:
   1343                             last = 4;
   1344                             break;
   1345                         case ADD_CONICTO:
   1346                         case ADD_QUADTO:
   1347                             last = 6;
   1348                             break;
   1349                         case ADD_CUBICTO:
   1350                             last = 8;
   1351                             break;
   1352                         case ADD_CLOSE:
   1353                         case ADD_FILL:
   1354                             break;
   1355                         default:
   1356                             console.log("unknown REC_TYPE_ADD frag type: " + fragType);
   1357                             throw "stop execution";
   1358                     }
   1359                     break;
   1360                 case REC_TYPE_AFTERPART:
   1361                     switch (fragType) {
   1362                         case PATH_LINE:
   1363                             last = 4;
   1364                             break;
   1365                         case PATH_CONIC:
   1366                         case PATH_QUAD:
   1367                             last = 6;
   1368                             break;
   1369                         case PATH_CUBIC:
   1370                             last = 8;
   1371                             break;
   1372                         default:
   1373                             console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
   1374                             throw "stop execution";
   1375                     }
   1376                     break;
   1377                 case REC_TYPE_SECT:
   1378                     switch (fragType) {
   1379                         case INTERSECT_LINE:
   1380                             first = 1; last = 5; first2 = 8; last2 = 12;
   1381                             break;
   1382                         case INTERSECT_LINE_2:
   1383                             first = 1; last = 5; first2 = 11; last2 = 15;
   1384                             break;
   1385                         case INTERSECT_LINE_NO:
   1386                             first = 0; last = 4; first2 = 4; last2 = 8;
   1387                             break;
   1388                         case INTERSECT_CONIC_LINE:
   1389                             first = 1; last = 7; first2 = 11; last2 = 15;
   1390                             break;
   1391                         case INTERSECT_QUAD_LINE:
   1392                             first = 1; last = 7; first2 = 10; last2 = 14;
   1393                             break;
   1394                         case INTERSECT_CONIC_LINE_2:
   1395                             first = 1; last = 7; first2 = 14; last2 = 18;
   1396                             break;
   1397                         case INTERSECT_QUAD_LINE_2:
   1398                             first = 1; last = 7; first2 = 13; last2 = 17;
   1399                             break;
   1400                         case INTERSECT_CONIC_LINE_NO:
   1401                             first = 0; last = 6; first2 = 7; last2 = 11;
   1402                             break;
   1403                         case INTERSECT_QUAD_LINE_NO:
   1404                             first = 0; last = 6; first2 = 6; last2 = 10;
   1405                             break;
   1406                         case INTERSECT_CONIC:
   1407                             first = 1; last = 7; first2 = 11; last2 = 17;
   1408                             break;
   1409                         case INTERSECT_QUAD:
   1410                             first = 1; last = 7; first2 = 10; last2 = 16;
   1411                             break;
   1412                         case INTERSECT_CONIC_2:
   1413                             first = 1; last = 7; first2 = 14; last2 = 20;
   1414                             break;
   1415                         case INTERSECT_QUAD_2:
   1416                             first = 1; last = 7; first2 = 13; last2 = 19;
   1417                             break;
   1418                         case INTERSECT_CONIC_NO:
   1419                             first = 0; last = 6; first2 = 7; last2 = 13;
   1420                             break;
   1421                         case INTERSECT_QUAD_NO:
   1422                             first = 0; last = 6; first2 = 6; last2 = 12;
   1423                             break;
   1424                         case INTERSECT_SELF_CUBIC:
   1425                             first = 1; last = 9;
   1426                             break;
   1427                         case INTERSECT_SELF_CUBIC_NO:
   1428                             first = 0; last = 8;
   1429                             break;
   1430                         case INTERSECT_CUBIC_LINE:
   1431                             first = 1; last = 9; first2 = 12; last2 = 16;
   1432                             break;
   1433                         case INTERSECT_CUBIC_LINE_2:
   1434                             first = 1; last = 9; first2 = 15; last2 = 19;
   1435                             break;
   1436                         case INTERSECT_CUBIC_LINE_3:
   1437                             first = 1; last = 9; first2 = 18; last2 = 22;
   1438                             break;
   1439                         case INTERSECT_CUBIC_LINE_NO:
   1440                             first = 0; last = 8; first2 = 8; last2 = 12;
   1441                             break;
   1442                         case INTERSECT_CONIC_QUAD:
   1443                             first = 1; last = 7; first2 = 11; last2 = 17;
   1444                             break;
   1445                         case INTERSECT_CONIC_QUAD_2:
   1446                             first = 1; last = 7; first2 = 14; last2 = 20;
   1447                             break;
   1448                         case INTERSECT_CONIC_QUAD_3:
   1449                             first = 1; last = 7; first2 = 17; last2 = 23;
   1450                             break;
   1451                         case INTERSECT_CONIC_QUAD_4:
   1452                             first = 1; last = 7; first2 = 20; last2 = 26;
   1453                             break;
   1454                         case INTERSECT_CONIC_QUAD_NO:
   1455                             first = 0; last = 6; first2 = 7; last2 = 13;
   1456                             break;
   1457                         case INTERSECT_CUBIC_QUAD:
   1458                             first = 1; last = 9; first2 = 12; last2 = 18;
   1459                             break;
   1460                         case INTERSECT_CUBIC_QUAD_2:
   1461                             first = 1; last = 9; first2 = 15; last2 = 21;
   1462                             break;
   1463                         case INTERSECT_CUBIC_QUAD_3:
   1464                             first = 1; last = 9; first2 = 18; last2 = 24;
   1465                             break;
   1466                         case INTERSECT_CUBIC_QUAD_4:
   1467                             first = 1; last = 9; first2 = 21; last2 = 27;
   1468                             break;
   1469                         case INTERSECT_CUBIC_QUAD_NO:
   1470                             first = 0; last = 8; first2 = 8; last2 = 14;
   1471                             break;
   1472                         case INTERSECT_CUBIC:
   1473                             first = 1; last = 9; first2 = 12; last2 = 20;
   1474                             break;
   1475                         case INTERSECT_CUBIC_2:
   1476                             first = 1; last = 9; first2 = 15; last2 = 23;
   1477                             break;
   1478                         case INTERSECT_CUBIC_3:
   1479                             first = 1; last = 9; first2 = 18; last2 = 26;
   1480                             break;
   1481                         case INTERSECT_CUBIC_4:
   1482                             first = 1; last = 9; first2 = 21; last2 = 29;
   1483                             break;
   1484                         case INTERSECT_CUBIC_NO:
   1485                             first = 0; last = 8; first2 = 8; last2 = 16;
   1486                             break;
   1487                         default:
   1488                             console.log("unknown REC_TYPE_SECT frag type: " + fragType);
   1489                             throw "stop execution";
   1490                     }
   1491                     break;
   1492                 default:
   1493                     continue;
   1494             }
   1495             for (var idx = first; idx < last; idx += 2) {
   1496                 xmin = Math.min(xmin, frags[idx]);
   1497                 xmax = Math.max(xmax, frags[idx]);
   1498                 ymin = Math.min(ymin, frags[idx + 1]);
   1499                 ymax = Math.max(ymax, frags[idx + 1]);
   1500             }
   1501             for (var idx = first2; idx < last2; idx += 2) {
   1502                 xmin = Math.min(xmin, frags[idx]);
   1503                 xmax = Math.max(xmax, frags[idx]);
   1504                 ymin = Math.min(ymin, frags[idx + 1]);
   1505                 ymax = Math.max(ymax, frags[idx + 1]);
   1506             }
   1507         }
   1508     }
   1509     var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
   1510     for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
   1511         var recType = test[tIndex];
   1512         var records = test[tIndex + 2];
   1513         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   1514             var fragType = records[recordIndex];
   1515             var frags = records[recordIndex + 1];
   1516             switch (recType) {
   1517                 case REC_TYPE_ACTIVE_OP:
   1518                     if (!draw_op) {
   1519                         break;
   1520                     }
   1521                     {
   1522                         var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
   1523                         curve_extremes(curve, angleBounds);
   1524                     }
   1525                     break;
   1526                 case REC_TYPE_ANGLE:
   1527                     if (!draw_angle) {
   1528                         break;
   1529                     }
   1530                     {
   1531                         var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
   1532                         curve_extremes(curve, angleBounds);
   1533                         curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
   1534                         curve_extremes(curve, angleBounds);
   1535                         curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
   1536                     }
   1537                     break;
   1538                 case REC_TYPE_COINCIDENCE:
   1539                     if (!draw_coincidence) {
   1540                         break;
   1541                     }
   1542                     {
   1543                         var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
   1544                         curve_extremes(curve, angleBounds);
   1545                     }
   1546                     break;
   1547                 case REC_TYPE_SORT:
   1548                     if (!draw_sort) {
   1549                         break;
   1550                     }
   1551                     if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
   1552                         var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
   1553                         curve_extremes(curve, angleBounds);
   1554                     }
   1555                     break;
   1556                 case REC_TYPE_TOP:
   1557                     if (!draw_top) {
   1558                         break;
   1559                     }
   1560                     {
   1561                         var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
   1562                         curve_extremes(curve, angleBounds);
   1563                     }
   1564                     break;
   1565             }
   1566         }
   1567     }
   1568     xmin = Math.min(xmin, angleBounds[0]);
   1569     ymin = Math.min(ymin, angleBounds[1]);
   1570     xmax = Math.max(xmax, angleBounds[2]);
   1571     ymax = Math.max(ymax, angleBounds[3]);
   1572     setScale(xmin, xmax, ymin, ymax);
   1573     if (hasPath == false && hasComputedPath == true && !draw_computed) {
   1574         draw_computed = 7; // show quadratics, conics, and cubics
   1575     }
   1576     if (hasPath == true && hasComputedPath == false && draw_computed) {
   1577         draw_computed = 0;
   1578     }
   1579 }
   1580 
   1581 function curveByIDMatch(test, id, recMatch) {
   1582     var tIndex = -3;
   1583     while ((tIndex += 3) < test.length) {
   1584         var recType = test[tIndex];
   1585         if (recType == REC_TYPE_OP) {
   1586             continue;
   1587         }
   1588         if (recType != recMatch) {
   1589             return [];
   1590         }
   1591         var records = test[tIndex + 2];
   1592         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   1593             var fragType = records[recordIndex];
   1594             var frags = records[recordIndex + 1];
   1595             if (frags[0] == id) {
   1596                 switch (fragType) {
   1597                     case PATH_LINE:
   1598                         return [frags[1], frags[2], frags[3], frags[4]];
   1599                     case PATH_QUAD:
   1600                         return [frags[1], frags[2], frags[3], frags[4],
   1601                                 frags[5], frags[6]];
   1602                     case PATH_CONIC:
   1603                         return [frags[1], frags[2], frags[3], frags[4],
   1604                                 frags[5], frags[6], frags[7]];
   1605                     case PATH_CUBIC:
   1606                         return [frags[1], frags[2], frags[3], frags[4],
   1607                                 frags[5], frags[6], frags[7], frags[8]];
   1608                 }
   1609             }
   1610         }
   1611     }
   1612     return [];
   1613 }
   1614 
   1615 function curveByID(test, id) {
   1616     var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : [];
   1617     if (!result.length) {
   1618         result = curveByIDMatch(test, id, REC_TYPE_PATH);
   1619     }
   1620     return result;
   1621 }
   1622 
   1623 function curvePartialByIDMatch(test, id, t0, t1, recMatch) {
   1624     var tIndex = -3;
   1625     while ((tIndex += 3) < test.length) {
   1626         var recType = test[tIndex];
   1627         if (recType == REC_TYPE_OP) {
   1628             continue;
   1629         }
   1630         if (recType != recMatch) {
   1631             return [];
   1632         }
   1633         var records = test[tIndex + 2];
   1634         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   1635             var fragType = records[recordIndex];
   1636             var frags = records[recordIndex + 1];
   1637             if (frags[0] == id) {
   1638                 switch (fragType) {
   1639                     case PATH_LINE:
   1640                         return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
   1641                     case PATH_QUAD:
   1642                         return quadPartial(frags[1], frags[2], frags[3], frags[4],
   1643                                 frags[5], frags[6], t0, t1);
   1644                     case PATH_CONIC:
   1645                         return conicPartial(frags[1], frags[2], frags[3], frags[4],
   1646                                 frags[5], frags[6], frags[7], t0, t1);
   1647                     case PATH_CUBIC:
   1648                         return cubicPartial(frags[1], frags[2], frags[3], frags[4],
   1649                                 frags[5], frags[6], frags[7], frags[8], t0, t1);
   1650                 }
   1651             }
   1652         }
   1653     }
   1654     return [];
   1655 }
   1656 
   1657 function curvePartialByID(test, id, t0, t1) {
   1658     var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : [];
   1659     if (!result.length) {
   1660         result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH);
   1661     }
   1662     return result;
   1663 }
   1664 
   1665 function idByCurveIDMatch(test, frag, type, recMatch) {
   1666     var tIndex = 0;
   1667     while (tIndex < test.length) {
   1668         var recType = test[tIndex];
   1669         if (recType != recMatch) {
   1670             ++tIndex;
   1671             continue;
   1672         }
   1673         var records = test[tIndex + 2];
   1674         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   1675             var fragType = records[recordIndex];
   1676             var frags = records[recordIndex + 1];
   1677             if (frag.length != frags.length - 1) {
   1678                 continue;
   1679             }
   1680             switch (fragType) {
   1681                 case PATH_LINE:
   1682                     if (frag[0] != frags[1] || frag[1] != frags[2]
   1683                             || frag[2] != frags[3] || frag[3] != frags[4]) {
   1684                         continue;
   1685                     }
   1686                     return frags[0];
   1687                 case PATH_QUAD:
   1688                     if (frag[0] != frags[1] || frag[1] != frags[2]
   1689                             || frag[2] != frags[3] || frag[3] != frags[4]
   1690                             || frag[4] != frags[5] || frag[5] != frags[6]) {
   1691                         continue;
   1692                     }
   1693                     return frags[0];
   1694                 case PATH_CONIC:
   1695                     if (frag[0] != frags[1] || frag[1] != frags[2]
   1696                             || frag[2] != frags[3] || frag[3] != frags[4]
   1697                             || frag[4] != frags[5] || frag[5] != frags[6]
   1698                             || frag[6] != frags[7]) {
   1699                         continue;
   1700                     }
   1701                     return frags[0];
   1702                 case PATH_CUBIC:
   1703                     if (frag[0] != frags[1] || frag[1] != frags[2]
   1704                             || frag[2] != frags[3] || frag[3] != frags[4]
   1705                             || frag[4] != frags[5] || frag[5] != frags[6]
   1706                             || frag[6] != frags[7] || frag[7] != frags[8]) {
   1707                         continue;
   1708                     }
   1709                     return frags[0];
   1710             }
   1711         }
   1712         ++tIndex;
   1713     }
   1714     return -1;
   1715 }
   1716 
   1717 function idByCurve(test, frag, type) {
   1718     var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : [];
   1719     if (!result.length) {
   1720         result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH);
   1721     }
   1722     return result;
   1723 }
   1724 
   1725 function curve_extremes(curve, bounds) {
   1726     var length = curve.length == 7 ? 6 : curve.length;
   1727     for (var index = 0; index < length; index += 2) {
   1728         var x = curve[index];
   1729         var y = curve[index + 1];
   1730         bounds[0] = Math.min(bounds[0], x);
   1731         bounds[1] = Math.min(bounds[1], y);
   1732         bounds[2] = Math.max(bounds[2], x);
   1733         bounds[3] = Math.max(bounds[3], y);
   1734     }
   1735 }
   1736 
   1737 function setScale(x0, x1, y0, y1) {
   1738     var srcWidth = x1 - x0;
   1739     var srcHeight = y1 - y0;
   1740     var usableWidth = screenWidth;
   1741     var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
   1742     var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
   1743     usableWidth -= (xDigits + yDigits) * 10;
   1744     usableWidth -= decimal_places * 10;
   1745     if (draw_legend) {
   1746         usableWidth -= 40;
   1747     }
   1748     var hscale = usableWidth / srcWidth;
   1749     var vscale = screenHeight / srcHeight;
   1750     scale = Math.min(hscale, vscale);
   1751     var invScale = 1 / scale;
   1752     var sxmin = x0 - invScale * 5;
   1753     var symin = y0 - invScale * 10;
   1754     var sxmax = x1 + invScale * (6 * decimal_places + 10);
   1755     var symax = y1 + invScale * 10;
   1756     srcWidth = sxmax - sxmin;
   1757     srcHeight = symax - symin;
   1758     hscale = usableWidth / srcWidth;
   1759     vscale = screenHeight / srcHeight;
   1760     scale = Math.min(hscale, vscale);
   1761     srcLeft = sxmin;
   1762     srcTop = symin;
   1763 }
   1764 
   1765 function drawArc(curve, op, from, to) {
   1766     var type = PATH_LINE + (curve.length / 2 - 2);
   1767     var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
   1768     var dy = pt.y - curve[1];
   1769     var dx = pt.x - curve[0];
   1770     var dist = Math.sqrt(dy * dy + dx * dx);
   1771     var _dist = dist * scale;
   1772     var angle = Math.atan2(dy, dx);
   1773     var _px = (curve[0] - srcLeft) * scale;
   1774     var _py = (curve[1] - srcTop) * scale;
   1775     var divisor = 4;
   1776     var endDist;
   1777     do {
   1778         var ends = [];
   1779         for (var index = -1; index <= 1; index += 2) {
   1780             var px = Math.cos(index * Math.PI / divisor);
   1781             var py = Math.sin(index * Math.PI / divisor);
   1782             ends.push(px);
   1783             ends.push(py);
   1784         }
   1785         var endDx = (ends[2] - ends[0]) * scale * dist;
   1786         var endDy = (ends[3] - ends[1]) * scale * dist;
   1787         endDist = Math.sqrt(endDx * endDx + endDy * endDy);
   1788         if (endDist < 100) {
   1789             break;
   1790         }
   1791         divisor *= 2;
   1792     } while (true);
   1793     if (endDist < 30) {
   1794         return;
   1795     }
   1796     if (op) {
   1797         divisor *= 2;
   1798     }
   1799     ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
   1800     ctx.beginPath();
   1801     ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
   1802     ctx.stroke();
   1803     var saveAlign = ctx.textAlign;
   1804     var saveStyle = ctx.fillStyle;
   1805     var saveFont = ctx.font;
   1806     ctx.textAlign = "center";
   1807     ctx.fillStyle = "black";
   1808     ctx.font = "normal 24px Arial";
   1809     divisor *= 0.8;
   1810     for (var index = -1; index <= 1; index += 2) {
   1811         var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
   1812         var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
   1813         var _px = (px - srcLeft) * scale;
   1814         var _py = (py - srcTop) * scale;
   1815         ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
   1816     }
   1817     ctx.textAlign = saveAlign;
   1818     ctx.fillStyle = saveStyle;
   1819     ctx.font = saveFont;
   1820 }
   1821 
   1822 function drawPoint(px, py, end) {
   1823     var length = drawnPts.length == 7 ? 6 : drawnPts.length;
   1824     for (var pts = 0; pts < length; pts += 2) {
   1825         var x = drawnPts[pts];
   1826         var y = drawnPts[pts + 1];
   1827         if (px == x && py == y) {
   1828             return;
   1829         }
   1830     }
   1831     drawnPts.push(px);
   1832     drawnPts.push(py);
   1833     var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
   1834     var _px = (px - srcLeft) * scale;
   1835     var _py = (py - srcTop) * scale;
   1836     ctx.beginPath();
   1837     ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
   1838     ctx.closePath();
   1839     if (end) {
   1840         ctx.fill();
   1841     } else {
   1842         ctx.stroke();
   1843     }
   1844     if (debug_xy) {
   1845         ctx.textAlign = "left";
   1846         ctx.fillText(label, _px + 5, _py);
   1847     }
   1848 }
   1849 
   1850 function coordCount(curveType) {
   1851     switch (curveType) {
   1852         case PATH_LINE:
   1853             return 4;
   1854         case PATH_QUAD:
   1855             return 6;
   1856         case PATH_CONIC:
   1857             return 6;
   1858         case PATH_CUBIC:
   1859             return 8;
   1860     }
   1861     return -1;
   1862 }
   1863 
   1864 function drawPoints(ptArray, curveType, drawControls) {
   1865     var count = coordCount(curveType);
   1866     for (var idx = 0; idx < count; idx += 2) {
   1867         if (!drawControls && idx != 0 && idx != count - 2) {
   1868             continue;
   1869         }
   1870         drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
   1871     }
   1872 }
   1873 
   1874 function drawControlLines(curve, curveType, drawEnd) {
   1875     if (curveType == PATH_LINE) {
   1876         return;
   1877     }
   1878     ctx.strokeStyle = "rgba(0,0,0, 0.3)";
   1879     drawLine(curve[0], curve[1], curve[2], curve[3]);
   1880     drawLine(curve[2], curve[3], curve[4], curve[5]);
   1881     if (curveType == PATH_CUBIC) {
   1882         drawLine(curve[4], curve[5], curve[6], curve[7]);
   1883         if (drawEnd > 1) {
   1884             drawLine(curve[6], curve[7], curve[0], curve[1]);
   1885             if (drawEnd > 2) {
   1886                 drawLine(curve[0], curve[1], curve[4], curve[5]);
   1887                 drawLine(curve[6], curve[7], curve[2], curve[3]);
   1888             }
   1889         }
   1890     } else if (drawEnd > 1) {
   1891         drawLine(curve[4], curve[5], curve[0], curve[1]);
   1892     }
   1893 }
   1894 
   1895 function pointAtT(curve, curveType, t) {
   1896     var xy = {};
   1897     switch (curveType) {
   1898         case PATH_LINE:
   1899             var a = 1 - t;
   1900             var b = t;
   1901             xy.x = a * curve[0] + b * curve[2];
   1902             xy.y = a * curve[1] + b * curve[3];
   1903             break;
   1904         case PATH_QUAD:
   1905             var one_t = 1 - t;
   1906             var a = one_t * one_t;
   1907             var b = 2 * one_t * t;
   1908             var c = t * t;
   1909             xy.x = a * curve[0] + b * curve[2] + c * curve[4];
   1910             xy.y = a * curve[1] + b * curve[3] + c * curve[5];
   1911             break;
   1912         case PATH_CONIC:
   1913             var one_t = 1 - t;
   1914             var a = one_t * one_t;
   1915             var b = 2 * one_t * t;
   1916             var c = t * t;
   1917             xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
   1918             xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
   1919             var d = a + b * curve[6] + c;
   1920             xy.x /= d;
   1921             xy.y /= d;
   1922             break;
   1923         case PATH_CUBIC:
   1924             var one_t = 1 - t;
   1925             var one_t2 = one_t * one_t;
   1926             var a = one_t2 * one_t;
   1927             var b = 3 * one_t2 * t;
   1928             var t2 = t * t;
   1929             var c = 3 * one_t * t2;
   1930             var d = t2 * t;
   1931             xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
   1932             xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
   1933             break;
   1934     }
   1935     return xy;
   1936 }
   1937 
   1938 function drawPointAtT(curve, curveType) {
   1939     var x, y;
   1940     var xy = pointAtT(curve, curveType, curveT);
   1941     drawPoint(xy.x, xy.y, true);
   1942     if (!draw_intersectT) {
   1943         return;
   1944     }
   1945     ctx.fillStyle = "red";
   1946     drawTAtPointUp(xy.x, xy.y, curveT);
   1947 }
   1948 
   1949 function drawTAtPointUp(px, py, t) {
   1950     var label = t.toFixed(decimal_places);
   1951     var _px = (px - srcLeft)* scale;
   1952     var _py = (py - srcTop) * scale;
   1953     ctx.fillText(label, _px + 5, _py - 10);
   1954 }
   1955 
   1956 function drawTAtPointDown(px, py, t) {
   1957     var label = t.toFixed(decimal_places);
   1958     var _px = (px - srcLeft)* scale;
   1959     var _py = (py - srcTop) * scale;
   1960     ctx.fillText(label, _px + 5, _py + 10);
   1961 }
   1962 
   1963 function alreadyDrawnLine(x1, y1, x2, y2) {
   1964     if (collect_bounds) {
   1965         if (focus_enabled) {
   1966             focusXmin = Math.min(focusXmin, x1, x2);
   1967             focusYmin = Math.min(focusYmin, y1, y2);
   1968             focusXmax = Math.max(focusXmax, x1, x2);
   1969             focusYmax = Math.max(focusYmax, y1, y2);
   1970         }
   1971         return true;
   1972     }
   1973     for (var pts = 0; pts < drawnLines.length; pts += 4) {
   1974         if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
   1975                 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
   1976             return true;
   1977         }
   1978     }
   1979     drawnLines.push(x1);
   1980     drawnLines.push(y1);
   1981     drawnLines.push(x2);
   1982     drawnLines.push(y2);
   1983     return false;
   1984 }
   1985 
   1986 function drawLine(x1, y1, x2, y2) {
   1987     if (alreadyDrawnLine(x1, y1, x2, y2)) {
   1988         return;
   1989     }
   1990     ctx.beginPath();
   1991     ctx.moveTo((x1 - srcLeft) * scale,
   1992             (y1 - srcTop) * scale);
   1993     ctx.lineTo((x2 - srcLeft) * scale,
   1994             (y2 - srcTop) * scale);
   1995     ctx.stroke();
   1996 }
   1997 
   1998 function linePartial(x1, y1, x2, y2, t1, t2) {
   1999     var dx = x1 - x2;
   2000     var dy = y1 - y2;
   2001     var array = [
   2002         x1 - t1 * dx,
   2003         y1 - t1 * dy,
   2004         x1 - t2 * dx,
   2005         y1 - t2 * dy
   2006     ];
   2007     return array;
   2008 }
   2009 
   2010 function drawLinePartial(x1, y1, x2, y2, t1, t2) {
   2011     var a = linePartial(x1, y1, x2, y2, t1, t2);
   2012     var ax = a[0];
   2013     var ay = a[1];
   2014     var bx = a[2];
   2015     var by = a[3];
   2016     if (alreadyDrawnLine(ax, ay, bx, by)) {
   2017         return;
   2018     }
   2019     ctx.beginPath();
   2020     ctx.moveTo((ax - srcLeft) * scale,
   2021             (ay - srcTop) * scale);
   2022     ctx.lineTo((bx - srcLeft) * scale,
   2023             (by - srcTop) * scale);
   2024     ctx.stroke();
   2025 }
   2026 
   2027 function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
   2028     if (collect_bounds) {
   2029         if (focus_enabled) {
   2030             focusXmin = Math.min(focusXmin, x1, x2, x3);
   2031             focusYmin = Math.min(focusYmin, y1, y2, y3);
   2032             focusXmax = Math.max(focusXmax, x1, x2, x3);
   2033             focusYmax = Math.max(focusYmax, y1, y2, y3);
   2034         }
   2035         return true;
   2036     }
   2037     for (var pts = 0; pts < drawnQuads.length; pts += 6) {
   2038         if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
   2039                 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
   2040                 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
   2041             return true;
   2042         }
   2043     }
   2044     drawnQuads.push(x1);
   2045     drawnQuads.push(y1);
   2046     drawnQuads.push(x2);
   2047     drawnQuads.push(y2);
   2048     drawnQuads.push(x3);
   2049     drawnQuads.push(y3);
   2050     return false;
   2051 }
   2052 
   2053 function drawQuad(x1, y1, x2, y2, x3, y3) {
   2054     if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
   2055         return;
   2056     }
   2057     ctx.beginPath();
   2058     ctx.moveTo((x1 - srcLeft) * scale,
   2059             (y1 - srcTop) * scale);
   2060     ctx.quadraticCurveTo((x2 - srcLeft) * scale,
   2061             (y2 - srcTop) * scale,
   2062             (x3 - srcLeft) * scale,
   2063             (y3 - srcTop) * scale);
   2064     ctx.stroke();
   2065 }
   2066 
   2067 function interp(A, B, t) {
   2068     return A + (B - A) * t;
   2069 }
   2070 
   2071 function interp_quad_coords(x1, x2, x3, t)
   2072 {
   2073     var ab = interp(x1, x2, t);
   2074     var bc = interp(x2, x3, t);
   2075     var abc = interp(ab, bc, t);
   2076     return abc;
   2077 }
   2078 
   2079 function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
   2080     var ax = interp_quad_coords(x1, x2, x3, t1);
   2081     var ay = interp_quad_coords(y1, y2, y3, t1);
   2082     var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
   2083     var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
   2084     var cx = interp_quad_coords(x1, x2, x3, t2);
   2085     var cy = interp_quad_coords(y1, y2, y3, t2);
   2086     var bx = 2*dx - (ax + cx)/2;
   2087     var by = 2*dy - (ay + cy)/2;
   2088     var array = [
   2089         ax, ay, bx, by, cx, cy
   2090     ];
   2091     return array;
   2092 }
   2093 
   2094 function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
   2095     var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
   2096     var ax = a[0];
   2097     var ay = a[1];
   2098     var bx = a[2];
   2099     var by = a[3];
   2100     var cx = a[4];
   2101     var cy = a[5];
   2102     if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
   2103         return;
   2104     }
   2105     ctx.beginPath();
   2106     ctx.moveTo((ax - srcLeft) * scale,
   2107             (ay - srcTop) * scale);
   2108     ctx.quadraticCurveTo((bx - srcLeft) * scale,
   2109             (by - srcTop) * scale,
   2110             (cx - srcLeft) * scale,
   2111             (cy - srcTop) * scale);
   2112     ctx.stroke();
   2113 }
   2114 
   2115 function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
   2116     if (collect_bounds) {
   2117         if (focus_enabled) {
   2118             focusXmin = Math.min(focusXmin, x1, x2, x3);
   2119             focusYmin = Math.min(focusYmin, y1, y2, y3);
   2120             focusXmax = Math.max(focusXmax, x1, x2, x3);
   2121             focusYmax = Math.max(focusYmax, y1, y2, y3);
   2122         }
   2123         return true;
   2124     }
   2125     for (var pts = 0; pts < drawnConics.length; pts += 8) {
   2126         if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
   2127                 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
   2128                 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
   2129                 && w == drawnCubics[pts + 6]) {
   2130             return true;
   2131         }
   2132     }
   2133     drawnConics.push(x1);
   2134     drawnConics.push(y1);
   2135     drawnConics.push(x2);
   2136     drawnConics.push(y2);
   2137     drawnConics.push(x3);
   2138     drawnConics.push(y3);
   2139     drawnCubics.push(w);
   2140     return false;
   2141 }
   2142 
   2143 var kMaxConicToQuadPOW2 = 5;
   2144 
   2145 function computeQuadPOW2(curve, tol) {
   2146     var a = curve[6] - 1;
   2147     var k = a / (4 * (2 + a));
   2148     var x = k * (curve[0] - 2 * curve[2] + curve[4]);
   2149     var y = k * (curve[1] - 2 * curve[3] + curve[5]);
   2150 
   2151     var error = Math.sqrt(x * x + y * y);
   2152     var pow2;
   2153     for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
   2154         if (error <= tol) {
   2155             break;
   2156         }
   2157         error *= 0.25;
   2158     }
   2159     return pow2;
   2160 }
   2161 
   2162 function subdivide_w_value(w) {
   2163     return Math.sqrt(0.5 + w * 0.5);
   2164 }
   2165 
   2166 function chop(curve, part1, part2) {
   2167     var w = curve[6];
   2168     var scale = 1 / (1 + w);
   2169     part1[0] = curve[0];
   2170     part1[1] = curve[1];
   2171     part1[2] = (curve[0] + curve[2] * w) * scale;
   2172     part1[3] = (curve[1] + curve[3] * w) * scale;
   2173     part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
   2174     part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
   2175     part2[2] = (curve[2] * w + curve[4]) * scale;
   2176     part2[3] = (curve[3] * w + curve[5]) * scale;
   2177     part2[4] = curve[4];
   2178     part2[5] = curve[5];
   2179     part1[6] = part2[6] = subdivide_w_value(w);
   2180 }
   2181 
   2182 function subdivide(curve, level, pts) {
   2183     if (0 == level) {
   2184         pts.push(curve[2]);
   2185         pts.push(curve[3]);
   2186         pts.push(curve[4]);
   2187         pts.push(curve[5]);
   2188     } else {
   2189         var part1 = [], part2 = [];
   2190         chop(curve, part1, part2);
   2191         --level;
   2192         subdivide(part1, level, pts);
   2193         subdivide(part2, level, pts);
   2194     }
   2195 }
   2196 
   2197 function chopIntoQuadsPOW2(curve, pow2, pts) {
   2198     subdivide(curve, pow2, pts);
   2199     return 1 << pow2;
   2200 }
   2201 
   2202 function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
   2203     if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
   2204         return;
   2205     }
   2206     ctx.beginPath();
   2207     ctx.moveTo((x1 - srcLeft) * scale,
   2208             (y1 - srcTop) * scale);
   2209     var tol = 1 / scale;
   2210     var curve = [x1, y1, x2, y2, x3, y3, w];
   2211     var pow2 = computeQuadPOW2(curve, tol);
   2212     var pts = [];
   2213     chopIntoQuadsPOW2(curve, pow2, pts);
   2214     for (var i = 0; i < pts.length; i += 4) {
   2215         ctx.quadraticCurveTo(
   2216             (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
   2217             (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
   2218     }
   2219     ctx.stroke();
   2220 }
   2221 
   2222 function conic_eval_numerator(x1, x2, x3, w, t) {
   2223     var src2w = x2 * w;
   2224     var C = x1;
   2225     var A = x3 - 2 * src2w + C;
   2226     var B = 2 * (src2w - C);
   2227     return (A * t + B) * t + C;
   2228 }
   2229 
   2230 
   2231 function conic_eval_denominator(w, t) {
   2232     var B = 2 * (w - 1);
   2233     var C = 1;
   2234     var A = -B;
   2235     return (A * t + B) * t + C;
   2236 }
   2237 
   2238 function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
   2239     var ax = conic_eval_numerator(x1, x2, x3, w, t1);
   2240     var ay = conic_eval_numerator(y1, y2, y3, w, t1);
   2241     var az = conic_eval_denominator(w, t1);
   2242     var midT = (t1 + t2) / 2;
   2243     var dx = conic_eval_numerator(x1, x2, x3, w, midT);
   2244     var dy = conic_eval_numerator(y1, y2, y3, w, midT);
   2245     var dz = conic_eval_denominator(w, midT);
   2246     var cx = conic_eval_numerator(x1, x2, x3, w, t2);
   2247     var cy = conic_eval_numerator(y1, y2, y3, w, t2);
   2248     var cz = conic_eval_denominator(w, t2);
   2249     var bx = 2 * dx - (ax + cx) / 2;
   2250     var by = 2 * dy - (ay + cy) / 2;
   2251     var bz = 2 * dz - (az + cz) / 2;
   2252     var dt = t2 - t1;
   2253     var dt_1 = 1 - dt;
   2254     var array = [
   2255         ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
   2256     ];
   2257     var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 };
   2258     var dMid = { x:dx / dz, y:dy / dz };
   2259     var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y };
   2260     var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] };
   2261     var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y)
   2262                 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y);
   2263     array[6] = partW;
   2264     return array;
   2265 }
   2266 
   2267 function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
   2268     var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
   2269     var ax = a[0];
   2270     var ay = a[1];
   2271     var bx = a[2];
   2272     var by = a[3];
   2273     var cx = a[4];
   2274     var cy = a[5];
   2275     var w_ = a[6];
   2276     drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
   2277 }
   2278 
   2279 function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
   2280     if (collect_bounds) {
   2281         if (focus_enabled) {
   2282             focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
   2283             focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
   2284             focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
   2285             focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
   2286         }
   2287         return true;
   2288     }
   2289     for (var pts = 0; pts < drawnCubics.length; pts += 8) {
   2290         if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
   2291                 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
   2292                 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
   2293                 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
   2294             return true;
   2295         }
   2296     }
   2297     drawnCubics.push(x1);
   2298     drawnCubics.push(y1);
   2299     drawnCubics.push(x2);
   2300     drawnCubics.push(y2);
   2301     drawnCubics.push(x3);
   2302     drawnCubics.push(y3);
   2303     drawnCubics.push(x4);
   2304     drawnCubics.push(y4);
   2305     return false;
   2306 }
   2307 
   2308 function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
   2309     if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
   2310         return;
   2311     }
   2312     ctx.beginPath();
   2313     ctx.moveTo((x1 - srcLeft) * scale,
   2314             (y1 - srcTop) * scale);
   2315     ctx.bezierCurveTo((x2 - srcLeft) * scale,
   2316             (y2 - srcTop) * scale,
   2317             (x3 - srcLeft) * scale,
   2318             (y3 - srcTop) * scale,
   2319             (x4 - srcLeft) * scale,
   2320             (y4 - srcTop) * scale);
   2321     ctx.stroke();
   2322 }
   2323 
   2324 function interp_cubic_coords(x1, x2, x3, x4, t)
   2325 {
   2326     var ab = interp(x1, x2, t);
   2327     var bc = interp(x2, x3, t);
   2328     var cd = interp(x3, x4, t);
   2329     var abc = interp(ab, bc, t);
   2330     var bcd = interp(bc, cd, t);
   2331     var abcd = interp(abc, bcd, t);
   2332     return abcd;
   2333 }
   2334 
   2335 function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
   2336     var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
   2337     var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
   2338     var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
   2339     var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
   2340     var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
   2341     var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
   2342     var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
   2343     var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
   2344     var mx = ex * 27 - ax * 8 - dx;
   2345     var my = ey * 27 - ay * 8 - dy;
   2346     var nx = fx * 27 - ax - dx * 8;
   2347     var ny = fy * 27 - ay - dy * 8;
   2348     var bx = (mx * 2 - nx) / 18;
   2349     var by = (my * 2 - ny) / 18;
   2350     var cx = (nx * 2 - mx) / 18;
   2351     var cy = (ny * 2 - my) / 18;
   2352     var array = [
   2353         ax, ay, bx, by, cx, cy, dx, dy
   2354     ];
   2355     return array;
   2356 }
   2357 
   2358 function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
   2359     var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
   2360     var ax = a[0];
   2361     var ay = a[1];
   2362     var bx = a[2];
   2363     var by = a[3];
   2364     var cx = a[4];
   2365     var cy = a[5];
   2366     var dx = a[6];
   2367     var dy = a[7];
   2368     if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
   2369         return;
   2370     }
   2371     ctx.beginPath();
   2372     ctx.moveTo((ax - srcLeft) * scale,
   2373             (ay - srcTop) * scale);
   2374     ctx.bezierCurveTo((bx - srcLeft) * scale,
   2375             (by - srcTop) * scale,
   2376             (cx - srcLeft) * scale,
   2377             (cy - srcTop) * scale,
   2378             (dx - srcLeft) * scale,
   2379             (dy - srcTop) * scale);
   2380     ctx.stroke();
   2381 }
   2382 
   2383 function drawCurve(c) {
   2384     switch (c.length) {
   2385         case 4:
   2386             drawLine(c[0], c[1], c[2], c[3]);
   2387             break;
   2388         case 6:
   2389             drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
   2390             break;
   2391         case 7:
   2392             drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
   2393             break;
   2394         case 8:
   2395             drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
   2396             break;
   2397     }
   2398 }
   2399 
   2400 function boundsWidth(pts) {
   2401     var min = pts[0];
   2402     var max = pts[0];
   2403     var length = pts.length == 7 ? 6 : pts.length;
   2404     for (var idx = 2; idx < length; idx += 2) {
   2405         min = Math.min(min, pts[idx]);
   2406         max = Math.max(max, pts[idx]);
   2407     }
   2408     return max - min;
   2409 }
   2410 
   2411 function boundsHeight(pts) {
   2412     var min = pts[1];
   2413     var max = pts[1];
   2414     var length = pts.length == 7 ? 6 : pts.length;
   2415     for (var idx = 3; idx < length; idx += 2) {
   2416         min = Math.min(min, pts[idx]);
   2417         max = Math.max(max, pts[idx]);
   2418     }
   2419     return max - min;
   2420 }
   2421 
   2422 function tangent(pts) {
   2423     var dx = pts[2] - pts[0];
   2424     var dy = pts[3] - pts[1];
   2425     if (dx == 0 && dy == 0 && pts.length > 4) {
   2426         dx = pts[4] - pts[0];
   2427         dy = pts[5] - pts[1];
   2428         if (dx == 0 && dy == 0 && pts.length == 8) {
   2429             dx = pts[6] - pts[0];
   2430             dy = pts[7] - pts[1];
   2431         }
   2432     }
   2433     return Math.atan2(-dy, dx);
   2434 }
   2435 
   2436 function hodograph(cubic) {
   2437     var hodo = [];
   2438     hodo[0] = 3 * (cubic[2] - cubic[0]);
   2439     hodo[1] = 3 * (cubic[3] - cubic[1]);
   2440     hodo[2] = 3 * (cubic[4] - cubic[2]);
   2441     hodo[3] = 3 * (cubic[5] - cubic[3]);
   2442     hodo[4] = 3 * (cubic[6] - cubic[4]);
   2443     hodo[5] = 3 * (cubic[7] - cubic[5]);
   2444     return hodo;
   2445 }
   2446 
   2447 function hodograph2(cubic) {
   2448     var quad = hodograph(cubic);
   2449     var hodo = [];
   2450     hodo[0] = 2 * (quad[2] - quad[0]);
   2451     hodo[1] = 2 * (quad[3] - quad[1]);
   2452     hodo[2] = 2 * (quad[4] - quad[2]);
   2453     hodo[3] = 2 * (quad[5] - quad[3]);
   2454     return hodo;
   2455 }
   2456 
   2457 function quadraticRootsReal(A, B, C, s) {
   2458     if (A == 0) {
   2459         if (B == 0) {
   2460             s[0] = 0;
   2461             return C == 0;
   2462         }
   2463         s[0] = -C / B;
   2464         return 1;
   2465     }
   2466     /* normal form: x^2 + px + q = 0 */
   2467     var p = B / (2 * A);
   2468     var q = C / A;
   2469     var p2 = p * p;
   2470     if (p2 < q) {
   2471         return 0;
   2472     }
   2473     var sqrt_D = 0;
   2474     if (p2 > q) {
   2475         sqrt_D = sqrt(p2 - q);
   2476     }
   2477     s[0] = sqrt_D - p;
   2478     s[1] = -sqrt_D - p;
   2479     return 1 + s[0] != s[1];
   2480 }
   2481 
   2482 function add_valid_ts(s, realRoots, t) {
   2483     var foundRoots = 0;
   2484     for (var index = 0; index < realRoots; ++index) {
   2485         var tValue = s[index];
   2486         if (tValue >= 0 && tValue <= 1) {
   2487             for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
   2488                 if (t[idx2] != tValue) {
   2489                     t[foundRoots++] = tValue;
   2490                 }
   2491             }
   2492         }
   2493     }
   2494     return foundRoots;
   2495 }
   2496 
   2497 function quadraticRootsValidT(a, b, c, t) {
   2498     var s = [];
   2499     var realRoots = quadraticRootsReal(A, B, C, s);
   2500     var foundRoots = add_valid_ts(s, realRoots, t);
   2501     return foundRoots != 0;
   2502 }
   2503 
   2504 function find_cubic_inflections(cubic, tValues) {
   2505     var Ax = src[2] - src[0];
   2506     var Ay = src[3] - src[1];
   2507     var Bx = src[4] - 2 * src[2] + src[0];
   2508     var By = src[5] - 2 * src[3] + src[1];
   2509     var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
   2510     var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
   2511     return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
   2512             Ax * By - Ay * Bx, tValues);
   2513 }
   2514 
   2515 function dxy_at_t(curve, type, t) {
   2516     var dxy = {};
   2517     if (type == PATH_LINE) {
   2518         dxy.x = curve[2] - curve[0];
   2519         dxy.y = curve[3] - curve[1];
   2520     } else if (type == PATH_QUAD) {
   2521         var a = t - 1;
   2522         var b = 1 - 2 * t;
   2523         var c = t;
   2524         dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
   2525         dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
   2526     } else if (type == PATH_CONIC) {
   2527         var p20x = curve[4] - curve[0];
   2528         var p20y = curve[5] - curve[1];
   2529         var p10xw = (curve[2] - curve[0]) * curve[6];
   2530         var p10yw = (curve[3] - curve[1]) * curve[6];
   2531         var coeff0x = curve[6] * p20x - p20x;
   2532         var coeff0y = curve[6] * p20y - p20y;
   2533         var coeff1x = p20x - 2 * p10xw;
   2534         var coeff1y = p20y - 2 * p10yw;
   2535         dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
   2536         dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
   2537     } else if (type == PATH_CUBIC) {
   2538         var one_t = 1 - t;
   2539         var a = curve[0];
   2540         var b = curve[2];
   2541         var c = curve[4];
   2542         var d = curve[6];
   2543         dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
   2544         a = curve[1];
   2545         b = curve[3];
   2546         c = curve[5];
   2547         d = curve[7];
   2548         dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
   2549     }
   2550     return dxy;
   2551 }
   2552 
   2553 function dpt_at_t(curve, t) {
   2554     var type = PATH_LINE + (curve.length / 2 - 2);
   2555     return dxy_at_t(curve, type, t);
   2556 }
   2557 
   2558 function drawLabel(num, px, py) {
   2559     ctx.beginPath();
   2560     ctx.arc(px, py, 8, 0, Math.PI*2, true);
   2561     ctx.closePath();
   2562     ctx.strokeStyle = "rgba(0,0,0, 0.4)";
   2563     ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
   2564     ctx.stroke();
   2565     ctx.fillStyle = "black";
   2566     ctx.font = "normal 10px Arial";
   2567   //  ctx.rotate(0.001);
   2568     ctx.fillText(num, px - 2, py + 3);
   2569   //  ctx.rotate(-0.001);
   2570 }
   2571 
   2572 function drawLabelX(ymin, num, loc) {
   2573     var px = (loc - srcLeft) * scale;
   2574     var py = (ymin - srcTop) * scale - 20;
   2575     drawLabel(num, px, py);
   2576 }
   2577 
   2578 function drawLabelY(xmin, num, loc) {
   2579     var px = (xmin - srcLeft) * scale - 20;
   2580     var py = (loc - srcTop) * scale;
   2581     drawLabel(num, px, py);
   2582 }
   2583 
   2584 function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
   2585     ctx.beginPath();
   2586     ctx.moveTo(hx, hy - 100);
   2587     ctx.lineTo(hx, hy);
   2588     ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
   2589     ctx.stroke();
   2590     ctx.beginPath();
   2591     ctx.moveTo(hx, hy);
   2592     ctx.lineTo(hx, hy + 100);
   2593     ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
   2594     ctx.stroke();
   2595     ctx.beginPath();
   2596     ctx.moveTo(hx - 100, hy);
   2597     ctx.lineTo(hx, hy);
   2598     ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
   2599     ctx.stroke();
   2600     ctx.beginPath();
   2601     ctx.moveTo(hx, hy);
   2602     ctx.lineTo(hx + 100, hy);
   2603     ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
   2604     ctx.stroke();
   2605 }
   2606 
   2607 function scalexy(x, y, mag) {
   2608     var length = Math.sqrt(x * x + y * y);
   2609     return mag / length;
   2610 }
   2611 
   2612 function drawArrow(x, y, dx, dy, s) {
   2613     var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
   2614     dx *= dscale;
   2615     dy *= dscale;
   2616     ctx.beginPath();
   2617     ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
   2618     x += dx;
   2619     y += dy;
   2620     ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
   2621     dx /= 10;
   2622     dy /= 10;
   2623     ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
   2624     ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
   2625     ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
   2626     ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
   2627     ctx.strokeStyle = "rgba(0,75,0, 0.4)";
   2628     ctx.stroke();
   2629 }
   2630 
   2631 function x_at_t(curve, t) {
   2632     var one_t = 1 - t;
   2633     if (curve.length == 4) {
   2634         return one_t * curve[0] + t * curve[2];
   2635     }
   2636     var one_t2 = one_t * one_t;
   2637     var t2 = t * t;
   2638     if (curve.length == 6) {
   2639         return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
   2640     }
   2641     if (curve.length == 7) {
   2642         return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
   2643                 / (one_t2 +2 * one_t * t * curve[6] + t2);
   2644     }
   2645     var a = one_t2 * one_t;
   2646     var b = 3 * one_t2 * t;
   2647     var c = 3 * one_t * t2;
   2648     var d = t2 * t;
   2649     return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
   2650 }
   2651 
   2652 function y_at_t(curve, t) {
   2653     var one_t = 1 - t;
   2654     if (curve.length == 4) {
   2655         return one_t * curve[1] + t * curve[3];
   2656     }
   2657     var one_t2 = one_t * one_t;
   2658     var t2 = t * t;
   2659     if (curve.length == 6) {
   2660         return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
   2661     }
   2662     if (curve.length == 7) {
   2663         return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
   2664                 / (one_t2 +2 * one_t * t * curve[6] + t2);
   2665     }
   2666     var a = one_t2 * one_t;
   2667     var b = 3 * one_t2 * t;
   2668     var c = 3 * one_t * t2;
   2669     var d = t2 * t;
   2670     return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
   2671 }
   2672 
   2673 function pt_at_t(curve, t) {
   2674     var pt = {};
   2675     pt.x = x_at_t(curve, t);
   2676     pt.y = y_at_t(curve, t);
   2677     return pt;
   2678 }
   2679 
   2680 function drawOrder(curve, t, label) {
   2681     var px = x_at_t(curve, t);
   2682     var py = y_at_t(curve, t);
   2683     var _px = (px - srcLeft) * scale;
   2684     var _py = (py - srcTop) * scale;
   2685     ctx.beginPath();
   2686     ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
   2687     ctx.closePath();
   2688     ctx.fillStyle = "white";
   2689     ctx.fill();
   2690     if (label == 'L') {
   2691         ctx.strokeStyle = "rgba(255,0,0, 1)";
   2692         ctx.fillStyle = "rgba(255,0,0, 1)";
   2693     } else {
   2694         ctx.strokeStyle = "rgba(0,0,255, 1)";
   2695         ctx.fillStyle = "rgba(0,0,255, 1)";
   2696     }
   2697     ctx.stroke();
   2698     ctx.font = "normal 16px Arial";
   2699     ctx.textAlign = "center";
   2700     ctx.fillText(label, _px, _py + 5);
   2701     ctx.font = "normal 10px Arial";
   2702 }
   2703 
   2704 function drawVisibleOrder(curve, label) {
   2705     var s = pt_at_t(curve, 0);
   2706     var e = pt_at_t(curve, 1);
   2707     var sOn = ptOnScreen(s);
   2708     var eOn = ptOnScreen(e);
   2709     var defaultT = 0.85;
   2710     if (sOn && eOn)
   2711         return drawOrder(curve, defaultT, label);
   2712     if (sOn || eOn) {
   2713         if (eOn) {
   2714             defaultT = 1 - defaultT;
   2715         }
   2716         var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
   2717         var t = defaultT;
   2718         var tries = 16;
   2719         do {
   2720             var mid = pt_at_t(curve, t);
   2721             if (ptOnScreen(mid))
   2722                 return drawOrder(curve, t, label);
   2723             t += step;
   2724             step /= 2;
   2725         } while (--tries > 0);
   2726         drawOrder(curve, defaultT, label);
   2727     }
   2728     // scattershot until we find a visible point
   2729     var denom = 2;  // visit odd number num / denom to hit unique pts
   2730     var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
   2731     do {
   2732         for (var numer = 1; numer < denom; numer += 2) {
   2733             var t = numer / denom + 0.1;
   2734             if (t >= 1) {
   2735                 break;
   2736             }
   2737             var mid = pt_at_t(curve, t);
   2738             if (ptOnScreen(mid))
   2739                 return drawOrder(curve, t, label);
   2740         }
   2741         denom *= 2;
   2742     } while (--tries > 0);
   2743     drawOrder(curve, defaultT, label);
   2744 }
   2745 
   2746 function set_length(pt, newLen) {
   2747     var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y);
   2748     var scale = newLen / len;
   2749     var newPt = { x: pt.x * scale, y: pt.y * scale };
   2750     return newPt;
   2751 }
   2752 
   2753 function drawDirection(curve, t) {
   2754     var d = dpt_at_t(curve, t);
   2755     d = set_length(d, 16);
   2756     var pt = localToGlobal(pt_at_t(curve, t));
   2757     ctx.beginPath();
   2758     ctx.moveTo(pt.x - d.y, pt.y + d.x);
   2759     ctx.lineTo(pt.x + d.x, pt.y + d.y);
   2760     ctx.lineTo(pt.x + d.y, pt.y - d.x);
   2761     ctx.strokeStyle = "rgba(0,75,0, 0.4)";
   2762     ctx.stroke();
   2763 }
   2764 
   2765 function drawVisibleDirection(curve) {
   2766     var s = pt_at_t(curve, 0);
   2767     var e = pt_at_t(curve, 1);
   2768     var sOn = ptOnScreen(s);
   2769     var eOn = ptOnScreen(e);
   2770     var defaultT = 0.65;
   2771     if (sOn && eOn) {
   2772         return drawDirection(curve, defaultT);
   2773     }
   2774     if (sOn || eOn) {
   2775         if (eOn) {
   2776             defaultT = 1 - defaultT;
   2777         }
   2778         var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
   2779         var t = defaultT;
   2780         var tries = 16;
   2781         do {
   2782             var mid = pt_at_t(curve, t);
   2783             if (ptOnScreen(mid))
   2784                 return drawDirection(curve, t);
   2785             t += step;
   2786             step /= 2;
   2787         } while (--tries > 0);
   2788         drawDirection(curve, defaultT);
   2789     }
   2790     // scattershot until we find a visible point
   2791     var denom = 2;  // visit odd number num / denom to hit unique pts
   2792     var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
   2793     do {
   2794         for (var numer = 1; numer < denom; numer += 2) {
   2795             var t = numer / denom + 0.1;
   2796             if (t >= 1) {
   2797                 break;
   2798             }
   2799             var mid = pt_at_t(curve, t);
   2800             if (ptOnScreen(mid))
   2801                 return drawDirection(curve, t);
   2802         }
   2803         denom *= 2;
   2804     } while (--tries > 0);
   2805     drawDirection(curve, defaultT);
   2806 }
   2807 
   2808 function drawID(curve, t, id) {
   2809     var px = x_at_t(curve, t);
   2810     var py = y_at_t(curve, t);
   2811     var _px = (px - srcLeft) * scale;
   2812     var _py = (py - srcTop) * scale;
   2813     draw_id_at(id, _px, _py);
   2814 }
   2815 
   2816 function localToGlobal(local) {
   2817     var global = {};
   2818     global.x = (local.x - srcLeft) * scale;
   2819     global.y = (local.y - srcTop) * scale;
   2820     return global;
   2821 }
   2822 
   2823 function ptOnScreen(local) {
   2824     var pt = localToGlobal(local);
   2825     return 10 <= pt.x && pt.x <= screenWidth - 10
   2826         && 10 <= pt.y && pt.y <= screenHeight - 10;
   2827 }
   2828 
   2829 function drawVisibleID(curve, defaultT, id) {
   2830     // determine if either or both ends are visible
   2831     var s = pt_at_t(curve, 0);
   2832     var e = pt_at_t(curve, 1);
   2833     var sOn = ptOnScreen(s);
   2834     var eOn = ptOnScreen(e);
   2835     if (sOn && eOn)
   2836         return drawID(curve, defaultT, id);
   2837     if (sOn || eOn) {
   2838         var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
   2839         var t = defaultT;
   2840         var tries = 16;
   2841         do {
   2842             var mid = pt_at_t(curve, t);
   2843             if (ptOnScreen(mid))
   2844                 return drawID(curve, t, id);
   2845             t += step;
   2846             step /= 2;
   2847         } while (--tries > 0);
   2848         drawID(curve, defaultT, id);
   2849     }
   2850     // scattershot until we find a visible point
   2851     var denom = 2;  // visit odd number num / denom to hit unique pts
   2852     var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
   2853     do {
   2854         for (var numer = 1; numer < denom; numer += 2) {
   2855             var t = numer / denom;
   2856             var mid = pt_at_t(curve, t);
   2857             if (ptOnScreen(mid))
   2858                 return drawID(curve, t, id);
   2859         }
   2860         denom *= 2;
   2861     } while (--tries > 0);
   2862     drawID(curve, defaultT, id);
   2863 }
   2864 
   2865 function draw_id_at(id, _px, _py) {
   2866     ctx.beginPath();
   2867     ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
   2868     ctx.closePath();
   2869     ctx.fillStyle = "white";
   2870     ctx.fill();
   2871     ctx.strokeStyle = "rgba(127,127,0, 1)";
   2872     ctx.fillStyle = "rgba(127,127,0, 1)";
   2873     ctx.stroke();
   2874     ctx.font = "normal 16px Arial";
   2875     ctx.textAlign = "center";
   2876     ctx.fillText(id, _px, _py + 5);
   2877     ctx.font = "normal 10px Arial";
   2878 }
   2879 
   2880 function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
   2881     var curve = [x1, y1, x2, y2];
   2882     drawCurvePartialID(id, curve, t1, t2);
   2883 }
   2884 
   2885 function drawLineID(id, x1, y1, x2, y2) {
   2886     drawLinePartialID(id, x1, y1, x2, y2, 0, 1);
   2887 }
   2888 
   2889 function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
   2890     var curve = [x1, y1, x2, y2, x3, y3];
   2891     drawCurvePartialID(id, curve, t1, t2);
   2892 }
   2893 
   2894 function drawQuadID(id, x1, y1, x2, y2, x3, y3) {
   2895     drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1);
   2896 }
   2897 
   2898 function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
   2899     var curve = [x1, y1, x2, y2, x3, y3, w];
   2900     drawCurvePartialID(id, curve, t1, t2);
   2901 }
   2902 
   2903 function drawConicID(id, x1, y1, x2, y2, x3, y3, w) {
   2904     drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1);
   2905 }
   2906 
   2907 function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
   2908     var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
   2909     drawCurvePartialID(id, curve, t1, t2);
   2910 }
   2911 
   2912 function drawCubicID(id, x1, y1, x2, y2, x3, y3, x4, y4) {
   2913     drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, 0, 1);
   2914 }
   2915 
   2916 function  drawCurvePartialID(id, curve, t1, t2) {
   2917     drawVisibleID(curve, (t1 + t2) / 2, id);
   2918 }
   2919 
   2920 function drawCurveSpecials(test, curve, type) {
   2921     if (pt_labels) {
   2922         drawPoints(curve, type, pt_labels == 2);
   2923     }
   2924     if (control_lines != 0) {
   2925         drawControlLines(curve, type, control_lines);
   2926     }
   2927     if (curve_t) {
   2928         drawPointAtT(curve, type);
   2929     }
   2930     if (draw_midpoint) {
   2931         var mid = pointAtT(curve, type, 0.5);
   2932         drawPoint(mid.x, mid.y, true);
   2933     }
   2934     if (draw_id) {
   2935         var id = idByCurve(test, curve, type);
   2936         if (id >= 0) {
   2937             drawVisibleID(curve, 0.5, id);
   2938         }
   2939     }
   2940     if (draw_direction) {
   2941         drawVisibleDirection(curve);
   2942     }
   2943     if (type == PATH_LINE) {
   2944         return;
   2945     }
   2946     if (draw_deriviatives > 0) {
   2947         var d = dxy_at_t(curve, type, 0);
   2948         drawArrow(curve[0], curve[1], d.x, d.y, 1);
   2949         if (draw_deriviatives == 2) {
   2950             d = dxy_at_t(curve, type, 1);
   2951             if (type == PATH_CUBIC) {
   2952                 drawArrow(curve[6], curve[7], d.x, d.y, 1);
   2953             } else {
   2954                 drawArrow(curve[4], curve[5], d.x, d.y, 1);
   2955             }
   2956         }
   2957         if (draw_midpoint) {
   2958             var mid = pointAtT(curve, type, 0.5);
   2959             d = dxy_at_t(curve, type, 0.5);
   2960             drawArrow(mid.x, mid.y, d.x, d.y, 1);
   2961         }
   2962     }
   2963     if (type != PATH_CUBIC) {
   2964         return;
   2965     }
   2966     if (draw_sequence) {
   2967         var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
   2968         for (var i = 0; i < 8; i+= 2) {
   2969             drawLabelX(ymin, i >> 1, curve[i]);
   2970         }
   2971         var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
   2972         for (var i = 1; i < 8; i+= 2) {
   2973             drawLabelY(xmin, i >> 1, curve[i]);
   2974         }
   2975     }
   2976 }
   2977 
   2978 function logCurves(test) {
   2979     for (curves in test) {
   2980         var curve = test[curves];
   2981         dumpCurve(curve);
   2982     }
   2983 }
   2984 
   2985 function curveToString(curve) {
   2986     var str = "{{";
   2987     var length = curve.length == 7 ? 6 : curve.length;
   2988     if (curve.length == 7) {
   2989         str += "{";
   2990     }
   2991     for (i = 0; i < length; i += 2) {
   2992         str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
   2993         if (i < curve.length - 2) {
   2994             str += "}, {";
   2995         }
   2996     }
   2997     str += "}";
   2998     if (curve.length == 7) {
   2999         str += "}, " + curve[6].toFixed(decimal_places);
   3000     }
   3001     str += "}";
   3002     return str;
   3003 }
   3004 
   3005 function dumpCurve(curve) {
   3006     console.log(curveToString(curve));
   3007 }
   3008 
   3009 function draw(test, lines, title) {
   3010     ctx.fillStyle = "rgba(0,0,0, 0.1)";
   3011     ctx.font = "normal 50px Arial";
   3012     ctx.textAlign = "left";
   3013     ctx.fillText(title, 50, 50);
   3014     ctx.font = "normal 10px Arial";
   3015     ctx.lineWidth = "1.001"; "0.999";
   3016     var secondPath = test.length;
   3017     var closeCount = 0;
   3018     logStart = -1;
   3019     logRange = 0;
   3020     // find last active rec type at this step
   3021     var curType = test[0];
   3022     var curStep = 0;
   3023     var hasOp = false;
   3024     var lastActive = 0;
   3025     var lastAdd = 0;
   3026     var lastCoin = 0;
   3027     var lastSect = 0;
   3028     var lastSort = 0;
   3029     var lastMark = 0;
   3030     var lastTop = 0;
   3031     activeCount = 0;
   3032     addCount = 0;
   3033     angleCount = 0;
   3034     opCount = 0;
   3035     sectCount = 0;
   3036     sortCount = 0;
   3037     topCount = 0;
   3038     markCount = 0;
   3039     activeMax = 0;
   3040     addMax = 0;
   3041     angleMax = 0;
   3042     coinMax = 0;
   3043     opMax = 0;
   3044     sectMax = 0;
   3045     sectMax2 = 0;
   3046     sortMax = 0;
   3047     topMax = 0;
   3048     markMax = 0;
   3049     lastIndex = test.length - 3;
   3050     for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
   3051         var recType = test[tIndex];
   3052         if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
   3053             console.log("unknown rec type: " + recType);
   3054             throw "stop execution";
   3055         }
   3056    //     if (curType == recType && curType != REC_TYPE_ADD) {
   3057    //         continue;
   3058    //     }
   3059         var inStepRange = step_limit == 0 || curStep < step_limit;
   3060         curType = recType;
   3061         if (recType == REC_TYPE_OP) {
   3062             hasOp = true;
   3063             continue;
   3064         }
   3065         if (recType == REC_TYPE_UNKNOWN) {
   3066             // these types do not advance step
   3067             continue;
   3068         }
   3069         var bumpStep = false;
   3070         var records = test[tIndex + 2];
   3071         var fragType = records[0];
   3072         if (recType == REC_TYPE_ADD) {
   3073             if (records.length != 2) {
   3074                 console.log("expect only two elements: " + records.length);
   3075                 throw "stop execution";
   3076             }
   3077             if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
   3078                 continue;
   3079             }
   3080             ++addMax;
   3081             if (!draw_add || !inStepRange) {
   3082                 continue;
   3083             }
   3084             lastAdd = tIndex;
   3085             ++addCount;
   3086             bumpStep = true;
   3087         }
   3088         if (recType == REC_TYPE_PATH && hasOp) {
   3089             secondPath = tIndex;
   3090         }
   3091         if (recType == REC_TYPE_PATH2 && hasOp) {
   3092             secondPath = tIndex;
   3093         }
   3094         if (recType == REC_TYPE_ACTIVE) {
   3095             ++activeMax;
   3096             if (!draw_active || !inStepRange) {
   3097                 continue;
   3098             }
   3099             lastActive = tIndex;
   3100             ++activeCount;
   3101             bumpStep = true;
   3102         }
   3103         if (recType == REC_TYPE_ACTIVE_OP) {
   3104             ++opMax;
   3105             if (!draw_op || !inStepRange) {
   3106                 continue;
   3107             }
   3108             lastOp = tIndex;
   3109             ++opCount;
   3110             bumpStep = true;
   3111         }
   3112         if (recType == REC_TYPE_AFTERPART) {
   3113             if (draw_angle != 3 || !inStepRange) {
   3114                 continue;
   3115             }
   3116             lastAngle = tIndex;
   3117             ++angleCount;
   3118             bumpStep = true;
   3119         }
   3120         if (recType == REC_TYPE_ANGLE) {
   3121             ++angleMax;
   3122             if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
   3123                 continue;
   3124             }
   3125             lastAngle = tIndex;
   3126             ++angleCount;
   3127             bumpStep = true;
   3128         }
   3129         if (recType == REC_TYPE_COINCIDENCE) {
   3130             ++coinMax;
   3131             if (!draw_coincidence || !inStepRange) {
   3132                 continue;
   3133             }
   3134             lastCoin = tIndex;
   3135             ++coinCount;
   3136             bumpStep = true;
   3137         }
   3138         if (recType == REC_TYPE_SECT) {
   3139             if (records.length != 2) {
   3140                 console.log("expect only two elements: " + records.length);
   3141                 throw "stop execution";
   3142             }
   3143             ++sectMax;
   3144             var sectBump = 1;
   3145             switch (fragType) {
   3146                 case INTERSECT_LINE:
   3147                 case INTERSECT_QUAD_LINE:
   3148                 case INTERSECT_QUAD:
   3149                 case INTERSECT_CONIC_LINE:
   3150                 case INTERSECT_CONIC_QUAD:
   3151                 case INTERSECT_CONIC:
   3152                 case INTERSECT_SELF_CUBIC:
   3153                 case INTERSECT_CUBIC_LINE:
   3154                 case INTERSECT_CUBIC_QUAD:
   3155                 case INTERSECT_CUBIC:
   3156                     sectBump = 1;
   3157                     break;
   3158                 case INTERSECT_LINE_2:
   3159                 case INTERSECT_QUAD_LINE_2:
   3160                 case INTERSECT_QUAD_2:
   3161                 case INTERSECT_CONIC_LINE_2:
   3162                 case INTERSECT_CONIC_QUAD_2:
   3163                 case INTERSECT_CONIC_2:
   3164                 case INTERSECT_CUBIC_LINE_2:
   3165                 case INTERSECT_CUBIC_QUAD_2:
   3166                 case INTERSECT_CUBIC_2:
   3167                     sectBump = 2;
   3168                     break;
   3169                 case INTERSECT_LINE_NO:
   3170                 case INTERSECT_QUAD_LINE_NO:
   3171                 case INTERSECT_QUAD_NO:
   3172                 case INTERSECT_CONIC_LINE_NO:
   3173                 case INTERSECT_CONIC_QUAD_NO:
   3174                 case INTERSECT_CONIC_NO:
   3175                 case INTERSECT_SELF_CUBIC_NO:
   3176                 case INTERSECT_CUBIC_LINE_NO:
   3177                 case INTERSECT_CUBIC_QUAD_NO:
   3178                 case INTERSECT_CUBIC_NO:
   3179                     sectBump = 0;
   3180                     break;
   3181                 case INTERSECT_CONIC_QUAD_3:
   3182                 case INTERSECT_CUBIC_LINE_3:
   3183                 case INTERSECT_CUBIC_QUAD_3:
   3184                 case INTERSECT_CUBIC_3:
   3185                     sectBump = 3;
   3186                     break;
   3187                 case INTERSECT_CONIC_QUAD_4:
   3188                 case INTERSECT_CUBIC_QUAD_4:
   3189                 case INTERSECT_CUBIC_4:
   3190                     sectBump = 4;
   3191                     break;
   3192                 default:
   3193                     console.log("missing case " + records.length);
   3194                     throw "stop execution";
   3195             }
   3196             sectMax2 += sectBump;
   3197             if (draw_intersection <= 1 || !inStepRange) {
   3198                 continue;
   3199             }
   3200             lastSect = tIndex;
   3201             sectCount += sectBump;
   3202             bumpStep = true;
   3203         }
   3204         if (recType == REC_TYPE_SORT) {
   3205             ++sortMax;
   3206             if (!draw_sort || !inStepRange) {
   3207                 continue;
   3208             }
   3209             lastSort = tIndex;
   3210             ++sortCount;
   3211             bumpStep = true;
   3212         }
   3213         if (recType == REC_TYPE_TOP) {
   3214             ++topMax;
   3215             if (!draw_top || !inStepRange) {
   3216                 continue;
   3217             }
   3218             lastTop = tIndex;
   3219             ++topCount;
   3220             bumpStep = true;
   3221         }
   3222         if (recType == REC_TYPE_MARK) {
   3223             ++markMax;
   3224             if (!draw_mark || !inStepRange) {
   3225                 continue;
   3226             }
   3227             lastMark = tIndex;
   3228             ++markCount;
   3229             bumpStep = true;
   3230         }
   3231         if (bumpStep) {
   3232             lastIndex = tIndex;
   3233             logStart = test[tIndex + 1];
   3234             logRange = records.length / 2;
   3235             ++curStep;
   3236         }
   3237     }
   3238     stepMax = (draw_add ? addMax : 0)
   3239             + (draw_active ? activeMax : 0)
   3240             + (draw_angle ? angleMax : 0)
   3241             + (draw_coincidence ? coinMax : 0)
   3242             + (draw_op ? opMax : 0)
   3243             + (draw_sort ? sortMax : 0)
   3244             + (draw_top ? topMax : 0)
   3245             + (draw_mark ? markMax : 0)
   3246             + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
   3247     if (stepMax == 0) {
   3248         stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
   3249     }
   3250     drawnPts = [];
   3251     drawnLines = [];
   3252     drawnQuads = [];
   3253     drawnConics = [];
   3254     drawnCubics = [];
   3255     focusXmin = focusYmin = Infinity;
   3256     focusXmax = focusYmax = -Infinity;
   3257     var pathIndex = 0;
   3258     var opLetter = 'S';
   3259     for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
   3260         var recType = test[tIndex];
   3261         var records = test[tIndex + 2];
   3262         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   3263             var fragType = records[recordIndex];
   3264             if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
   3265                 console.log("unknown in range frag type: " + fragType);
   3266                 throw "stop execution";
   3267             }
   3268             var frags = records[recordIndex + 1];
   3269             focus_enabled = false;
   3270             switch (recType) {
   3271                 case REC_TYPE_COMPUTED:
   3272                     if (draw_computed == 0) {
   3273                         continue;
   3274                     }
   3275                     ctx.lineWidth = 1;
   3276                     ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
   3277                     ctx.fillStyle = "blue";
   3278                     var drawThis = false;
   3279                     switch (fragType) {
   3280                         case PATH_QUAD:
   3281                             if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
   3282                                     && (draw_computed & 7) == pathIndex)) {
   3283                                 drawQuad(frags[0], frags[1], frags[2], frags[3],
   3284                                         frags[4], frags[5]);
   3285                                 drawThis = true;
   3286                             }
   3287                             break;
   3288                         case PATH_CONIC:
   3289                             if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
   3290                                     && (draw_computed & 7) == pathIndex)) {
   3291                                 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
   3292                                         frags[4], frags[5], frags[6]);
   3293                                 drawThis = true;
   3294                             }
   3295                             break;
   3296                         case PATH_CUBIC:
   3297                             if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
   3298                                      && (draw_computed & 7) == pathIndex)) {
   3299                                 drawCubic(frags[0], frags[1], frags[2], frags[3],
   3300                                         frags[4], frags[5], frags[6], frags[7]);
   3301                                 drawThis = true;
   3302                             }
   3303                             ++pathIndex;
   3304                             break;
   3305                         case COMPUTED_SET_1:
   3306                             pathIndex = 0;
   3307                             break;
   3308                         case COMPUTED_SET_2:
   3309                             pathIndex = 1;
   3310                             break;
   3311                         default:
   3312                             console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
   3313                             throw "stop execution";
   3314                     }
   3315                     if (!drawThis || collect_bounds) {
   3316                         break;
   3317                     }
   3318                     drawCurveSpecials(test, frags, fragType);
   3319                     break;
   3320                 case REC_TYPE_ALIGNED:
   3321                     if (draw_path < 4) {
   3322                         continue;
   3323                     }
   3324                 case REC_TYPE_PATH:
   3325                 case REC_TYPE_PATH2:
   3326                     if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
   3327                         continue;
   3328                     }
   3329                     if (!draw_path) {
   3330                         continue;
   3331                     }
   3332                     var firstPath = tIndex < secondPath;
   3333                     if ((draw_path & (firstPath ? 1 : 2)) == 0) {
   3334                         continue;
   3335                     }
   3336                     ctx.lineWidth = 1;
   3337                     ctx.strokeStyle = firstPath ? "black" : "red";
   3338                     ctx.fillStyle = "blue";
   3339                     var frags2 = [];
   3340                     switch (fragType) {
   3341                         case PATH_LINE:
   3342                             for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
   3343                             drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
   3344                             break;
   3345                         case PATH_QUAD:
   3346                             for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
   3347                             drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
   3348                                     frags2[4], frags2[5]);
   3349                             break;
   3350                         case PATH_CONIC:
   3351                             for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
   3352                             drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
   3353                                     frags2[4], frags2[5], frags2[6]);
   3354                             break;
   3355                         case PATH_CUBIC:
   3356                             for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
   3357                             drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
   3358                                     frags2[4], frags2[5], frags2[6], frags2[7]);
   3359                             break;
   3360                         default:
   3361                             console.log("unknown " + recType + " frag type: " + fragType);
   3362                             throw "stop execution";
   3363                     }
   3364                     if (collect_bounds) {
   3365                         break;
   3366                     }
   3367                     drawCurveSpecials(test, frags2, fragType);
   3368                     break;
   3369                 case REC_TYPE_OP:
   3370                     switch (fragType) {
   3371                         case OP_INTERSECT: opLetter = 'I'; break;
   3372                         case OP_DIFFERENCE: opLetter = 'D'; break;
   3373                         case OP_UNION: opLetter = 'U'; break;
   3374                         case OP_XOR: opLetter = 'X'; break;
   3375                         default:
   3376                             console.log("unknown REC_TYPE_OP frag type: " + fragType);
   3377                             throw "stop execution";
   3378                     }
   3379                     break;
   3380                 case REC_TYPE_ACTIVE:
   3381                     if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
   3382                         continue;
   3383                     }
   3384                     var x1 = frags[SPAN_X1];
   3385                     var y1 = frags[SPAN_Y1];
   3386                     var x2 = frags[SPAN_X2];
   3387                     var y2 = frags[SPAN_Y2];
   3388                     var x3, y3, x3, y4, w;
   3389                     ctx.lineWidth = 3;
   3390                     ctx.strokeStyle = "rgba(0,0,255, 0.3)";
   3391                     focus_enabled = true;
   3392                     switch (fragType) {
   3393                         case ACTIVE_LINE_SPAN:
   3394                             drawLine(x1, y1, x2, y2);
   3395                             if (draw_id) {
   3396                                 drawLineID(frags[0], x1, y1, x2, y2);
   3397                             }
   3398                             if (pt_labels) {
   3399                                 var curve = [x1, y1, x2, y2];
   3400                                 ctx.fillStyle = "blue";
   3401                                 drawPoints(curve, PATH_LINE, pt_labels == 2);
   3402                             }
   3403                              break;
   3404                         case ACTIVE_QUAD_SPAN:
   3405                             x3 = frags[SPAN_X3];
   3406                             y3 = frags[SPAN_Y3];
   3407                             drawQuad(x1, y1, x2, y2, x3, y3);
   3408                             if (draw_id) {
   3409                                 drawQuadID(frags[0], x1, y1, x2, y2, x3, y3);
   3410                             }
   3411                             if (pt_labels) {
   3412                                 var curve = [x1, y1, x2, y2, x3, y3];
   3413                                 ctx.fillStyle = "blue";
   3414                                 drawPoints(curve, PATH_QUAD, pt_labels == 2);
   3415                             }
   3416                             break;
   3417                         case ACTIVE_CONIC_SPAN:
   3418                             x3 = frags[SPAN_X3];
   3419                             y3 = frags[SPAN_Y3];
   3420                             w = frags[SPAN_K_W];
   3421                             drawConicWithQuads(x1, y1, x2, y2, x3, y3, w);
   3422                             if (draw_id) {
   3423                                 drawConicID(frags[0], x1, y1, x2, y2, x3, y3, w);
   3424                             }
   3425                             if (pt_labels) {
   3426                                 var curve = [x1, y1, x2, y2, x3, y3, w];
   3427                                 ctx.fillStyle = "blue";
   3428                                 drawPoints(curve, PATH_CONIC, pt_labels == 2);
   3429                             }
   3430                             break;
   3431                         case ACTIVE_CUBIC_SPAN:
   3432                             x3 = frags[SPAN_X3];
   3433                             y3 = frags[SPAN_Y3];
   3434                             x4 = frags[SPAN_X4];
   3435                             y4 = frags[SPAN_Y4];
   3436                             drawCubic(x1, y1, x2, y2, x3, y3, x4, y4);
   3437                             if (draw_id) {
   3438                                 drawCubicID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4);
   3439                             }
   3440                             if (pt_labels) {
   3441                                 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
   3442                                 ctx.fillStyle = "blue";
   3443                                 drawPoints(curve, PATH_CUBIC, pt_labels == 2);
   3444                             }
   3445                             break;
   3446                         default:
   3447                             console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
   3448                             throw "stop execution";
   3449                     }
   3450                     break;
   3451                 case REC_TYPE_ACTIVE_OP:
   3452                     if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
   3453                         continue;
   3454                     }
   3455                     focus_enabled = true;
   3456                     ctx.lineWidth = 3;
   3457                     var activeSpan = frags[7] == "1";
   3458                     ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
   3459                     var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
   3460                     drawCurve(curve);
   3461                     if (draw_op > 1) {
   3462                         drawArc(curve, false, frags[3], frags[4]);
   3463                         drawArc(curve, true, frags[5], frags[6]);
   3464                     }
   3465                     break;
   3466                 case REC_TYPE_ADD:
   3467                     if (!draw_add) {
   3468                         continue;
   3469                     }
   3470                     ctx.lineWidth = 3;
   3471                     ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
   3472                             : closeCount == 1 ? "rgba(0,127,0, 0.3)"
   3473                             : closeCount == 2 ? "rgba(0,127,127, 0.3)"
   3474                             : closeCount == 3 ? "rgba(127,127,0, 0.3)"
   3475                             : "rgba(127,0,127, 0.3)";
   3476                     focus_enabled = true;
   3477                     switch (fragType) {
   3478                         case ADD_MOVETO:
   3479                             break;
   3480                         case ADD_LINETO:
   3481                             if (step_limit == 0 || tIndex >= lastAdd) {
   3482                                 drawLine(frags[0], frags[1], frags[2], frags[3]);
   3483                             }
   3484                             break;
   3485                         case ADD_QUADTO:
   3486                             if (step_limit == 0 || tIndex >= lastAdd) {
   3487                                 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
   3488                             }
   3489                             break;
   3490                         case ADD_CONICTO:
   3491                             if (step_limit == 0 || tIndex >= lastAdd) {
   3492                                 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
   3493                                         frags[4], frags[5], frags[6]);
   3494                             }
   3495                             break;
   3496                         case ADD_CUBICTO:
   3497                             if (step_limit == 0 || tIndex >= lastAdd) {
   3498                                 drawCubic(frags[0], frags[1], frags[2], frags[3],
   3499                                         frags[4], frags[5], frags[6], frags[7]);
   3500                             }
   3501                             break;
   3502                         case ADD_CLOSE:
   3503                             ++closeCount;
   3504                             break;
   3505                         case ADD_FILL:
   3506                             break;
   3507                         default:
   3508                             console.log("unknown REC_TYPE_ADD frag type: " + fragType);
   3509                             throw "stop execution";
   3510                     }
   3511                     break;
   3512                 case REC_TYPE_ANGLE:
   3513                     angleBetween = frags[18] == "T";
   3514                     afterIndex = 0;
   3515                     if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
   3516                         continue;
   3517                     }
   3518                     focus_enabled = true;
   3519                     ctx.lineWidth = 3;
   3520                     ctx.strokeStyle = "rgba(127,45,127, 0.3)";
   3521                     var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
   3522                     var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
   3523                     var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
   3524                     drawCurve(leftCurve);
   3525                     drawCurve(rightCurve);
   3526                     ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
   3527                     drawCurve(midCurve);
   3528                     if (draw_angle > 1) {
   3529                         drawVisibleOrder(leftCurve, 'L');
   3530                         drawVisibleOrder(rightCurve, 'R');
   3531                     }
   3532                     if (draw_id) {
   3533                         drawVisibleID(leftCurve, 0.5, frags[0]);
   3534                         drawVisibleID(midCurve, 0.5, frags[6]);
   3535                         drawVisibleID(rightCurve, 0.5, frags[12]);
   3536                     }
   3537                     break;
   3538                 case REC_TYPE_AFTERPART:
   3539                     if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
   3540                         continue;
   3541                     }
   3542                     ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
   3543                             : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
   3544                             : "rgba(0,0,255, 1.0)";
   3545                     var curve;
   3546                     var id;
   3547                     switch (fragType) {
   3548                         case PATH_LINE:
   3549                             curve = [ frags[0], frags[1], frags[2], frags[3] ];
   3550                             id = frags[4];
   3551                             break;
   3552                         case PATH_QUAD:
   3553                             curve = [ frags[0], frags[1], frags[2], frags[3],
   3554                                      frags[4], frags[5] ];
   3555                             id = frags[6];
   3556                             break;
   3557                         case PATH_CONIC:
   3558                             curve = [ frags[0], frags[1], frags[2], frags[3],
   3559                                      frags[4], frags[5], frags[6] ];
   3560                             id = frags[7];
   3561                             break;
   3562                         case PATH_CUBIC:
   3563                             curve = [ frags[0], frags[1], frags[2], frags[3],
   3564                                      frags[4], frags[5], frags[6], frags[7] ];
   3565                             id = frags[8];
   3566                             break;
   3567                         default:
   3568                             console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
   3569                             throw "stop execution";
   3570                     }
   3571                     drawCurve(curve);
   3572                     if (draw_id) {
   3573                         drawVisibleID(curve, 0.5, id);
   3574                     }
   3575                     ++afterIndex;
   3576                     break;
   3577                 case REC_TYPE_COINCIDENCE:
   3578                     if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
   3579                         continue;
   3580                     }
   3581                     focus_enabled = true;
   3582                     ctx.lineWidth = 3;
   3583                     ctx.strokeStyle = "rgba(127,45,63, 0.3)";
   3584                     var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
   3585                     drawCurve(curve);
   3586                     break;
   3587                 case REC_TYPE_SECT:
   3588                     if (!draw_intersection) {
   3589                         continue;
   3590                     }
   3591                     if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
   3592                         continue;
   3593                     }
   3594                     // draw_intersection == 1 : show all
   3595                     // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
   3596                     // draw_intersection == 3 : step == 0 ? show all : show intersection #step
   3597                     ctx.lineWidth = 1;
   3598                     ctx.strokeStyle = "rgba(0,0,255, 0.3)";
   3599                     ctx.fillStyle = "blue";
   3600                     focus_enabled = true;
   3601                     var f = [];
   3602                     var c1s;
   3603                     var c1l;
   3604                     var c2s;
   3605                     var c2l;
   3606                     switch (fragType) {
   3607                         case INTERSECT_LINE:
   3608                             f.push(5, 6, 0, 7);
   3609                             c1s = 1; c1l = 4; c2s = 8; c2l = 4;
   3610                             break;
   3611                         case INTERSECT_LINE_2:
   3612                             f.push(5, 6, 0, 10);
   3613                             f.push(8, 9, 7, 15);
   3614                             c1s = 1; c1l = 4; c2s = 11; c2l = 4;
   3615                             break;
   3616                         case INTERSECT_LINE_NO:
   3617                             c1s = 0; c1l = 4; c2s = 4; c2l = 4;
   3618                             break;
   3619                         case INTERSECT_QUAD_LINE:
   3620                             f.push(7, 8, 0, 9);
   3621                             c1s = 1; c1l = 6; c2s = 10; c2l = 4;
   3622                             break;
   3623                         case INTERSECT_QUAD_LINE_2:
   3624                             f.push(7, 8, 0, 12);
   3625                             f.push(10, 11, 9, 17);
   3626                             c1s = 1; c1l = 6; c2s = 13; c2l = 4;
   3627                             break;
   3628                         case INTERSECT_QUAD_LINE_NO:
   3629                             c1s = 0; c1l = 6; c2s = 6; c2l = 4;
   3630                             break;
   3631                         case INTERSECT_QUAD:
   3632                             f.push(7, 8, 0, 9);
   3633                             c1s = 1; c1l = 6; c2s = 10; c2l = 6;
   3634                             break;
   3635                         case INTERSECT_QUAD_2:
   3636                             f.push(7, 8, 0, 12);
   3637                             f.push(10, 11, 9, 19);
   3638                             c1s = 1; c1l = 6; c2s = 13; c2l = 6;
   3639                             break;
   3640                         case INTERSECT_QUAD_NO:
   3641                             c1s = 0; c1l = 6; c2s = 6; c2l = 6;
   3642                             break;
   3643                         case INTERSECT_CONIC_LINE:
   3644                             f.push(8, 9, 0, 10);
   3645                             c1s = 1; c1l = 7; c2s = 11; c2l = 4;
   3646                             break;
   3647                         case INTERSECT_CONIC_LINE_2:
   3648                             f.push(8, 9, 0, 12);
   3649                             f.push(11, 12, 10, 18);
   3650                             c1s = 1; c1l = 7; c2s = 14; c2l = 4;
   3651                             break;
   3652                         case INTERSECT_CONIC_LINE_NO:
   3653                             c1s = 0; c1l = 7; c2s = 7; c2l = 4;
   3654                             break;
   3655                         case INTERSECT_CONIC_QUAD:
   3656                             f.push(8, 9, 0, 10);
   3657                             c1s = 1; c1l = 7; c2s = 11; c2l = 6;
   3658                             break;
   3659                         case INTERSECT_CONIC_QUAD_2:
   3660                             f.push(8, 9, 0, 12);
   3661                             f.push(11, 12, 10, 18);
   3662                             c1s = 1; c1l = 7; c2s = 14; c2l = 6;
   3663                             break;
   3664                         case INTERSECT_CONIC_QUAD_3:
   3665                             f.push(8, 9, 0, 15);
   3666                             f.push(11, 12, 10, 21);
   3667                             f.push(14, 15, 13, 22);
   3668                             c1s = 1; c1l = 7; c2s = 17; c2l = 6;
   3669                             break;
   3670                         case INTERSECT_CONIC_QUAD_4:
   3671                             f.push(8, 9, 0, 18);
   3672                             f.push(11, 12, 10, 24);
   3673                             f.push(14, 15, 13, 25);
   3674                             f.push(17, 18, 16, 26);
   3675                             c1s = 1; c1l = 7; c2s = 20; c2l = 6;
   3676                             break;
   3677                         case INTERSECT_CONIC_QUAD_NO:
   3678                             c1s = 0; c1l = 7; c2s = 7; c2l = 6;
   3679                             break;
   3680                         case INTERSECT_CONIC:
   3681                             f.push(8, 9, 0, 10);
   3682                             c1s = 1; c1l = 7; c2s = 11; c2l = 7;
   3683                             break;
   3684                         case INTERSECT_CONIC_2:
   3685                             f.push(8, 9, 0, 13);
   3686                             f.push(11, 12, 10, 21);
   3687                             c1s = 1; c1l = 7; c2s = 14; c2l = 7;
   3688                             break;
   3689                         case INTERSECT_CONIC_NO:
   3690                             c1s = 0; c1l = 7; c2s = 7; c2l = 7;
   3691                             break;
   3692                         case INTERSECT_SELF_CUBIC:
   3693                             f.push(9, 10, 0, 11);
   3694                             c1s = 1; c1l = 8; c2s = 0; c2l = 0;
   3695                             break;
   3696                         case INTERSECT_SELF_CUBIC_NO:
   3697                             c1s = 0; c1l = 8; c2s = 0; c2l = 0;
   3698                             break;
   3699                         case INTERSECT_CUBIC_LINE:
   3700                             f.push(9, 10, 0, 11);
   3701                             c1s = 1; c1l = 8; c2s = 12; c2l = 4;
   3702                             break;
   3703                         case INTERSECT_CUBIC_LINE_2:
   3704                             f.push(9, 10, 0, 14);
   3705                             f.push(12, 13, 11, 19);
   3706                             c1s = 1; c1l = 8; c2s = 15; c2l = 4;
   3707                             break;
   3708                         case INTERSECT_CUBIC_LINE_3:
   3709                             f.push(9, 10, 0, 17);
   3710                             f.push(12, 13, 11, 22);
   3711                             f.push(15, 16, 14, 23);
   3712                             c1s = 1; c1l = 8; c2s = 18; c2l = 4;
   3713                             break;
   3714                         case INTERSECT_CUBIC_QUAD_NO:
   3715                             c1s = 0; c1l = 8; c2s = 8; c2l = 6;
   3716                             break;
   3717                         case INTERSECT_CUBIC_QUAD:
   3718                             f.push(9, 10, 0, 11);
   3719                             c1s = 1; c1l = 8; c2s = 12; c2l = 6;
   3720                             break;
   3721                         case INTERSECT_CUBIC_QUAD_2:
   3722                             f.push(9, 10, 0, 14);
   3723                             f.push(12, 13, 11, 21);
   3724                             c1s = 1; c1l = 8; c2s = 15; c2l = 6;
   3725                             break;
   3726                         case INTERSECT_CUBIC_QUAD_3:
   3727                             f.push(9, 10, 0, 17);
   3728                             f.push(12, 13, 11, 24);
   3729                             f.push(15, 16, 14, 25);
   3730                             c1s = 1; c1l = 8; c2s = 18; c2l = 6;
   3731                             break;
   3732                         case INTERSECT_CUBIC_QUAD_4:
   3733                             f.push(9, 10, 0, 20);
   3734                             f.push(12, 13, 11, 27);
   3735                             f.push(15, 16, 14, 28);
   3736                             f.push(18, 19, 17, 29);
   3737                             c1s = 1; c1l = 8; c2s = 21; c2l = 6;
   3738                             break;
   3739                         case INTERSECT_CUBIC_LINE_NO:
   3740                             c1s = 0; c1l = 8; c2s = 8; c2l = 4;
   3741                             break;
   3742                         case INTERSECT_CUBIC:
   3743                             f.push(9, 10, 0, 11);
   3744                             c1s = 1; c1l = 8; c2s = 12; c2l = 8;
   3745                             break;
   3746                         case INTERSECT_CUBIC_2:
   3747                             f.push(9, 10, 0, 14);
   3748                             f.push(12, 13, 11, 23);
   3749                             c1s = 1; c1l = 8; c2s = 15; c2l = 8;
   3750                             break;
   3751                         case INTERSECT_CUBIC_3:
   3752                             f.push(9, 10, 0, 17);
   3753                             f.push(12, 13, 11, 26);
   3754                             f.push(15, 16, 14, 27);
   3755                             c1s = 1; c1l = 8; c2s = 18; c2l = 8;
   3756                             break;
   3757                         case INTERSECT_CUBIC_4:
   3758                             f.push(9, 10, 0, 20);
   3759                             f.push(12, 13, 11, 29);
   3760                             f.push(15, 16, 14, 30);
   3761                             f.push(18, 19, 17, 31);
   3762                             c1s = 1; c1l = 8; c2s = 21; c2l = 8;
   3763                             break;
   3764                         case INTERSECT_CUBIC_NO:
   3765                             c1s = 0; c1l = 8; c2s = 8; c2l = 8;
   3766                             break;
   3767                         default:
   3768                             console.log("unknown REC_TYPE_SECT frag type: " + fragType);
   3769                             throw "stop execution";
   3770                     }
   3771                     if (draw_intersection != 1) {
   3772                         var id = -1;
   3773                         var curve;
   3774                         switch (c1l) {
   3775                             case 4:
   3776                                 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
   3777                                 if (draw_id) {
   3778                                     curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
   3779                                     id = idByCurve(test, curve, PATH_LINE);
   3780                                 }
   3781                                 break;
   3782                             case 6:
   3783                                 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
   3784                                         frags[c1s + 4], frags[c1s + 5]);
   3785                                 if (draw_id) {
   3786                                     curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
   3787                                             frags[c1s + 4], frags[c1s + 5]];
   3788                                     id = idByCurve(test, curve, PATH_QUAD);
   3789                                 }
   3790                                 break;
   3791                             case 7:
   3792                                 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
   3793                                         frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
   3794                                 if (draw_id) {
   3795                                     curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
   3796                                             frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
   3797                                     id = idByCurve(test, curve, PATH_CONIC);
   3798                                 }
   3799                                 break;
   3800                             case 8:
   3801                                 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
   3802                                         frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
   3803                                 if (draw_id) {
   3804                                     curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
   3805                                             frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
   3806                                     id = idByCurve(test, curve, PATH_CUBIC);
   3807                                 }
   3808                                 break;
   3809                         }
   3810                         if (id >= 0) {
   3811                             drawVisibleID(curve, 0.5, id);
   3812                         }
   3813                         id = -1;
   3814                         switch (c2l) {
   3815                             case 0:
   3816                                 break;
   3817                             case 4:
   3818                                 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
   3819                                 if (draw_id) {
   3820                                     curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
   3821                                     id = idByCurve(test, curve, PATH_LINE);
   3822                                 }
   3823                                 break;
   3824                             case 6:
   3825                                 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
   3826                                         frags[c2s + 4], frags[c2s + 5]);
   3827                                 if (draw_id) {
   3828                                     curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
   3829                                             frags[c2s + 4], frags[c2s + 5]];
   3830                                     id = idByCurve(test, curve, PATH_QUAD);
   3831                                 }
   3832                                 break;
   3833                             case 7:
   3834                                 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
   3835                                         frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
   3836                                 if (draw_id) {
   3837                                     curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
   3838                                             frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
   3839                                     id = idByCurve(test, curve, PATH_CONIC);
   3840                                 }
   3841                                 break;
   3842                             case 8:
   3843                                 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
   3844                                         frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
   3845                                 if (draw_id) {
   3846                                     curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
   3847                                             frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
   3848                                     id = idByCurve(test, curve, PATH_CUBIC);
   3849                                 }
   3850                                 break;
   3851                         }
   3852                         if (id >= 0) {
   3853                             drawVisibleID(curve, 0.5, id);
   3854                         }
   3855                     }
   3856                     if (collect_bounds) {
   3857                         break;
   3858                     }
   3859                     if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
   3860                         for (var idx = 0; idx < f.length; idx += 4) {
   3861                             drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
   3862                         }
   3863                     }
   3864                     if (!draw_intersectT) {
   3865                         break;
   3866                     }
   3867                     ctx.fillStyle = "red";
   3868                     if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
   3869                         for (var idx = 0; idx < f.length; idx += 4) {
   3870                             drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
   3871                             drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
   3872                         }
   3873                     }
   3874                     break;
   3875                 case REC_TYPE_SORT:
   3876                     if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
   3877                         continue;
   3878                     }
   3879                     ctx.lineWidth = 3;
   3880                     ctx.strokeStyle = "rgba(127,127,0, 0.5)";
   3881                     focus_enabled = true;
   3882                     switch (fragType) {
   3883                         case SORT_UNARY:
   3884                         case SORT_BINARY:
   3885                             var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
   3886                             drawCurve(curve);
   3887                             break;
   3888                         default:
   3889                             console.log("unknown REC_TYPE_SORT frag type: " + fragType);
   3890                             throw "stop execution";
   3891                     }
   3892                     break;
   3893                 case REC_TYPE_TOP:
   3894                     if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
   3895                         continue;
   3896                     }
   3897                     ctx.lineWidth = 3;
   3898                     ctx.strokeStyle = "rgba(127,127,0, 0.5)";
   3899                     focus_enabled = true;
   3900                     {
   3901                         var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
   3902                         drawCurve(curve);
   3903                         var type = PATH_LINE + (curve.length / 2 - 2);
   3904                         var mid = pointAtT(curve, type, 0.5);
   3905                         var d = dxy_at_t(curve, type, 0.5);
   3906                         drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
   3907                     }
   3908                     break;
   3909                 case REC_TYPE_MARK:
   3910                     if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
   3911                         continue;
   3912                     }
   3913                     ctx.lineWidth = 3;
   3914                     ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
   3915                             "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
   3916                     focus_enabled = true;
   3917                     switch (fragType) {
   3918                         case MARK_LINE:
   3919                         case MARK_DONE_LINE:
   3920                         case MARK_UNSORTABLE_LINE:
   3921                         case MARK_SIMPLE_LINE:
   3922                         case MARK_SIMPLE_DONE_LINE:
   3923                         case MARK_DONE_UNARY_LINE:
   3924                             drawLinePartial(frags[1], frags[2], frags[3], frags[4],
   3925                                 frags[5], frags[9]);
   3926                             if (draw_id) {
   3927                                 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
   3928                                 frags[5], frags[9]);
   3929                             }
   3930                             break;
   3931                         case MARK_QUAD:
   3932                         case MARK_DONE_QUAD:
   3933                         case MARK_UNSORTABLE_QUAD:
   3934                         case MARK_SIMPLE_QUAD:
   3935                         case MARK_SIMPLE_DONE_QUAD:
   3936                         case MARK_DONE_UNARY_QUAD:
   3937                             drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
   3938                                 frags[5], frags[6], frags[7], frags[11]);
   3939                             if (draw_id) {
   3940                                 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
   3941                                 frags[5], frags[6], frags[7], frags[11]);
   3942                             }
   3943                             break;
   3944                         case MARK_CUBIC:
   3945                         case MARK_DONE_CUBIC:
   3946                         case MARK_UNSORTABLE_CUBIC:
   3947                         case MARK_SIMPLE_CUBIC:
   3948                         case MARK_SIMPLE_DONE_CUBIC:
   3949                         case MARK_DONE_UNARY_CUBIC:
   3950                             drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
   3951                                 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
   3952                             if (draw_id) {
   3953                                 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
   3954                                 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
   3955                             }
   3956                             break;
   3957                         case MARK_ANGLE_LAST:
   3958                             // FIXME: ignored for now
   3959                             break;
   3960                         default:
   3961                             console.log("unknown REC_TYPE_MARK frag type: " + fragType);
   3962                             throw "stop execution";
   3963                     }
   3964                     break;
   3965                 default:
   3966                     continue;
   3967             }
   3968         }
   3969         switch (recType) {
   3970             case REC_TYPE_SORT:
   3971                 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
   3972                     break;
   3973                 }
   3974                 var angles = []; // use tangent lines to describe arcs
   3975                 var windFrom = [];
   3976                 var windTo = [];
   3977                 var opp = [];
   3978                 var minXY = Number.MAX_VALUE;
   3979                 var partial;
   3980                 focus_enabled = true;
   3981                 var someUnsortable = false;
   3982                 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   3983                     var fragType = records[recordIndex];
   3984                     var frags = records[recordIndex + 1];
   3985                     var unsortable = (fragType == SORT_UNARY && frags[14]) ||
   3986                             (fragType == SORT_BINARY && frags[16]);
   3987                     someUnsortable |= unsortable;
   3988                     switch (fragType) {
   3989                         case SORT_UNARY:
   3990                         case SORT_BINARY:
   3991                             partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
   3992                             break;
   3993                         default:
   3994                             console.log("unknown REC_TYPE_SORT frag type: " + fragType);
   3995                             throw "stop execution";
   3996                     }
   3997                     var dx = boundsWidth(partial);
   3998                     var dy = boundsHeight(partial);
   3999                     minXY = Math.min(minXY, dx * dx + dy * dy);
   4000                     if (collect_bounds) {
   4001                         continue;
   4002                     }
   4003                     angles.push(tangent(partial));
   4004                     var from = frags[12];
   4005                     var to = frags[12];
   4006                     var sgn = frags[10];
   4007                     if (sgn < 0) {
   4008                         from -= frags[11];
   4009                     } else if (sgn > 0) {
   4010                         to -= frags[11];
   4011                     }
   4012                     windFrom.push(from + (unsortable ? "!" : ""));
   4013                     windTo.push(to + (unsortable ? "!" : ""));
   4014                     opp.push(fragType == SORT_BINARY);
   4015                     if (draw_sort == 1) {
   4016                         drawVisibleOrder(partial, frags[12]);
   4017                     } else {
   4018                         drawVisibleOrder(partial, (recordIndex / 2) + 1);
   4019                     }
   4020                 }
   4021                 var radius = Math.sqrt(minXY) / 2 * scale;
   4022                 radius = Math.min(50, radius);
   4023                 var scaledRadius = radius / scale;
   4024                 var centerX = partial[0];
   4025                 var centerY = partial[1];
   4026                 if (collect_bounds) {
   4027                     if (focus_enabled) {
   4028                         focusXmin = Math.min(focusXmin, centerX - scaledRadius);
   4029                         focusYmin = Math.min(focusYmin, centerY - scaledRadius);
   4030                         focusXmax = Math.max(focusXmax, centerX + scaledRadius);
   4031                         focusYmax = Math.max(focusYmax, centerY + scaledRadius);
   4032                     }
   4033                     break;
   4034                 }
   4035                 break;
   4036             default:
   4037                 break;
   4038         }
   4039     }
   4040     if (collect_bounds) {
   4041         return;
   4042     }
   4043     if (draw_log && logStart >= 0) {
   4044         ctx.font = "normal 10px Arial";
   4045         ctx.textAlign = "left";
   4046         ctx.beginPath();
   4047         var top = screenHeight - 20 - (logRange + 2) * 10;
   4048         ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
   4049         ctx.fillStyle = "white";
   4050         ctx.fill();
   4051         ctx.fillStyle = "rgba(0,0,0, 0.5)";
   4052         if (logStart > 0) {
   4053             ctx.fillText(lines[logStart - 1], 50, top + 8);
   4054         }
   4055         ctx.fillStyle = "black";
   4056         for (var idx = 0; idx < logRange; ++idx) {
   4057             ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
   4058         }
   4059         ctx.fillStyle = "rgba(0,0,0, 0.5)";
   4060         if (logStart + logRange < lines.length) {
   4061             ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
   4062         }
   4063     }
   4064     if (draw_legend) {
   4065         var pos = 0;
   4066         var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
   4067    //     drawBox(pos++, "yellow", "black", opLetter, true, '');
   4068         drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
   4069         drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
   4070         drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
   4071         drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
   4072         drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
   4073         drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
   4074         drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
   4075         drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
   4076         drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
   4077         drawBox(pos++, "black", "white",
   4078                 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
   4079         drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
   4080                 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
   4081                 draw_computed != 0, computedKey);
   4082         drawBox(pos++, "green", "black", step_limit, drawSomething, '');
   4083         drawBox(pos++, "green", "black", stepMax, drawSomething, '');
   4084         drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
   4085         drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
   4086         if (curve_t) {
   4087             drawCurveTControl();
   4088         }
   4089         ctx.font = "normal 20px Arial";
   4090         ctx.fillStyle = "rgba(0,0,0, 0.3)";
   4091         ctx.textAlign = "right";
   4092         ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
   4093     }
   4094     if (draw_hints) {
   4095         ctx.font = "normal 10px Arial";
   4096         ctx.fillStyle = "rgba(0,0,0, 0.5)";
   4097         ctx.textAlign = "right";
   4098         var y = 4;
   4099         ctx.fillText("control lines : " +  controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
   4100         ctx.fillText("curve t : " +  curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
   4101         ctx.fillText("deriviatives : " +  deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
   4102         ctx.fillText("intersect t : " +  intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
   4103         ctx.fillText("log : " +  logKey, screenWidth - 10, pos * 50 + y++ * 10);
   4104         ctx.fillText("log curve : " +  logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
   4105         ctx.fillText("mid point : " +  midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
   4106         ctx.fillText("points : " +  ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
   4107         ctx.fillText("sequence : " +  sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
   4108         ctx.fillText("xy : " +  xyKey, screenWidth - 10, pos * 50 + y++ * 10);
   4109     }
   4110 }
   4111 
   4112 function drawBox(y, backC, foreC, str, enable, label) {
   4113     ctx.beginPath();
   4114     ctx.fillStyle = backC;
   4115     ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
   4116     ctx.fill();
   4117     ctx.font = "normal 16px Arial";
   4118     ctx.fillStyle = foreC;
   4119     ctx.textAlign = "center";
   4120     ctx.fillText(str, screenWidth - 20, y * 50 + 32);
   4121     if (!enable) {
   4122         ctx.fillStyle = "rgba(255,255,255, 0.5)";
   4123         ctx.fill();
   4124     }
   4125     if (label != '') {
   4126         ctx.font = "normal 9px Arial";
   4127         ctx.fillStyle = "black";
   4128         ctx.fillText(label, screenWidth - 47, y * 50 + 40);
   4129     }
   4130 }
   4131 
   4132 function drawCurveTControl() {
   4133     ctx.lineWidth = 2;
   4134     ctx.strokeStyle = "rgba(0,0,0, 0.3)";
   4135     ctx.beginPath();
   4136     ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
   4137     ctx.stroke();
   4138     var ty = 40 + curveT * (screenHeight - 80);
   4139     ctx.beginPath();
   4140     ctx.moveTo(screenWidth - 80, ty);
   4141     ctx.lineTo(screenWidth - 85, ty - 5);
   4142     ctx.lineTo(screenWidth - 85, ty + 5);
   4143     ctx.lineTo(screenWidth - 80, ty);
   4144     ctx.fillStyle = "rgba(0,0,0, 0.6)";
   4145     ctx.fill();
   4146     var num = curveT.toFixed(decimal_places);
   4147     ctx.font = "normal 10px Arial";
   4148     ctx.textAlign = "left";
   4149     ctx.fillText(num, screenWidth - 78, ty);
   4150 }
   4151 
   4152 function ptInTControl() {
   4153     var e = window.event;
   4154     var tgt = e.target || e.srcElement;
   4155     var left = tgt.offsetLeft;
   4156     var top = tgt.offsetTop;
   4157     var x = (e.clientX - left);
   4158     var y = (e.clientY - top);
   4159     if (x < screenWidth - 80 || x > screenWidth - 50) {
   4160         return false;
   4161     }
   4162     if (y < 40 || y > screenHeight - 80) {
   4163         return false;
   4164     }
   4165     curveT = (y - 40) / (screenHeight - 120);
   4166     if (curveT < 0 || curveT > 1) {
   4167         throw "stop execution";
   4168     }
   4169     return true;
   4170 }
   4171 
   4172 function drawTop() {
   4173     if (tests[testIndex] == null) {
   4174         var str = testDivs[testIndex].textContent;
   4175         parse_all(str);
   4176         var title = testDivs[testIndex].id.toString();
   4177         testTitles[testIndex] = title;
   4178     }
   4179     init(tests[testIndex]);
   4180     redraw();
   4181 }
   4182 
   4183 function redraw() {
   4184     if (focus_on_selection) {
   4185         collect_bounds = true;
   4186         draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
   4187         collect_bounds = false;
   4188         if (focusXmin < focusXmax && focusYmin < focusYmax) {
   4189             setScale(focusXmin, focusXmax, focusYmin, focusYmax);
   4190         }
   4191     }
   4192     ctx.beginPath();
   4193     ctx.fillStyle = "white";
   4194     ctx.rect(0, 0, screenWidth, screenHeight);
   4195     ctx.fill();
   4196     draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
   4197 }
   4198 
   4199 function dumpCurvePartial(test, id, t0, t1) {
   4200     var curve = curveByID(test, id);
   4201     var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
   4202     console.log("id=" + id + " " + name + "=" +  curveToString(curve)
   4203         + " t0=" + t0 + " t1=" + t1
   4204         + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
   4205 }
   4206 
   4207 function dumpAngleTest(test, id, t0, t1) {
   4208     var curve = curveByID(test, id);
   4209     console.log("    { {" + curveToString(curve) + "}, "
   4210             + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
   4211 }
   4212 
   4213 function dumpLogToConsole() {
   4214     if (logStart < 0) {
   4215         return;
   4216     }
   4217     var test = tests[testIndex];
   4218     var recType = REC_TYPE_UNKNOWN;
   4219     var records;
   4220     for (var index = 0; index < test.length; index += 3) {
   4221         var lastLineNo = test[index + 1];
   4222         if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
   4223             recType = test[index];
   4224             records = test[index + 2];
   4225             break;
   4226         }
   4227     }
   4228     if (recType == REC_TYPE_UNKNOWN) {
   4229         return;
   4230     }
   4231     var lines = testLines[testIndex];
   4232     for (var idx = 0; idx < logRange; ++idx) {
   4233         var line = lines[logStart + idx];
   4234         console.log(line);
   4235         for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
   4236             var fragType = records[recordIndex];
   4237             var frags = records[recordIndex + 1];
   4238             if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
   4239                 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
   4240                 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
   4241                 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
   4242                 console.log("\nstatic IntersectData intersectDataSet[] = { //");
   4243                 dumpAngleTest(test, frags[0], frags[4], frags[5]);
   4244                 dumpAngleTest(test, frags[6], frags[10], frags[11]);
   4245                 dumpAngleTest(test, frags[12], frags[16], frags[17]);
   4246                 console.log("}; //");
   4247             }
   4248         }
   4249     }
   4250 }
   4251 
   4252 var activeKey = 'a';
   4253 var pathKey = 'b';
   4254 var pathBackKey = 'B';
   4255 var centerKey = 'c';
   4256 var coincidenceKey = 'C';
   4257 var addKey = 'd';
   4258 var deriviativesKey = 'f';
   4259 var angleKey = 'g';
   4260 var angleBackKey = 'G';
   4261 var intersectionKey = 'i';
   4262 var intersectionBackKey = 'I';
   4263 var sequenceKey = 'j';
   4264 var midpointKey = 'k';
   4265 var logKey = 'l';
   4266 var logToConsoleKey = 'L';
   4267 var markKey = 'm';
   4268 var sortKey = 'o';
   4269 var opKey = 'p';
   4270 var opBackKey = 'P';
   4271 var computedKey = 'q';
   4272 var computedBackKey = 'Q';
   4273 var directionKey = 'r';
   4274 var stepKey = 's';
   4275 var stepBackKey = 'S';
   4276 var intersectTKey = 't';
   4277 var topKey = 'T';
   4278 var curveTKey = 'u';
   4279 var controlLinesBackKey = 'V';
   4280 var controlLinesKey = 'v';
   4281 var ptsKey = 'x';
   4282 var xyKey = 'y';
   4283 var logCurvesKey = 'z';
   4284 var focusKey = '`';
   4285 var idKey = '.';
   4286 var retinaKey = '\\';
   4287 
   4288 function doKeyPress(evt) {
   4289     var char = String.fromCharCode(evt.charCode);
   4290     var focusWasOn = false;
   4291     switch (char) {
   4292     case '0':
   4293     case '1':
   4294     case '2':
   4295     case '3':
   4296     case '4':
   4297     case '5':
   4298     case '6':
   4299     case '7':
   4300     case '8':
   4301     case '9':
   4302         decimal_places = char - '0';
   4303         redraw();
   4304         break;
   4305     case activeKey:
   4306         draw_active ^= true;
   4307         redraw();
   4308         break;
   4309     case addKey:
   4310         draw_add ^= true;
   4311         redraw();
   4312         break;
   4313     case angleKey:
   4314         draw_angle = (draw_angle + 1) % 4;
   4315         redraw();
   4316         break;
   4317     case angleBackKey:
   4318         draw_angle = (draw_angle + 2) % 3;
   4319         redraw();
   4320         break;
   4321     case centerKey:
   4322         setScale(xmin, xmax, ymin, ymax);
   4323         redraw();
   4324         break;
   4325     case coincidenceKey:
   4326         draw_coincidence ^= true;
   4327         redraw();
   4328         break;
   4329     case controlLinesBackKey:
   4330         control_lines = (control_lines + 3) % 4;
   4331         redraw();
   4332         break;
   4333     case controlLinesKey:
   4334         control_lines = (control_lines + 1) % 4;
   4335         redraw();
   4336         break;
   4337     case computedBackKey:
   4338         draw_computed = (draw_computed + 5) % 6;
   4339         redraw();
   4340         break;
   4341     case computedKey:
   4342         draw_computed = (draw_computed + 1) % 6;
   4343         redraw();
   4344         break;
   4345     case curveTKey:
   4346         curve_t ^= true;
   4347         if (curve_t) {
   4348             draw_legend = true;
   4349         }
   4350         redraw();
   4351         break;
   4352     case deriviativesKey:
   4353         draw_deriviatives = (draw_deriviatives + 1) % 3;
   4354         redraw();
   4355         break;
   4356     case directionKey:
   4357         draw_direction ^= true;
   4358         redraw();
   4359         break;
   4360     case focusKey:
   4361         focus_on_selection ^= true;
   4362         setScale(xmin, xmax, ymin, ymax);
   4363         redraw();
   4364         break;
   4365     case idKey:
   4366         draw_id ^= true;
   4367         redraw();
   4368         break;
   4369     case intersectionBackKey:
   4370         draw_intersection = (draw_intersection + 3) % 4;
   4371         redraw();
   4372         break;
   4373     case intersectionKey:
   4374         draw_intersection = (draw_intersection + 1) % 4;
   4375         redraw();
   4376         break;
   4377     case intersectTKey:
   4378         draw_intersectT ^= true;
   4379         redraw();
   4380         break;
   4381     case logCurvesKey:
   4382         logCurves(tests[testIndex]);
   4383         break;
   4384     case logKey:
   4385         draw_log ^= true;
   4386         redraw();
   4387         break;
   4388     case logToConsoleKey:
   4389         if (draw_log) {
   4390             dumpLogToConsole();
   4391         }
   4392         break;
   4393     case markKey:
   4394         draw_mark ^= true;
   4395         redraw();
   4396         break;
   4397     case midpointKey:
   4398         draw_midpoint ^= true;
   4399         redraw();
   4400         break;
   4401     case opKey:
   4402         draw_op = (draw_op + 1) % 3;
   4403         redraw();
   4404         break;
   4405     case opBackKey:
   4406         draw_op = (draw_op + 2) % 3;
   4407         redraw();
   4408         break;
   4409     case pathKey:
   4410         draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
   4411         redraw();
   4412         break;
   4413     case pathBackKey:
   4414         draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
   4415         redraw();
   4416         break;
   4417     case ptsKey:
   4418         pt_labels = (pt_labels + 1) % 3;
   4419         redraw();
   4420         break;
   4421     case retinaKey:
   4422         retina_scale ^= true;
   4423         drawTop();
   4424         break;
   4425     case sequenceKey:
   4426         draw_sequence ^= true;
   4427         redraw();
   4428         break;
   4429     case sortKey:
   4430         draw_sort = (draw_sort + 1) % 3;
   4431         drawTop();
   4432         break;
   4433     case stepKey:
   4434         step_limit++;
   4435         if (step_limit > stepMax) {
   4436             step_limit = stepMax;
   4437         }
   4438         redraw();
   4439         break;
   4440     case stepBackKey:
   4441         step_limit--;
   4442         if (step_limit < 0) {
   4443             step_limit = 0;
   4444         }
   4445         redraw();
   4446         break;
   4447     case topKey:
   4448         draw_top ^= true;
   4449         redraw();
   4450         break;
   4451     case xyKey:
   4452         debug_xy = (debug_xy + 1) % 3;
   4453         redraw();
   4454         break;
   4455     case '-':
   4456         focusWasOn = focus_on_selection;
   4457         if (focusWasOn) {
   4458             focus_on_selection = false;
   4459             scale /= 1.2;
   4460         } else {
   4461             scale /= 2;
   4462             calcLeftTop();
   4463         }
   4464         redraw();
   4465         focus_on_selection = focusWasOn;
   4466         break;
   4467     case '=':
   4468     case '+':
   4469         focusWasOn = focus_on_selection;
   4470         if (focusWasOn) {
   4471             focus_on_selection = false;
   4472             scale *= 1.2;
   4473         } else {
   4474             scale *= 2;
   4475             calcLeftTop();
   4476         }
   4477         redraw();
   4478         focus_on_selection = focusWasOn;
   4479         break;
   4480     case '?':
   4481         draw_hints ^= true;
   4482         if (draw_hints && !draw_legend) {
   4483             draw_legend = true;
   4484         }
   4485         redraw();
   4486         break;
   4487     case '/':
   4488         draw_legend ^= true;
   4489         redraw();
   4490         break;
   4491     }
   4492 }
   4493 
   4494 function doKeyDown(evt) {
   4495     var char = evt.keyCode;
   4496     var preventDefault = false;
   4497     switch (char) {
   4498     case 37: // left arrow
   4499         if (evt.shiftKey) {
   4500             testIndex -= 9;
   4501         }
   4502         if (--testIndex < 0)
   4503             testIndex = tests.length - 1;
   4504         drawTop();
   4505         preventDefault = true;
   4506         break;
   4507     case 39: // right arrow
   4508         if (evt.shiftKey) {
   4509             testIndex += 9;
   4510         }
   4511         if (++testIndex >= tests.length)
   4512             testIndex = 0;
   4513         drawTop();
   4514         preventDefault = true;
   4515         break;
   4516     }
   4517     if (preventDefault) {
   4518           evt.preventDefault();
   4519           return false;
   4520     }
   4521     return true;
   4522 }
   4523 
   4524 (function() {
   4525     var hidden = "hidden";
   4526 
   4527     // Standards:
   4528     if (hidden in document)
   4529         document.addEventListener("visibilitychange", onchange);
   4530     else if ((hidden = "mozHidden") in document)
   4531         document.addEventListener("mozvisibilitychange", onchange);
   4532     else if ((hidden = "webkitHidden") in document)
   4533         document.addEventListener("webkitvisibilitychange", onchange);
   4534     else if ((hidden = "msHidden") in document)
   4535         document.addEventListener("msvisibilitychange", onchange);
   4536     // IE 9 and lower:
   4537     else if ('onfocusin' in document)
   4538         document.onfocusin = document.onfocusout = onchange;
   4539     // All others:
   4540     else
   4541         window.onpageshow = window.onpagehide
   4542             = window.onfocus = window.onblur = onchange;
   4543 
   4544     function onchange (evt) {
   4545         var v = 'visible', h = 'hidden',
   4546             evtMap = {
   4547                 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
   4548             };
   4549 
   4550         evt = evt || window.event;
   4551         if (evt.type in evtMap)
   4552             document.body.className = evtMap[evt.type];
   4553         else
   4554             document.body.className = this[hidden] ? "hidden" : "visible";
   4555     }
   4556 })();
   4557 
   4558 function calcXY() {
   4559     var e = window.event;
   4560     var tgt = e.target || e.srcElement;
   4561     var left = tgt.offsetLeft;
   4562     var top = tgt.offsetTop;
   4563     mouseX = (e.clientX - left) / scale + srcLeft;
   4564     mouseY = (e.clientY - top) / scale + srcTop;
   4565 }
   4566 
   4567 function calcLeftTop() {
   4568     srcLeft = mouseX - screenWidth / 2 / scale;
   4569     srcTop = mouseY - screenHeight / 2 / scale;
   4570 }
   4571 
   4572 var disableClick = false;
   4573 
   4574 function handleMouseClick() {
   4575     if (disableClick) {
   4576         return;
   4577     }
   4578     if (!curve_t || !ptInTControl()) {
   4579         calcXY();
   4580         calcLeftTop();
   4581     }
   4582     redraw();
   4583 //    if (!curve_t || !ptInTControl()) {
   4584 //        mouseX = screenWidth / 2 / scale + srcLeft;
   4585 //        mouseY = screenHeight / 2 / scale + srcTop;
   4586 //    }
   4587 }
   4588 
   4589 function handleMouseOver() {
   4590     calcXY();
   4591     if (debug_xy != 2) {
   4592         return;
   4593     }
   4594     var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
   4595     ctx.beginPath();
   4596     ctx.rect(300,100,num.length * 6,10);
   4597     ctx.fillStyle="white";
   4598     ctx.fill();
   4599     ctx.font = "normal 10px Arial";
   4600     ctx.fillStyle="black";
   4601     ctx.textAlign = "left";
   4602     ctx.fillText(num, 300, 108);
   4603 }
   4604 
   4605 function start() {
   4606     for (var i = 0; i < testDivs.length; ++i) {
   4607         tests[i] = null;
   4608     }
   4609     testIndex = 0;
   4610     drawTop();
   4611     window.addEventListener('keypress', doKeyPress, true);
   4612     window.addEventListener('keydown', doKeyDown, true);
   4613     window.onresize = function() {
   4614         drawTop();
   4615     }
   4616     /*
   4617     window.onpagehide = function() {
   4618         disableClick = true;
   4619     }
   4620     */
   4621     window.onpageshow = function () {
   4622         disableClick = false;
   4623     }
   4624 }
   4625 
   4626 </script>
   4627 </head>
   4628 
   4629 <body onLoad="start();">
   4630 <canvas id="canvas" width="750" height="500"
   4631     onmousemove="handleMouseOver()"
   4632     onclick="handleMouseClick()"
   4633     ></canvas >
   4634 </body>
   4635 </html>
   4636