skia2/tools/pathops_sorter.htm
commit-bot@chromium.org 4431e7757c Mike R: please sanity check SkPostConfig.h
Mike K: please sanity check Test.cpp and skia_test.cpp

Feel free to look at the rest, but I don't expect any in depth review of path ops innards.

Path Ops first iteration used QuickSort to order segments radiating from an intersection to compute the winding rule.

This revision uses a circular sort instead. Breaking out the circular sort into its own long-lived structure (SkOpAngle) allows doing less work and provides a home for caching additional sorting data.

The circle sort is more stable than the former sort, has a robust ordering and fewer exceptions. It finds unsortable ordering less often. It is less reliant on the initial curve  tangent, using convex hulls instead whenever it can.

Additional debug validation makes sure that the computed structures are self-consistent. A new visualization tool helps verify that the angle ordering is correct.

The 70+M tests pass with this change on Windows, Mac, Linux 32 and Linux 64 in debug and release.

R=mtklein@google.com, reed@google.com

Author: caryclark@google.com

Review URL: https://codereview.chromium.org/131103009

git-svn-id: http://skia.googlecode.com/svn/trunk@14183 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-04-14 17:08:59 +00:00

2051 lines
79 KiB
HTML

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<div style="height:0">
<div id="quad1">
{{3.13,2.74}, {1.08,4.62}, {3.71,0.94}}
{{3.13,2.74}, {7.99,2.75}, {8.27,1.96}}
</div>
<div id="quad2">
{{4.838888984361574,4.399276078363981}, {5.947577332875065,2.02910379790342}, {3.8092258119951885,2.108659563498883}}
{{4.838888984361574,4.399276078363981}, {6.192910293864926,1.7797920604914939}, {3.3638348513490293,1.4969462106891218}}
</div>
<div id="quad3">
{{4.838888984361574,4.399276078363981}, {5.962263714769107,1.654601059605365}, {3.8789861259918847,2.8650082310420126}}
{{4.838888984361574,4.399276078363981}, {6.192910293864926,1.7797920604914939}, {3.3638348513490293,1.4969462106891218}}
</div>
<div id="quad4">
{{4.838888984361574,4.399276078363981}, {5.77868394109359,1.852867215174923}, {3.915702080726988,2.1820914729690903}}
{{4.838888984361574,4.399276078363981}, {6.681232491841801,2.5287975370876032}, {3.3638348513490293,1.4969462106891218}}
</div>
<div id="quad5">
{{4.838888984361574,4.399276078363981}, {6.082937568878361,1.9951156645288415}, {3.915702080726988,2.1820914729690903}}
{{4.838888984361574,4.399276078363981}, {6.681232491841801,2.5287975370876032}, {3.3638348513490293,1.4969462106891218}}
</div>
<div id="quad6">
{{4.898159171592373,4.367665311840888}, {6.695396170263287,1.769888953051804}, {3.6312051820191513,2.727377195492444}}
{{4.898159171592373,4.367665311840888}, {6.961778044734251,2.4813813873029633}, {3.3638348513490293,1.4969462106891218}}
</div>
<div id="quad7">
{{4.838888984361574,4.399276078363981}, {3.012741870322956,2.449520433298304}, {5.140619283496844,2.110967248292131}}
{{4.838888984361574,4.399276078363981}, {2.804962246947524,2.232446600933607}, {6.60393841996606,2.077794045550955}}
</div>
<div id="quad8">
{{4.838888984361574,4.399276078363981}, {3.1707957029384213,2.607574265913769}, {4.626944327496585,2.2848264641691425}}
{{4.838888984361574,4.399276078363981}, {2.804962246947524,2.232446600933607}, {6.60393841996606,2.077794045550955}}
</div>
<div id="quad9">
{{4.838888984361574,4.399276078363981}, {3.463749932092156,2.935940544745428}, {5.161344349908893,2.4940794849932386}}
{{4.838888984361574,4.399276078363981}, {2.804962246947524,2.232446600933607}, {6.60393841996606,2.077794045550955}}
</div>
<div id="quad10">
{{4.838888984361574,4.399276078363981}, {5.82508561259808,2.495362604119041}, {3.4377993053488463,2.7132154732530362}}
{{4.838888984361574,4.399276078363981}, {6.192910293864926,1.7797920604914939}, {2.435268584733173,1.817005221735438}}
</div>
<div id="cubic1">
{{0,0}, {1,0}, {0,1}, {1,1}}
{{0,0}, {2,0}, {0,2}, {2,2}}
</div>
<div id="cubic2" >
{{0.4655213647959181,1.5608657525510201}, {0.6599868463010203,0.4290098852040817}, {2.473652742346939,1.2464524872448977}, {1.8511738679846936,0.5344786352040818}}
{{0.4655213647959181,1.5608657525510201}, {0.3250358737244896,0.819226323341837}, {1.4399214764030612,0.3318817761479596}, {1.2703414571528546,0.9081465322144181}}
</div>
<div id="quad11">
{{-378.22698974609375, -987.8935546875}, {-47.53326416015625, 482.7139892578125}, {-626.4708251953125, -338.62969970703125}}
{{-378.22698974609375, -987.8935546875}, {-847.94854736328125, -861.42230224609375}, {-390.9146728515625, 402.08740234375}}
</div>
<div id="quad12">
{{-173.3448486328125, -962.89422607421875}, {-778.321533203125, -161.47637939453125}, {-196.77374267578125, -736.40155029296875}}
{{-173.3448486328125, -962.89422607421875}, {652.3017578125, -400.67816162109375}, {-386.7855224609375, 361.1614990234375}}
</div>
<div id="quad13">
{{{-968.181396484375, 544.0128173828125}, {592.2825927734375, 870.552490234375}, {593.435302734375, 557.8828125}}}
{{{-968.181396484375, 544.0128173828125}, {593.677001953125, 865.5810546875}, {-66.57171630859375, -847.849853515625}}}
</div>
<div id="quad14">
{{{769.693115234375, -626.35089111328125}, {6.60491943359375, -210.43756103515625}, {-898.26654052734375, -17.76312255859375}}}
{{{769.693115234375, -626.35089111328125}, {192.8486328125, 609.8062744140625}, {888.317626953125, -551.27215576171875}}}
</div>
<div id="quad15">
{{{187.410400390625, -343.557373046875}, {-752.7930908203125, 431.57177734375}, {387.663330078125, 701.281982421875}}}
{{{187.410400390625, -343.557373046875}, {-86.16302490234375, -366.027099609375}, {-468.3883056640625, -25.736572265625}}}
</div>
<div id="quad16">
{{{-353.9388427734375, 76.8973388671875}, {-36.00189208984375, 282.289306640625}, {-531.37969970703125, 683.95751953125}}}
{{{-353.9388427734375, 76.8973388671875}, {-779.3529052734375, 509.6165771484375}, {-662.34088134765625, 124.4027099609375}}}
</div>
<div id="quad17">
{{{-657.0289306640625, 681.611083984375}, {-991.8365478515625, 964.4644775390625}, {-843.3585205078125, 904.47998046875}}}
{{{-657.0289306640625, 681.611083984375}, {-763.1571044921875, 39.1097412109375}, {618.2041015625, 840.6429443359375}}}
</div>
<div id="quad18">
{{{-609.406005859375, -684.37506103515625}, {766.4923095703125, 583.657958984375}, {-912.6832275390625, -949.553466796875}}}
{{{-609.406005859375, -684.37506103515625}, {774.140380859375, 82.2415771484375}, {540.9007568359375, -136.982666015625}}}
</div>
<div id="quad19">
{{{-657.0289306640625, 681.611083984375}, {-991.8365478515625, 964.4644775390625}, {-843.3585205078125, 904.47998046875}}}
{{{-657.0289306640625, 681.611083984375}, {-763.1571044921875, 39.1097412109375}, {618.2041015625, 840.6429443359375}}}
</div>
<div id="quad20">
{{{123.2955322265625, -577.799560546875}, {-491.892578125, 704.91748046875}, {478.03759765625, -951.92333984375}}}
{{{123.2955322265625, -577.799560546875}, {-550.6966552734375, 812.216796875}, {-816.3184814453125, -705.0025634765625}}}
</div>
<div id="quad21">
{{{123.2955322265625, -577.799560546875}, {-481.892578125, 704.91748046875}, {478.03759765625, -951.92333984375}}}
{{{123.2955322265625, -577.799560546875}, {-550.6966552734375, 812.216796875}, {-816.3184814453125, -705.0025634765625}}}
</div>
<div id="quad22">
{{{187.410400390625, -343.557373046875}, {-752.7930908203125, 431.57177734375}, {387.663330078125, 701.281982421875}}}
{{{187.410400390625, -343.557373046875}, {-86.16302490234375, -366.027099609375}, {-468.3883056640625, -25.736572265625}}}
</div>
<div id="quad23">
{{{-341.26922607421875, 964.1964111328125}, {883.2567138671875, 812.7301025390625}, {286.0372314453125, 94.979248046875}}}
{{{-341.26922607421875, 964.1964111328125}, {-158.90765380859375, 597.1875}, {-282.2255859375, 262.430908203125}}}
</div>
<div id="quad24">
{{{123.2955322265625, -577.799560546875}, {-481.892578125, 704.91748046875}, {478.03759765625, -951.92333984375}}}
{{{123.2955322265625, -577.799560546875}, {-550.6966552734375, 812.216796875}, {-816.3184814453125, -705.0025634765625}}}
{{{417.3499131065152, -577.799560546875}, {417.3499131065152, -699.60087482901156}, {331.22337542585541, -785.72740374616797}}}
</div>
<div id="quad25">
{{{922.6107177734375, 291.412109375}, {-939.361572265625, 589.8492431640625}, {-515.70941162109375, 120.2764892578125}}}
{{{922.6107177734375, 291.412109375}, {148.5115966796875, -751.42095947265625}, {-347.47503662109375, 331.1798095703125}}}
{{{922.6107177734375, -143.9114969433939}, {742.29377357777753, -143.9114969433939}, {614.79044900323777, -16.408159395199732}}}
{{{487.2871114550436, 291.412109375}, {487.2871114550436, 471.72905357065997}, {614.79044900323777, 599.23237814519973}}}
</div>
<div id="quad26">
{{{187.410400390625, -343.557373046875}, {-752.7930908203125, 431.57177734375}, {387.663330078125, 701.281982421875}}}
{{{187.410400390625, -343.557373046875}, {-86.16302490234375, -366.027099609375}, {-468.3883056640625, -25.736572265625}}}
{{{33.221887415632978, -343.557373046875}, {33.221887415632978, -279.69039894717827}, {78.38265915086852, -234.52963180711851}}}
</div>
<div id="quad27">
{{{-173.3448486328125, -962.89422607421875}, {-778.321533203125, -161.47637939453125}, {-196.77374267578125, -736.40155029296875}}}
{{{-173.3448486328125, -962.89422607421875}, {652.3017578125, -400.67816162109375}, {-386.7855224609375, 361.1614990234375}}}
{{{-270.84959533883426, -865.38947936819704}, {-230.46180860703427, -825.00168852687921}, {-173.3448486328125, -825.00168852687921}}}
{{{-75.840101926790737, -865.38947936819704}, {-35.4523110854729, -905.77726609999695}, {-35.4523110854729, -962.89422607421875}}}
</div>
<div id="quad28">
{{{344.2755126953125, -689.900390625}, {743.6728515625, 512.8448486328125}, {928.598388671875, 111.946044921875}}}
{{{344.2755126953125, -689.900390625}, {-950.03106689453125, -511.25741577148437}, {850.8173828125, 798.4874267578125}}}
{{{344.2755126953125, -689.900390625}, {850.8173828125, 798.4874267578125}}}
{{{344.2755126953125, -689.900390625}, {391.39917554828793, -551.43545842779145}}}
</div>
<div id="quad29">
{{{351.8946533203125, 512.8131103515625}, {-294.22332763671875, 183.2200927734375}, {624.4842529296875, 862.0753173828125}}}
{{{351.8946533203125, 512.8131103515625}, {489.1907958984375, -543.4212646484375}, {-432.7445068359375, 812.5205078125}}}
</div>
<div id="quad30">
{{{627.6910400390625, 81.144287109375}, {168.9248046875, -211.72735595703125}, {-61.57086181640625, 915.171875}}}
{{{627.6910400390625, 81.144287109375}, {918.159423828125, -325.468994140625}, {359.0523681640625, 817.4888916015625}}}
{{{235.78221371860315, 81.144287109375}, {235.78221371860315, 243.47824037936314}, {350.56965608373537, 358.26567106470213}}},
</div>
<div id="quad31">
{{{178.1549072265625, 62.724609375}, {541.3643798828125, 223.823486328125}, {-446.77471923828125, -15.990478515625}}}
{{{178.1549072265625, 62.724609375}, {-347.14031982421875, -834.27191162109375}, {-495.13888549804687, 96.476806640625}}}
</div>
<div id="quad32">
{{{-809.41009521484375, 370.4566650390625}, {622.44677734375, -166.97119140625}, {-285.6748046875, 333.81005859375}}},
{{{-809.41009521484375, 370.4566650390625}, {-110.36346435546875, -656.96044921875}, {906.4796142578125, 530.2061767578125}}}
</div>
<div id="quad33">
{{{-918.58624267578125, 653.6695556640625}, {-639.37548828125, 61.493896484375}, {-198.9605712890625, 243.704345703125}}},
{{{-918.58624267578125, 653.6695556640625}, {-302.093505859375, -107.10955810546875}, {696.4962158203125, 600.738525390625}}}
</div>
<div id="quad34">
{{{-610.4193115234375, 861.173095703125}, {403.3203125, 215.3988037109375}, {-373.5546875, 179.88134765625}}},
{{{-610.4193115234375, 861.173095703125}, {-757.244140625, -222.137451171875}, {705.892822265625, 87.4090576171875}}}
</div>
<div id="quad35">
{{{282.5767822265625, -529.4022216796875}, {392.0968017578125, 768.1014404296875}, {712.11572265625, 189.19677734375}}},
{{{282.5767822265625, -529.4022216796875}, {699.360595703125, 465.6171875}, {438.5755615234375, 125.5230712890625}}}
</div>
<div id="quad36">
{{{-170.1510009765625, -184.905517578125}, {654.734130859375, 120.339599609375}, {-470.98443603515625, -69.4737548828125}}},
{{{-170.1510009765625, -184.905517578125}, {-500.9822998046875, -148.40911865234375}, {-446.35821533203125, -840.5694580078125}}}
</div>
<div id="quad37">
{{{-119.55023193359375, -39.2008056640625}, {-618.14306640625, -620.1419677734375}, {-779.53790283203125, -681.9923095703125}}},
{{{-119.55023193359375, -39.2008056640625}, {365.968994140625, 55.4974365234375}, {98.1297607421875, -192.474609375}}}
</div>
<div id="quad38">
{{{607.9136962890625, 484.1448974609375}, {280.619140625, 982.736572265625}, {-577.5596923828125, 798.9134521484375}}},
{{{607.9136962890625, 484.1448974609375}, {374.318115234375, -590.5146484375}, {-258.30438232421875, 592.958984375}}}
</div>
<div id="quad39">
{{{-491.48846435546875, -470.9105224609375}, {109.7149658203125, -989.5384521484375}, {-275.900390625, 657.1920166015625}}},
{{{-491.48846435546875, -470.9105224609375}, {-796.935791015625, 191.326171875}, {-852.120849609375, 62.06005859375}}}
</div>
<div id="quad40">
{{{-872.76458740234375, -163.30078125}, {723.6697998046875, 177.8204345703125}, {206.470703125, 147.9564208984375}}},
{{{-872.76458740234375, -163.30078125}, {556.937744140625, 715.4345703125}, {627.348388671875, 77.0643310546875}}}
</div>
<div id="quad108">
{{{282.5767822265625, -529.4022216796875}, {392.0968017578125, 768.1014404296875}, {712.11572265625, 189.19677734375}}},
{{{282.5767822265625, -529.4022216796875}, {699.360595703125, 465.6171875}, {438.5755615234375, 125.5230712890625}}}
</div>
<div id="quad159">
{{{-868.3076171875, -212.74591064453125}, {-208.84014892578125, -57.353515625}, {393.79736328125, -986.03607177734375}}},
{{{-868.3076171875, -212.74591064453125}, {371.0980224609375, -960.9017333984375}, {-236.2821044921875, -441.20074462890625}}}
</div>
<div id="quad212">
{{{-610.4193115234375, 861.173095703125}, {403.3203125, 215.3988037109375}, {-373.5546875, 179.88134765625}}},
{{{-610.4193115234375, 861.173095703125}, {-757.244140625, -222.137451171875}, {705.892822265625, 87.4090576171875}}}
</div>
<div id="quad232">
{{{766.497802734375, 675.660400390625}, {639.0235595703125, 351.4776611328125}, {345.9315185546875, 624.685791015625}}},
{{{766.497802734375, 675.660400390625}, {-901.72650146484375, 923.99169921875}, {755.665283203125, 416.728759765625}}}
</div>
<div id="quad379">
{{{-872.76458740234375, -163.30078125}, {723.6697998046875, 177.8204345703125}, {206.470703125, 147.9564208984375}}},
{{{-872.76458740234375, -163.30078125}, {556.937744140625, 715.4345703125}, {627.348388671875, 77.0643310546875}}}
</div>
<div id="quad413">
{{{-127.60784912109375, 384.614990234375}, {-184.46685791015625, 717.5728759765625}, {-981.56524658203125, -827.18109130859375}}},
{{{-127.60784912109375, 384.614990234375}, {-125.78131103515625, 751.187744140625}, {562.529541015625, -277.5535888671875}}}
</div>
<div id="quad179">
{{{-595.956298828125, -113.24383544921875}, {-730.611572265625, 481.5323486328125}, {505.58447265625, -504.9130859375}}},
{{{-595.956298828125, -113.24383544921875}, {-971.0836181640625, -849.73907470703125}, {-32.39227294921875, -906.3277587890625}}}
</div>
<div id="quad584">
{{{-406.65435791015625, 599.96630859375}, {-566.71881103515625, -400.65362548828125}, {-486.0682373046875, 100.34326171875}}},
{{{-406.65435791015625, 599.96630859375}, {799.783935546875, 992.77783203125}, {180.6688232421875, -490.0054931640625}}}
</div>
<div id="quad653">
{{{-46.6143798828125, 164.224853515625}, {-161.7724609375, 327.61376953125}, {168.5106201171875, -948.4150390625}}},
{{{-46.6143798828125, 164.224853515625}, {412.9364013671875, -199.26715087890625}, {-278.044677734375, 472.3961181640625}}}
</div>
<div id="quad809">
{{{-176.8541259765625, -275.9761962890625}, {-723.969482421875, -7.4718017578125}, {931.6959228515625, 231.6737060546875}}},
{{{-176.8541259765625, -275.9761962890625}, {-250.86737060546875, -748.8143310546875}, {-96.77099609375, -287.76336669921875}}}
</div>
<div id="quad14a">
{{{-609.406005859375, -684.37506103515625}, {766.4923095703125, 583.657958984375}, {-912.6832275390625, -949.553466796875}}},
{{{-609.406005859375, -684.37506103515625}, {774.140380859375, 82.2415771484375}, {540.9007568359375, -136.982666015625}}}
</div>
<div id="quad22a">
{{{-728.5626220703125, 141.134521484375}, {749.9122314453125, -645.93359375}, {67.1751708984375, -285.85528564453125}}},
{{{-728.5626220703125, 141.134521484375}, {-841.0341796875, -988.058349609375}, {34.87939453125, -489.359130859375}}}
{{{276.48354206343231, -395.24293552482953}, {-728.5626220703125, 141.134521484375}}}
{{{fX=97.702285839737073, -301.95147049201717}, {-728.5626220703125, 141.134521484375}}}
{{{fX=-52.525628917174856, -536.31069276053427}, {-728.5626220703125, 141.134521484375}}}
{{{fX=-5.2463328209585285, -511.63085965304060}, {-728.5626220703125, 141.134521484375}}}
</div>
<div id="quad77">
{{{383.7933349609375, -397.5057373046875}, {480.7408447265625, 92.927490234375}, {690.7930908203125, -267.44964599609375}}},
{{{383.7933349609375, -397.5057373046875}, {83.3685302734375, 619.781005859375}, {688.14111328125, 416.241455078125}}}
</div>
<div id="quad94">
{{{627.6910400390625, 81.144287109375}, {168.9248046875, -211.72735595703125}, {-61.57086181640625, 915.171875}}},
{{{627.6910400390625, 81.144287109375}, {918.159423828125, -325.468994140625}, {359.0523681640625, 817.4888916015625}}}
{{{564.43435948662466, 47.034527772832369}, {627.6910400390625, 81.144287109375}}}
{{{699.34014109378302, 79.147174806567705}, {627.6910400390625, 81.144287109375}}}
</div>
<div id="quad4a">
{{{187.410400390625, -343.557373046875}, {-752.7930908203125, 431.57177734375}, {387.663330078125, 701.281982421875}}},
{{{187.410400390625, -343.557373046875}, {-86.16302490234375, -366.027099609375}, {-468.3883056640625, -25.736572265625}}}
</div>
<div id="quad0">
{{{-708.0077926931004413, -154.6166947224404566}, {-701.0429781735874712, -128.8517387364408933}, {505.58447265625, -504.9130859375}}},
{{{-708.0077926931004413, -154.6166947224404566}, {-721.5125661899801344, -174.4028951148648048}, {-32.39227294921875, -906.3277587890625}}}
{{{-707.8363172079705237, -154.25350453766481}, {-708.0077926931004413, -154.6166947224404566}}}
{{{-708.1792267111628689, -154.9799046892118213}, {-708.0077926931004413, -154.6166947224404566}}}
</div>
<div id="quad999">
{{{-708.00779269310044, -154.61669472244046}, {-707.92342686353186, -154.30459999551294}, {505.58447265625, -504.9130859375}}},
{{{-708.00779269310044, -154.61669472244046}, {-708.1713780141481, -154.85636789757655}, {-32.39227294921875, -906.3277587890625}}}
{{{-708.0077672218041, -154.61664072892336}, {-708.00779269310044, -154.61669472244046}}}
{{{-708.00781827681976, -154.61674895426012}, {-708.00779269310044, -154.61669472244046}}}
</div>
<div id="quad113">
{{{425.018310546875, -866.61865234375}, {-918.76531982421875, 209.05322265625}, {964.34716796875, 199.52587890625}}},
{{{425.018310546875, -866.61865234375}, {703.10693359375, -955.0738525390625}, {-952.24664306640625, -717.94775390625}}}
</div>
<div id="quad136">
{{{178.1549072265625, 62.724609375}, {541.3643798828125, 223.823486328125}, {-446.77471923828125, -15.990478515625}}},
{{{178.1549072265625, 62.724609375}, {-347.14031982421875, -834.27191162109375}, {-495.138885498046875, 96.476806640625}}}
</div>
<div id="quad206">
{{{-503.007415771484375, -318.59490966796875}, {-798.330810546875, -881.21630859375}, {-127.2027587890625, 769.6160888671875}}},
{{{-503.007415771484375, -318.59490966796875}, {-153.6217041015625, -776.896728515625}, {-378.43701171875, -296.3197021484375}}}
{{{-468.9176053311167607, -89.39573455985038208}, {-503.007415771484375, -318.59490966796875}}}
{{{-356.1573846604815685, -497.6768266540607328}, {-503.007415771484375, -318.59490966796875}}}
{{{-559.0376987487186398, -420.2054253473417589}, {-503.007415771484375, -318.59490966796875}}}
{{{-431.6586315464865606, -409.8353728177644371}, {-503.007415771484375, -318.59490966796875}}}
</div>
<div id="quad640">
{{{412.260498046875, 49.193603515625}, {838.97900390625, 86.9951171875}, {427.7896728515625, -605.6881103515625}}},
{{{412.260498046875, 49.193603515625}, {-995.54583740234375, 990.032470703125}, {-881.18670654296875, 461.211669921875}}}
</div>
<div id="quad3160">
{{{426.645751953125, 813.79150390625}, {-387.23828125, -588.89483642578125}, {792.4261474609375, -704.4637451171875}}},
{{{426.645751953125, 813.79150390625}, {19.24896240234375, -416.09906005859375}, {233.8497314453125, 350.778564453125}}}
</div>
<div id="quad35237">
{{{-770.8492431640625, 948.2369384765625}, {-853.37066650390625, 972.0301513671875}, {-200.62042236328125, -26.7174072265625}}},
{{{-770.8492431640625, 948.2369384765625}, {513.602783203125, 578.8681640625}, {960.641357421875, -813.69757080078125}}}
</div>
<div id="quad37226">
{{{563.8267822265625, -107.4566650390625}, {-44.67724609375, -136.57452392578125}, {492.3856201171875, -268.79644775390625}}},
{{{563.8267822265625, -107.4566650390625}, {708.049072265625, -100.77789306640625}, {-48.88226318359375, 967.9022216796875}}}
</div>
<div id="quad67242">
{{{598.857421875, 846.345458984375}, {-644.095703125, -316.12921142578125}, {-97.64599609375, 20.6158447265625}}},
{{{598.857421875, 846.345458984375}, {715.7142333984375, 955.3599853515625}, {-919.9478759765625, 691.611328125}}}
</div>
<div id="quad208">
{{{481.1463623046875, -687.09613037109375}, {643.64697265625, -951.9462890625}, {162.5869140625, 698.7342529296875}}},
{{{481.1463623046875, -687.09613037109375}, {171.8175048828125, -919.07977294921875}, {153.3433837890625, -587.43072509765625}}}
</div>
<div id="quad8a">
{{{344.2755126953125, -689.900390625}, {743.6728515625, 512.8448486328125}, {928.598388671875, 111.946044921875}}},
{{{344.2755126953125, -689.900390625}, {-950.03106689453125, -511.25741577148437}, {850.8173828125, 798.4874267578125}}}
</div>
<div id="quad8b">
{{{344.2755126953125, -689.900390625}, {928.598388671875, 111.946044921875}, {743.6728515625, 512.8448486328125}}},
{{{344.2755126953125, -689.900390625}, {-950.03106689453125, -511.25741577148437}, {850.8173828125, 798.4874267578125}}}
</div>
<div id="quad8741">
{{{944.9024658203125, 939.454345703125}, {-971.06219482421875, -914.24395751953125}, {-878.764404296875, -297.61602783203125}}},
{{{944.9024658203125, 939.454345703125}, {-838.96612548828125, -785.837646484375}, {-126.80029296875, 921.1981201171875}}}
{{{107.03238931174118, 218.460612766889}, {944.9024658203125, 939.454345703125}}}
{{{-292.72752350740279, 99.917575976335598}, {944.9024658203125, 939.454345703125}}}
</div>
<div id="quad89987">
{{{939.4808349609375, 914.355224609375}, {-357.7921142578125, 590.842529296875}, {736.8936767578125, -350.717529296875}}},
{{{939.4808349609375, 914.355224609375}, {-182.85418701171875, 634.4552001953125}, {-509.62615966796875, 576.1182861328125}}}
</div>
<div id="simplifyQuadratic36">
{{{1.9474306106567383, 2.3777823448181152}, {1.9234547048814592, 2.2418855043499213}, {1.8885438442230225, 2.1114561557769775}}}
{{{1.9474306106567383, 2.3777823448181152}, {2.0764266380046235, 2.2048800651418379}, {1.8888888359069824, 2.1111111640930176}}}
</div>
<div id="simplifyQuadratic58">
{{326.236786,205.854996}, {329.104431,231.663818}, {351.512085,231.663818}}
{{303.12088,141.299606}, {330.463562,217.659027}}
</div>
<div id="simplifyQuadratic58a">
{{{326.23678588867188, 205.85499572753906}, {328.04376176056422, 222.11778818951981}, {337.6092529296875, 228.13298034667969}
{{{303.12088012695312, 141.29960632324219}, {330.46356201171875, 217.65902709960937}
</div>
<div id="quadratic58again">
{{322.935669,231.030273}, {312.832214,220.393295}, {312.832214,203.454178}}
{{322.12738,233.397751}, {295.718353,159.505829}}
</div>
<div id="simplifyQuadratic56">
{{{380.29449462890625, 140.44486999511719}, {387.29080200195312, 136.67460632324219}, {396.0399169921875, 136.67460632324219}}}
{{{380.29449462890625, 140.44486999511719}, {388.29925537109375, 136.67460632324219}, {398.16494750976562, 136.67460632324219}}}
{{{380.29449462890625, 140.44486999511719}, {387.692810, 137.858429}}}
</div>
<div id="simplifyQuadratic56a">
{{{380.29449462890625, 140.44486999511719}, {387.29079954793264, 136.67460632324219}, {396.0399169921875, 136.67460632324219}}}
{{{380.29449462890625, 140.44486999511719}, {388.29925767018653, 136.67460632324219}, {398.16494750976562, 136.67460632324219}}}
{{fX=380.29449462890625 fY=140.44486999511719 }, {fX=398.16494750976562 fY=136.67460632324219 }} }
{{fX=380.29449462890625 fY=140.44486999511719 }, {fX=396.03991699218750 fY=136.67460632324219 }}
</div>
<div id="simplifyQuadratic27">
{{{1, 1}, {1, 0.666666687f}, {0.888888896f, 0.444444448f}}}
{{{1, 1}, {1, 0.5f}, {0, 0}}}
{{fX=1.0000000000000000 fY=1.0000000000000000 }, {fX=0.00000000000000000 fY=0.00000000000000000 }} }
{{fX=1.0000000000000000 fY=1.0000000000000000 }, {fX=0.88888889551162720 fY=0.44444444775581360 }} }
</div>
<div id="cubicOp7d">
{{{0.7114982008934021, 1.6617077589035034}, {0.51239079236984253, 1.4952657222747803}, {0.27760171890258789, 1.2776017189025879}, {0, 1}}}
{{{0.7114982008934021, 1.6617077589035034}, {0.20600014925003052, 1.7854888439178467}, {9.8686491813063348e-017, 1.9077447652816772}, {0, 1}}}
</div>
<div id="cubicOp25i">
{{{3.3856770992279053, 1.6298094987869263}, {3.777235186270762, 1.2744716237277114}, {3.7191683314895783, 1.4127666421509713}, {3.3995792865753174, 1.6371387243270874}}}
{{{3.3856770992279053, 1.6298094987869263}, {3.3902986605112582, 1.6322361865810757}, {3.3949326825525121, 1.6346792563210237}, {3.3995792865753174, 1.6371387243270874}}}
{{3.3856770992279053, 1.6298094987869263 }, {3.3995792865753174, 1.6371387243270874 }}
</div>
<div id="eldorado1">
{{{1006.69513f, 291}, {1023.26367f, 291}, {1033.84021f, 304.431458f}, {1030.31836f, 321}}}
{{{1030.318359375, 321}, {1036.695068359375, 291}}}
{{fX=1030.3183593750000 fY=321.00000000000000 }, {fX=1006.6951293945312 fY=291.00000000000000 }} }
</div>
<div id="carpetplanet1">
{{fX=67.000000000000000, 913.00000000000000 }, {194.00000000000000, 1041.0000000000000 }} }
{{fX=67.000000000000000, 913.00000000000000 }, {67.662002563476562, 926.00000000000000 }} }
{{{67, 913}, {67, 917.388977f}, {67.223999f, 921.726013f}, {67.6620026f, 926}}}
{{{67, 913}, {67, 983.692017f}, {123.860001f, 1041}, {194, 1041}}}
{{{67, 913}, {67.17070902440698, 919.69443917507760}}}
</div>
<div id="cubicOp104">
{{{2.25, 2.5}, {4.5, 1}}}
{{{2.25, 2.5}, {3.0833333333333321, 1.9999999999999973}, {4.0277778307596899, 1.2777777777777759}, {4.8611111640930176, 1}}}
{{{2.25, 2.5}, {1.9476099234472042, 2.6814340459316774}, {1.6598502000264239, 2.8336073904096661}, {1.3973386287689209, 2.9246666431427002}}}
{{{2.25, 2.5}, {1.2674896717071533, 3.1550068855285645}}}
</div>
<div id="cubicOp105">
{{{2.4060275554656982, 3.4971563816070557}, {2.9702522134213849, 4.2195279679982622}, {3.8172613958721247, 5.0538091166976979}, {5, 6}}}
{{{2.4060275554656982, 3.4971563816070557}, {3.4194286958002023, 3.5574883660881684}, {4.0077197935900575, 2.6628073781813661}, {2.2602717876434326, 0.33545622229576111}}}
</div>
<div id="cubicOp106">
{{{0.80825299024581909, 1.9691258668899536}, {0.8601454496383667, 1.9885541200637817}, {0.92434978485107422, 2}, {1, 2}}}
{{{0.80825299024581909, 1.9691258668899536}, {2.2400102615356445, 3.5966837406158447}, {2.5486805438995361, 3.362929105758667}, {2.494147777557373, 2.5976591110229492}}}
{{{0.80825299024581909, 1.9691258668899536}, {2.494147777557373, 2.5976591110229492}}}
{{{0.80825299024581909, 1.9691258668899536}, {1, 2}}}
</div>
<div id="cubicOp109">
{{{5, 4}, {5.443139240552143931, 3.556860759447856069}, {5.297161243696338673, 3.702838775882067335}, {4.649086475372314453, 3.654751062393188477}}}
{{{5, 4}, {4.876459521889748849, 3.876459521889748849}, {4.759596556247283949, 3.761504502886134915}, {4.649086475372314453, 3.654751062393188477}}}
</div>
<div id="skpwww_joomla_org_23">
{{{421, 378}, {421, 380.209137f}, {418.761414f, 382}, {416, 382}}}
{{{320, 378}, {421, 378.000031f}}}
{{{421, 378.000031f}, {421, 383}}}
{{{416, 383}, {418.761414f, 383}, {421, 380.761414f}, {421, 378}}}
</div>
<div id="xop1i">
{{5.000,1.000}, {5.191,0.809}, {5.163,0.837}, {4.993,1.000}}
{{5.000,1.000}, {4.968,1.024}}
{{5.000,1.000}, {4.998,1.000}, {4.995,1.000}, {4.993,1.000}}
</div>
<div id="xop1u">
{{3.500,3.500}, {3.000,4.000}, {2.500,4.500}, {1.000,4.000}}
{{3.500,3.500}, {3.113,3.887}, {2.725,4.275}, {2.338,3.732}}
</div>
<div id="xOp2i">
{{{2, 3}, {1.3475509011665685, 4.9573472965002949}, {2.8235509286078759, 3.5091759365574173}, {3.6505906581878662, 1.9883773326873779}}}
{{{2, 3}, {2.4604574005585795, 2.654656949581065}, {3.0269255632437986, 2.3093137214344743}, {3.6505906581878662, 1.9883773326873779}}}
{{{2, 3}, {1.0000000000000013, 3.7500000000000004}, {0.500000000000001, 4.5}, {1, 5}}}
</div>
<div id="testQuadratic56">
{{{380.29449462890625, 140.44486999511719}, {379.59701460635523, 140.8207374882179}, {378.91729736328125, 141.23385620117187}}}
{{{380.29449462890625, 140.44486999511719}, {387.29079954793264, 136.67460632324219}, {396.0399169921875, 136.67460632324219}}}
{{{380.29449462890625, 140.44486999511719}, {388.29925767018653, 136.67460632324219}, {398.16494750976562, 136.67460632324219}}}
</div>
<div id="testQuad15">
{{{1, 3}, {1, 1}}}
{{{1, 3}, {0, 0}}}
{{{1, 3}, {2, 0}, {0, 0}}}
</div>
<div id="testQuad21">
{{{0, 0}, {1, 1}}}
{{{0, 0}, {3, 0}, {2, 3}}}
{{{0, 0}, {2, 3}}}
{{{0, 0}, {2, 1}}}
</div>
<div id="testQuad22">
{{{0, 0}, {1.2000000476837158, 0.80000001192092896}}}
{{{0, 0}, {2, 0}}}
{{{0, 0}, {0, 1}, {3, 2}}}
{{{0, 0}, {1, 1}}}
</div>
<div id="testQuad23">
{{{1, 3}, {1.9090908914804459, 1.1818182170391081}, {0.33884298801422119, 1.0165289640426636}}}
{{{1, 3}, {0.33884298801422119, 1.0165289640426636}}}
{{{1, 3}, {3, 0}}}
</div>
<div id="cubicOp35d">
{{{2.211416482925415, 1.6971458196640015}, {1.2938009262874868, 2.8273619288830005}, {0.64690048634813535, 3.5876019453925414}, {0, 1}}}
{{{2.211416482925415, 1.6971458196640015}, {1.0082962512969971, 1.997925877571106}}}
{{{2.211416482925415, 1.6971458196640015}, {5, 1}}}
</div>
<div id="skpnational_com_au81">
{{{1110.7071533203125, 817.29290771484375}, {1110.9998779296875, 817.58587646484375}, {1111, 818}}}
{{{1110.7071533203125, 817.29290771484375}, {1110.526180767307778, 817.1119214508684081}, {1110.276144384999725, 817}, {1110, 817}}}
{{{1110.7071533203125, 817.29290771484375}, {1110.888097894721341, 817.4738660071997174}, {1111, 817.7238677851287321}, {1111, 818}}}
{{{1110.7071533203125, 817.29290771484375}, {1110.4140625, 817.0001220703125}, {1110, 817}}}
</div>
<div id="cubicOp85d">
{{{1.0648664236068726, 2.9606373310089111}, {0.80208036362614099, 2.7936484180272374}, {0.49170560730211144, 2.2292640182552783}, {0, 1}}}
{{{1.0648664236068726, 2.9606373310089111}, {0.6261905430171294, 3.2248910899179175}, {0.38860045191888659, 2.9430022595944321}, {0, 1}}}
{{{1.0648664236068726, 2.9606373310089111}, {1.4282355765013004, 3.191542348791669}, {1.7006143409852195, 2.6626209548338378}, {2.2355968952178955, 2.0810616016387939}}}
{{{1.0648664236068726, 2.9606373310089111}, {1.3437142856601656, 2.7926622975690494}, {1.7038131304059798, 2.4040122748806132}, {2.2355968952178955, 2.0810616016387939}}}
</div>
<div id="testQuads22">
{{{0, 0}, {1.20000004768371582, 0.8000000119209289551}}}
{{{0, 0}, {2, 0}}}
{{{0, 0}, {0, 1}, {3, 2}}}
{{{0, 0}, {1, 1}}}
</div>
<div id="cubicOp59d">
{{{4, 1}, {4, 0.37698365082686142}, {4.3881493046286568, 2.4710128800004547}, {3.4716842174530029, 2.9292664527893066}}}
{{{4, 1}, {0, 1}}}
</div>
<div id="findFirst1">
{{{2.5767931938171387, 0.88524383306503296}, {2.4235948002142855, 0.88692501490384834}, {2.2328897699358898, 0.92237007668803672}, {2, 1}}}
{{{2.5767931938171387, 0.88524383306503296}, {1.6008643534817426, 1.1609015907463158}, {1.1200849961943122, 1.8138386966264941}, {0.75343161821365356, 2.7170474529266357}}}
{{{2.5767931938171387, 0.88524383306503296}, {4.0492746201577932, 0.86908498848619054}, {2.0567957107800288, 3.9721309710522448}, {0.75343161821365356, 2.7170474529266357}}}
{{{2.5767931938171387, 0.88524383306503296}, {3.3470152174198557, 0.66768936887879282}, {4.4256496583071421, 0.68512993166142844}, {6, 1}}}
{{{2.57679319, 0.885243833}, {5.15358639, 0.885243833}}}
</div>
<div id="testQuads54">
{{1.000,1.000}, {1.500,0.500}, {1.500,0.250}}
{{1.000,1.000}, {1.667,0.333}}
{{1.000,1.000}, {2.000,3.000}}
</div>
<div id="testQuads45">
{{{3, 3}, {3, 2.7999999523162842}, {2.880000114440918, 2.6400001049041748}}}
{{{3, 3}, {3, 2}, {2, 0}}}
{{{3, 3}, {2, 0}}}
{{{3, 3}, {2.880000114440918, 2.6400001049041748}}}
</div>
<div id="testQuads59">
{{{3, 1}, {3, 0}}}
{{{3, 1}, {2.6666667461395264, 0.66666668653488159}}}
{{{3, 1}, {2.8000003099441542, 1.1999996900558463}, {2.6800000667572021, 1.3600000143051147}}}
{{{3, 1}, {2.6666667461395264, 1.3333333730697632}}}
</div>
<div id="skpcarrot_is24">
{{{1020.08099, 672.161987}, {1020.08051, 651.450988}, {1011.68576, 632.700988}, {998.113511, 619.128738}}}
{{{1020.08099, 672.161987}, {1019.27607, 640.291301}, {998.113511, 619.128738}}}
{{{1020, 672}, {1020, 651.289307}, {1012.67767, 633.611633}, {998.03302, 618.96698}}}
{{{1020, 672}, {1020, 640.93396}, {998.03302, 618.96698}}}
</div>
<div id="skpcarrot_is24a">
{{{1020, 672}, {1020, 651.289307}, {1012.67767, 633.611633}, {998.03302, 618.96698}}}
{{{1020, 672}, {1020, 640.93396}, {998.03302, 618.96698}}}
</div>
<div id="skpcarrot_is24b">
{{{1020.08099, 672.161987}, {1020.08051, 651.450988}, {1011.68576, 632.700988}, {998.113511, 619.128738}}}
{{{1020.08099, 672.161987}, {1019.27607, 640.291301}, {998.113511, 619.128738}}}
</div>
<div id="skpcarrot_is24c">
{{{{1020.08099,672.161987}, {1020.08002,630.73999}, {986.502014,597.161987}, {945.080994,597.161987}}},
{{{1020,672}, {1020,640.93396}, {998.03302,618.96698}}},
</div>
<div id="skpcarrot_is24d">
{{{1020.08099, 672.161987}, {1019.27607, 640.291301}, {998.113511, 619.128738}}}
{{{1020, 672}, {1020, 640.93396}, {998.03302, 618.96698}}}
</div>
<div id="skpcarrot_is24e">
{{{{1020.08099,672.161987}, {1020.08002,630.73999}, {986.502014,597.161987}, {945.080994,597.161987}}},
{{{1020.08099, 672.161987}, {1019.27607, 640.291301}, {998.113511, 619.128738}}}
{{{1020, 672}, {1020, 640.93396}, {998.03302, 618.96698}}}
</div>
<div id="slop1">
{{{-378.22698974609375, -987.8935546875}, {-47.53326416015625, 482.7139892578125}, {-626.4708251953125, -338.62969970703125}, {-847.94854736328125, -861.42230224609375}}}
{{{-378.61790442466736, -987.49146723747253}, {-282.51787429804051, -556.39065286764685}, {-278.55106873374694, -364.17984985308294}}}
{{{-305.5273847156202, -615.99979442705023}, {-305.04071954345704, -612.87932617187505}}}
</div>
qT=0.98917687 cT=0.788725084 dist=312.188493 cross=-40759.4852
<div id="slop2">
{{{79.5137939,-249.867188}, {260.778931,-561.349854}, {343.375977,-472.657898}, {610.251465,97.8208008}}}
{{{312.993284,-406.178762}, {418.053808,-326.9483}, {610.036929,97.2408578}}}
{{{463.107827,-200.015424}, {602.008878,79.5702581}}}
</div>
qT=0.0192863061 cT=0.241285225 dist=652.007881 cross=528435.665
<div id="slop3">
{{{-895.015015,-523.545288}, {223.166992,-999.644531}, {615.428711,-767.162109}, {605.479736,480.355713}}}
{{{-894.932414,-523.605499}, {-66.4040558,-889.938889}, {278.515212,-667.684158}}}
{{{-207.851881,-740.109296}, {-831.819002,-550.955104}}}
</div>
qT=0.0245724525 cT=0.231316637 dist=407.103004 cross=-46286.5686
<div id="slop4">
{{{876.492798,-849.716187}, {519.430908,-288.374207}, {187.2771,314.324341}, {335.363403,533.086548}}}
{{{876.323133,-849.535824}, {594.868958,-415.229224}, {416.667192,-30.0277669}}}
{{{638.343827,-458.798274}, {849.023879,-807.14691}}}
</div>
qT=0.000316393778 cT=0.248252634 dist=489.678412 cross=-57352.7653
<div id="slop5">
{{{876.492798,-849.716187}, {519.430908,-288.374207}, {187.2771,314.324341}, {335.363403,533.086548}}}
{{{876.147506,-849.184429}, {593.963775,-414.437342}, {416.842819,-30.3791618}}}
{{{622.139843,-430.512844}, {876.135915,-849.166571}}}
</div>
qT=0.989562776 cT=0.760518485 dist=211.50589 cross=134901.42
<div id="slop6">
{{{876.492798,-849.716187}, {519.430908,-288.374207}, {187.2771,314.324341}, {335.363403,533.086548}}}
{{{416.141554,-30.4534414}, {237.846068,356.664216}, {335.719378,533.692585}}}
{{{305.345404,315.701195}, {331.440368,525.591152}}}
</div>
qT=0.0978245708 cT=0.397465904 dist=959.737748 cross=158093.403
<div id="slop7">
{{{895.800171,-222.213013}, {-528.78833,526.47644}, {-967.299927,776.05603}, {-611.228027,319.934814}}}
{{{629.666617,-82.159942}, {-661.943328,620.81113}, {-723.44072,537.121833}}}
{{{-347.560585,421.003177}, {507.062151,-15.707855}}}
</div>
qT=0.169803964 cT=0.389326872 dist=658.039939 cross=107865.424
<div id="slop8">
{{{895.800171,-222.213013}, {-528.78833,526.47644}, {-967.299927,776.05603}, {-611.228027,319.934814}}}
{{{629.536617,-81.7990275}, {-662.457623,620.485316}, {-723.31072,536.760918}}}
{{{-330.996421,413.091598}, {257.080063,117.824582}}}
</div>
qT=0.0863836955 cT=0.387901231 dist=986.24777 cross=157348.113
<div id="slop9">
{{{895.800171,-222.213013}, {-528.78833,526.47644}, {-967.299927,776.05603}, {-611.228027,319.934814}}}
{{{629.248316,-81.8984216}, {-662.339696,620.351182}, {-723.022419,536.860313}}}
{{{-328.058099,411.68229}, {549.399512,-38.5985162}}}
</div>
qT=0.175359403 cT=0.390420692 dist=640.051938 cross=105488.084
<div id="slop10">
{{{895.800171,-222.213013}, {-528.78833,526.47644}, {-967.299927,776.05603}, {-611.228027,319.934814}}}
{{{629.760605,-81.9577046}, {-661.301606,620.029216}, {-723.534707,536.919596}}}
{{{-333.243516,414.168229}, {238.961251,127.37878}}}
</div>
qT=0.0986412358 cT=0.382365595 dist=921.951857 cross=145651.761
<div id="slop11">
{{{895.800171,-222.213013}, {-528.78833,526.47644}, {-967.299927,776.05603}, {-611.228027,319.934814}}}
{{{629.919588,-82.1841825}, {-662.488256,620.04494}, {-723.693691,537.146073}}}
{{{-316.541641,406.142013}, {504.067361,-14.0913644}}}
</div>
qT=0.146746849 cT=0.391456086 dist=750.006927 cross=123679.094
<div id="slop12">
{{{895.800171,-222.213013}, {-528.78833,526.47644}, {-967.299927,776.05603}, {-611.228027,319.934814}}}
{{{629.712675,-82.0366321}, {-661.487948,620.191832}, {-723.486777,536.998523}}}
{{{-335.364605,415.183549}, {334.079508,77.0194322}}}
</div>
qT=0.00196158131 cT=0.20357489 dist=466.080185 cross=241741.95
<div id="slop13">
{{{-627.671509,-359.277039}, {222.414551,-791.598328}, {390.603027,-581.903687}, {-21.7962036,560.33728}}}
{{{-627.675958,-359.282959}, {-52.012535,-659.029798}, {116.967835,-524.756101}}}
{{{-192.427848,-541.033993}, {-622.696937,-361.871356}}}
</div>
qT=0.948725598 cT=0.744200608 dist=699.694313 cross=179509.878
<div id="slop14">
{{{-362.331848,427.292603}, {634.418701,-661.946533}, {438.438599,-626.147278}, {-893.060425,214.243408}}}
{{{259.978301,-393.549091}, {181.692599,-474.452437}, {-892.389834,213.689096}}}
{{{-95.1310032,-267.365579}, {-696.89984,89.6307768}}}
</div>
qT=0.971677129 cT=0.755306143 dist=771.998962 cross=189468.817
<div id="slop15">
{{{-362.331848,427.292603}, {634.418701,-661.946533}, {438.438599,-626.147278}, {-893.060425,214.243408}}}
{{{259.662278,-393.355886}, {181.612843,-473.935297}, {-892.073812,213.495892}}}
{{{-120.438346,-253.451518}, {-782.461182,143.673352}}}
</div>
qT=0.571797795 cT=0.773951562 dist=495.560209 cross=221091.889
<div id="slop16">
{{{447.192383,-883.210205}, {359.794678,-987.765808}, {755.427612,-754.328735}, {963.672119,746.545776}}}
{{{635.795655,-580.726915}, {810.704547,-228.491534}, {963.345162,745.921688}}}
{{{801.470356,-87.7105789}, {646.551495,-558.433498}}}
</div>
qT=0.579236693 cT=0.782683167 dist=281.750564 cross=65125.1655
<div id="slop17">
{{{-931.259155,-883.589966}, {-485.682007,-615.793701}, {-68.5913696,-928.695923}, {431.499268,-810.584778}}}
{{{-177.087049,-804.265618}, {110.452267,-866.525236}, {430.718323,-810.414444}}}
{{{116.080189,-836.904702}, {-164.080748,-807.017753}}}
</div>
qT=0.0102075348 cT=0.2448024 dist=855.408492 cross=463614.179
<div id="slop18">
{{{-867.011292,844.139282}, {-136.156799,-281.244263}, {583.27771,-926.761414}, {998.710205,6.19244385}}}
{{{-866.7221,843.65105}, {-308.756317,-34.8353977}, {183.843514,-346.222431}}}
{{{-336.612013,120.039627}, {-844.283739,808.5112}}}
</div>
qT=0.473968306 cT=0.266805943 dist=567.851844 cross=-461509.104
<div id="slop19">
{{{-867.011292,844.139282}, {-136.156799,-281.244263}, {583.27771,-926.761414}, {998.710205,6.19244385}}}
{{{-867.218781,844.133445}, {-310.496711,-35.0458119}, {184.340195,-346.704825}}}
{{{-290.018097,66.7065093}, {132.536746,-312.639141}}}
</div>
qT=0.0232589401 cT=0.241085469 dist=789.989464 cross=428119.544
<div id="slop20">
{{{-867.011292,844.139282}, {-136.156799,-281.244263}, {583.27771,-926.761414}, {998.710205,6.19244385}}}
{{{-866.942271,843.928587}, {-309.178151,-34.0018497}, {184.063685,-346.499968}}}
{{{-344.507162,129.265381}, {-815.30119,763.644082}}}
</div>
<div id="skpnamecheap_405">
{{{141.008835f, 837.9646f}, {141.235291f, 1109.05884f}}}
{{{141, 842}, {141.14502f, 1000}}}
{{{141.14502f, 1000}, {140, 1000}}}
</div>
<div id="skpwww_dealnews_com_315">
{{{969.87066650390625, 4279.810546875}, {967.7166748046875, 4260}}}
{{{969.87066650390625, 4279.810546875}, {969.866972698829386, 4279.809233889284769}, {969.88751220703125, 4279.81640625}}}
{{{969.87066650390625, 4279.810546875}, {970, 4281}}}
{{{969.87066650390625, 4279.810546875}, {968.9217161046863112, 4279.473236623693992}, {968.17156982421875, 4278.53564453125}}}
{{{969.8706626470486754, 4279.810469740555163}, {969.8790796016525064, 4279.813461598796493}, {969.88751220703125, 4279.81640625}}}
</div>
<div id="skpwww_dealnews_com_315_a">
{{{969.8706626470486754, 4279.810469740555163}, {969.8790796016525064, 4279.813461598796493}, {969.88751220703125, 4279.81640625}}}
{{{969.87066650390625, 4279.810546875}, {969.8790834585100811, 4279.81353873324133}}}
{{{969.88751220703125, 4279.81640625}, {969.8790796016525064, 4279.813461598796493}}}
</div>
<div id="testQuads60">
{{{2, 2}, {1.977731304590550021, 1.97773134708404541}, {1.95645439624786377, 1.95546269416809082}}}
{{{2, 2}, {2, 3}}}
{{{2, 2}, {2, 1.960000038146972656}}}
{{{2, 2}, {1.955341815948486328, 1.955341815948486328}}}
</div>
<div id="testQuads60_a">
{{{2, 0}, {1, 1}, {2, 2}}}
{{{2, 2}, {0, 0}}}
</div>
<div id="testQuads60_b">
{{2,1}, {0,2}, {3,2}},
{{3,2}, {2,3}},
{{2,3}, {2,1}},
{{0,0}, {2,0}},
{{2,0}, {1,1}, {2,2}},
{{2,2}, {0,0}},
</div>
<div id="skpelpais_com_18">
{{183,8507}, {552,8506.99023}},
{{552,8506.99023}, {552,8508}},
{{552,8508}, {183,8508}},
{{183,8508}, {183,8507}},
op intersect
{{183,8508}, {183,8506.99023}},
{{183,8506.99023}, {552,8507}},
{{552,8507}, {552,8508}},
</div>
<div id="skpwww_cityads_ru_249">
{{{1000, 10.4003992f}, {1000, 13.3527431f}}}
{{{1000, 13.3527431f}, {999.917603f, 13.2607508f}, {999.82843f, 13.1715727f}}}
{{{1000, 13}, {999.969971f, 37.0299988f}}}
</div>
</div>
<script type="text/javascript">
var testDivs = [
skpwww_cityads_ru_249,
skpelpais_com_18,
testQuads60_b,
testQuads60_a,
testQuads60,
skpwww_dealnews_com_315_a,
skpwww_dealnews_com_315,
skpnamecheap_405,
slop1,
slop2,
slop3,
slop4,
slop5,
slop6,
slop7,
slop8,
slop9,
slop10,
slop11,
slop12,
slop13,
slop14,
slop15,
slop16,
slop17,
slop18,
slop19,
slop20,
skpcarrot_is24e,
skpcarrot_is24d,
skpcarrot_is24c,
skpcarrot_is24b,
skpcarrot_is24a,
skpcarrot_is24,
testQuads59,
testQuads45,
testQuads54,
findFirst1,
cubicOp59d,
testQuads22,
cubicOp85d,
cubicOp104,
skpnational_com_au81,
cubicOp35d,
testQuad23,
testQuad22,
testQuad21,
testQuad15,
testQuadratic56,
xop1i,
xOp2i,
xop1u,
skpwww_joomla_org_23,
cubicOp109,
cubicOp106,
cubicOp105,
carpetplanet1,
eldorado1,
cubicOp25i,
cubicOp7d,
simplifyQuadratic27,
simplifyQuadratic56a,
simplifyQuadratic56,
quadratic58again,
simplifyQuadratic58a,
simplifyQuadratic58,
simplifyQuadratic36,
quad89987,
quad8741,
quad8b,
quad8a,
quad208,
quad67242,
quad37226,
quad35237,
quad108,
quad212,
quad3160,
quad640,
quad206,
quad136,
quad113,
quad999,
quad0,
quad179,
quad4a,
quad94,
quad77,
quad22a,
quad14a,
quad809,
quad653,
quad584,
quad413,
quad379,
quad159,
quad232,
quad40,
quad39,
quad38,
quad37,
quad36,
quad35,
quad34,
quad33,
quad32,
quad31,
quad30,
quad29,
quad28,
quad27,
quad26,
quad25,
quad24,
quad23,
quad22,
quad21,
quad20,
quad19,
quad18,
quad17,
quad16,
quad15,
quad14,
quad13,
quad12,
quad11,
cubic2,
cubic1,
quad1,
quad2,
quad3,
quad4,
quad5,
quad6,
quad7,
quad8,
quad9,
quad10,
];
var tests = [];
var testTitles = [];
var testIndex = 0;
var ctx;
var subscale = 1;
var xmin, xmax, ymin, ymax;
var scale;
var initScale;
var mouseX, mouseY;
var mouseDown = false;
var srcLeft, srcTop;
var screenWidth, screenHeight;
var drawnPts;
var curveT = 0;
var lastX, lastY;
var activeCurve = [];
var activePt;
var decimal_places = 3;
var draw_t = false;
var draw_closest_t = false;
var draw_derivative = false;
var draw_endpoints = true;
var draw_midpoint = 0;
var draw_mouse_xy = false;
var draw_order = false;
var draw_point_xy = false;
var draw_ray_intersect = false;
var draw_quarterpoint = 0;
var draw_tangents = 1;
var draw_sortpoint = 0;
var retina_scale = !!window.devicePixelRatio;
function parse(test, title) {
var curveStrs = test.split("{{");
var pattern = /-?\d+\.*\d*e?-?\d*/g;
var curves = [];
for (var c in curveStrs) {
var curveStr = curveStrs[c];
var points = curveStr.match(pattern);
var pts = [];
for (var wd in points) {
var num = parseFloat(points[wd]);
if (isNaN(num)) continue;
pts.push(num);
}
if (pts.length > 2)
curves.push(pts);
}
if (curves.length >= 1) {
tests.push(curves);
testTitles.push(title);
}
}
function init(test) {
var canvas = document.getElementById('canvas');
if (!canvas.getContext) return;
ctx = canvas.getContext('2d');
var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
var unscaledWidth = window.innerWidth - 20;
var unscaledHeight = window.innerHeight - 20;
screenWidth = unscaledWidth;
screenHeight = unscaledHeight;
canvas.width = unscaledWidth * resScale;
canvas.height = unscaledHeight * resScale;
canvas.style.width = unscaledWidth + 'px';
canvas.style.height = unscaledHeight + 'px';
if (resScale != 1) {
ctx.scale(resScale, resScale);
}
xmin = Infinity;
xmax = -Infinity;
ymin = Infinity;
ymax = -Infinity;
for (var curves in test) {
var curve = test[curves];
var last = curve.length;
for (var idx = 0; idx < last; idx += 2) {
xmin = Math.min(xmin, curve[idx]);
xmax = Math.max(xmax, curve[idx]);
ymin = Math.min(ymin, curve[idx + 1]);
ymax = Math.max(ymax, curve[idx + 1]);
}
}
xmin -= 1;
var testW = xmax - xmin;
var testH = ymax - ymin;
subscale = 1;
while (testW * subscale < 0.1 && testH * subscale < 0.1) {
subscale *= 10;
}
while (testW * subscale > 10 && testH * subscale > 10) {
subscale /= 10;
}
setScale(xmin, xmax, ymin, ymax);
mouseX = (screenWidth / 2) / scale + srcLeft;
mouseY = (screenHeight / 2) / scale + srcTop;
initScale = scale;
}
function setScale(x0, x1, y0, y1) {
var srcWidth = x1 - x0;
var srcHeight = y1 - y0;
var usableWidth = screenWidth;
var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
usableWidth -= (xDigits + yDigits) * 10;
usableWidth -= decimal_places * 10;
var hscale = usableWidth / srcWidth;
var vscale = screenHeight / srcHeight;
scale = Math.min(hscale, vscale);
var invScale = 1 / scale;
var sxmin = x0 - invScale * 5;
var symin = y0 - invScale * 10;
var sxmax = x1 + invScale * (6 * decimal_places + 10);
var symax = y1 + invScale * 10;
srcWidth = sxmax - sxmin;
srcHeight = symax - symin;
hscale = usableWidth / srcWidth;
vscale = screenHeight / srcHeight;
scale = Math.min(hscale, vscale);
srcLeft = sxmin;
srcTop = symin;
}
function dxy_at_t(curve, t) {
var dxy = {};
if (curve.length == 6) {
var a = t - 1;
var b = 1 - 2 * t;
var c = t;
dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
} else if (curve.length == 8) {
var one_t = 1 - t;
var a = curve[0];
var b = curve[2];
var c = curve[4];
var d = curve[6];
dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
a = curve[1];
b = curve[3];
c = curve[5];
d = curve[7];
dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
}
return dxy;
}
var flt_epsilon = 1.19209290E-07;
function approximately_zero(A) {
return Math.abs(A) < flt_epsilon;
}
function approximately_zero_inverse(A) {
return Math.abs(A) > (1 / flt_epsilon);
}
function quad_real_roots(A, B, C) {
var s = [];
var p = B / (2 * A);
var q = C / A;
if (approximately_zero(A) && (approximately_zero_inverse(p)
|| approximately_zero_inverse(q))) {
if (approximately_zero(B)) {
if (C == 0) {
s[0] = 0;
}
return s;
}
s[0] = -C / B;
return s;
}
/* normal form: x^2 + px + q = 0 */
var p2 = p * p;
if (!approximately_zero(p2 - q) && p2 < q) {
return s;
}
var sqrt_D = 0;
if (p2 > q) {
sqrt_D = Math.sqrt(p2 - q);
}
s[0] = sqrt_D - p;
var flip = -sqrt_D - p;
if (!approximately_zero(s[0] - flip)) {
s[1] = flip;
}
return s;
}
function cubic_real_roots(A, B, C, D) {
if (approximately_zero(A)) { // we're just a quadratic
return quad_real_roots(B, C, D);
}
if (approximately_zero(D)) { // 0 is one root
var s = quad_real_roots(A, B, C);
for (var i = 0; i < s.length; ++i) {
if (approximately_zero(s[i])) {
return s;
}
}
s.push(0);
return s;
}
if (approximately_zero(A + B + C + D)) { // 1 is one root
var s = quad_real_roots(A, A + B, -D);
for (var i = 0; i < s.length; ++i) {
if (approximately_zero(s[i] - 1)) {
return s;
}
}
s.push(1);
return s;
}
var a, b, c;
var invA = 1 / A;
a = B * invA;
b = C * invA;
c = D * invA;
var a2 = a * a;
var Q = (a2 - b * 3) / 9;
var R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
var R2 = R * R;
var Q3 = Q * Q * Q;
var R2MinusQ3 = R2 - Q3;
var adiv3 = a / 3;
var r;
var roots = [];
if (R2MinusQ3 < 0) { // we have 3 real roots
var theta = Math.acos(R / Math.sqrt(Q3));
var neg2RootQ = -2 * Math.sqrt(Q);
r = neg2RootQ * Math.cos(theta / 3) - adiv3;
roots.push(r);
r = neg2RootQ * Math.cos((theta + 2 * Math.PI) / 3) - adiv3;
if (!approximately_zero(roots[0] - r)) {
roots.push(r);
}
r = neg2RootQ * Math.cos((theta - 2 * Math.PI) / 3) - adiv3;
if (!approximately_zero(roots[0] - r) && (roots.length == 1
|| !approximately_zero(roots[1] - r))) {
roots.push(r);
}
} else { // we have 1 real root
var sqrtR2MinusQ3 = Math.sqrt(R2MinusQ3);
var A = Math.abs(R) + sqrtR2MinusQ3;
A = Math.pow(A, 1/3);
if (R > 0) {
A = -A;
}
if (A != 0) {
A += Q / A;
}
r = A - adiv3;
roots.push(r);
if (approximately_zero(R2 - Q3)) {
r = -A / 2 - adiv3;
if (!approximately_zero(s[0] - r)) {
roots.push(r);
}
}
}
return roots;
}
function approximately_zero_or_more(tValue) {
return tValue >= -flt_epsilon;
}
function approximately_one_or_less(tValue) {
return tValue <= 1 + flt_epsilon;
}
function approximately_less_than_zero(tValue) {
return tValue < flt_epsilon;
}
function approximately_greater_than_one(tValue) {
return tValue > 1 - flt_epsilon;
}
function add_valid_ts(s) {
var t = [];
nextRoot:
for (var index = 0; index < s.length; ++index) {
var tValue = s[index];
if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) {
if (approximately_less_than_zero(tValue)) {
tValue = 0;
} else if (approximately_greater_than_one(tValue)) {
tValue = 1;
}
for (var idx2 = 0; idx2 < t.length; ++idx2) {
if (approximately_zero(t[idx2] - tValue)) {
continue nextRoot;
}
}
t.push(tValue);
}
}
return t;
}
function quad_roots(A, B, C) {
var s = quad_real_roots(A, B, C);
var foundRoots = add_valid_ts(s);
return foundRoots;
}
function cubic_roots(A, B, C, D) {
var s = cubic_real_roots(A, B, C, D);
var foundRoots = add_valid_ts(s);
return foundRoots;
}
function ray_curve_intersect(startPt, endPt, curve) {
var adj = endPt[0] - startPt[0];
var opp = endPt[1] - startPt[1];
var r = [];
for (var n = 0; n < curve.length / 2; ++n) {
r[n] = (curve[n * 2 + 1] - startPt[1]) * adj - (curve[n * 2] - startPt[0]) * opp;
}
if (curve.length == 6) {
var A = r[2];
var B = r[1];
var C = r[0];
A += C - 2 * B; // A = a - 2*b + c
B -= C; // B = -(b - c)
return quad_roots(A, 2 * B, C);
}
var A = r[3]; // d
var B = r[2] * 3; // 3*c
var C = r[1] * 3; // 3*b
var D = r[0]; // a
A -= D - C + B; // A = -a + 3*b - 3*c + d
B += 3 * D - 2 * C; // B = 3*a - 6*b + 3*c
C -= 3 * D; // C = -3*a + 3*b
return cubic_roots(A, B, C, D);
}
function x_at_t(curve, t) {
var one_t = 1 - t;
if (curve.length == 4) {
return one_t * curve[0] + t * curve[2];
}
var one_t2 = one_t * one_t;
var t2 = t * t;
if (curve.length == 6) {
return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
}
var a = one_t2 * one_t;
var b = 3 * one_t2 * t;
var c = 3 * one_t * t2;
var d = t2 * t;
return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
}
function y_at_t(curve, t) {
var one_t = 1 - t;
if (curve.length == 4) {
return one_t * curve[1] + t * curve[3];
}
var one_t2 = one_t * one_t;
var t2 = t * t;
if (curve.length == 6) {
return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
}
var a = one_t2 * one_t;
var b = 3 * one_t2 * t;
var c = 3 * one_t * t2;
var d = t2 * t;
return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
}
function drawPointAtT(curve) {
var x = x_at_t(curve, curveT);
var y = y_at_t(curve, curveT);
drawPoint(x, y);
}
function drawLine(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo((x1 - srcLeft) * scale,
(y1 - srcTop) * scale);
ctx.lineTo((x2 - srcLeft) * scale,
(y2 - srcTop) * scale);
ctx.stroke();
}
function drawPoint(px, py) {
for (var pts = 0; pts < drawnPts.length; pts += 2) {
var x = drawnPts[pts];
var y = drawnPts[pts + 1];
if (px == x && py == y) {
return;
}
}
drawnPts.push(px);
drawnPts.push(py);
var _px = (px - srcLeft) * scale;
var _py = (py - srcTop) * scale;
ctx.beginPath();
ctx.arc(_px, _py, 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.stroke();
if (draw_point_xy) {
var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
ctx.font = "normal 10px Arial";
ctx.textAlign = "left";
ctx.fillStyle = "black";
ctx.fillText(label, _px + 5, _py);
}
}
function drawPointSolid(px, py) {
drawPoint(px, py);
ctx.fillStyle = "rgba(0,0,0, 0.4)";
ctx.fill();
}
function crossPt(origin, pt1, pt2) {
return ((pt1[0] - origin[0]) * (pt2[1] - origin[1])
- (pt1[1] - origin[1]) * (pt2[0] - origin[0])) > 0 ? 0 : 1;
}
// may not work well for cubics
function curveClosestT(curve, x, y) {
var closest = -1;
var closestDist = Infinity;
var l = Infinity, t = Infinity, r = -Infinity, b = -Infinity;
for (var i = 0; i < 16; ++i) {
var testX = x_at_t(curve, i / 16);
l = Math.min(testX, l);
r = Math.max(testX, r);
var testY = y_at_t(curve, i / 16);
t = Math.min(testY, t);
b = Math.max(testY, b);
var dx = testX - x;
var dy = testY - y;
var dist = dx * dx + dy * dy;
if (closestDist > dist) {
closestDist = dist;
closest = i;
}
}
var boundsX = r - l;
var boundsY = b - t;
var boundsDist = boundsX * boundsX + boundsY * boundsY;
if (closestDist > boundsDist) {
return -1;
}
console.log("closestDist = " + closestDist + " boundsDist = " + boundsDist
+ " t = " + closest / 16);
return closest / 16;
}
function draw(test, title) {
ctx.font = "normal 50px Arial";
ctx.textAlign = "left";
ctx.fillStyle = "rgba(0,0,0, 0.1)";
ctx.fillText(title, 50, 50);
ctx.font = "normal 10px Arial";
// ctx.lineWidth = "1.001"; "0.999";
var hullStarts = [];
var hullEnds = [];
var midSpokes = [];
var midDist = [];
var origin = [];
var shortSpokes = [];
var shortDist = [];
var sweeps = [];
drawnPts = [];
for (var curves in test) {
var curve = test[curves];
origin.push(curve[0]);
origin.push(curve[1]);
var startPt = [];
startPt.push(curve[2]);
startPt.push(curve[3]);
hullStarts.push(startPt);
var endPt = [];
if (curve.length == 4) {
endPt.push(curve[2]);
endPt.push(curve[3]);
} else if (curve.length == 6) {
endPt.push(curve[4]);
endPt.push(curve[5]);
} else if (curve.length == 8) {
endPt.push(curve[6]);
endPt.push(curve[7]);
}
hullEnds.push(endPt);
var sweep = crossPt(origin, startPt, endPt);
sweeps.push(sweep);
var midPt = [];
midPt.push(x_at_t(curve, 0.5));
midPt.push(y_at_t(curve, 0.5));
midSpokes.push(midPt);
var shortPt = [];
shortPt.push(x_at_t(curve, 0.25));
shortPt.push(y_at_t(curve, 0.25));
shortSpokes.push(shortPt);
var dx = midPt[0] - origin[0];
var dy = midPt[1] - origin[1];
var dist = Math.sqrt(dx * dx + dy * dy);
midDist.push(dist);
dx = shortPt[0] - origin[0];
dy = shortPt[1] - origin[1];
dist = Math.sqrt(dx * dx + dy * dy);
shortDist.push(dist);
}
var intersect = [];
var useIntersect = false;
var maxWidth = Math.max(xmax - xmin, ymax - ymin);
for (var curves in test) {
var curve = test[curves];
if (curve.length == 6 || curve.length == 8) {
var opp = curves == 1 ? 0 : 1;
var sects = ray_curve_intersect(origin, hullEnds[opp], curve);
intersect.push(sects);
if (sects.length > 1) {
var intersection = sects[0];
if (intersection == 0) {
intersection = sects[1];
}
var ix = x_at_t(curve, intersection) - origin[0];
var iy = y_at_t(curve, intersection) - origin[1];
var ex = hullEnds[opp][0] - origin[0];
var ey = hullEnds[opp][1] - origin[1];
if (ix * ex >= 0 && iy * ey >= 0) {
var iDist = Math.sqrt(ix * ix + iy * iy);
var eDist = Math.sqrt(ex * ex + ey * ey);
var delta = Math.abs(iDist - eDist) / maxWidth;
if (delta > (curve.length == 6 ? 1e-5 : 1e-4)) {
useIntersect ^= true;
}
}
}
}
}
var midLeft = crossPt(origin, midSpokes[0], midSpokes[1]);
var firstInside;
if (useIntersect) {
var sect1 = intersect[0].length > 1;
var sIndex = sect1 ? 0 : 1;
var sects = intersect[sIndex];
var intersection = sects[0];
if (intersection == 0) {
intersection = sects[1];
}
var curve = test[sIndex];
var ix = x_at_t(curve, intersection) - origin[0];
var iy = y_at_t(curve, intersection) - origin[1];
var opp = sect1 ? 1 : 0;
var ex = hullEnds[opp][0] - origin[0];
var ey = hullEnds[opp][1] - origin[1];
var iDist = ix * ix + iy * iy;
var eDist = ex * ex + ey * ey;
firstInside = (iDist > eDist) ^ (sIndex == 0) ^ sweeps[0];
// console.log("iDist=" + iDist + " eDist=" + eDist + " sIndex=" + sIndex
// + " sweeps[0]=" + sweeps[0]);
} else {
// console.log("midLeft=" + midLeft);
firstInside = midLeft != 0;
}
var shorter = midDist[1] < midDist[0];
var shortLeft = shorter ? crossPt(origin, shortSpokes[0], midSpokes[1])
: crossPt(origin, midSpokes[0], shortSpokes[1]);
var startCross = crossPt(origin, hullStarts[0], hullStarts[1]);
var disallowShort = midLeft == startCross && midLeft == sweeps[0]
&& midLeft == sweeps[1];
// console.log("midLeft=" + midLeft + " startCross=" + startCross);
var intersectIndex = 0;
for (var curves in test) {
var curve = test[curves];
if (curve.length != 4 && curve.length != 6 && curve.length != 8) {
continue;
}
ctx.lineWidth = 1;
if (draw_tangents != 0) {
if (firstInside == curves) {
ctx.strokeStyle = "rgba(255,0,0, 0.3)";
} else {
ctx.strokeStyle = "rgba(0,0,255, 0.3)";
}
drawLine(curve[0], curve[1], curve[2], curve[3]);
if (draw_tangents != 2) {
if (curve.length > 4) drawLine(curve[2], curve[3], curve[4], curve[5]);
if (curve.length > 6) drawLine(curve[4], curve[5], curve[6], curve[7]);
}
if (draw_tangents != 1) {
if (curve.length == 6) drawLine(curve[0], curve[1], curve[4], curve[5]);
if (curve.length == 8) drawLine(curve[0], curve[1], curve[6], curve[7]);
}
}
ctx.beginPath();
ctx.moveTo((curve[0] - srcLeft) * scale, (curve[1] - srcTop) * scale);
if (curve.length == 4) {
ctx.lineTo((curve[2] - srcLeft) * scale, (curve[3] - srcTop) * scale);
} else if (curve.length == 6) {
ctx.quadraticCurveTo(
(curve[2] - srcLeft) * scale, (curve[3] - srcTop) * scale,
(curve[4] - srcLeft) * scale, (curve[5] - srcTop) * scale);
} else {
ctx.bezierCurveTo(
(curve[2] - srcLeft) * scale, (curve[3] - srcTop) * scale,
(curve[4] - srcLeft) * scale, (curve[5] - srcTop) * scale,
(curve[6] - srcLeft) * scale, (curve[7] - srcTop) * scale);
}
if (firstInside == curves) {
ctx.strokeStyle = "rgba(255,0,0, 1)";
} else {
ctx.strokeStyle = "rgba(0,0,255, 1)";
}
ctx.stroke();
if (draw_endpoints) {
drawPoint(curve[0], curve[1]);
drawPoint(curve[2], curve[3]);
if (curve.length > 4) drawPoint(curve[4], curve[5]);
if (curve.length > 6) drawPoint(curve[6], curve[7]);
}
if (draw_midpoint != 0) {
if ((curves == 0) == (midLeft == 0)) {
ctx.strokeStyle = "rgba(0,180,127, 0.6)";
} else {
ctx.strokeStyle = "rgba(127,0,127, 0.6)";
}
var midX = x_at_t(curve, 0.5);
var midY = y_at_t(curve, 0.5);
drawPointSolid(midX, midY);
if (draw_midpoint > 1) {
drawLine(curve[0], curve[1], midX, midY);
}
}
if (draw_quarterpoint != 0) {
if ((curves == 0) == (shortLeft == 0)) {
ctx.strokeStyle = "rgba(0,191,63, 0.6)";
} else {
ctx.strokeStyle = "rgba(63,0,191, 0.6)";
}
var midT = (curves == 0) == shorter ? 0.25 : 0.5;
var midX = x_at_t(curve, midT);
var midY = y_at_t(curve, midT);
drawPointSolid(midX, midY);
if (draw_quarterpoint > 1) {
drawLine(curve[0], curve[1], midX, midY);
}
}
if (draw_sortpoint != 0) {
if ((curves == 0) == ((disallowShort == -1 ? midLeft : shortLeft) == 0)) {
ctx.strokeStyle = "rgba(0,155,37, 0.6)";
} else {
ctx.strokeStyle = "rgba(37,0,155, 0.6)";
}
var midT = (curves == 0) == shorter && disallowShort != curves ? 0.25 : 0.5;
console.log("curves=" + curves + " disallowShort=" + disallowShort
+ " midLeft=" + midLeft + " shortLeft=" + shortLeft
+ " shorter=" + shorter + " midT=" + midT);
var midX = x_at_t(curve, midT);
var midY = y_at_t(curve, midT);
drawPointSolid(midX, midY);
if (draw_sortpoint > 1) {
drawLine(curve[0], curve[1], midX, midY);
}
}
if (draw_ray_intersect != 0) {
ctx.strokeStyle = "rgba(75,45,199, 0.6)";
if (curve.length == 6 || curve.length == 8) {
var intersections = intersect[intersectIndex];
for (var i in intersections) {
var intersection = intersections[i];
var x = x_at_t(curve, intersection);
var y = y_at_t(curve, intersection);
drawPointSolid(x, y);
if (draw_ray_intersect > 1) {
drawLine(curve[0], curve[1], x, y);
}
}
}
++intersectIndex;
}
if (draw_order) {
var px = x_at_t(curve, 0.75);
var py = y_at_t(curve, 0.75);
var _px = (px - srcLeft) * scale;
var _py = (py - srcTop) * scale;
ctx.beginPath();
ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
if (firstInside == curves) {
ctx.strokeStyle = "rgba(255,0,0, 1)";
ctx.fillStyle = "rgba(255,0,0, 1)";
} else {
ctx.strokeStyle = "rgba(0,0,255, 1)";
ctx.fillStyle = "rgba(0,0,255, 1)";
}
ctx.stroke();
ctx.font = "normal 16px Arial";
ctx.textAlign = "center";
ctx.fillText(parseInt(curves) + 1, _px, _py + 5);
}
if (draw_closest_t) {
var t = curveClosestT(curve, mouseX, mouseY);
if (t >= 0) {
var x = x_at_t(curve, t);
var y = y_at_t(curve, t);
drawPointSolid(x, y);
}
}
if (!approximately_zero(scale - initScale)) {
ctx.font = "normal 20px Arial";
ctx.fillStyle = "rgba(0,0,0, 0.3)";
ctx.textAlign = "right";
ctx.fillText(scale.toFixed(decimal_places) + 'x',
screenWidth - 10, screenHeight - 5);
}
if (draw_t) {
drawPointAtT(curve);
}
}
if (draw_t) {
drawCurveTControl();
}
}
function drawCurveTControl() {
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(0,0,0, 0.3)";
ctx.beginPath();
ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
ctx.stroke();
var ty = 40 + curveT * (screenHeight - 80);
ctx.beginPath();
ctx.moveTo(screenWidth - 80, ty);
ctx.lineTo(screenWidth - 85, ty - 5);
ctx.lineTo(screenWidth - 85, ty + 5);
ctx.lineTo(screenWidth - 80, ty);
ctx.fillStyle = "rgba(0,0,0, 0.6)";
ctx.fill();
var num = curveT.toFixed(decimal_places);
ctx.font = "normal 10px Arial";
ctx.textAlign = "left";
ctx.fillText(num, screenWidth - 78, ty);
}
function ptInTControl() {
var e = window.event;
var tgt = e.target || e.srcElement;
var left = tgt.offsetLeft;
var top = tgt.offsetTop;
var x = (e.clientX - left);
var y = (e.clientY - top);
if (x < screenWidth - 80 || x > screenWidth - 50) {
return false;
}
if (y < 40 || y > screenHeight - 80) {
return false;
}
curveT = (y - 40) / (screenHeight - 120);
if (curveT < 0 || curveT > 1) {
throw "stop execution";
}
return true;
}
function drawTop() {
init(tests[testIndex]);
redraw();
}
function redraw() {
ctx.beginPath();
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = "white";
ctx.fill();
draw(tests[testIndex], testTitles[testIndex]);
}
function doKeyPress(evt) {
var char = String.fromCharCode(evt.charCode);
switch (char) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
decimal_places = char - '0';
redraw();
break;
case '-':
scale /= 2;
calcLeftTop();
redraw();
break;
case '=':
case '+':
scale *= 2;
calcLeftTop();
redraw();
break;
case 'c':
drawTop();
break;
case 'd':
var test = tests[testIndex];
var testClone = [];
for (var curves in test) {
var c = test[curves];
var cClone = [];
for (var index = 0; index < c.length; ++index) {
cClone.push(c[index]);
}
testClone.push(cClone);
}
tests.push(testClone);
testTitles.push(testTitles[testIndex] + " copy");
testIndex = tests.length - 1;
redraw();
break;
case 'e':
draw_endpoints ^= true;
redraw();
break;
case 'f':
draw_derivative ^= true;
redraw();
break;
case 'i':
draw_ray_intersect = (draw_ray_intersect + 1) % 3;
redraw();
break;
case 'l':
var test = tests[testIndex];
console.log("<div id=\"" + testTitles[testIndex] + "\" >");
for (var curves in test) {
var c = test[curves];
var s = "{{";
for (var i = 0; i < c.length; i += 2) {
s += "{";
s += c[i] + "," + c[i + 1];
s += "}";
if (i + 2 < c.length) {
s += ", ";
}
}
console.log(s + "}},");
}
console.log("</div>");
break;
case 'm':
draw_midpoint = (draw_midpoint + 1) % 3;
redraw();
break;
case 'N':
testIndex += 9;
case 'n':
testIndex = (testIndex + 1) % tests.length;
drawTop();
break;
case 'o':
draw_order ^= true;
redraw();
break;
case 'P':
testIndex -= 9;
case 'p':
if (--testIndex < 0)
testIndex = tests.length - 1;
drawTop();
break;
case 'q':
draw_quarterpoint = (draw_quarterpoint + 1) % 3;
redraw();
break;
case 'r':
for (var i = 0; i < testDivs.length; ++i) {
var title = testDivs[i].id.toString();
if (title == testTitles[testIndex]) {
var str = testDivs[i].firstChild.data;
parse(str, title);
var original = tests.pop();
testTitles.pop();
tests[testIndex] = original;
break;
}
}
redraw();
break;
case 's':
draw_sortpoint = (draw_sortpoint + 1) % 3;
redraw();
break;
case 't':
draw_t ^= true;
redraw();
break;
case 'u':
draw_closest_t ^= true;
redraw();
break;
case 'v':
draw_tangents = (draw_tangents + 1) % 4;
redraw();
break;
case 'x':
draw_point_xy ^= true;
redraw();
break;
case 'y':
draw_mouse_xy ^= true;
redraw();
break;
case '\\':
retina_scale ^= true;
drawTop();
break;
}
}
function doKeyDown(evt) {
var char = evt.keyCode;
var preventDefault = false;
switch (char) {
case 37: // left arrow
if (evt.shiftKey) {
testIndex -= 9;
}
if (--testIndex < 0)
testIndex = tests.length - 1;
drawTop();
preventDefault = true;
break;
case 39: // right arrow
if (evt.shiftKey) {
testIndex += 9;
}
if (++testIndex >= tests.length)
testIndex = 0;
drawTop();
preventDefault = true;
break;
}
if (preventDefault) {
evt.preventDefault();
return false;
}
return true;
}
function calcXY() {
var e = window.event;
var tgt = e.target || e.srcElement;
var left = tgt.offsetLeft;
var top = tgt.offsetTop;
mouseX = (e.clientX - left) / scale + srcLeft;
mouseY = (e.clientY - top) / scale + srcTop;
}
function calcLeftTop() {
srcLeft = mouseX - screenWidth / 2 / scale;
srcTop = mouseY - screenHeight / 2 / scale;
}
function handleMouseClick() {
if (!draw_t || !ptInTControl()) {
calcXY();
} else {
redraw();
}
}
function initDown() {
var test = tests[testIndex];
var bestDistance = 1000000;
activePt = -1;
for (var curves in test) {
var testCurve = test[curves];
if (testCurve.length != 4 && testCurve.length != 6 && testCurve.length != 8) {
continue;
}
for (var i = 0; i < testCurve.length; i += 2) {
var testX = testCurve[i];
var testY = testCurve[i + 1];
var dx = testX - mouseX;
var dy = testY - mouseY;
var dist = dx * dx + dy * dy;
if (dist > bestDistance) {
continue;
}
activeCurve = testCurve;
activePt = i;
bestDistance = dist;
}
}
if (activePt >= 0) {
lastX = mouseX;
lastY = mouseY;
}
}
function handleMouseOver() {
calcXY();
if (draw_mouse_xy) {
var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
ctx.beginPath();
ctx.rect(300, 100, num.length * 6, 10);
ctx.fillStyle = "white";
ctx.fill();
ctx.font = "normal 10px Arial";
ctx.fillStyle = "black";
ctx.textAlign = "left";
ctx.fillText(num, 300, 108);
}
if (!mouseDown) {
activePt = -1;
return;
}
if (activePt < 0) {
initDown();
return;
}
var deltaX = mouseX - lastX;
var deltaY = mouseY - lastY;
lastX = mouseX;
lastY = mouseY;
if (activePt == 0) {
var test = tests[testIndex];
for (var curves in test) {
var testCurve = test[curves];
testCurve[0] += deltaX;
testCurve[1] += deltaY;
}
} else {
activeCurve[activePt] += deltaX;
activeCurve[activePt + 1] += deltaY;
}
redraw();
}
function start() {
for (var i = 0; i < testDivs.length; ++i) {
var title = testDivs[i].id.toString();
var str = testDivs[i].firstChild.data;
parse(str, title);
}
drawTop();
window.addEventListener('keypress', doKeyPress, true);
window.addEventListener('keydown', doKeyDown, true);
window.onresize = function () {
drawTop();
}
}
</script>
</head>
<body onLoad="start();">
<canvas id="canvas" width="750" height="500"
onmousedown="mouseDown = true"
onmouseup="mouseDown = false"
onmousemove="handleMouseOver()"
onclick="handleMouseClick()"
></canvas >
</body>
</html>