Disabled external gits

This commit is contained in:
2022-04-07 18:46:57 +02:00
parent 88cb3426ad
commit 15e7120d6d
5316 changed files with 4563444 additions and 6 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
A167
A173
A178
A146
A159
A291
A49
A40
A254
A57
A15
A65
A268
A341
A283
B119
B203
B188
B129
B95
B66
B308
B298
B290
B282
B335
B143
B81
B73
B33

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,8 @@
A29
A10809
A1810
A6544
B29
B10809
B1810
B6544

View File

@@ -0,0 +1,862 @@
A0_-0.5368038286318639,-0.34860495068858793,-1.59429548045615
A0_-0.522113251104043,-0.3390644658232838,-1.6096877497152235
A0_-0.5207116894946694,-0.3381542512795262,-1.6111562565614523
A0_-0.5193101278852956,-0.33724403673576864,-1.6126247634076811
A0_-0.517908566275922,-0.336333822192011,-1.61409327025391
A0_-0.5045795190939573,-0.32470484315914855,-1.6014849600222352
A0_-0.49554149430416544,-0.31664694461193565,-1.5919100139260485
A0_-0.47824102981380945,-0.3013359096122926,-1.5738265973925805
A0_-0.46569612521481313,-0.2901869253820262,-1.560634054231189
A0_-0.4511890498312793,-0.27717493657258546,-1.5444948198363777
A0_-0.4428358596680487,-0.2696914393476939,-1.5344971124383002
A0_-0.4352805996754019,-0.26271485579143883,-1.5251654410575624
A0_-0.42730822403902663,-0.2554909520342417,-1.5152054252829952
A0_-0.4206160541495669,-0.24918206430575887,-1.506134908759575
A0_-0.4066458536239672,-0.2362694511619266,-1.4874466685467589
A0_-0.40151731315781675,-0.23134987880862126,-1.479954519168154
A0_-0.3912789345958006,-0.22170562757160464,-1.4650848550349247
A0_-0.38182129561178957,-0.21273391878102618,-1.451355983361323
A0_-0.3723837101180505,-0.203626482017175,-1.436914773448536
A0_-0.3602023257485043,-0.19183001318274231,-1.4175891991622251
A0_-0.35215642077684967,-0.1838382238331663,-1.4039528984525167
A0_-0.3459223188881521,-0.17765734986975132,-1.3929775839734904
A0_-0.33695610775529244,-0.16842238262350606,-1.3766850714189436
A0_-0.33093243978979714,-0.16236302470680286,-1.3655664205898264
A0_-0.3253335906602621,-0.156531266963027,-1.3550758174166533
A0_-0.3130241957265801,-0.14371804974247895,-1.3313994279247043
A0_-0.30152833718233485,-0.13137210619207762,-1.3074872283733707
A0_-0.2933290475156549,-0.12268356256265668,-1.2904332590861631
A0_-0.2881083590141729,-0.11694320554356624,-1.279287648067493
A0_-0.2817378275639507,-0.10986827347153229,-1.2652623559457274
A0_-0.27473102442697966,-0.10217188072431964,-1.2493072254873976
A0_-0.2705822095633542,-0.09729522376075506,-1.2394872355773092
A0_-0.26520622822580797,-0.09122817308894192,-1.226794637175988
A0_-0.2584285052639951,-0.08339952337778453,-1.2102845674911
A0_-0.2500853862073688,-0.07356406473148354,-1.1896704026815013
A0_-0.24100399449766638,-0.062420402945443744,-1.1654630120357334
A0_-0.2356960835181193,-0.05590303408113756,-1.1510089400264791
A0_-0.23242704292481342,-0.051837954422693844,-1.1422802165046864
A0_-0.2263094466790289,-0.044443603417188296,-1.126207335693367
A0_-0.22080452799872738,-0.03743932213300931,-1.1105725508578173
A0_-0.21424378985273312,-0.02889389424624926,-1.091329294721469
A0_-0.2055730826480087,-0.01716248897052216,-1.0649897704333207
A0_-0.1968882865657118,-0.0052085191896091634,-1.0381508197873646
A0_-0.19252096533782953,0.0008815528130583345,-1.0256848515714736
A0_-0.1884088746700077,0.0056986579658845436,-1.0142904917561923
A0_-0.18077747585237025,0.015499988892196658,-0.9925083601484932
A0_-0.17719326434570298,0.02029356957783885,-0.9830059299449873
A0_-0.1693092895427159,0.029407937593112075,-0.9627287054218973
A0_-0.15910810989570742,0.04043532416806453,-0.9392378970054879
A0_-0.15444473316612664,0.045162228100296284,-0.9276722507323147
A0_-0.1478344472338818,0.05273118691021983,-0.9119750025036094
A0_-0.13844117209467316,0.06226884345627484,-0.8905853739461533
A0_-0.13035436733496245,0.06962220704141302,-0.8739357998388922
A0_-0.12367901072338013,0.07514083511087398,-0.8614121203476189
A0_-0.11569057100483654,0.08167785200877889,-0.8463877634235567
A0_-0.11107435060348735,0.08499579043908553,-0.8370986910559878
A0_-0.10593512551617353,0.08901958095238235,-0.8284570386728881
A0_-0.09750568038761956,0.09523781865143863,-0.8131750215958403
A0_-0.0882233351026566,0.1022770589655697,-0.7963940613510552
A1_0.41631365432721573,0.27035733559711267,-1.697938952551663
A1_0.40600211414683185,0.26199362682243826,-1.67494241568414
A1_0.40155476672619617,0.2583463882153001,-1.6649845488472705
A1_0.39336093620839185,0.25166740488822126,-1.6466712102916705
A1_0.3854626131566793,0.24514011750768785,-1.628930761964429
A1_0.3761291696031735,0.23740708359963125,-1.607948587114619
A1_0.36906296775654596,0.23153227239579866,-1.592037514375418
A1_0.3619903209641249,0.22561464478016413,-1.5760775387226789
A1_0.3541254832529614,0.2189946811392308,-1.5582914230770852
A1_0.3425845930308888,0.2092435055984018,-1.532147745972871
A1_0.332344296324326,0.20050765302546897,-1.5088694075164188
A1_0.31896196343556393,0.1890067790876159,-1.478367354997602
A1_0.30992415568926546,0.18120673127998646,-1.4577309028521062
A1_0.3052891058959341,0.1771155539383807,-1.4470690859133915
A1_0.2947573099327361,0.16794686534137426,-1.422951313319071
A1_0.28153372085632095,0.15633823472497502,-1.3925751383121543
A1_0.2753409809743805,0.15085222162934614,-1.378307890975088
A1_0.270628251359254,0.14662806692768052,-1.3674097860203396
A1_0.26597438575930715,0.14241771716655863,-1.3566167183168922
A1_0.2606709135236761,0.13773516958090765,-1.344406140041305
A1_0.25600462304809574,0.13359905361769991,-1.3336501079296792
A1_0.24853083507280124,0.1267900759724333,-1.3162798846995618
A1_0.24322068295827537,0.12208520077409175,-1.304036976609588
A1_0.2341862660505251,0.11391817345648472,-1.2830884307547812
A1_0.225792337454666,0.10627002032262,-1.26358211061287
A1_0.21779062477973107,0.09902400897428566,-1.245018787766674
A1_0.21123762712191302,0.09321995832536581,-1.2302289767423684
A1_0.2075692543855539,0.08970116248830814,-1.2212317778850192
A1_0.20033082447488612,0.08301084869128773,-1.203457264846015
A1_0.1952977288738703,0.07836516862325496,-1.1910353101551578
A1_0.19171426770790256,0.07488419766809776,-1.182061147620017
A1_0.1844041943486437,0.06798520363353472,-1.1637501771740175
A1_0.1783002976082751,0.06241591189126476,-1.1491941576223967
A1_0.16758989012842332,0.05228422801242776,-1.1226090149693855
A1_0.16324310617248933,0.04779645357323392,-1.1106455050057653
A1_0.15554615460078886,0.040150032734686196,-1.0896155878597336
A1_0.15022537950419584,0.035009694368458424,-1.075038451264981
A1_0.14500905883504994,0.02963819041918031,-1.0604949350501198
A1_0.1340542012196821,0.018443514276467052,-1.0299238214007458
A1_0.12802976121536896,0.011431046242354826,-1.0100497248151437
A1_0.12232339924367192,0.004590779195436599,-0.9920803308752792
A1_0.11481830137812296,-0.003401631018706362,-0.9690308459129096
A1_0.10603997017960633,-0.01260282800961984,-0.9445518163198975
A1_0.09868207497282296,-0.01982107933376497,-0.924025431702618
A1_0.09076622476076017,-0.027511965943943326,-0.9021338731496086
A1_0.08649053379727403,-0.0322766752890777,-0.889009301577932
A1_0.08108783892846969,-0.037793823755939156,-0.8729810654748724
A1_0.07588091431506537,-0.04371568790580365,-0.8566819713115227
A1_0.07293598926666679,-0.046777986047717476,-0.8471905073497429
A1_0.06805181100674132,-0.05238352261013918,-0.833649865900727
A1_0.06515731253973855,-0.05541150293387902,-0.8239915600744279
A1_0.060829892974351374,-0.05957538145674636,-0.8119899247177005
A1_0.055573749104702766,-0.06456464580871968,-0.7973753660283084
A2_-1.0111293113631337,0.6966991403257031,-0.4592468852716723
A2_-1.0021405807180213,0.6802632578477851,-0.4567184044356555
A2_-0.9926695735262759,0.6627378911222723,-0.45417718109487326
A2_-0.9817540974848189,0.6421914289804014,-0.451414327748659
A2_-0.9756746299727143,0.6304225373420307,-0.45000608968310696
A2_-0.9705752600015486,0.6205426363095251,-0.44886821100119473
A2_-0.9629998453820052,0.6055539767116256,-0.44726982901556467
A2_-0.9528507851606789,0.5853800788555058,-0.4452418683626538
A2_-0.948594687438409,0.5763523166168751,-0.4445579554572815
A2_-0.9415456796274554,0.5619945928576345,-0.44329524646356044
A2_-0.936662165149892,0.5513607593657062,-0.4426078780611528
A2_-0.9287490336848985,0.5348693730756657,-0.4413607442199027
A2_-0.9214129215936155,0.518530788687175,-0.4404742637060432
A2_-0.9169516447770164,0.5091241493889549,-0.43982863332528527
A2_-0.9060019630397673,0.4845534996388073,-0.438611092533713
A2_-0.8969772092951764,0.4636790569257859,-0.4377527618228695
A2_-0.8916198651868826,0.4508870363330275,-0.43733039351289893
A2_-0.8872878222869442,0.44105655467942884,-0.43690427402370924
A2_-0.8795216151499461,0.4224041123495423,-0.436321759204997
A2_-0.8726626369197301,0.40590992229907885,-0.4358182623717017
A2_-0.8689196760194717,0.39651650357671625,-0.43560166019469626
A2_-0.8621802825438054,0.3805067450388013,-0.4351003371138223
A2_-0.8576403097736114,0.3690259637762504,-0.43484765529330466
A2_-0.847260451393578,0.3431008123983614,-0.4342338437852116
A2_-0.8383420302965295,0.3213804236795066,-0.4336634406393221
A2_-0.8339299260144559,0.3098169444452097,-0.4334430818848536
A2_-0.8297590890580562,0.29988585614190133,-0.4331705216007159
A2_-0.8255595576279345,0.2887371161768435,-0.43296131890100875
A2_-0.8205284075963992,0.2766848683594151,-0.4326465665346285
A2_-0.8162658508145275,0.26528636077812456,-0.432425733495708
A2_-0.8099070369090016,0.2500116228792328,-0.43204443835844336
A2_-0.8010032191828147,0.22748450441739057,-0.4315466707754363
A2_-0.7925063574235955,0.20597886550651082,-0.4310604138419702
A2_-0.783365286089981,0.182834321261614,-0.430533183457631
A2_-0.7717525537074016,0.15378300489002314,-0.4298744141361231
A2_-0.7605151738501638,0.1256654130397724,-0.42857880977001833
A2_-0.7547051323074344,0.11048265391410808,-0.42757087298867086
A2_-0.7495711146321856,0.09859205671349223,-0.42666948218056805
A2_-0.7429752432062302,0.08158614062613564,-0.4250570026152049
A2_-0.7383812636716602,0.07107265136584508,-0.4239510679220416
A2_-0.7314436886994186,0.05407724621284413,-0.4219240221468435
A2_-0.7238659528267655,0.03606406562372443,-0.41958689687430367
A2_-0.7163240601899087,0.01853191831396845,-0.41638705031892764
A2_-0.7088863421683236,0.0015028625348311349,-0.4128680272270661
A2_-0.7013838154044434,-0.014870130914192403,-0.40872252863118114
A2_-0.6961820844804315,-0.025404121218242516,-0.40593306918053157
A2_-0.6861588787830956,-0.045656410219529965,-0.39955297951305596
A2_-0.6772202808116581,-0.062456917459215555,-0.39298309042282104
A2_-0.6686641428262144,-0.0780366413763315,-0.38640010237764655
A2_-0.6621682730123559,-0.08914904489863354,-0.38121181871589577
A2_-0.6524750791244555,-0.10457567587446848,-0.3730339255648052
A2_-0.6436231653686832,-0.11783626813571864,-0.365233986650182
A2_-0.6350626314830305,-0.1299183209849334,-0.35739136418571676
A2_-0.6259365264100776,-0.14154896731611807,-0.3488560478951627
A2_-0.6207328581713053,-0.14840097919503803,-0.34367701120048727
A2_-0.6174976644395258,-0.15297668024776037,-0.340858884727592
A3_-0.349754047551988,0.38691514147578665,0.007361142470593354
A3_-0.34848728255409805,0.36677208937013134,0.019745078727648406
A3_-0.34841371986387204,0.35737238479732547,0.025768441615279306
A3_-0.3481528738653995,0.34657223013326044,0.032430853479591855
A3_-0.3479536763322027,0.3373314950454782,0.03810523323849542
A3_-0.34821136339205805,0.32646875556161303,0.045080216074475536
A3_-0.3487917630037583,0.3096479492758613,0.05603406404956641
A3_-0.34943830825887967,0.2966331791633044,0.06448372017848229
A3_-0.35079536786771903,0.27797085517591996,0.07701234336639858
A3_-0.3519644771031814,0.2658919205913629,0.0853170479519706
A3_-0.3541127500738923,0.24553166719564906,0.0994881736645613
A3_-0.3552124811069373,0.23399967487440085,0.10725717593469747
A3_-0.3567555397619428,0.22418973347149612,0.11467070327896665
A3_-0.35806086626083244,0.21211748666316557,0.1229304107864862
A3_-0.3608337042915286,0.19256732833491275,0.1372441122782605
A3_-0.36215683459629716,0.18263901026881013,0.1443708906104574
A3_-0.3634337298674506,0.174681746483613,0.15046824375464055
A3_-0.3658540153364855,0.15783652143710192,0.16284292668607775
A3_-0.368330280585251,0.141260486424584,0.175202702318017
A3_-0.370977217705785,0.12331845654688357,0.18850293366169577
A3_-0.37232539571569256,0.11518017061521223,0.1946498659321278
A3_-0.37607370880413354,0.09326796800223318,0.21059718215338585
A3_-0.3782614314399737,0.08178506108961205,0.21881957729317353
A3_-0.3804266468396751,0.07037839345648442,0.22725023778785014
A3_-0.38207825199902995,0.06125203787059785,0.23390067138761902
A3_-0.3847439868658396,0.04642228697136376,0.24452754211854763
A3_-0.38680687217484233,0.035096800943336275,0.2528394725570686
A3_-0.39144931822360785,0.010119732712941941,0.27094804504863523
A3_-0.39466766901786937,-0.006484559569153548,0.28328331310243626
A3_-0.39915544505362627,-0.029805335211148636,0.2999917521684463
A3_-0.402369322500189,-0.04718483359749693,0.3127070878733237
A3_-0.40600747267476145,-0.06753899922015524,0.32751425455266125
A3_-0.40938918224142523,-0.0903534418940968,0.34416322160012724
A3_-0.4128579001514087,-0.11285886961079558,0.36055609009110234
A3_-0.41572721059948115,-0.13240759887916356,0.37472655859024284
A3_-0.41761058355654895,-0.15190254586614466,0.3887537594756058
A3_-0.4184365432351577,-0.16210707832910948,0.3961422068502405
A3_-0.4196784536788956,-0.1800845104802427,0.4090224344955222
A3_-0.421580326325936,-0.20524280743018686,0.42699355686244406
A3_-0.4221332067567168,-0.2154336686685304,0.4341476488062792
A3_-0.42253291966952783,-0.2259597053773189,0.441607620490103
A3_-0.42299210981044444,-0.24858047761809765,0.45744204653675696
A3_-0.4230039323934037,-0.2638455382106352,0.46822174832870456
A3_-0.42291566101895284,-0.27265297579398523,0.47417840769587916
A3_-0.4226075696691828,-0.2869414455046992,0.48392848198279675
A3_-0.42224740161257257,-0.2974360984858462,0.4911482073547757
A3_-0.42111778475804335,-0.32232032439408265,0.5080251366405546
A3_-0.4196044577763573,-0.3423170380434222,0.5213313348131897
A3_-0.4171230660664786,-0.36609960436619304,0.536932443845237
A3_-0.4142285950835504,-0.3880775463080735,0.5510352294137549
A3_-0.4127834823208305,-0.397541879211687,0.5571386746436605
A3_-0.41070637235968577,-0.40968930008657733,0.5646293322683315
A3_-0.4075851992432434,-0.42695748424182633,0.5752712976190311
A3_-0.40212052332161047,-0.45530838862015716,0.5927010907974246
A3_-0.3980599172006215,-0.473557999293188,0.6036112049995324
A3_-0.3922687817269167,-0.4964820304196037,0.6169121607862146
A3_-0.38950461560535027,-0.506695769400271,0.6226457893579523
A3_-0.3859274921171974,-0.5190210558298676,0.6295884762531692
A3_-0.3824963442988262,-0.53023205985157,0.635821058698815
A3_-0.3780084154531611,-0.5443091808973833,0.6433430537223428
A3_-0.3733740139480262,-0.5580310473224895,0.6507002816921749
A3_-0.3703082687819037,-0.5670436341837909,0.6553871161334525
A3_-0.36520156001438503,-0.5812262136153685,0.6627909246723315
A3_-0.361713753816706,-0.5905820741301584,0.6674567443420084
A3_-0.35468661291095016,-0.6086414082797345,0.6765313940029611
A3_-0.3475867110161785,-0.6255839852991673,0.6845694665935241
A3_-0.3424277777018025,-0.6379158490059512,0.6905200803177417
A3_-0.3374530072625456,-0.6498465370395203,0.6964220369775946
A3_-0.3303649001361244,-0.665016372278552,0.7030987246796108
B0_-0.7858101863837181,-0.510170359208038,-1.1413072007030751
B0_-0.7829507161599136,-0.5081519592659008,-1.1502666481310904
B0_-0.7703470316226032,-0.497134646572484,-1.176105913130397
B0_-0.7628166362025368,-0.4907595362973936,-1.1912309512535233
B0_-0.7513969611635304,-0.48149439995620513,-1.2135311879188702
B0_-0.7369623556606596,-0.47056246793262946,-1.2407515371002447
B0_-0.7264218640119788,-0.4629044212177864,-1.2601823431878798
B0_-0.7196009649250451,-0.45817322950962935,-1.2724877167947455
B0_-0.7094497455668184,-0.4509995419114022,-1.2909272633075437
B0_-0.703395101041477,-0.44691569594273,-1.3016855363387039
B0_-0.697140030078241,-0.4426025822817504,-1.3129061314400303
B0_-0.6886331786525544,-0.4371144048239524,-1.3277182950905353
B0_-0.6827573276022342,-0.43322398951738933,-1.3380578605427857
B0_-0.6727948364331616,-0.4269388147109419,-1.3552310307870465
B0_-0.6665405204787732,-0.42306631386262483,-1.365927385400654
B0_-0.6564781924100231,-0.4167773740629304,-1.383190697801415
B0_-0.6408285590255203,-0.4072451844498222,-1.4097637284772209
B0_-0.6217813237187473,-0.3958757770133878,-1.44183275535302
B0_-0.6080812705163023,-0.3878987597563527,-1.4646826563129844
B0_-0.5948175969744374,-0.38024690506784187,-1.486729221188225
B0_-0.5844086762381862,-0.37422164688661363,-1.5040500348202221
B0_-0.5702250247419477,-0.36608809248125174,-1.5275737989459106
B0_-0.5556134099629494,-0.35774766506006306,-1.5517683031021368
B0_-0.5448014045505561,-0.351698988324416,-1.5695497120288198
B0_-0.5305062863111728,-0.3435921121993253,-1.5931680618394766
B0_-0.517908566275922,-0.336333822192011,-1.61409327025391
B0_-0.498512300929292,-0.3237377230273699,-1.6331156790813197
B1_-0.4188712014633513,-0.2720181436075475,-1.6968075281899906
B1_-0.4140463035277519,-0.2683920641588703,-1.695420352946519
B1_-0.39809635838876123,-0.25598059489888425,-1.6837404231108286
B1_-0.38561992210166934,-0.24626570959169658,-1.6746042199761475
B1_-0.375560807812143,-0.2384367638044574,-1.6672610342878615
B1_-0.3630418499794761,-0.2287857611316861,-1.6581517194854505
B1_-0.35588001168707223,-0.22329005054384726,-1.6529620599317627
B1_-0.343697411619633,-0.2139989056844632,-1.6441485048279774
B1_-0.331248671414003,-0.20452990321474965,-1.6351749964252988
B1_-0.3158203829437968,-0.19294279251453503,-1.6240886246009416
B1_-0.30471829538193856,-0.18471037902170875,-1.6161488864890012
B1_-0.2967094500569452,-0.17874066374686368,-1.6104378945956612
B1_-0.27661023877055035,-0.16406834875077744,-1.596201914912362
B1_-0.26369344874135886,-0.15472134678513125,-1.5870873646188373
B1_-0.24791228699473494,-0.14352851514335624,-1.5759938552663473
B1_-0.2344603106291702,-0.1340217033800835,-1.5665684975744647
B1_-0.21667495799091577,-0.12176772642065624,-1.554179230701407
B1_-0.19953306371334445,-0.11006880510777474,-1.5422907280410663
B1_-0.18625860847839532,-0.10125273801110204,-1.5331391069661275
B1_-0.16370565698105327,-0.08651728539197537,-1.5176983907123032
B1_-0.14882245549706097,-0.07697464491134816,-1.507541899068363
B1_-0.1385581256397875,-0.07055372167662775,-1.5005631425839545
B1_-0.12606155189353913,-0.06276878935642523,-1.4920788289494005
B1_-0.10830004988898273,-0.05201001709948657,-1.480074662069056
B1_-0.09010456159152597,-0.04127857215017066,-1.4678288097005991
B1_-0.07428065546346921,-0.03210318326741385,-1.457229142268645
B1_-0.052593979954492984,-0.01999551556371678,-1.4427917951244378
B1_-0.03155726559792736,-0.008544872831105277,-1.4288402733978534
B1_-0.012780660002456534,0.001331457805289862,-1.4164616928168796
B1_-0.002759313622707803,0.006391600696666053,-1.4098970126504575
B1_0.013157720723961309,0.014492960453954151,-1.3994267295152312
B1_0.023686842855221133,0.019705905406954972,-1.3925418811279195
B1_0.03649461906257061,0.02587827142502638,-1.3841973953974698
B1_0.05108211659205275,0.03278202248831404,-1.3747281574411774
B1_0.06050899708272383,0.03711022953264479,-1.3686401134185961
B1_0.08512895768470169,0.048271115155175674,-1.3527646891710752
B1_0.10822782069376037,0.05841137792217968,-1.3379491277525293
B1_0.13620588386559038,0.0702190074376282,-1.3201301340043872
B1_0.1563661236224279,0.07858936976224509,-1.3073168258882781
B1_0.17211890651907205,0.08494905172548674,-1.2973669586700725
B1_0.19268576876313168,0.09315327534686259,-1.2844098712724525
B1_0.20836531596434876,0.09944249528512544,-1.2745157420775668
B1_0.225792337454666,0.10627002032262,-1.26358211061287
B1_0.24995528921890733,0.11582037933201329,-1.2483892486761694
B1_0.2699918251937579,0.12355436968274633,-1.2344682761679826
B1_0.2884565598625223,0.13044083470305784,-1.2205989223021714
B1_0.3017242416246158,0.13511504943272826,-1.2098348750677335
B1_0.31578735856448503,0.1400656429229383,-1.1975950727986726
B1_0.3248808722934327,0.14297796382452604,-1.1891491249870023
B1_0.34152843107900255,0.14836745670066753,-1.172804007503201
B1_0.3502715707992247,0.15091158283833178,-1.163868573727824
B1_0.35918573457221764,0.15358488995380679,-1.1541711660584224
B1_0.375835021179811,0.1581925471657002,-1.135439674835299
B1_0.39119680353701103,0.16197898361795787,-1.1164671832140742
B1_0.39857801342680893,0.1635166904411148,-1.1070842275498154
B1_0.4092320141478845,0.16587152988822837,-1.0927227288800465
B1_0.4263413132116659,0.16921076697205364,-1.0692500413297945
B1_0.43497124880796006,0.17019869618900574,-1.0560043902611418
B1_0.44117484563239523,0.17105177474439015,-1.046088704380635
B1_0.4500881328354407,0.17193020366003015,-1.0317922392712469
B1_0.4582309490715106,0.17251941167775525,-1.0177907083191204
B1_0.4679974015835489,0.17260046525020686,-1.000316104639582
B1_0.4747170277750094,0.17253619706367446,-0.98739365571986
B1_0.4820719914425378,0.17209896290458343,-0.9730051992671772
B1_0.49113493691094257,0.17132862908177676,-0.9544889632288771
B1_0.49843248317372624,0.17032778524456382,-0.9388657706946069
B1_0.5076571350704393,0.1686223735117728,-0.9185277992845013
B1_0.5163701338764507,0.16633503875714606,-0.8978417696412005
B1_0.5205890207007421,0.16491141645308116,-0.886908405644296
B1_0.5245179990037684,0.163347123452461,-0.8768112911383816
B1_0.5296163939518127,0.1610681037373056,-0.8629109187858351
B1_0.5361011034755773,0.15752246749395316,-0.8444344518878979
B1_0.5422995534830257,0.15378496137847425,-0.8261886581687848
B1_0.5455908013652248,0.15136936612573895,-0.8153604152467325
B1_0.550174511209103,0.15099011131307255,-0.8055558293259868
B1_0.5532488850983334,0.14816270332615195,-0.7951566159830286
B1_0.5602064254786072,0.14166319625066087,-0.7707181090432701
B1_0.5654968883430697,0.13540918607576372,-0.7502676909045118
B1_0.5686284271338592,0.13141647271513474,-0.7380728240943164
B1_0.5759933364641063,0.12101167582743025,-0.7076842556467114
B1_0.5788813047230472,0.1156017294755962,-0.6936925490849977
B1_0.5811106506178827,0.11132850939945646,-0.68313515252474
B1_0.5837446577347287,0.10632407778790585,-0.6709484287223433
B1_0.5859794863817156,0.10159280250390768,-0.6597400275099767
B1_0.5900196818514133,0.09226737475225306,-0.6389340594973316
B1_0.5921980925755279,0.0858852269641257,-0.6254002902968259
B1_0.5949975566694469,0.07819234754452518,-0.610247988495256
B1_0.597621229872722,0.07006169154423605,-0.594429468778678
B1_0.5998714409269108,0.06265822669486304,-0.5799943321646548
B1_0.6025624068721223,0.05381134365775862,-0.5636532694429686
B1_0.6046470669094943,0.045830680459610085,-0.5497771721858526
B1_0.6066889656818553,0.03802144660428363,-0.5359586055954909
B1_0.6086244229745377,0.02976994535905978,-0.52234640355956
B1_0.611493511154737,0.017343013028164923,-0.5020602056675726
B1_0.6140229400383561,0.006829076838469821,-0.48485854963851444
B1_0.6161438805906617,-0.0027139791382199806,-0.4698862604237391
B1_0.6186741352257075,-0.014558698862774071,-0.45121492922087836
B1_0.6202138891266694,-0.020176791436948525,-0.44225470882435813
B1_0.6211927430640103,-0.025625474998234442,-0.4336656076163398
B1_0.6227985499408287,-0.03160287104441033,-0.42419260876620957
B1_0.6254494571226009,-0.04333328538262781,-0.40546981320251224
B1_0.6284290659410375,-0.05675909628634279,-0.38296399663828207
B1_0.6306599852054368,-0.06607365394262606,-0.3667007174342389
B1_0.6327137772267215,-0.07456723674302748,-0.3514757860309482
B1_0.6350634955211488,-0.08495725744763939,-0.33218860496261987
B1_0.6375988607376828,-0.09616683687535496,-0.3093258383977622
B1_0.6396158369042121,-0.10490611728185162,-0.28897796387639096
B1_0.6406052877623741,-0.10970010936907015,-0.2769873821453875
B1_0.6413405097747062,-0.11686149402753686,-0.25798836871541686
B1_0.641910125594339,-0.12452434002640975,-0.23416961731407204
B1_0.6414314928855491,-0.13022885657405922,-0.21242991997940044
B1_0.6402589827459813,-0.13444573835346613,-0.19540070663390058
B1_0.6367499949242986,-0.13884202899454562,-0.16924733683818133
B1_0.6333156684329464,-0.14197809752748175,-0.1490025002921201
B1_0.6305518995548568,-0.14316778181843362,-0.1365146162512502
B1_0.6261869241980511,-0.14506286753358566,-0.12054946088635271
B1_0.6211172535478964,-0.14654591484626975,-0.1039669698810615
B1_0.6130800233988929,-0.14754984308723976,-0.08372979219589753
B1_0.6055971420185204,-0.14831777412944158,-0.06723535791512289
B1_0.6049920589350902,-0.14830178027367033,-0.06602087336681801
B1_0.5953192874481477,-0.1491177758225432,-0.0468016031642262
B1_0.5816091897106505,-0.14979430241446015,-0.02533373764350428
B1_0.5648894019977797,-0.15016863329039654,-0.0031833150248830946
B1_0.550043141383199,-0.1507254553289145,0.01441587156131465
B1_0.5300053266666301,-0.15220664081600607,0.035236490637277386
B1_0.5017429423657986,-0.15431624157852028,0.0607549123411564
B1_0.47901580279633077,-0.156538778845621,0.07873548168578332
B1_0.4624334762172898,-0.15854818565271378,0.09048373222864246
B1_0.4359957541027636,-0.1625994686506063,0.10791467080801104
B1_0.4184141792921716,-0.1659372637529172,0.11880851710700716
B1_0.39123658427755165,-0.17140277782584204,0.13447650411963694
B1_0.3809541347191502,-0.17398262286297644,0.1401540077003912
B1_0.3596197126203056,-0.17924994510694464,0.15131866530763066
B1_0.3483214034137781,-0.1820106527438519,0.15673687547999526
B1_0.33448835446598707,-0.1858142516102385,0.16383180624130436
B1_0.31684075336870243,-0.1907370538113013,0.1726127469413992
B1_0.3036731949018353,-0.1946867869127695,0.17914060352527267
B1_0.28178252630895434,-0.2013432969808975,0.18965967470397282
B1_0.26882245789955317,-0.20528638804132449,0.1956604148055738
B1_0.2540347040089296,-0.20998830325783233,0.20288675933720152
B1_0.23249171513765443,-0.2169052346162121,0.2130619507946972
B1_0.21875554174313772,-0.2214134703299378,0.21949634596949386
B1_0.2007935461188475,-0.22701910582466603,0.2280280184696611
B1_0.19121766269528753,-0.2300868681186833,0.23253508711432697
B1_0.1732116838731628,-0.2357682619379133,0.24118589210032543
B1_0.15378876683460838,-0.24205160688234384,0.25041402550397845
B1_0.13376816053959406,-0.24834039742726322,0.25987030801894667
B1_0.11845504230460467,-0.252808503182846,0.26715455917638664
B1_0.10833099511626455,-0.25576084908774954,0.27218386821294926
B1_0.08021125958742424,-0.2636899413699668,0.2855955486624066
B1_0.05678658709001569,-0.27013712492931624,0.29684699450953045
B1_0.03646183362457614,-0.27560207429517614,0.30646916898325655
B1_0.013211274775021617,-0.2816874095729691,0.31761400352096303
B1_-0.007206093220198445,-0.2865554006786222,0.32735699450796063
B1_-0.019849896561845565,-0.2893473618457688,0.3335477882867438
B1_-0.04093624790128063,-0.29393850982450853,0.3433204853815265
B1_-0.06401871361445902,-0.2985341604781928,0.35413845805317623
B1_-0.07623613014482855,-0.3006068822188785,0.36005917869864623
B1_-0.09079434345781558,-0.3030771347022155,0.3666534220864446
B1_-0.10271585112520215,-0.30491612488045844,0.3722955901187989
B1_-0.1270066444880836,-0.30877087408828624,0.3835104012770508
B1_-0.15159205625985453,-0.31197470512891523,0.3944612154341398
B1_-0.17324462952871722,-0.3142876122406472,0.4041004929057984
B1_-0.18974455286149985,-0.315814985894229,0.4114302831756799
B1_-0.21173691435445202,-0.31748317025275613,0.4208939570508836
B1_-0.23042884444957443,-0.3185930811296551,0.4289105334302419
B1_-0.25466489763660316,-0.31981570552488947,0.4390630165445558
B1_-0.2710123032692869,-0.3199173046195775,0.4456528780809848
B1_-0.29027089035585624,-0.31992967994333554,0.45327978475889935
B1_-0.30081641940011145,-0.319780386636369,0.45731001647400515
B1_-0.3167449438994009,-0.3194214707887809,0.463597081385374
B1_-0.32705815519902304,-0.31906618005416465,0.46739055146059644
B1_-0.3484795953410789,-0.3178333186207197,0.4752112683509917
B1_-0.3699339098590322,-0.316080141328433,0.48282836471515367
B1_-0.3806950082548558,-0.3151395210355487,0.4864778627662633
B1_-0.40044844854258327,-0.3132262728748988,0.49328587868915846
B1_-0.41576942997344796,-0.31159918879603166,0.49840580169717524
B1_-0.4325617018005271,-0.30938931871981445,0.5037889366931151
B1_-0.446205967588951,-0.30732085005931864,0.5078491787369785
B1_-0.4585084503975965,-0.30524575041885266,0.5114971194395219
B1_-0.47922897454884705,-0.30139863958183516,0.5172793780830356
B1_-0.5041609596312067,-0.296362835421097,0.5240028519732637
B1_-0.520052578044148,-0.29296002807882054,0.5280129541657366
B1_-0.533593537765867,-0.2897655759513928,0.5312908533214796
B1_-0.5600731001538916,-0.2831458410835563,0.5374495447014729
B1_-0.5902927234361585,-0.2748494617937108,0.5437960879544746
B1_-0.5997946263394185,-0.2720416568768335,0.5455121459321669
B1_-0.6182841380789197,-0.26619896896379536,0.5488653447712266
B1_-0.641039049058087,-0.25874055690497144,0.5525699613038564
B1_-0.6632476020495324,-0.2507027824699068,0.5555360482225656
B1_-0.6771120189162617,-0.2453296606483199,0.5571321969765315
B1_-0.6876479000542058,-0.24117591836277238,0.5581399302694479
B1_-0.7073887078282929,-0.23311949166486112,0.5599918414709513
B1_-0.7343749399893138,-0.22197238105595835,0.5622798763149527
B1_-0.7566206989045732,-0.21188216386043002,0.563338960645633
B1_-0.77749688227646,-0.20205625259459317,0.5639468718873589
B1_-0.7874255600746881,-0.1971579944950027,0.5640711020031576
B1_-0.8040762989379838,-0.18881975999448755,0.5640269138346187
B1_-0.8137886037982348,-0.18368634480443932,0.5637100457609329
B1_-0.8233927806645557,-0.17846688634135247,0.5633183981878429
B1_-0.8415318314019157,-0.16818625386877717,0.5620648912215003
B1_-0.8668055291458775,-0.15334559893069283,0.5597772978966434
B1_-0.8764705682182513,-0.14742995735456,0.5585886401182881
B1_-0.8894816729020889,-0.13923878612670487,0.5568262163298637
B1_-0.9028910935583471,-0.13052971303329597,0.5546061453156096
B1_-0.9153194170978737,-0.12213554158406219,0.5523613846728519
B1_-0.9307003405164469,-0.11172619400012626,0.5493203317383667
B1_-0.9422179274511285,-0.10364675635899553,0.546896005359058
B1_-0.9554366552323642,-0.09429159266945271,0.5438578996265658
B1_-0.9816423467748959,-0.07501170905282466,0.5371393126109507
B1_-1.0031297696324728,-0.0579775302249433,0.5301923195563297
B1_-1.0209142503986972,-0.0431324376128126,0.5235531872269329
B1_-1.0289539500771314,-0.03610689415957091,0.5202356196254585
B1_-1.0372030039132802,-0.02878842180286221,0.5165852636015144
B1_-1.053449803940122,-0.013890441852238786,0.5089387362422719
B1_-1.071632051172221,0.0036320426109101678,0.4993196673086347
B1_-1.0800107880647896,0.012082319225866991,0.4944031275465449
B1_-1.0938439316588469,0.026434423542151746,0.4858329271592638
B1_-1.1048830707023234,0.03813760696957518,0.4786688131489627
B1_-1.1236113240097343,0.059441813219689346,0.4647314515893119
B1_-1.1396806921957263,0.07888422996037837,0.45129088973282916
B1_-1.1448826501670164,0.0857759270631798,0.44621686830687396
B1_-1.151644648017085,0.09483040262871106,0.43941505830750344
B1_-1.1622794604204594,0.10984070660993842,0.4278062892648457
B1_-1.1743132970881596,0.1277642223493794,0.41338974803993345
B1_-1.1800102525792904,0.13670022549368332,0.4060108270852148
B1_-1.189352464085823,0.15174049418402538,0.39337362761142153
B1_-1.197610415337513,0.1660729263028989,0.38085864927321045
B1_-1.2061835710589865,0.18200682223500245,0.3664519928796963
B1_-1.2141456653027458,0.1989865988943653,0.3502438835313439
B1_-1.2228348379242981,0.21946949869827917,0.329924786649031
B1_-1.2295960176984564,0.2379907698190093,0.31068296735482653
B1_-1.234806662401683,0.25417203558167645,0.2932534135164594
B1_-1.23699174442211,0.2620701429880713,0.28450972668568764
B1_-1.24064131732571,0.2764057347411223,0.26825734281990266
B1_-1.2431725412176866,0.2890142712629503,0.25346646079320484
B1_-1.245316099099912,0.30312841536915835,0.23628716607806274
B1_-1.2467705610780977,0.3158309939267606,0.22038492242429084
B1_-1.247940510547441,0.330772050982666,0.20124782568520214
B1_-1.2480744242995858,0.3466866590537411,0.17985817620527705
B1_-1.2474198730934234,0.35993099521792027,0.1614225666005928
B1_-1.246725285699602,0.3660468673447245,0.15245295492289118
B2_-1.1452280410160283,-0.14644438476119914,0.725113877076668
B2_-1.1296323257470644,-0.15605176545521474,0.7254933883907381
B2_-1.1124843422894028,-0.16661559205041176,0.7259105391766499
B2_-1.09340231096064,-0.17833131112906103,0.726400147256776
B2_-1.084153027287061,-0.18400490691746307,0.7266407710519902
B2_-1.0733239635342928,-0.19066798298487336,0.7269092623466396
B2_-1.058177007607437,-0.19995798794400224,0.7273041445428653
B2_-1.0377288693571416,-0.2125106401179085,0.7278298845847562
B2_-1.0150229952685534,-0.22644049333541438,0.7284194046213762
B2_-1.008916378458068,-0.2174712943747915,0.7147525437864448
B2_-1.0053624508690493,-0.2122497355935576,0.7067671590025328
B2_-1.000073061942241,-0.20437763247650312,0.6948612780819718
B2_-0.992865418689679,-0.19362478580865677,0.6785406984696706
B2_-0.9860383980846014,-0.1832101137421725,0.6628061200683592
B2_-0.979607970799639,-0.1733833012757133,0.6480215608775259
B2_-0.9745542546784194,-0.16554177252747743,0.6361687112322234
B2_-0.9661951565581434,-0.15235991254724018,0.6164535774685054
B2_-0.9636973522671932,-0.1483815986083319,0.6104409163473904
B2_-0.9544590824158423,-0.13351790289113638,0.5882230001606227
B2_-0.9505693550610582,-0.12717054747541237,0.5786446839698867
B2_-0.9431083963222376,-0.11464491065334943,0.5600255570372998
B2_-0.9343040486558942,-0.09989664229104235,0.5379065159285262
B2_-0.9265945540543488,-0.08634064923693534,0.5177170878705663
B2_-0.9214564904123967,-0.07730162315578874,0.5040318570507899
B2_-0.9173706046728981,-0.0698994042802447,0.49303188038399615
B2_-0.9127638371195956,-0.06158804670076982,0.4805532274383703
B2_-0.9078245138335006,-0.05240745221383179,0.46662188781298847
B2_-0.9016974523718516,-0.041077763767611936,0.44929656517219546
B2_-0.8982366860668547,-0.034389682202442096,0.43923632952651714
B2_-0.8919881753545141,-0.022017010624083056,0.4202773102755823
B2_-0.8849020161190224,-0.008080960655829413,0.3986080132273472
B2_-0.882187263857787,-0.0026483686188473526,0.3899997453015568
B2_-0.8786384080225689,0.004821742959829163,0.37835673690167787
B2_-0.8757943684720668,0.010783071151340752,0.36885281898078126
B2_-0.8705318253991049,0.021711425928472985,0.35126705413237186
B2_-0.8627240525839862,0.038338416059849126,0.323913489473548
B2_-0.8574410921575671,0.04994017661467593,0.30440427290947686
B2_-0.8554738261800954,0.05440819953513316,0.2966590131370343
B2_-0.8505500931813478,0.06554186131739564,0.277289835472609
B2_-0.8478344218671606,0.07196919620546188,0.26576899102039203
B2_-0.8439388995190246,0.0809988418596372,0.24932901484788042
B2_-0.841175121758541,0.08769369126815335,0.2366974396298877
B2_-0.8391197446959465,0.0928069570459364,0.2271903157524672
B2_-0.8340484083886399,0.10530365946282785,0.20239479083033377
B2_-0.8289236360970212,0.11755425840715095,0.1768651755326338
B2_-0.825596052017928,0.12575955455698154,0.15841721078069335
B2_-0.8231996036746225,0.1315829626633712,0.14519690768937002
B2_-0.8189099782342312,0.14229017600568736,0.11884011236726809
B2_-0.8146004431143323,0.15295946528298715,0.09008455273498554
B2_-0.8124588163227149,0.15764783359412793,0.07677640009771038
B2_-0.810721116082046,0.16138694606637918,0.06483998676309798
B2_-0.808932248983079,0.1652886087315799,0.05251787221085467
B2_-0.805208707392358,0.1733280768919513,0.023274912131549225
B2_-0.8020542882941243,0.1796297008707417,-0.002369626535520626
B2_-0.8004353886884638,0.18240104054589615,-0.016856213659702336
B2_-0.7985881587153515,0.18543695314683198,-0.03155700442832944
B2_-0.7959563430987456,0.1891874372555488,-0.05702828277730673
B2_-0.7944480266760003,0.19118117131812543,-0.07101117757411718
B2_-0.792560210502176,0.19328979260679066,-0.09037596422568853
B2_-0.79081449985047,0.19506116038723714,-0.11131242644476974
B2_-0.7898500328280951,0.19576661928669037,-0.12520281391981775
B2_-0.7884033166453339,0.1967184396639282,-0.14265867213990974
B2_-0.7870374676534404,0.1972499993961446,-0.16510136660557856
B2_-0.7856636718947171,0.1971728966030602,-0.1945764979720163
B2_-0.7841789047753371,0.19660126604568778,-0.22668199646727194
B2_-0.7835866021026361,0.19549275898865445,-0.251164800185473
B2_-0.7832516244906274,0.19465635104022178,-0.2676505749328362
B2_-0.7832147515830821,0.19393695263320596,-0.27828654364780325
B2_-0.7828891425482324,0.19298439950003227,-0.29534075028745155
B2_-0.7829230709407369,0.19172504180128186,-0.3124886466103144
B2_-0.7826355746136896,0.19105722636744163,-0.32460769780586557
B2_-0.7827903580499191,0.19013281851827096,-0.3359164500300919
B2_-0.7829750975011206,0.1890249426043722,-0.34947651831895254
B2_-0.7827369215019477,0.1882643677531483,-0.36172838885481035
B2_-0.782860586119635,0.18645495934036405,-0.38524789320736225
B2_-0.783048189106591,0.18454229425832547,-0.4096124190865887
B2_-0.783365286089981,0.182834321261614,-0.430533183457631
B2_-0.7835521994799426,0.18125985742038397,-0.4504317558255163
B2_-0.783780436268619,0.1797541217046735,-0.4681371178894889
B2_-0.7840190879618573,0.17799402032572675,-0.4916036568194001
B2_-0.7841854186712104,0.17675679250607357,-0.5102860180849459
B2_-0.7845957278295581,0.17523559354678034,-0.5353986848999703
B2_-0.7848928546382485,0.17470152104410702,-0.546565087404241
B2_-0.7851071514621893,0.17425772136900788,-0.5565995058632335
B2_-0.785491537829968,0.1734347674958308,-0.5757026218161905
B2_-0.7860670952802881,0.1727631680820536,-0.5972743215098154
B2_-0.7861354000173839,0.17193769358762653,-0.6172011141369191
B2_-0.7864824383140486,0.1712408973652084,-0.6254667968260841
B3_-0.7901536674057548,0.49085809073538195,-0.6222497169957618
B3_-0.8000924602762916,0.4904411561853674,-0.6068743059505027
B3_-0.8106504617679581,0.48998939886994025,-0.5905426065108268
B3_-0.8212644625944653,0.48952646040721215,-0.5740489323190477
B3_-0.832608320806793,0.48902845885905755,-0.5561912029105369
B3_-0.8455568347160168,0.48845149571563234,-0.5359480708724349
B3_-0.8556481120697603,0.48802065914610177,-0.5198684709002255
B3_-0.8663935305173102,0.4875337811628319,-0.5030216060183813
B3_-0.8740663841396124,0.4872474411951206,-0.4904778410266971
B3_-0.8864951079044928,0.4867107054445437,-0.47080351990336333
B3_-0.9009936509292927,0.48607804577884084,-0.44781338593030745
B3_-0.9042153210046557,0.4711823124549976,-0.431827311815375
B3_-0.9054497743188669,0.46415025049088493,-0.42410383662637086
B3_-0.9070320684434272,0.45445020585444296,-0.4131600648620534
B3_-0.9083476605458943,0.44460424794804354,-0.4019121664254174
B3_-0.9092587399871572,0.4367600085751135,-0.39267137440935507
B3_-0.910163192140125,0.42571447001530005,-0.37942924679858125
B3_-0.9106258391087683,0.4195821379560959,-0.3719805353424465
B3_-0.9109001433884715,0.409251916598447,-0.35897846182703247
B3_-0.9111257475830089,0.4024485603855962,-0.3502972173987173
B3_-0.9109104556376201,0.38589048544053806,-0.32840949328149555
B3_-0.909826771961338,0.369252197809001,-0.3054836880307268
B3_-0.9074971200830764,0.35139837400708135,-0.2802563074551325
B3_-0.9061032198850535,0.3435186455675956,-0.26866867515067877
B3_-0.9049628182103907,0.33732519021441265,-0.2594863861485178
B3_-0.9030155711130857,0.32909195516010975,-0.24678251735102236
B3_-0.9016493938204808,0.3232743921888644,-0.2378228224937376
B3_-0.8988775451645062,0.3132493991948092,-0.22189292259588414
B3_-0.8958174250016867,0.3038946768145603,-0.20645964446088494
B3_-0.8940697621389803,0.298593077550019,-0.19772329463650357
B3_-0.8909333201974652,0.2902898915051073,-0.18352871999106435
B3_-0.8873583609391381,0.28131454405523515,-0.1678895239692765
B3_-0.8842189375757853,0.27447048509399824,-0.15537654399262368
B3_-0.8806190936480124,0.2663140045245327,-0.1407657622236576
B3_-0.877070204110852,0.2594695512742643,-0.12765881428999995
B3_-0.8738546660429468,0.2530263700965416,-0.11556289204791229
B3_-0.8683872500950238,0.2432457343583671,-0.09627024745035606
B3_-0.8607721048448249,0.23014824270958323,-0.06988026853527941
B3_-0.8558238810173141,0.22161734894494045,-0.052767929691466674
B3_-0.8525165891014157,0.2166774950661461,-0.04200882342702086
B3_-0.8481644049913493,0.2093022288318168,-0.027105884649778964
B3_-0.8441065521348965,0.2032576691437544,-0.013892018896715382
B3_-0.840023357369431,0.19644515623265407,-1.8740026141900873e-05
B3_-0.8244014318368189,0.1872649336579051,0.005386650739343069
B3_-0.8087551872817847,0.17840036947407262,0.01093066863431557
B3_-0.7927391159935798,0.17033887362725306,0.016397241526599736
B3_-0.7846804222602208,0.1662200695590626,0.01908920649789384
B3_-0.7757489035840697,0.16227441705247947,0.022050947942033917
B3_-0.764960648297142,0.15726313394100241,0.025794553127720058
B3_-0.7391517222681653,0.14710883328474175,0.03501987953865015
B3_-0.7087422765481379,0.1368626641269413,0.045986069018811866
B3_-0.6842839130080483,0.12989234625432383,0.05441914106302702
B3_-0.6553697113760284,0.12426584900666213,0.06450932394542921
B3_-0.6451691430038579,0.12282144057415333,0.06796506337689442
B3_-0.6199171421690689,0.118851807510466,0.07658906767245371
B3_-0.5931515188566201,0.11849841366984473,0.08644075950137045
B3_-0.5811873448197719,0.11743021728384889,0.09034618692742571
B3_-0.5669411042138791,0.11775223880534838,0.09546597941932794
B3_-0.5465544681693094,0.11814740773082696,0.10278359885436762
B3_-0.5323985095977656,0.11956378125269543,0.1083948345175138
B3_-0.5160425473988586,0.12023965929834872,0.11420202347609415
B3_-0.49177235618732645,0.12276156975955353,0.12363399626509679
B3_-0.46272587059055764,0.12643897062292345,0.13524506907236727
B3_-0.44746049150571937,0.1286638597987041,0.1415709063975721
B3_-0.4304071549093499,0.13152106781211736,0.14895232040259918
B3_-0.41512909433708917,0.13363438372025524,0.15511391150363263
B3_-0.4007761613802486,0.13621928921951018,0.16155224883948655
B3_-0.38997027333139944,0.13766688722677836,0.1658188730034393
B3_-0.368330280585251,0.141260486424584,0.175202702318017
B3_-0.3490107230689468,0.14432458701157555,0.18338701553436446
B3_-0.3311695058181496,0.14750771478656127,0.19082986616638936
B3_-0.32074550637038685,0.14961706136782368,0.19520866905979126
B3_-0.29807783357335976,0.15405695626518054,0.2040462523803649
B3_-0.2767340149778881,0.15862623263320205,0.21241136843923286
B3_-0.26145450196639897,0.1620592992579566,0.21819520920016255
B3_-0.24790260143805148,0.16546395796535865,0.22345889224930984
B3_-0.23512784668141917,0.16850783825121515,0.22808220487113673
B3_-0.21761192086916248,0.17282893584528403,0.234847687199572
B3_-0.20753966951958572,0.17523272871680204,0.23845234741598473
B3_-0.19759775708561458,0.17773398723144967,0.2424023881803366
B3_-0.1788122678567832,0.18230603087044814,0.24933179505934586
B3_-0.15430353343467212,0.18824557183054258,0.2586740362502925
B3_-0.13317589823300835,0.19351960498776657,0.2665190019048269
B3_-0.12412216471051522,0.195794449287909,0.2701411686397406
B3_-0.11147689667717904,0.19879212879137037,0.2746717094855295
B3_-0.09413987953912954,0.20298281550358332,0.2812340859137678
B3_-0.07252304878413951,0.2080261441885644,0.2894769466697779
B3_-0.060887738036595265,0.21067402338393532,0.2936044590344676
B3_-0.04670233055621953,0.21389537980868537,0.2992468544018612
B3_-0.03532148870820582,0.21643693695886518,0.3033169661924793
B3_-0.020777030411128872,0.21966662165623965,0.3089809899086235
B3_0.002575623803628014,0.22501061832201424,0.3178283065153263
B3_0.01879813778171819,0.22839191084409657,0.32396311158530006
B3_0.04003654243049389,0.23245534149903216,0.3319946056014526
B3_0.058131648159110635,0.2354134152417535,0.3385988399471096
B3_0.07005655097923871,0.2372658862551549,0.3431435053322066
B3_0.08177899436291489,0.23911986834372254,0.34742106676114265
B3_0.09479757759249582,0.24105458541473998,0.3522188413181451
B3_0.10754511723629004,0.24269507998719184,0.35704981086092485
B3_0.1207350725884641,0.24425018370078266,0.36168925121012696
B3_0.13944622995375958,0.24616327173867464,0.36845324203247976
B3_0.15853555415447124,0.2479615523202375,0.3751222732887133
B3_0.1869975103755983,0.250115217000379,0.38516242330322825
B3_0.19667550392568603,0.2507536215609698,0.3883253428813493
B3_0.20726869419436583,0.25112301107484414,0.39202212926620345
B3_0.22308473905352427,0.25159281875466294,0.39712489027077924
B3_0.24477723130648005,0.25232629813377006,0.40436242311166387
B3_0.2686237631581183,0.2526285152886045,0.41214359974138726
B3_0.2857819289811871,0.25253034010325687,0.417434038404177
B3_0.2965428897913884,0.2521727719302471,0.42078415670043934
B3_0.31198888207855857,0.2514972106302134,0.4252868864941082
B3_0.33019019650374865,0.250279767998817,0.4304721402682169
B3_0.35056674815769795,0.2488205531767197,0.4360545094244705
B3_0.37191196699654294,0.24666639721207217,0.4418757842996738
B3_0.38354044255817077,0.2453079463854315,0.4446822083264811
B3_0.40331565443066536,0.24270812444911485,0.44946063067812897
B3_0.41546876545147,0.24090893802126095,0.4523923813811331
B3_0.44510428218319154,0.2364686955205168,0.459209269302315
B3_0.4460889669095927,0.23628345890846555,0.4594306712296287
B3_0.45572401027572096,0.23455044722640872,0.4614708917516802
B3_0.4718439805690242,0.23147224464403748,0.46475333044734785
B3_0.4984103750725486,0.22585846811029883,0.4697873673231966
B3_0.5208558927939839,0.22036741325219153,0.4734464203172672
B3_0.5508417811383213,0.21259853641284593,0.4779870727900025
B3_0.5785195582045193,0.20440926392127534,0.4813926485789918
B3_0.605170329186147,0.19571966342987407,0.4839689932534587
B3_0.620541325754842,0.19039555989678203,0.4853139101838324
B3_0.6431958891291792,0.1823206055881866,0.48689696379252684
B3_0.6644623723518264,0.17404578966712697,0.48780292751063203
B3_0.6781244879345742,0.16847078260381557,0.4880509608040636
B3_0.6881608376552569,0.16453354017778013,0.48853143268965254
B3_0.6988463159778636,0.1599461838703205,0.48861734273374025
B3_0.7093886219396651,0.15475741622088104,0.4879368993347064
B3_0.7316322180739833,0.1441612485092104,0.4870035397934489
B3_0.7528611025304672,0.1334539097644685,0.4854970778964537
B3_0.775859085079709,0.12134850878132608,0.4833104138928093
B3_0.7866448597230475,0.1152713127282502,0.4819795222893044
B3_0.8021846501640588,0.10641036219206512,0.47970591620354097
B3_0.8265735934128458,0.09182737481938984,0.47558020711594357
B3_0.8550478151143158,0.07389100585788536,0.4698017536468273
B3_0.8751190815914189,0.060443224238283126,0.4647956443855719
B3_0.8862636336335022,0.05250858113268107,0.46153265612425626
B3_0.8942675959883624,0.04667795915423794,0.458928778843423
B3_0.9032004105241916,0.04000750267882114,0.45587572987229025
B3_0.9140065281004593,0.03164323322112149,0.45194625561066054
B3_0.9299225888560002,0.01911814153061734,0.4457261517121594
B3_0.9412584411850313,0.00972060724983791,0.44086618097290553
B3_0.9540659355713307,-0.0010752378607098978,0.43503254940432606
B3_0.9736160715879535,-0.018088691468660555,0.42553680261026144
B3_0.9837574912897254,-0.02745111392079585,0.41983916991629155
B3_0.9919476031649155,-0.035389507807210244,0.4149244835152968
B3_1.0014165889261055,-0.04481735814630394,0.408855594092927
B3_1.008156130643193,-0.05173357201690524,0.40420489523503556
B3_1.0208230296941223,-0.06507004114756587,0.3951983982043615
B3_1.044562527161818,-0.09108189885182112,0.37684535557306625
B3_1.061562675907389,-0.11185596735236752,0.36094594229418014
B3_1.0784836872416204,-0.13420353971183052,0.3429405247188081
B3_1.0890816345071854,-0.1490195502160056,0.330683983551606
B3_1.102959933518623,-0.17025297961029282,0.312011304802755
B3_1.1074174897845224,-0.17777038707260703,0.3050584796398744
B3_1.1140161993373843,-0.18947368454091074,0.29405787570140074
B3_1.1236411414167418,-0.20762616384228003,0.2765099540214448
B3_1.129539978936872,-0.21987865876097232,0.26419268745000474
B3_1.1371147301547428,-0.23798739460838625,0.24520224483452066
B3_1.1406861251230451,-0.2472991822304157,0.2351027004539602
B3_1.1485294628237102,-0.2707815149994461,0.2089111399692366
B3_1.152354735501028,-0.28500944630602526,0.19226249638165577
B3_1.1547500834717992,-0.29709634057405127,0.1774552423527045
B3_1.1573977062256107,-0.3140026985887355,0.1561238748571234
B3_1.1589713093376393,-0.33058259907255844,0.13435422384604606
B3_1.1595178554027559,-0.34946120856320245,0.10846254158472846
B3_1.158427455903206,-0.36189196970402177,0.09016903613961207
B3_1.1569962360844182,-0.37411131232041106,0.07187364623095077
B3_1.1540342541316861,-0.38957867906195315,0.047671269420377506
B3_1.1499720469643242,-0.4033694296484038,0.024813530500199063
B3_1.1440682636175885,-0.4190779982798393,-0.002406624321174154
B3_1.1373125817014265,-0.43377169649919056,-0.029035991402156517
B3_1.1302983254620331,-0.4451558894681593,-0.05135025108188199
B3_1.121992577611788,-0.4561326142737073,-0.07431218090624207
B3_1.115062914148435,-0.4641054009089679,-0.09189141209598846
B3_1.1095956412201355,-0.4695307371194389,-0.10454465572416467
B3_1.1014172940111553,-0.4768441675354837,-0.12244892746725226
B3_1.0923453129440044,-0.483690908941228,-0.14061812635221968
B3_1.0861131416086425,-0.4879616372438859,-0.1526800699904391
B3_1.0804116602664497,-0.4915775921799529,-0.16309867563399383
B3_1.0693203582890718,-0.49805963811249704,-0.18286562474457166
B3_1.0531558728683,-0.506111266398948,-0.20989825422718852
B3_1.0359189034407525,-0.5134957145902211,-0.2371462921779626
B3_1.020780410554139,-0.5187700821806988,-0.2595748047571389
B3_1.0055659652404108,-0.5227368993412502,-0.28042197587285594
B3_0.9884957808939917,-0.5260961068028579,-0.30255448583134636
B3_0.9616261221685597,-0.5298611965304649,-0.3354937714638009
B3_0.9512534907949189,-0.5306689425603636,-0.34742228810935416
B3_0.9431004157149336,-0.5311240582438995,-0.356637990302114
B3_0.9250851677212063,-0.5317805843572184,-0.37659689579429173
B3_0.9175603863572029,-0.531579420314705,-0.3845598004847694
B3_0.9075964799183767,-0.5312088550232588,-0.39471004746472865
B3_0.8911439430205275,-0.5300533840283345,-0.41102120772097395
B3_0.8707644074363867,-0.5278952836736821,-0.4304877343900746
B3_0.8480796649734496,-0.5248542700864406,-0.45162373544829887
B3_0.8280557701145869,-0.5211624242954713,-0.4692757895957704
B3_0.8108599065591463,-0.5174013878349247,-0.4838766012924559
B3_0.7917699818499728,-0.5128262975896544,-0.4998465207327888
B3_0.7755784742478687,-0.5083709336135371,-0.5128251974492855
B3_0.7607413422052866,-0.5036408867813102,-0.5241554484955402
B3_0.7426139527582553,-0.4977037093613406,-0.5378203087386845
B3_0.7236477293040643,-0.49091587161707634,-0.5518161478090161
B3_0.7046636303765224,-0.48351850398205215,-0.5653843570897324
B3_0.6967859262262839,-0.4801614140963729,-0.5706097951805679
B3_0.6854088939922995,-0.47508561565028695,-0.5784577408191908
B3_0.6684886581171567,-0.4672456800662972,-0.5897421780521066
B3_0.655409708407736,-0.461255900095482,-0.5982643036699395
B3_0.6404175468383537,-0.4536460603718454,-0.60799179767586
B3_0.6292227400380495,-0.44742642356028745,-0.6147311974344035
B3_0.6152885204877635,-0.4394969652057174,-0.6231808333052737
B3_0.6054040612959797,-0.43340982295682556,-0.6291843764235067
B3_0.5972587860712728,-0.4283977416485197,-0.6337659470542218
B3_0.580406167431578,-0.4176019199514643,-0.6436421720718696
B3_0.5588336036185874,-0.40404159324739813,-0.6559814927875259
B3_0.5424653586951917,-0.3930513701118113,-0.6654022028554574
B3_0.5255598563556638,-0.38160602385517245,-0.674853881555107
B3_0.5168800338247364,-0.3752143746107778,-0.6794051958753621
B3_0.5063625359748026,-0.36716001322948744,-0.6851936306141224
B3_0.49778514860454975,-0.36060940111399614,-0.6897340268886762
B3_0.48462479424203797,-0.3504030721913014,-0.6968106128750384
B3_0.4758547290904142,-0.3433506728023599,-0.7012693318626642
B3_0.46710272830808897,-0.3361100386430654,-0.7060291944253106
B3_0.45660758011388924,-0.3274145874175438,-0.7112537261182433
B3_0.44714409848739073,-0.31918413688891756,-0.7163523177770641
B3_0.4321626699009194,-0.30624067979340963,-0.724002961945399
B3_0.4166831867428491,-0.29280026112429836,-0.7321187949424741
B3_0.403093712105666,-0.2805763200729794,-0.7390369995354649
B3_0.3882700393313837,-0.2671537737142598,-0.7465000595156813
B3_0.37146691621193906,-0.2517980457058086,-0.755250099081784
B3_0.3596402595014898,-0.24076262656139022,-0.7615161795056014
B3_0.34116212386930406,-0.22359317261594372,-0.7708816295256632
B3_0.3231371949387773,-0.20732155024509336,-0.780125997234045
B3_0.30408655806329127,-0.19020016335049675,-0.7899086398898988
B3_0.2859022076922352,-0.1738634763045433,-0.7991728891657315
B3_0.2681679634658453,-0.1586914211661155,-0.8080830001036596
B3_0.2564208689118886,-0.14917155702231055,-0.8141348358896395
B3_0.24514939432567223,-0.13998836906720427,-0.8191324028840004
B3_0.23175462743301511,-0.1295399512951032,-0.8257796421897962
B3_0.21326652521924086,-0.11538281665376891,-0.8343716434780197
B3_0.19554485213402326,-0.10251544256489598,-0.8422237492833611
B3_0.1748991782663156,-0.08825787260890199,-0.8507722712515448
B3_0.15151030273011898,-0.07337058158415176,-0.8593813166919909
B3_0.1262506530478234,-0.05883773001398499,-0.8677484957138653
B3_0.11680257249761239,-0.053207077989671184,-0.8703157819581393
B3_0.10279202241339487,-0.04627644290279138,-0.8743074330392828
B3_0.08797927990433597,-0.03798411691199193,-0.8777389896069464
B3_0.07598784645182081,-0.03251225190744025,-0.8806174052136362
B3_0.05776861341027464,-0.022858635963867655,-0.8840681737635465
B3_0.04581799861305301,-0.017615305286380306,-0.8860509815765062
B3_0.03550908288948348,-0.012634295833517804,-0.8874265238034493
B3_0.007671003063450623,8.755852132987093e-05,-0.8906898672805696
B3_-0.006538956754170083,0.007024792657887356,-0.8916081763224454
B3_-0.034260049492814436,0.019280730251464484,-0.8937505529283122
B3_-0.04412065182561209,0.023097730164962523,-0.8933853742061586
B3_-0.05972429932940365,0.030586178314107197,-0.892757028116519
B3_-0.07816995421203837,0.038420339676592564,-0.891320862450204
B3_-0.10144246205266569,0.04901884313022177,-0.8890419225435165
B3_-0.1255326842941673,0.06020837201471361,-0.8858886532123881
B3_-0.13519712885564664,0.06532933429240087,-0.884366646075314
B3_-0.14853887540534202,0.07152896149213285,-0.8816354851148028
B3_-0.15980425807783288,0.07754647181847288,-0.8795299441853717
B3_-0.17130140928710863,0.083171444698235,-0.8768066894028346
B3_-0.18952978598824918,0.09283142047442296,-0.8724034377635862

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,2 @@
# Blender MTL File: 'mesh.blend'
# Material Count: 0

View File

@@ -0,0 +1,457 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Interactive Design Tool for Asymptotic Grid-Shells "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import igl\n",
"import pyvista as pv\n",
"import numpy as np\n",
"\n",
"import sys\n",
"sys.path.append('../src')\n",
"\n",
"import importlib, fabrication_helper, tracer_tool\n",
"importlib.reload(fabrication_helper)\n",
"importlib.reload(tracer_tool)\n",
"from tracer_tool import AsymptoticTracer\n",
"from fabrication_helper import FabricationHelper"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load Mesh\n",
"Import your own mesh as an .obj.\n",
"<br>Note that the filename should not contain the file extension because it will be used as the basis for saving further data. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"filename = \"../data/Model01\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialize Interface\n",
"Don't modify this part. All parameters can be tuned with the interface."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Fabrication parameters in cm\n",
"strips_scale = 3\n",
"strips_width = 2\n",
"strips_spacing = 0.2\n",
"strips_thickness = 0.3\n",
"board_width = 60\n",
"board_length = 100\n",
"# Creation parameters\n",
"sampling_distance = 1.0\n",
"num_neighbors = 4\n",
"iter_sampling = False\n",
"# Visualisation\n",
"strips_actor = []\n",
"points_actor = []\n",
"labels_actor = []\n",
"samples_actor = {}\n",
"pathA_actor = {}\n",
"pathA_indexes = {}\n",
"pathB_actor = {}\n",
"pathB_indexes = {}\n",
"intersections = np.empty((0,3), float)\n",
"visual_scaling = 0.2\n",
"\n",
"# Initialise tracer\n",
"mesh = pv.read(filename + \".obj\")\n",
"v,f = igl.read_triangle_mesh(filename + \".obj\")\n",
"tracer = AsymptoticTracer(filename + \".obj\")\n",
"helper = FabricationHelper(strips_width, strips_thickness, strips_spacing, strips_scale)\n",
"\n",
"plot = pv.Plotter(notebook=0)\n",
"\n",
"def add_pathA(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, True, num_neighbors, sampling_distance) \n",
"\n",
" if len(points)> 1:\n",
" pathA_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='white', line_width=10, pickable=False)\n",
" pathA_indexes[pid] = tracer.num_pathsA()-1\n",
" tracer.samples_indexes[0].append(pid)\n",
" return samples\n",
"\n",
"def add_pathB(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, False, num_neighbors, sampling_distance) \n",
" if len(points)> 1:\n",
" pathB_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='yellow', line_width=10, pickable=False)\n",
" pathB_indexes[pid] = tracer.num_pathsB()-1\n",
" tracer.samples_indexes[1].append(pid) \n",
" return samples\n",
"\n",
"def remove_pathA(pid):\n",
" plot.remove_actor(pathA_actor[pid])\n",
" tracer.delete_path(pathA_indexes[pid], True)\n",
" del pathA_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, True)\n",
"\n",
"def remove_pathB(pid):\n",
" plot.remove_actor(pathB_actor[pid])\n",
" tracer.delete_path(pathB_indexes[pid], False)\n",
" del pathB_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, False)\n",
"\n",
"def add_or_delete_sample_point(pid):\n",
" orig = v[pid]\n",
"\n",
" if pid not in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" if pid in samples_actor.keys():\n",
" plot.remove_actor(samples_actor[pid])\n",
" del samples_actor[pid]\n",
" clean_intersections()\n",
" else:\n",
" if pid not in samples_actor.keys():\n",
" color = 'blue'\n",
" if tracer.flagA and not tracer.flagB:\n",
" color = 'white'\n",
" elif tracer.flagB and not tracer.flagA:\n",
" color = 'yellow'\n",
"\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
" else:\n",
" plot.remove_actor(samples_actor[pid])\n",
" color = 'blue'\n",
" if pid not in pathB_actor.keys() and pid in pathA_actor.keys():\n",
" color = 'white'\n",
" elif pid in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" color = 'yellow'\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
"\n",
"def update_indexes(path_index, first_principal_direction):\n",
" if first_principal_direction:\n",
" if path_index in pathA_indexes.keys():\n",
" del pathA_indexes[path_index]\n",
" idx = 0\n",
" for key in pathA_indexes:\n",
" pathA_indexes[key] = idx\n",
" idx+=1\n",
" else:\n",
" if path_index in pathB_indexes.keys():\n",
" del pathB_indexes[path_index]\n",
" idx = 0\n",
" for key in pathB_indexes:\n",
" pathB_indexes[key] = idx\n",
" idx+=1\n",
"\n",
"def callback_first_family(value):\n",
" tracer.flagA = value\n",
"\n",
"def callback_second_family(value):\n",
" tracer.flagB = value\n",
"\n",
"def clean_intersections():\n",
" if len(points_actor)>0:\n",
" callback_remove_labels()\n",
" plot.remove_actor(points_actor)\n",
" points_actor.clear()\n",
" labels_actor.clear()\n",
" tracer.flag_intersections = False\n",
"\n",
"def callback_intersection():\n",
" clean_intersections() \n",
" global intersections\n",
" intersections = np.empty((0,3), float)\n",
" intersections = np.append(intersections, tracer.generate_intersection_network(), axis=0)\n",
" if len(tracer.intersection_points)>0:\n",
" points_actor.append(plot.add_points(tracer.intersection_points, color='red',point_size=13.0, pickable=False)) \n",
"\n",
"def callback_flatten():\n",
" if not tracer.flag_intersections:\n",
" callback_intersection()\n",
" \n",
" helper.generate_flatten_network(tracer)\n",
" \n",
" strips_num = helper.strips_numA if helper.strips_numA > helper.strips_numB else helper.strips_numB\n",
" plot.remove_actor(strips_actor)\n",
" strips_actor.clear()\n",
" if strips_num:\n",
" for i in range(strips_num):\n",
" if i<helper.strips_numA:\n",
" points = helper.paths_flatten[0][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='white', width=3))\n",
" if i<helper.strips_numB:\n",
" points = helper.paths_flatten[1][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='yellow', width=3))\n",
" # Board boundary\n",
" points = np.array([[0.,0.,0.],[board_length*visual_scaling,0.,0.],[board_length*visual_scaling, board_width*visual_scaling,0.],[0., board_width*visual_scaling,0],[0.,0.,0.]])\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='red', width=3))\n",
" \n",
"def callback_save_indexes():\n",
" file = open(filename + \"_indexes.txt\", 'w')\n",
" for i in range(len(tracer.samples_indexes)):\n",
" for idx in tracer.samples_indexes[i]:\n",
" if i==0: \n",
" file.write(\"A\"+str(idx))\n",
" elif i==1:\n",
" file.write(\"B\"+str(idx))\n",
" file.write('\\n')\n",
" file.close()\n",
"\n",
"def callback_load_indexes():\n",
" indexes = np.loadtxt(filename + \"_indexes.txt\", dtype=str)\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" for data in indexes:\n",
" pid = int(data[1:])\n",
"\n",
" tracer.flagA = True if data[0] == \"A\" else False\n",
" tracer.flagB = True if data[0] == \"B\" else False\n",
"\n",
" callback_picking(mesh,pid)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
"def lines_from_points(points):\n",
" cells = np.empty((len(points)-1, 2), dtype=np.int_)\n",
" cells[:,0] = np.arange(0, len(points)-1, dtype=np.int_)\n",
" cells[:,1] = np.arange(1, len(points), dtype=np.int_)\n",
" cells = cells.flatten()\n",
" return np.array([points[i] for i in cells])\n",
"\n",
"def callback_picking(mesh, pid, iterative_sampling=None):\n",
"\n",
" if(iterative_sampling==None):\n",
" iterative_sampling = iter_sampling\n",
"\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" # Generate first family of asymptotic curves\n",
" if tracer.flagA:\n",
" if pid in pathA_actor.keys():\n",
" remove_pathA(pid)\n",
" else:\n",
" samples = add_pathA(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = False\n",
" tracer.flagB = True\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
" # Generate second family of asymptotic curves\n",
" if tracer.flagB:\n",
" if pid in pathB_actor.keys():\n",
" remove_pathB(pid)\n",
" else:\n",
" samples = add_pathB(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = True\n",
" tracer.flagB = False\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
" \n",
" add_or_delete_sample_point(pid)\n",
" \n",
"def callback_save_svg():\n",
" cutting_color = \"red\"\n",
" engraving_color = \"black\"\n",
" font_size = 0.4\n",
" if helper.flag_flatten==False:\n",
" helper.generate_flatten_network()\n",
" helper.generate_svg_file(filename + \"_cutting.svg\", font_size, cutting_color, engraving_color, board_length, board_width)\n",
"\n",
"def callback_width(value):\n",
" helper.strips_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_width(value):\n",
" global board_width\n",
" board_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_thickness(value):\n",
" helper.strips_thickness = value\n",
" callback_flatten()\n",
"\n",
"def callback_length(value):\n",
" helper.scale_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_spacing(value):\n",
" helper.strips_spacing = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_length(value):\n",
" global board_length\n",
" board_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_remove_labels():\n",
" plot.remove_actor(labels_actor)\n",
" labels_actor.clear()\n",
"\n",
"def callback_add_all_labels():\n",
" callback_add_labels(True, True)\n",
"\n",
"def callback_add_labelsA():\n",
" callback_add_labels(True, False)\n",
"\n",
"def callback_add_labelsB():\n",
" callback_add_labels(False, True)\n",
" \n",
"def callback_add_labels(labelsA, labelsB):\n",
" callback_remove_labels()\n",
"\n",
" if len(tracer.paths_indexes[0])>0 and labelsA:\n",
" labels = np.core.defchararray.add('A', np.arange(len(tracer.paths_indexes[0])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[0]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[0][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[0] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
" if len(tracer.paths_indexes[1])>0 and labelsB:\n",
" labels = np.core.defchararray.add('B', np.arange(len(tracer.paths_indexes[1])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[1]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[1][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[1] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
"def callback_save_network():\n",
" file = open(filename + \"_rhino.txt\", 'w')\n",
" for i in range(2):\n",
" label = \"A\"\n",
" if i==1:\n",
" label =\"B\"\n",
"\n",
" # positions\n",
" for j in range(len(tracer.paths_indexes[i])):\n",
" path = tracer.paths_indexes[i][j]\n",
" for idx in path:\n",
" pt = tracer.paths[i][idx]\n",
" file.write(label + str(j)+ \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
"\n",
" # Intersections \n",
" for i in range( len(tracer.intersection_points) ):\n",
" pt = tracer.intersection_points[i]\n",
" file.write(\"C\" + str(i) + \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
" file.close()\n",
"\n",
"def callback_sampling_distance(value):\n",
" global sampling_distance\n",
" sampling_distance = value\n",
"\n",
"def callback_iterative_sampling(value):\n",
" global iter_sampling\n",
" iter_sampling = value\n",
"\n",
"plot.add_mesh(mesh, show_edges=True)\n",
"plot.add_axes()\n",
"msg = \"Press <K> for saving indexes, <L> for loading indexes or <O> to save the curve network model.\\n\"\n",
"msg += \"Press <I> for computing intersections, <J> for generating the flatten strips and <H> for saving the laser-cutting file.\\n\"\n",
"msg += \"Press <M> for hiding labels, <N> for showing all labels, <U> for showing A labels or <Y> for showing B labels.\\n\"\n",
"plot.add_text(msg, position='lower_right', font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_checkbox_button_widget(callback_first_family, value=tracer.flagA, position=(10, 200.0), size=40, border_size=1, color_on='white', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_second_family, value=tracer.flagB, position=(10, 300.0), size=40, border_size=1, color_on='yellow', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_iterative_sampling, value=iter_sampling, position=(10, 400.0), size=40, border_size=1, color_on='green', color_off='grey', background_color='red')\n",
"plot.add_text(\"First Family\", position=(80.0, 200.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Second Family\", position=(80, 300.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Iterative sampling\", position=(80, 400.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_key_event('i', callback_intersection)\n",
"plot.add_key_event('j', callback_flatten)\n",
"plot.add_key_event('k', callback_save_indexes)\n",
"plot.add_key_event('l', callback_load_indexes)\n",
"plot.add_key_event('h', callback_save_svg)\n",
"plot.add_key_event('m', callback_remove_labels)\n",
"plot.add_key_event('n', callback_add_all_labels)\n",
"plot.add_key_event('u', callback_add_labelsA)\n",
"plot.add_key_event('y', callback_add_labelsB)\n",
"plot.add_key_event('o', callback_save_network)\n",
"plot.enable_point_picking(callback=callback_picking, show_message=True, color='pink', point_size=10, use_mesh=True, show_point=True)\n",
"plot.add_slider_widget(callback_width, [0.1, 5.0], value=strips_width, title=\"Strip Width (cm)\", pointa=(.83, .15), pointb=(.98, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_thickness, [0.1, 1], value=strips_thickness, title=\"Strip Thickness (cm)\", pointa=(.67, .15), pointb=(.82, .15), title_height=0.02, fmt=\"%0.2f\", style='modern')\n",
"plot.add_slider_widget(callback_length, [1, 10], value=strips_scale, title=\"Scale Strip Length\", pointa=(.51, .15), pointb=(.66, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_spacing, [0., 0.5], value=strips_spacing, title=\"Strip spacing\", pointa=(.51, .88), pointb=(.66, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_board_width, [10, 100], value=board_width, title=\"Board width (cm)\", pointa=(.67, .88), pointb=(.82, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_board_length, [10, 100], value=board_length, title=\"Board length (cm)\", pointa=(.83, .88), pointb=(.98, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_sampling_distance, [0.1, 2.0], value=sampling_distance, title=\"Sampling distance\", pointa=(.005, .88), pointb=(.16, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.show(\"Asymptotic GridShell\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "294c9a689e437aa1430c5ffd3595515046a5cee981399d48a2291c079c814bc8"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,171 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from meshplot import plot"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../src')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import importlib, tracer_helper, tracer_utils\n",
"importlib.reload(tracer_helper)\n",
"importlib.reload(tracer_utils)\n",
"from tracer_utils import asymptotic_path\n",
"from tracer_helper import Mesh"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example\n",
"Build mesh from file"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f19ce42be2f6405796de381ba4b89b42",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(aspect=1.5, children=(DirectionalLight(color='white', intensity=0.6, positio…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mesh = Mesh(\"../data/Model01.obj\")\n",
"p = plot(mesh.V, mesh.F, shading={\"wireframe\": True,\"width\": 900, \"height\": 600}, return_plot=True, c=np.array([0,0.7,1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace first asymptotic curve\n",
"Use principal directions V1"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = False\n",
"\n",
"# Pre-selection of vertices\n",
"idxA = [167,173,178,146,159,291,49,40,254,57,15,65,268,341,283]\n",
"# Tracing\n",
"for idx in idxA:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
"\n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"white\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"white\"})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace second asymptotic curve\n",
"Use principal directions V2"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = True\n",
"\n",
"# Pre-selection of vertices\n",
"idxB = [119,203,188,129,95,66,308,298,290,282,335,143,81,73,33]\n",
"# Tracing\n",
"for idx in idxB:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
" \n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"yellow\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"yellow\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "d74ce2d711eca57e47550fdd427f707c5faa08517318f0967f4aae699c902c0e"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,509 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Interactive Design Tool for Asymptotic Grid-Shells "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import igl\n",
"import pyvista as pv\n",
"import numpy as np\n",
"\n",
"import sys\n",
"sys.path.append('../src')\n",
"\n",
"import importlib, fabrication_helper, tracer_tool\n",
"importlib.reload(fabrication_helper)\n",
"importlib.reload(tracer_tool)\n",
"from tracer_tool import AsymptoticTracer\n",
"from fabrication_helper import FabricationHelper"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load Mesh\n",
"Import your own mesh as an .obj.\n",
"<br>Note that the filename should not contain the file extension because it will be used as the basis for saving further data. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"filename = \"../data/final\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialize Interface\n",
"Don't modify this part. All parameters can be tuned with the interface."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hit Boundary\n",
"Duplicate Point\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Duplicate Point\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Duplicate Point\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n",
"Hit Boundary\n"
]
}
],
"source": [
"# Fabrication parameters in cm\n",
"strips_scale = 3\n",
"strips_width = 2\n",
"strips_spacing = 0.2\n",
"strips_thickness = 0.3\n",
"board_width = 60\n",
"board_length = 100\n",
"# Creation parameters\n",
"sampling_distance = 1.0\n",
"num_neighbors = 4\n",
"iter_sampling = False\n",
"# Visualisation\n",
"strips_actor = []\n",
"points_actor = []\n",
"labels_actor = []\n",
"samples_actor = {}\n",
"pathA_actor = {}\n",
"pathA_indexes = {}\n",
"pathB_actor = {}\n",
"pathB_indexes = {}\n",
"intersections = np.empty((0,3), float)\n",
"visual_scaling = 0.2\n",
"\n",
"# Initialise tracer\n",
"mesh = pv.read(filename + \".obj\")\n",
"v,f = igl.read_triangle_mesh(filename + \".obj\")\n",
"tracer = AsymptoticTracer(filename + \".obj\")\n",
"helper = FabricationHelper(strips_width, strips_thickness, strips_spacing, strips_scale)\n",
"\n",
"plot = pv.Plotter(notebook=0)\n",
"\n",
"def add_pathA(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, True, num_neighbors, sampling_distance) \n",
"\n",
" if len(points)> 1:\n",
" pathA_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='white', line_width=10, pickable=False)\n",
" pathA_indexes[pid] = tracer.num_pathsA()-1\n",
" tracer.samples_indexes[0].append(pid)\n",
" return samples\n",
"\n",
"def add_pathB(pid):\n",
" points, samples = tracer.generate_asymptotic_path(pid, False, num_neighbors, sampling_distance) \n",
" if len(points)> 1:\n",
" pathB_actor[pid] = plot.add_mesh(pv.Spline(points, 400), color='yellow', line_width=10, pickable=False)\n",
" pathB_indexes[pid] = tracer.num_pathsB()-1\n",
" tracer.samples_indexes[1].append(pid) \n",
" return samples\n",
"\n",
"def remove_pathA(pid):\n",
" plot.remove_actor(pathA_actor[pid])\n",
" tracer.delete_path(pathA_indexes[pid], True)\n",
" del pathA_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, True)\n",
"\n",
"def remove_pathB(pid):\n",
" plot.remove_actor(pathB_actor[pid])\n",
" tracer.delete_path(pathB_indexes[pid], False)\n",
" del pathB_actor[pid]\n",
" #Update indexes\n",
" update_indexes(pid, False)\n",
"\n",
"def add_or_delete_sample_point(pid):\n",
" orig = v[pid]\n",
"\n",
" if pid not in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" if pid in samples_actor.keys():\n",
" plot.remove_actor(samples_actor[pid])\n",
" del samples_actor[pid]\n",
" clean_intersections()\n",
" else:\n",
" if pid not in samples_actor.keys():\n",
" color = 'blue'\n",
" if tracer.flagA and not tracer.flagB:\n",
" color = 'white'\n",
" elif tracer.flagB and not tracer.flagA:\n",
" color = 'yellow'\n",
"\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
" else:\n",
" plot.remove_actor(samples_actor[pid])\n",
" color = 'blue'\n",
" if pid not in pathB_actor.keys() and pid in pathA_actor.keys():\n",
" color = 'white'\n",
" elif pid in pathB_actor.keys() and pid not in pathA_actor.keys():\n",
" color = 'yellow'\n",
" samples_actor[pid] = plot.add_points(np.array(orig), color=color, render_points_as_spheres=True, point_size=20.0, pickable=False)\n",
" clean_intersections()\n",
"\n",
"def update_indexes(path_index, first_principal_direction):\n",
" if first_principal_direction:\n",
" if path_index in pathA_indexes.keys():\n",
" del pathA_indexes[path_index]\n",
" idx = 0\n",
" for key in pathA_indexes:\n",
" pathA_indexes[key] = idx\n",
" idx+=1\n",
" else:\n",
" if path_index in pathB_indexes.keys():\n",
" del pathB_indexes[path_index]\n",
" idx = 0\n",
" for key in pathB_indexes:\n",
" pathB_indexes[key] = idx\n",
" idx+=1\n",
"\n",
"def callback_first_family(value):\n",
" tracer.flagA = value\n",
"\n",
"def callback_second_family(value):\n",
" tracer.flagB = value\n",
"\n",
"def clean_intersections():\n",
" if len(points_actor)>0:\n",
" callback_remove_labels()\n",
" plot.remove_actor(points_actor)\n",
" points_actor.clear()\n",
" labels_actor.clear()\n",
" tracer.flag_intersections = False\n",
"\n",
"def callback_intersection():\n",
" clean_intersections() \n",
" global intersections\n",
" intersections = np.empty((0,3), float)\n",
" intersections = np.append(intersections, tracer.generate_intersection_network(), axis=0)\n",
" if len(tracer.intersection_points)>0:\n",
" points_actor.append(plot.add_points(tracer.intersection_points, color='red',point_size=13.0, pickable=False)) \n",
"\n",
"def callback_flatten():\n",
" if not tracer.flag_intersections:\n",
" callback_intersection()\n",
" \n",
" helper.generate_flatten_network(tracer)\n",
" \n",
" strips_num = helper.strips_numA if helper.strips_numA > helper.strips_numB else helper.strips_numB\n",
" plot.remove_actor(strips_actor)\n",
" strips_actor.clear()\n",
" if strips_num:\n",
" for i in range(strips_num):\n",
" if i<helper.strips_numA:\n",
" points = helper.paths_flatten[0][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='white', width=3))\n",
" if i<helper.strips_numB:\n",
" points = helper.paths_flatten[1][i] * visual_scaling\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='yellow', width=3))\n",
" # Board boundary\n",
" points = np.array([[0.,0.,0.],[board_length*visual_scaling,0.,0.],[board_length*visual_scaling, board_width*visual_scaling,0.],[0., board_width*visual_scaling,0],[0.,0.,0.]])\n",
" strips_actor.append(plot.add_lines(lines_from_points(points), color='red', width=3))\n",
" \n",
"def callback_save_indexes():\n",
" file = open(filename + \"_indexes.txt\", 'w')\n",
" for i in range(len(tracer.samples_indexes)):\n",
" for idx in tracer.samples_indexes[i]:\n",
" if i==0: \n",
" file.write(\"A\"+str(idx))\n",
" elif i==1:\n",
" file.write(\"B\"+str(idx))\n",
" file.write('\\n')\n",
" file.close()\n",
"\n",
"def callback_load_indexes():\n",
" indexes = np.loadtxt(filename + \"_indexes.txt\", dtype=str)\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" for data in indexes:\n",
" pid = int(data[1:])\n",
"\n",
" tracer.flagA = True if data[0] == \"A\" else False\n",
" tracer.flagB = True if data[0] == \"B\" else False\n",
"\n",
" callback_picking(mesh,pid)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
"def lines_from_points(points):\n",
" cells = np.empty((len(points)-1, 2), dtype=np.int_)\n",
" cells[:,0] = np.arange(0, len(points)-1, dtype=np.int_)\n",
" cells[:,1] = np.arange(1, len(points), dtype=np.int_)\n",
" cells = cells.flatten()\n",
" return np.array([points[i] for i in cells])\n",
"\n",
"def callback_picking(mesh, pid, iterative_sampling=None):\n",
"\n",
" if(iterative_sampling==None):\n",
" iterative_sampling = iter_sampling\n",
"\n",
" old_flagA = tracer.flagA\n",
" old_flagB = tracer.flagB\n",
"\n",
" # Generate first family of asymptotic curves\n",
" if tracer.flagA:\n",
" if pid in pathA_actor.keys():\n",
" remove_pathA(pid)\n",
" else:\n",
" samples = add_pathA(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = False\n",
" tracer.flagB = True\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
"\n",
" # Generate second family of asymptotic curves\n",
" if tracer.flagB:\n",
" if pid in pathB_actor.keys():\n",
" remove_pathB(pid)\n",
" else:\n",
" samples = add_pathB(pid)\n",
"\n",
" if iterative_sampling:\n",
" for pt in samples:\n",
" idx = tracer.mesh.kd_tree.query(pt)[1]\n",
" tracer.flagA = True\n",
" tracer.flagB = False\n",
" callback_picking(mesh, idx, iterative_sampling=False)\n",
"\n",
" tracer.flagA = old_flagA\n",
" tracer.flagB = old_flagB\n",
" \n",
" add_or_delete_sample_point(pid)\n",
" \n",
"def callback_save_svg():\n",
" cutting_color = \"red\"\n",
" engraving_color = \"black\"\n",
" font_size = 0.4\n",
" if helper.flag_flatten==False:\n",
" helper.generate_flatten_network()\n",
" helper.generate_svg_file(filename + \"_cutting.svg\", font_size, cutting_color, engraving_color, board_length, board_width)\n",
"\n",
"def callback_width(value):\n",
" helper.strips_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_width(value):\n",
" global board_width\n",
" board_width = value\n",
" callback_flatten()\n",
"\n",
"def callback_thickness(value):\n",
" helper.strips_thickness = value\n",
" callback_flatten()\n",
"\n",
"def callback_length(value):\n",
" helper.scale_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_spacing(value):\n",
" helper.strips_spacing = value\n",
" callback_flatten()\n",
"\n",
"def callback_board_length(value):\n",
" global board_length\n",
" board_length = value\n",
" callback_flatten()\n",
"\n",
"def callback_remove_labels():\n",
" plot.remove_actor(labels_actor)\n",
" labels_actor.clear()\n",
"\n",
"def callback_add_all_labels():\n",
" callback_add_labels(True, True)\n",
"\n",
"def callback_add_labelsA():\n",
" callback_add_labels(True, False)\n",
"\n",
"def callback_add_labelsB():\n",
" callback_add_labels(False, True)\n",
" \n",
"def callback_add_labels(labelsA, labelsB):\n",
" callback_remove_labels()\n",
"\n",
" if len(tracer.paths_indexes[0])>0 and labelsA:\n",
" labels = np.core.defchararray.add('A', np.arange(len(tracer.paths_indexes[0])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[0]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[0][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[0] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
" if len(tracer.paths_indexes[1])>0 and labelsB:\n",
" labels = np.core.defchararray.add('B', np.arange(len(tracer.paths_indexes[1])).astype(str))\n",
" indexes = [idx[:1][0] for idx in tracer.paths_indexes[1]]\n",
" labels_actor.append(plot.add_point_labels(tracer.paths[1][indexes], labels, font_size=22, always_visible=True, show_points=False))\n",
"\n",
" indexes = np.unique(np.array([item for sublist in tracer.intersections[1] for item in sublist[:,2]], int).flatten())\n",
" labels = np.core.defchararray.add('c', indexes.astype(str))\n",
" labels_actor.append(plot.add_point_labels(tracer.intersection_points[indexes], labels, bold=False, font_size=18, always_visible=True, show_points=False))\n",
"\n",
"def callback_save_network():\n",
" file = open(filename + \"_rhino.txt\", 'w')\n",
" for i in range(2):\n",
" label = \"A\"\n",
" if i==1:\n",
" label =\"B\"\n",
"\n",
" # positions\n",
" for j in range(len(tracer.paths_indexes[i])):\n",
" path = tracer.paths_indexes[i][j]\n",
" for idx in path:\n",
" pt = tracer.paths[i][idx]\n",
" file.write(label + str(j)+ \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
"\n",
" # Intersections \n",
" for i in range( len(tracer.intersection_points) ):\n",
" pt = tracer.intersection_points[i]\n",
" file.write(\"C\" + str(i) + \"_\" +str(pt[0]) + \",\" + str(pt[1]) + \",\" +str(pt[2]) + \"\\n\")\n",
" file.close()\n",
"\n",
"def callback_sampling_distance(value):\n",
" global sampling_distance\n",
" sampling_distance = value\n",
"\n",
"def callback_iterative_sampling(value):\n",
" global iter_sampling\n",
" iter_sampling = value\n",
"\n",
"plot.add_mesh(mesh, show_edges=True)\n",
"plot.add_axes()\n",
"msg = \"Press <K> for saving indexes, <L> for loading indexes or <O> to save the curve network model.\\n\"\n",
"msg += \"Press <I> for computing intersections, <J> for generating the flatten strips and <H> for saving the laser-cutting file.\\n\"\n",
"msg += \"Press <M> for hiding labels, <N> for showing all labels, <U> for showing A labels or <Y> for showing B labels.\\n\"\n",
"plot.add_text(msg, position='lower_right', font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_checkbox_button_widget(callback_first_family, value=tracer.flagA, position=(10, 200.0), size=40, border_size=1, color_on='white', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_second_family, value=tracer.flagB, position=(10, 300.0), size=40, border_size=1, color_on='yellow', color_off='grey', background_color='red')\n",
"plot.add_checkbox_button_widget(callback_iterative_sampling, value=iter_sampling, position=(10, 400.0), size=40, border_size=1, color_on='green', color_off='grey', background_color='red')\n",
"plot.add_text(\"First Family\", position=(80.0, 200.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Second Family\", position=(80, 300.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_text(\"Iterative sampling\", position=(80, 400.0), font_size=12, color=None, font=None, shadow=False, name=None, viewport=False)\n",
"plot.add_key_event('i', callback_intersection)\n",
"plot.add_key_event('j', callback_flatten)\n",
"plot.add_key_event('k', callback_save_indexes)\n",
"plot.add_key_event('l', callback_load_indexes)\n",
"plot.add_key_event('h', callback_save_svg)\n",
"plot.add_key_event('m', callback_remove_labels)\n",
"plot.add_key_event('n', callback_add_all_labels)\n",
"plot.add_key_event('u', callback_add_labelsA)\n",
"plot.add_key_event('y', callback_add_labelsB)\n",
"plot.add_key_event('o', callback_save_network)\n",
"plot.enable_point_picking(callback=callback_picking, show_message=True, color='pink', point_size=10, use_mesh=True, show_point=True)\n",
"plot.add_slider_widget(callback_width, [0.1, 5.0], value=strips_width, title=\"Strip Width (cm)\", pointa=(.83, .15), pointb=(.98, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_thickness, [0.1, 1], value=strips_thickness, title=\"Strip Thickness (cm)\", pointa=(.67, .15), pointb=(.82, .15), title_height=0.02, fmt=\"%0.2f\", style='modern')\n",
"plot.add_slider_widget(callback_length, [1, 10], value=strips_scale, title=\"Scale Strip Length\", pointa=(.51, .15), pointb=(.66, .15), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_spacing, [0., 0.5], value=strips_spacing, title=\"Strip spacing\", pointa=(.51, .88), pointb=(.66, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.add_slider_widget(callback_board_width, [10, 100], value=board_width, title=\"Board width (cm)\", pointa=(.67, .88), pointb=(.82, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_board_length, [10, 100], value=board_length, title=\"Board length (cm)\", pointa=(.83, .88), pointb=(.98, .88), title_height=0.02, fmt=\"%0.0f\", style='modern')\n",
"plot.add_slider_widget(callback_sampling_distance, [0.1, 2.0], value=sampling_distance, title=\"Sampling distance\", pointa=(.005, .88), pointb=(.16, .88), title_height=0.02, fmt=\"%0.1f\", style='modern')\n",
"plot.show(\"Asymptotic GridShell\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "294c9a689e437aa1430c5ffd3595515046a5cee981399d48a2291c079c814bc8"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,171 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from meshplot import plot"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../src')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import importlib, tracer_helper, tracer_utils\n",
"importlib.reload(tracer_helper)\n",
"importlib.reload(tracer_utils)\n",
"from tracer_utils import asymptotic_path\n",
"from tracer_helper import Mesh"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example\n",
"Build mesh from file"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f19ce42be2f6405796de381ba4b89b42",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(aspect=1.5, children=(DirectionalLight(color='white', intensity=0.6, positio…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mesh = Mesh(\"../data/Model01.obj\")\n",
"p = plot(mesh.V, mesh.F, shading={\"wireframe\": True,\"width\": 900, \"height\": 600}, return_plot=True, c=np.array([0,0.7,1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace first asymptotic curve\n",
"Use principal directions V1"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = False\n",
"\n",
"# Pre-selection of vertices\n",
"idxA = [167,173,178,146,159,291,49,40,254,57,15,65,268,341,283]\n",
"# Tracing\n",
"for idx in idxA:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
"\n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"white\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"white\"})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trace second asymptotic curve\n",
"Use principal directions V2"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Set tracing parameters\n",
"num_steps = 1000\n",
"step_size = 1e-6\n",
"num_neighbors = 4\n",
"first_principal_direction = True\n",
"\n",
"# Pre-selection of vertices\n",
"idxB = [119,203,188,129,95,66,308,298,290,282,335,143,81,73,33]\n",
"# Tracing\n",
"for idx in idxB:\n",
" P, A, PP = asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors)\n",
" \n",
" # Plot starting vertex\n",
" p.add_points(np.array([mesh.V[idx]]), shading={\"point_size\": 0.7, \"point_color\": \"black\"})\n",
" # Plot edge-points shaping the asymptotic path\n",
" p.add_points(P, shading={\"point_size\": 0.2,\"point_color\": \"yellow\"})\n",
" # Plot asymptotic curve\n",
" if(len(P)>1): \n",
" p.add_lines(P[:-1], P[1:], shading={\"line_color\": \"yellow\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "d74ce2d711eca57e47550fdd427f707c5faa08517318f0967f4aae699c902c0e"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,186 @@
import numpy as np
import numpy.linalg as la
import svgwrite
from tracer_tool import AsymptoticTracer
class FabricationHelper:
def __init__(self, width, thickness, spacing, scale_length=1.0):
self.strips_width = width
self.strips_spacing = spacing
self.strips_thickness = thickness
self.scale_length = scale_length
self.flag_flatten = False
def generate_flatten_path(self, pathIndex, second_direction=False, position=np.array([0,0,0])):
length_direction = np.array([1,0,0])
width_direction = np.array([0,1,0]) * self.strips_width * 0.5
if second_direction:
width_direction *= -1
self.intersection_points[second_direction][pathIndex] = np.empty((0,3), float)
self.intersection_labels[second_direction][pathIndex] = []
intersections = self.intersections[second_direction][pathIndex]
paths_lengths = self.paths_lengths[second_direction][pathIndex]
length = np.trace(np.diag(paths_lengths)) * self.scale_length
path_forwards = np.empty((0,3), float)
path_backwards = np.empty((0,3), float)
path_intersection = np.empty((0,3), float)
# Add start point
start_position_forward = position + width_direction
start_position_backward = position - width_direction
end_position_forward = position + width_direction + length_direction * length
end_position_backward = position - width_direction + length_direction * length
path_forwards = np.append(path_forwards, np.array([start_position_forward]),axis=0)
path_backwards = np.append(path_backwards, np.array([start_position_backward]),axis=0)
# Connections
if len(intersections)>0:
for i in range(len(intersections)):
intersection_event = intersections[i]
# Store label
self.intersection_labels[second_direction][pathIndex].append(int(intersection_event[2]))
# Add intersection points
edge_index = int(intersection_event[0])
partial_length = (np.trace(np.diag(paths_lengths[:edge_index])) + paths_lengths[edge_index] * intersection_event[1]) * self.scale_length
p = position + length_direction * partial_length
path_intersection = np.append(path_intersection, np.array([p]), axis=0)
p += width_direction
vec_offset = length_direction * self.strips_thickness * 0.5
if partial_length - self.strips_thickness * 0.5 <= 0:
p0 = position
p1 = p + vec_offset - width_direction
p2 = p + vec_offset
path_forwards = np.array([p0, p1, p2])
elif partial_length + self.strips_thickness * 0.5 >= length:
p0 = p - vec_offset
p1 = p - vec_offset - width_direction
p2 = position + length_direction * length
path_forwards = np.append(path_forwards, np.array([p0, p1, p2]), axis=0)
else:
p0 = p - vec_offset
p1 = p - vec_offset - width_direction
p2 = p + vec_offset - width_direction
p3 = p + vec_offset
path_forwards = np.append(path_forwards, np.array([p0, p1, p2, p3]), axis=0)
if end_position_forward[0]>path_forwards[len(path_forwards)-1][0]:
path_forwards = np.append(path_forwards, np.array([end_position_forward]), axis=0)
path_backwards = np.append(path_backwards, np.array([end_position_backward]), axis=0)
else:
path_forwards = np.append(path_forwards, np.array([end_position_forward]), axis=0)
path_backwards = np.append(path_backwards, np.array([end_position_backward]), axis=0)
path = path_backwards[::-1]
# Combine paths
path = np.append(path, path_forwards, axis=0)
path = np.append(path, np.array([path[0]]), axis=0)
self.paths_flatten[second_direction][pathIndex] = path
self.intersection_points[second_direction][pathIndex] = path_intersection
return path, length
def generate_flatten_network(self, tracer):
self.paths_flatten = tracer.paths_flatten
self.paths_lengths = tracer.paths_lengths
self.intersection_points = tracer.paths_labels
self.intersection_labels = [[] for i in range(2) ]
self.intersections = tracer.intersections
self.strips_numA = len(tracer.paths_indexes[0])
self.strips_numB = len(tracer.paths_indexes[1])
# init labels
self.intersection_labels[0] = [[] for i in range(self.strips_numA)]
self.intersection_labels[1] = [[] for i in range(self.strips_numB)]
strips_num = self.strips_numA if self.strips_numA > self.strips_numB else self.strips_numB
# Generate flat strips
strips_added = 0
# Fabrication parameters
self.board_width = self.strips_width * (self.strips_numA+self.strips_numB) + self.strips_spacing * (self.strips_numA+self.strips_numB+1)
self.board_length = 0
for i in range(strips_num):
if i< self.strips_numA:
position = np.array([ self.strips_spacing, self.strips_width * 0.5 + self.strips_spacing + (self.strips_width + self.strips_spacing) * strips_added, 0 ] )
points, path_len = self.generate_flatten_path(i, False, position)
strips_added +=1
if path_len>self.board_length:
self.board_length = path_len
if i< self.strips_numB:
position = np.array([ self.strips_spacing, self.strips_width * 0.5 + self.strips_spacing + (self.strips_width + self.strips_spacing) * strips_added, 0 ] )
points, path_len = self.generate_flatten_path(i, True, position)
strips_added +=1
if path_len>self.board_length:
self.board_length = path_len
self.flag_flatten = True
def generate_svg_file(self, filename, font_size=1, cutting_color="red", engraving_color="black", length=None, width=None):
if length!=None:
self.board_length = length
if width!=None:
self.board_width = width
dwg = svgwrite.Drawing(filename,size=(str(self.board_length), str(self.board_width)), fill="none", stroke_width=".005cm")
strips_numA = len(self.paths_flatten[0])
strips_numB = len(self.paths_flatten[1])
strips_num = strips_numA if strips_numA > strips_numB else strips_numB
for i in range(strips_num):
if i< strips_numA:
pts = self.paths_flatten[0][i][:,[0,1]]
dwg.add(dwg.polyline(pts, stroke=cutting_color))
p0 = self.paths_flatten[0][i][0]
p1 = self.paths_flatten[0][i][len(self.paths_flatten[0][i])-2]
p2 = self.paths_flatten[0][i][len(self.paths_flatten[0][i])-3]
vecX = p1-p2
vecY = (p1-p0) * 0.5
vecX /= la.norm(vecX)
pos = p0 + vecY - vecX * self.strips_width * 0.9
dwg.add(dwg.text('A'+str(i), insert=pos, fill=engraving_color, font_family="Code Light" ,font_size=str(font_size)))
pts = self.intersection_points[0][i]
labels = self.intersection_labels[0][i]
for j in range(len(pts)):
pos = pts[j] - vecY * 0.5
dwg.add(dwg.text('c' + str(labels[j]), insert=pos, fill=engraving_color, font_family="Code Light" ,font_size=str(font_size * 0.7)))
if i< strips_numB:
pts = self.paths_flatten[1][i][:,[0,1]]
dwg.add(dwg.polyline(pts, stroke=cutting_color))
p0 = self.paths_flatten[1][i][0]
p1 = self.paths_flatten[1][i][len(self.paths_flatten[1][i])-2]
p2 = self.paths_flatten[1][i][len(self.paths_flatten[1][i])-3]
vecX = p1-p2
vecY = (p1-p0) * 0.5
vecX /= la.norm(vecX)
pos = p0 + vecY - vecX * self.strips_width * 0.9
dwg.add(dwg.text('B'+str(i), insert=pos, fill=engraving_color, font_family="Code Light" ,font_size=str(font_size)))
pts = self.intersection_points[1][i]
labels = self.intersection_labels[1][i]
for j in range(len(pts)):
pos = pts[j] - vecY * 0.5
dwg.add(dwg.text('c' + str(labels[j]), insert=pos, fill=engraving_color, font_family="Code Light" ,font_size=str(font_size * 0.7)))
#Board boundary
points = np.array([[0.,0.],[self.board_length,0.],[self.board_length, self.board_width],[0., self.board_width],[0.,0.]])
dwg.add(dwg.polyline(points, stroke=engraving_color))
dwg.save()

View File

@@ -0,0 +1,219 @@
import numpy as np
from scipy import sparse
from scipy.sparse import linalg
import igl
from smooth_surfaces import *
from utils import *
# -----------------------------------------------------------------------------
# UTILITIES
# -----------------------------------------------------------------------------
def compute_orthogonal_frames(N):
"""Computes an orthonormal frame {e1, e2, e3} at vertices x_i.
Parameters:
- N : np.array (|n|, 3)
The i-th row contains a vector in direction e3 at x_i.
Returns:
- e1: np.array (|n|, 3)
The i-th row contains the axis e1 at vertex x_i.
- e2: np.array (|n|, 3)
The i-th row contains the axis e2 at vertex x_i.
- e3: np.array (|n|, 3)
The i-th row contains the axis e3 at vertex x_i.
"""
e3 = N / np.linalg.norm(N, axis=1, keepdims=True)
e1 = np.zeros(e3.shape)
e1[:, 0] = - e3[:, 1]
e1[:, 1] = e3[:, 0]
e1[np.where((e1[:, 0] == 0) & (e1[:, 1] == 0))[0], 1] = 1
e1 = e1 / np.linalg.norm(e1, axis=1, keepdims=True)
e2 = np.cross(e3, e1)
return e1, e2, e3
def vertex_double_rings(F):
"""Computes double rings of mesh vertices.
Parameters:
- F : np.array (|F|, 3)
The array of triangle faces.
Returns:
- v_i : np.array (n, )
The indices of the central vertices i.
- v_j : np.array (n, )
The indices of the vertices j connected to vertex i by at most two
edges, such that v_j[k] belongs to the double ring of v_i[k].
"""
M = igl.adjacency_matrix(F)
vi, vj = M.nonzero()
N = M[vj]
vii, vjj = N.nonzero()
L = sparse.coo_matrix((np.ones(len(vii)), (vii, np.arange(len(vii)))))
k = np.array(L.sum(axis=1)).flatten().astype('i')
vii = np.repeat(vi, k)
M = sparse.coo_matrix((np.ones(len(vii)), (vii, vjj)), shape=M.shape)
M = M.tolil()
M.setdiag(0)
return M.nonzero()
# -----------------------------------------------------------------------------
# OSCULATING PARABOLOID
# -----------------------------------------------------------------------------
def compute_osculating_paraboloids(V, F, e1, e2, e3):
"""Computes the coefficients of the osculating paraboloid at vertices x_i
in local orthonormal coordinates with base {x_i; e1, e2, e3}, with
eta(x,y) = a x^2 + b y^2 + c xy + d x + e y
through least squares fitting. Try to vectorize this function.
Parameters:
- V : np.array (|V|, 3)
The array of vertices positions.
Contains the global coordinates of the vertex x_i in i-th row
- F : np.array (|F|, 3)
The array of triangle faces.
- e1: np.array (|V|, 3)
The i-th row contains the axis e1 at vertex x_i.
- e2: np.array (|V|, 3)
The i-th row contains the axis e2 at vertex x_i.
- e3: np.array (|V|, 3)
The i-th row contains the axis e3 at vertex x_i.
Returns:
- a : np.array (|V|, 5)
The paraboloid coefficients. i-th row contains the coefficients
[a, b, c, d, e] of the paraboloid at x_i.
"""
# we compute the indices for the double ring vj at each vertex vi
vi, vj = vertex_double_rings(F)
Pj = V[vj] - V[vi]
x = np.einsum('ij,ij->i',Pj, e1[vi])
y = np.einsum('ij,ij->i',Pj, e2[vi])
z = np.einsum('ij,ij->i',Pj, e3[vi])
i = np.arange(vj.shape[0])
i = np.hstack((i,i,i,i,i))
j = 5*vi
j = np.hstack((j,j+1,j+2,j+3,j+4))
data = np.hstack((x**2, y**2, x*y, x,y))
X = sparse.coo_matrix((data,(i,j)), shape=(vj.shape[0],5*len(V)))
X = X.tocsr()
A = X.T.dot(X)
b = X.T.dot(z)
a = sparse.linalg.spsolve(A,b)
a = np.reshape(a,(len(V),5))
return a
def compute_osculating_paraboloid_first_derivatives(a):
"""Computes the first derivatives of the osculating paraboloid at vertices x_i
in local orthonormal coordinates with base {x_i; e1, e2, e3}, with
eta(x,y) = a x^2 + b y^2 + c xy + d x + e y,
evaluated at the point x_i. Try to vectorize this function.
Parameters:
- a : np.array (|V|, 5)
The paraboloid coefficients. i-th row contains the coefficients
[a, b, c, d, e] of the paraboloid at x_i.
Returns:
- x_x : np.array (|V|, 3)
The first derivatives x_x, where the i-th row contains the local (x,y,z)
coordinates of the vector x_x(x_i).
- x_y : np.array (|V|, 3)
The second derivatives x_y, where the i-th row contains the local (x,y,z)
coordinates of the vector x_y(x_i).
"""
x_x = np.column_stack((np.ones(len(a)), np.zeros(len(a)), a[:,3]))
x_y = np.column_stack((np.zeros(len(a)), np.ones(len(a)), a[:,4]))
return x_x, x_y
def compute_osculating_paraboloid_second_derivatives(a):
"""Computes the second derivatives of the osculating paraboloid at vertices x_i
in local orthonormal coordinates with base {x_i; e1, e2, e3}, with
eta(x,y) = a x^2 + b y^2 + c xy + d x + e y,
evaluated at the point x_i. Try to vectorize this function.
Parameters:
- a : np.array (|V|, 5)
The paraboloid coefficients. i-th row contains the coefficients
[a, b, c, d, e] of the paraboloid at x_i.
Returns:
- x_xx : np.array (|V|, 3)
The second derivatives x_xx, where the i-th row contains the local (x,y,z)
coordinates of the vector x_xx(x_i).
- x_xy : np.array (|V|, 3)
The second derivatives x_xy, where the i-th row contains the local (x,y,z)
coordinates of the vector x_xy(x_i).
- x_yy : np.array (|V|, 3)
The second derivatives x_yy, where the i-th row contains the local (x,y,z)
coordinates of the vector x_yy(x_i).
"""
x_xx = np.column_stack((np.zeros(len(a)), np.zeros(len(a)), 2*a[:,0]))
x_xy = np.column_stack((np.zeros(len(a)), np.zeros(len(a)), a[:,2]))
x_yy = np.column_stack((np.zeros(len(a)), np.zeros(len(a)), 2*a[:,1]))
return x_xx, x_xy, x_yy
def compute_mesh_principal_curvatures(V, F):
"""Computes the principal curvatures at mesh vertices v_i through quadratic
fitting.
Parameters:
- V : np.array (|V|, 3)
The array of vertices positions.
Contains the global coordinates of the vertex x_i in i-th row
- F : np.array (|F|, 3)
The array of triangle faces.
Returns:
- k_1 : np.array (n)
The min principal curvature. i-th element contains the curvature
at vertex x_i.
- k_2 : np.array (n)
The max principal curvature. i-th element contains the curvature
at vertex x_i.
- d_1 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_1.
The i-th row contains the global coordinates of d_1(x_i).
- d_2 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_2.
The i-th row contains the global coordinates of d_2(x_i).
"""
# we compute a vertex normal with libigl and use it as local axis e3:
N = igl.per_vertex_normals(V, F)
# then we compute the local axes:
e1, e2, e3 = compute_orthogonal_frames(N)
a = compute_osculating_paraboloids(V,F,e1,e2,e3)
x_x, x_y = compute_osculating_paraboloid_first_derivatives(a)
x_xx, x_xy, x_yy = compute_osculating_paraboloid_second_derivatives(a)
n = compute_surface_normal(x_x, x_y)
I = compute_first_fundamental_form(x_x, x_y)
II = compute_second_fundamental_form(x_xx, x_xy, x_yy, n)
S = compute_shape_operator(I, II)
k_1,k_2, d_1, d_2 = compute_principal_curvatures(S, x_x, x_y)
d_1 = np.einsum('i,ij->ij', d_1[:,0], e1) +\
np.einsum('i,ij->ij', d_1[:,1], e2) +\
np.einsum('i,ij->ij', d_1[:,2], e3)
d_2 = np.einsum('i,ij->ij', d_2[:,0], e1) +\
np.einsum('i,ij->ij', d_2[:,1], e2) +\
np.einsum('i,ij->ij', d_2[:,2], e3)
return k_1, k_2, d_1, d_2

View File

@@ -0,0 +1,423 @@
import numpy as np
# -----------------------------------------------------------------------------
# DERIVATIVES OF PARABOLOID
# -----------------------------------------------------------------------------
def compute_paraboloid_points(P, a, b, c, d, e):
"""Computes the points of the paraboloid x(u,v) = (u, v, z(u,v)) with
z(u,v) = a*u^2 + b*v^2 + c*u*v + d*u + e*v.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- a, b, c, d, e : float
The parameters of the paraboloid.
Returns:
- x : np.array (n, 3)
The points x(P), where the i-th row contains the (x,y,z) coordinates
of the point x(p_i)
"""
n = a*P[:,0]**2 + \
b*P[:,1]**2 + \
c*P[:,0]*P[:,1] + \
d*P[:,0] + \
e*P[:,1]
x = np.dstack((P[:,0],P[:,1],n))[0]
return x
def compute_paraboloid_first_derivatives(P, a, b, c, d, e):
"""Computes the first derivatives of the paraboloid x(u,v) = (u, v, z(u,v))
with z(u,v) = a*u^2 + b*v^2 + c*u*v + d*u + e*v.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- a, b, c, d, e : float
The parameters of the paraboloid.
Returns:
- x_u : np.array (n, 3)
The vectors x_u(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_u(p_i).
- x_v : np.array (n, 3)
The vectors x_v(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_v(p_i).
"""
nu = 2*a*P[:,0] + \
c*P[:,1] + \
d
nv = 2*b*P[:,1] + \
c*P[:,0] + \
e
z = np.zeros(P.shape[0])
o = np.ones(P.shape[0])
x_u = np.dstack((o,z,nu))[0]
x_v = np.dstack((z,o,nv))[0]
return x_u, x_v
def compute_paraboloid_second_derivatives(P, a, b, c, d, e):
"""Computes the second derivatives of the paraboloid x(u,v) = (u, v, z(u,v))
with z(u,v) = a*u^2 + b*v^2 + c*u*v + d*u + e*v.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- a, b, c, d, e : float
The parameters of the paraboloid.
Returns:
- x_uu : np.array (n, 3)
The vectors x_uu(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uu(p_i).
- x_uv : np.array (n, 3)
The vectors x_uv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uv(p_i).
- x_vv : np.array (n, 3)
The vectors x_vv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_vv(p_i).
"""
nuu = np.repeat(2*a, P.shape[0])
nuv = np.repeat( c, P.shape[0])
nvv = np.repeat(2*b, P.shape[0])
z = np.zeros(P.shape[0])
x_uu = np.dstack((z,z,nuu))[0]
x_uv = np.dstack((z,z,nuv))[0]
x_vv = np.dstack((z,z,nvv))[0]
return x_uu, x_uv, x_vv
# -----------------------------------------------------------------------------
# DERIVATIVES OF TORUS
# -----------------------------------------------------------------------------
def compute_torus_points(P, R, r):
"""Computes the second derivatives of a torus.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- R : float
The radius of revolution.
- r : float
The radius of the cross section.
Returns:
- x : np.array (n, 3)
The points x(P), where the i-th row contains the (x,y,z) coordinates
of the point x(p_i)
"""
cosu = np.cos(P[:,0])
sinu = np.sin(P[:,0])
cosv = np.cos(P[:,1])
sinv = np.sin(P[:,1])
fx = (r * cosu+ R) * cosv
fy = (r * cosu+ R) * sinv
fz = r * sinu
x = np.dstack((fx, fy, fz))[0]
return x
def compute_torus_first_derivatives(P, R, r):
"""Computes the second derivatives of a torus.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- R : float
The radius of revolution.
- r : float
The radius of the cross section.
Returns:
- x_u : np.array (n, 3)
The vectors x_u(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_u(p_i).
- x_v : np.array (n, 3)
The vectors x_v(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_v(p_i).
"""
cosu = np.cos(P[:,0])
sinu = np.sin(P[:,0])
cosv = np.cos(P[:,1])
sinv = np.sin(P[:,1])
z = np.zeros(P.shape[0])
fx_u = - r * sinu * cosv
fy_u = - r * sinu * sinv
fz_u = r * cosu
fx_v = -(r * cosu+ R) * sinv
fy_v = (r * cosu+ R) * cosv
fz_v = z
x_u = np.dstack((fx_u, fy_u, fz_u))[0]
x_v = np.dstack((fx_v, fy_v, fz_v))[0]
return x_u, x_v
def compute_torus_second_derivatives(P, R, r):
"""Computes the second derivatives of a torus.
Try to vectorize this function.
Parameters:
- P : np.array (n, 2)
Contains in i-th row the (u, v) coordinates of the i-th parameter point p_i.
- R : float
The radius of revolution.
- r : float
The radius of the cross section.
Returns:
- x_uu : np.array (n, 3)
The vectors x_uu(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uu(p_i).
- x_uv : np.array (n, 3)
The vectors x_uv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_uv(p_i).
- x_vv : np.array (n, 3)
The vectors x_vv(P), where the i-th row contains the (x,y,z) coordinates
of the vector x_vv(p_i).
"""
cosu = np.cos(P[:,0])
sinu = np.sin(P[:,0])
cosv = np.cos(P[:,1])
sinv = np.sin(P[:,1])
z = np.zeros(P.shape[0])
fx_uu = - r * cosu * cosv
fy_uu = - r * cosu * sinv
fz_uu = - r * sinu
fx_uv = (r * sinu) * sinv
fy_uv = -(r * sinu) * cosv
fz_uv = z
fx_vv = -(r * cosu+ R) * cosv
fy_vv = -(r * cosu+ R) * sinv
fz_vv = z
x_uu = np.dstack((fx_uu, fy_uu, fz_uu))[0]
x_uv = np.dstack((fx_uv, fy_uv, fz_uv))[0]
x_vv = np.dstack((fx_vv, fy_vv, fz_vv))[0]
return x_uu, x_uv, x_vv
# -----------------------------------------------------------------------------
# SHAPE OPERATOR
# -----------------------------------------------------------------------------
def compute_first_fundamental_form(x_u, x_v):
"""Computes the first fundamental form I.
Try to vectorize this function.
Parameters:
- x_u : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_u(p_i).
- x_v : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_v(p_i).
Returns:
- I : np.array (n, 2, 2)
The first fundamental forms.
The (i, j, k) position contains the (j, k) element of the first
fundamental form I(p_i).
"""
e00 = np.einsum('lm,ml->m',x_u.T,x_u)
e01 = np.einsum('lm,ml->m',x_u.T,x_v)
e10 = np.einsum('lm,ml->m',x_v.T,x_u)
e11 = np.einsum('lm,ml->m',x_v.T,x_v)
I = np.dstack((e00,e01,e10,e11))[0].reshape((x_u.shape[0],2,2))
return I
def compute_surface_normal(x_u, x_v):
"""Computes the surface normal n.
Try to vectorize this function.
Parameters:
- x_u : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_u(p_i).
- x_v : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_v(p_i).
Returns:
- n : np.array (n, 3)
The surface normals.
The i-th row contains the (x,y,z) coordinates of the vector n(p_i).
"""
exp = np.cross(x_u, x_v)
div = np.linalg.norm(exp, axis=1)
n = exp/div[:,None]
return n
def compute_second_fundamental_form(x_uu, x_uv, x_vv, n):
"""Computes the second fundamental form II.
Try to vectorize this function.
Parameters:
- x_uu : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_uu(p_i).
- x_uv : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_uv(p_i).
- x_vv : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_vv(p_i).
- n : np.array (n, 3)
The surface normals.
The i-th row contains the (x,y,z) coordinates of the vector n(p_i).
Returns:
- II : np.array (n, 2, 2)
The second fundamental forms.
The (i, j, k) position contains the (j, k) element of the second
fundamental form II(p_i).
"""
e00 = np.einsum('lm,ml->m',n.T, x_uu)
e01 = np.einsum('lm,ml->m',n.T, x_uv)
e10 = np.einsum('lm,ml->m',n.T, x_uv)
e11 = np.einsum('lm,ml->m',n.T, x_vv)
II = np.dstack((e00,e01,e10,e11))[0].reshape((n.shape[0],2,2))
return II
def compute_shape_operator(I, II):
"""Computes the shape operator S.
Try to vectorize this function.
Parameters:
- I : np.array (n, 2, 2)
The first fundamental forms.
The (i, j, k) position contains the (j, k) element of the first
fundamental form I(p_i).
- II : np.array (n, 2, 2)
The second fundamental forms.
The (i, j, k) position contains the (j, k) element of the second
fundamental form II(p_i).
Returns:
- S : np.array (n, 2, 2)
The shape operators.
The (i, j, k) position contains the (j, k) element of the shape
operator S(p_i).
"""
Iinv = np.linalg.inv(I)
S = Iinv @ II
return S
# -----------------------------------------------------------------------------
# PRINCIPAL CURVATURES
# -----------------------------------------------------------------------------
def compute_principal_curvatures(S, x_u, x_v):
"""Computes principal curvatures and corresponding principal directions.
Try to vectorize this function.
Parameters:
- S : np.array (n, 2, 2)
The shape operators.
The (i, j, k) position contains the (j, k) element of the shape
operator S(p_i).
- x_u : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_u(p_i).
- x_v : np.array (n, 3)
The i-th row contains the (x,y,z) coordinates of the vector x_v(p_i).
Returns:
- k_1 : np.array (n)
The min principal curvature. i-th element contains the curvature k_1(p_i).
- k_2 : np.array (n)
The max principal curvature. i-th element contains the curvature k_2(p_i).
- e_1 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_1.
The i-th row contains the (x,y,z) coordinates of e_1(p_i).
- e_2 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_2.
The i-th row contains the (x,y,z) coordinates of e_2(p_i).
"""
# this section computes the ordered eigenvalues and eigenvectors of S where
# k_1[i] = min eigenvalue at p_i, k_2[i] = max eigenvalue at p_i,
# bar_e_1[i] = [u, v] components of the eigenvector of k_1,
# bar_e_2[i] = [u, v] components of the eigenvector of k_2
eig = np.linalg.eig(S)
index = np.argsort(eig[0], axis=1)
k_1 = eig[0][np.arange(len(S)), index[:, 0]]
k_2 = eig[0][np.arange(len(S)), index[:, 1]]
bar_e_1 = eig[1][np.arange(len(S)), :, index[:, 0]]
bar_e_2 = eig[1][np.arange(len(S)), :, index[:, 1]]
# Compute the normalized 3D vectors e_1, e_2
J = np.concatenate((x_u,x_v), axis=1).reshape((S.shape[0],2,3))
Je1 = np.einsum('lnm,ln->lm',J, bar_e_1)
Je2 = np.einsum('lnm,ln->lm',J, bar_e_2)
e_1 = Je1/np.linalg.norm(Je1, axis=1)[:,None]
e_2 = Je2/np.linalg.norm(Je2, axis=1)[:,None]
return k_1, k_2, e_1, e_2
# -----------------------------------------------------------------------------
# ASYMPTOTIC DIRECTIONS
# -----------------------------------------------------------------------------
def compute_asymptotic_directions(k_1, k_2, e_1, e_2):
"""Computes principal curvatures and corresponding principal directions.
Try to vectorize this function.
Parameters:
- k_1 : np.array (n)
The min principal curvature. i-th element contains the curvature k_1(p_i).
- k_2 : np.array (n)
The max principal curvature. i-th element contains the curvature k_2(p_i).
- e_1 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_1.
The i-th row contains the (x,y,z) coordinates of e_1(p_i).
- e_2 : np.array (n, 3)
The unitized principal curvature direction corresponding to k_2.
The i-th row contains the (x,y,z) coordinates of e_2(p_i).
Returns:
- a_1 : np.array (n, 3)
The first unitized asymptotic direction. The i-th row contains the
(x,y,z) coordinates of a_2(p_i) if it exists, (0, 0, 0) otherwise.
- a_2 : np.array (n, 3)
The second unitized asymptotic direction. The i-th row contains the
(x,y,z) coordinates of a_2(p_i) if it exists, (0, 0, 0) otherwise.
"""
a_1 = np.zeros((k_1.shape[0],3))
a_2 = np.zeros((k_1.shape[0],3))
k1k2 = k_1*k_2
v1 = np.where(k1k2<=0)
v2 = np.where(k1k2<0)
f = np.zeros((k_1.shape[0]))
ff = np.zeros((k_1.shape[0]))
v3 = np.where((k_1-k_2)!=0)
f[v3] = (k_1[v3]/((k_1 - k_2)[v3]))
ff[v1] = f[v1]
cosT = np.sqrt(1-f)
sinT = np.sqrt(f)
a_1[v1] =(e_1*cosT[:,None] + e_2*sinT[:,None])[v1]
a_2[v2] =(e_1*cosT[:,None] - e_2*sinT[:,None])[v2]
return a_1, a_2

View File

@@ -0,0 +1,52 @@
import igl
import numpy as np
import numpy.linalg as la
import scipy.spatial as ds
from meshplot import plot
from fitting import compute_mesh_principal_curvatures
class Mesh():
def __init__(self, *args):
'''
Inputs:
- filename : str
Path to mesh file.
'''
if isinstance(args[0], str):
# Build vertices and faces from file
self.V, self.F = igl.read_triangle_mesh(args[0])
self.build()
elif len(args)==2:
self.V = args[0]
self.F = args[1]
self.build()
def build(self):
# Calculate principal curvatures
self.K1, self.K2, self.V1, self.V2 = compute_mesh_principal_curvatures(self.V, self.F)
# Calculate normals
self.N = igl.per_vertex_normals(self.V, self.F)
# Build topology
self.edge_vertices, self.face_edges, self.edge_faces = igl.edge_topology(self.V,self.F)
# Build KDTree for topologic queries
self.kd_tree = ds.KDTree(self.V)
def get_closest_vertices(self, point, numNeighbors):
return self.kd_tree.query(point,numNeighbors)
def get_closest_mesh_point(self, point):
D,F,P = igl.point_mesh_squared_distance(point, self.V, self.F)
return F, P
def rotate_vector(v, ang, v1, v2, n):
v1 /= la.norm(v1, axis = -1)
v2 /= la.norm(v2, axis = -1)
sign = np.sign(np.dot(np.cross(v1, v2), n.transpose()))
v2 *= sign * -1
v_arr = igl.rotate_vectors(np.array(v, ndmin=2), np.array([ang], ndmin=2), np.array(v1, ndmin=2), np.array(v2, ndmin=2))
return v_arr

View File

@@ -0,0 +1,165 @@
import igl
import scipy.spatial as ds
import numpy as np
import math
import numpy.linalg as la
from tracer_helper import Mesh, rotate_vector
from tracer_utils import intersection_event, asymptotic_path
class AsymptoticTracer:
def __init__(self, filename, step_size=0.01, num_steps=200):
self.mesh = Mesh(filename)
self.step_size = step_size
self.num_steps = num_steps
# Variables for visualisation
self.flagA = False
self.flagB = False
self.flag_intersections = False
# Main data
self.paths = [np.empty((0,3), float) for i in range(2)]
self.paths_indexes = [[] for i in range(2)]
self.paths_flatten = [[] for i in range(2)]
self.paths_lengths = [[] for i in range(2)]
self.paths_labels = [[] for i in range(2)]
self.intersections = [[] for i in range(2)]
self.samples_indexes = [[] for i in range(2)]
self.intersection_points = np.empty((0,3), float)
def delete_path(self, path_index, first_principal_direction=True):
self.paths_indexes[1-first_principal_direction].pop(path_index)
self.paths_flatten[1-first_principal_direction].pop(path_index)
self.paths_lengths[1-first_principal_direction].pop(path_index)
self.paths_labels[1-first_principal_direction].pop(path_index)
self.intersections[1-first_principal_direction].pop(path_index)
self.samples_indexes[1-first_principal_direction].pop(path_index)
def num_pathsA(self):
return len(self.paths_indexes[0])
def num_pathsB(self):
return len(self.paths_indexes[1])
def generate_asymptotic_path(self, vertex_idx, first_principal_direction, num_neighbors, sampling_dist):
P,A,PP = asymptotic_path(vertex_idx, self.mesh, self.num_steps, self.step_size, first_principal_direction, num_neighbors, sampling_dist)
if len(P)>0:
start_vertex = len(self.paths[1-first_principal_direction])
self.paths[1-first_principal_direction] = np.append(self.paths[1-first_principal_direction], P, axis=0)
self.paths_indexes[1-first_principal_direction].append(np.arange(start_vertex, start_vertex+len(P)))
# Initialize data for flattening
self.intersections[1-first_principal_direction].append(np.empty((0,3), float))
self.paths_lengths[1-first_principal_direction].append(np.zeros(len(P)-1))
self.paths_flatten[1-first_principal_direction].append(np.empty((0,2), float))
self.paths_labels[1-first_principal_direction].append(np.empty((0,2), float))
self.flag_intersections = False
return P, PP
def generate_intersection_network(self):
treeA = ds.KDTree(self.paths[0])
treeB = ds.KDTree(self.paths[1])
strips_numA = len(self.paths_indexes[0])
strips_numB = len(self.paths_indexes[1])
strips_num = strips_numA if strips_numA > strips_numB else strips_numB
self.intersection_points = np.empty((0,3), float)
for i in range(strips_num):
if i< strips_numA:
self.generate_intersection_path(i, treeB, False)
if i< strips_numB:
self.generate_intersection_path(i, treeA, True)
self.flag_intersections = True
return self.intersection_points
def generate_intersection_path(self, pathIndex, tree, second_direction=False):
self.intersections[second_direction][pathIndex] = np.empty((0,3), float)
path_indexesA = self.paths_indexes[second_direction][pathIndex]
self.paths_lengths[second_direction][pathIndex] = np.zeros(len(path_indexesA)-1)
for i in range (len(path_indexesA)-1):
# Get the segment on the first path
origA = self.paths[second_direction][path_indexesA[i]]
endA = self.paths[second_direction][path_indexesA[i+1]]
vecA = endA - origA
# Store the length of the edge
self.paths_lengths[second_direction][pathIndex][i] = la.norm(vecA)
for j in range(len(self.paths_indexes[1-second_direction])):
# Get the KDTree
path_indexesB = self.paths_indexes[1-second_direction][j]
# Query for closest nodes on the second path (Find closest nodes for both ends)
dist, closest_idxB = tree.query([origA,endA], 1)
# Find intersections in both end-nodes
count = len(path_indexesB)
for idx in closest_idxB:
origB = tree.data[idx]
# Check for intersection events with the node following the closest node on the second path
# Break if an intersection is found
if idx in path_indexesB:
local_idx = np.where(path_indexesB==idx)[0][0]
vecB = None
if local_idx<=count-2:
vecB = tree.data[path_indexesB[local_idx+1]] - origB
t, u, inter = intersection_event(origA, vecA, origB, vecB)
if inter==0 and t>=0 and t<=1 and u>=0 and u<=1:
# Store edge index and the parameter where the intersection occured.
p = origA + vecA * t
distance = (self.intersection_points[:,0]-p[0])**2 + (self.intersection_points[:,1]-p[1])**2 + (self.intersection_points[:,2]-p[2])**2
closest_intersection = np.where(distance<1e-3)[0]
if len(closest_intersection)==0: # No duplicate intersection
label = len(self.intersection_points)
self.intersections[second_direction][pathIndex] = np.append(self.intersections[second_direction][pathIndex],np.array([[i,t,label]]), axis=0)
self.intersection_points = np.append(self.intersection_points, np.array([p]), axis=0)
break
else: # Duplicated intersection
label = closest_intersection[0]
self.intersections[second_direction][pathIndex] = np.append(self.intersections[second_direction][pathIndex],np.array([[i,t,label]]), axis=0)
break
# If no intersection is found, check with the node preceding the closest node on the second path
# Break if an intersection is found
if local_idx >= 1:
vecB = tree.data[path_indexesB[local_idx-1]] - origB
t, u, inter = intersection_event(origA, vecA, origB, vecB)
if inter==0 and t>=0 and t<=1 and u>=0 and u<=1:
# Store edge index and the parameter where the intersection occured.
p = origA + vecA * t
distance = (self.intersection_points[:,0]-p[0])**2 + (self.intersection_points[:,1]-p[1])**2 + (self.intersection_points[:,2]-p[2])**2
closest_intersection = np.where(distance<1e-3)[0]
if len(closest_intersection)==0: # No duplicate intersection
label = len(self.intersection_points)
self.intersections[second_direction][pathIndex] = np.append(self.intersections[second_direction][pathIndex],np.array([[i,t,label]]), axis=0)
self.intersection_points = np.append(self.intersection_points, np.array([p]), axis=0)
break
else: # Duplicated intersection
label = closest_intersection[0]
self.intersections[second_direction][pathIndex] = np.append(self.intersections[second_direction][pathIndex],np.array([[i,t,label]]), axis=0)
break

View File

@@ -0,0 +1,324 @@
import igl
import numpy as np
import math
import numpy.linalg as la
from tracer_helper import rotate_vector
def asymptotic_path(idx, mesh, num_steps, step_size, first_principal_direction, num_neighbors, sampling_dist=0):
'''Computes both tracing direction (backward and forward) following an asymptotic path.
Try to compute an asymptotic path with both tracing directions
Inputs:
- idx : int
The index of the vertex on the mesh to start tracing.
- mesh : Mesh
The mesh for tracing.
- num_steps : int
The number of tracing steps.
- step_size : int
The size of the projection at each tracing step.
- first_principal_direction : bool
Indicator for using the first principal curvature to do the tracing.
- num_neighbors : int
Number of closest vertices to consider for avering principal curvatures.
- sampling_distance : float
The distance to sample points on the path (For the design interface - Don't need to be define).
Outputs:
- P : np.array (n, 3)
The ordered set of unique points representing a full asymptotic path.
- A : np.array (n,)
The ordered set of deviated angles in degrees calculated for the asymptotic directions.
- PP : np.array (m,3)
The ordered set of points laying on the path spaced with a given distance (For the design interface).
'''
Pf, Af, PPf = trace(idx, mesh, num_steps, step_size, first_principal_direction, False, num_neighbors, sampling_dist)
Pb, Ab, PPb = trace(idx, mesh, num_steps, step_size, first_principal_direction, True, num_neighbors, sampling_dist)
P = np.concatenate((np.flip(Pb[1:],0), Pf), axis=0)
A = np.concatenate((np.flip(Ab[1:],0), Af), axis=0)
PP = np.concatenate((np.flip(PPb[1:],0), PPf), axis=0)
return P, A, PP
def trace(idx, mesh, num_steps, step_size, first_principal_direction, trace_backwards, num_neighbors, sampling_dist=0):
'''Computes one tracing direction following an asymptotic path.
Try to compute the points on the asymptotic path.
Inputs:
- idx : int
The index of the vertex on the mesh to start tracing.
- mesh : Mesh
The mesh for tracing.
- num_steps : int
The number of tracing steps.
- step_size : int
The size of the projection at each tracing step.
- first_principal_direction : bool
Indicator for using the first principal curvature to do the tracing.
- trace_backwards : bool
Indicator for mirroring the deviated angle
- num_neighbors : int
Number of closest vertices to consider for avering principal curvatures.
- sampling_distance : float
The distance to sample points on the path (For the design interface - Don't need to be define).
Outputs:
- P : np.array (n, 3)
The ordered set of points representing one tracing direction.
- A : np.array (n,)
The ordered set of deviated angles calculated for the asymptotic directions.
- PP : np.array (m,3)
The ordered set of points laying on the path spaced with a given distance (For the design interface).
'''
P = np.empty((0, 3), float)
PP = np.empty((0,3), float)
A = np.array([],float)
#Get the data of the first vertex in the path
pt = mesh.V[idx]
# Store partial distance (For the design interface)
partial_dist = 0
prev_dir = None
while len(P) < num_steps:
# Add the current point to the path
P = np.append(P, np.array([pt]), axis=0)
# Get the averaged principal curvature directions & values
k1_aver, k2_aver, v1_aver, v2_aver, n_aver = averaged_principal_curvatures(pt, mesh, num_neighbors)
# Calculate deviation angle (theta) based on principal curvature values
theta = 2* np.arctan(
np.sqrt(
(
2*np.sqrt(k2_aver*(k2_aver - k1_aver))
+ k1_aver - 2*k2_aver
) / k1_aver
)
)
# Store theta
A = np.append(A, np.array([theta]), axis=0)
# Mirror the angle for tracing backwards. Use trace_backwards indicator
if trace_backwards:
theta -= math.pi
if(prev_dir is not None and np.dot(prev_dir,v1_aver)<0):
v1_aver = -v1_aver
if(prev_dir is not None and np.dot(prev_dir,v2_aver)<0):
v2_aver = -v2_aver
# Rotate principal curvature direction to get asymptotic direction. Use first_principal_direction indicator
a_dir = None
if first_principal_direction:
a_dir = rotate_vector(v1_aver, theta, v1_aver, v2_aver, n_aver)
else:
a_dir = rotate_vector(v1_aver, -theta, v1_aver, v2_aver, n_aver)
# Check for anticlastic surface-regions
if (k1_aver * k2_aver) > 0:
print("Anticlastic")
break
# Check for valid asymptotic direction and unitize
if(np.linalg.norm(a_dir)<0):
print("Invalid Asymptotic Direction")
break
a_dir = a_dir / np.linalg.norm(a_dir)
# Prevent the tracer to go in the opposite direction
if prev_dir is not None and np.dot(prev_dir, a_dir)<0:
a_dir = prev_dir
else:
prev_dir = a_dir
# Scale the asymptotic direction to the given step-size
a_dir = a_dir * step_size
# Compute edge-point
edge_point, is_boundary_edge = find_edge_point(mesh, pt, a_dir)
# Check for boundaries
if is_boundary_edge:
P = np.append(P, np.array([edge_point]), axis=0)
print("Hit Boundary")
break
# Check for duplicated points
if (np.any(np.linalg.norm(P-edge_point,axis=1)<1e-6)):
print("Duplicate Point")
break
# Store sampling points (For the design interface)
if sampling_dist>0:
partial_dist += la.norm(edge_point-pt)
if partial_dist >= sampling_dist :
partial_dist = 0
PP = np.append(PP, np.array([edge_point]), axis=0)
pt = edge_point
return P, A, PP
def averaged_principal_curvatures(pt, mesh, num_neighbors=2, eps=1e-6):
'''Computes inverse weighted distance average of principal curvatures of a given mesh-point
on the basis of the two closest vertices.
Try to compute values, directions and normal at the given query point.
Inputs:
- pt : np.array (3,)
The query point position.
- mesh : Mesh
The mesh for searching nearest vertices.
- num_neighbors : int
Number of closest vertices to consider for avering.
- eps : float
The distance tolerance to consider whether the given point and a mesh-vertex are coincident.
Outputs:
- k_1 : np.array (n)
The min principal curvature average at the given query point.
- k_2 : np.array (n)
The max principal curvature average at the given query point.
- v1_aver : np.array (3,)
The unitized min principal curvature direction average at the given query point.
- v2_aver : np.array (3,)
The unitized max principal curvature direction average at the given query point.
- n_aver : np.array (3,)
The unitized normal average at the given query point.
'''
# Get the closest vertices and distances to the query point
# Use these data to compute principal curvature weighted averages.
dist, neighbors = mesh.get_closest_vertices(pt, num_neighbors)
if(np.any(dist <= eps)):
n = neighbors[dist <= eps][0]
return mesh.K1[n], mesh.K2[n], mesh.V1[n], mesh.V2[n], mesh.N[n]
sidx = np.argsort(dist)
dist,neighbors = dist[sidx][:2], neighbors[sidx][:2]
w_dist = 1/dist
k1_aver = np.average(mesh.K1[neighbors],weights=w_dist)
k2_aver = np.average(mesh.K2[neighbors],weights=w_dist)
v1_aver = np.average(mesh.V1[neighbors],weights=w_dist, axis=0)
v2_aver = np.average(mesh.V2[neighbors],weights=w_dist, axis=0)
n_aver = np.average(mesh.N[neighbors],weights=w_dist, axis=0)
v1_aver /= np.linalg.norm(v1_aver)
v2_aver /= np.linalg.norm(v2_aver)
n_aver /= np.linalg.norm(n_aver)
# print(v1_aver, neighbors, mesh.V1[neighbors])
return k1_aver, k2_aver, v1_aver, v2_aver, n_aver
def find_edge_point(mesh, a_orig, a_dir):
'''Computes the point where a mesh-edge intersects with the asymptotic projection.
Try to compute the edge-point resulting from this intersection.
Inputs:
- mesh : Mesh
The mesh for searching edge intersections.
- a_orig : np.array (3,)
The start position of the asymptotic projection.
- a_dic : np.array (3,)
The direction of the asymptotic projection.
Outputs:
- edge_point : np.array (3,)
The position of the edge-point.
- is_boundary_point : bool
Indicator for whether the edge-point is at the boundary of the mesh.
'''
# Get the closest face-index and mesh-point (point laying on the mesh)
proj_pt = a_orig+a_dir
face_index, mesh_point = mesh.get_closest_mesh_point(proj_pt)
# Update the projection vector with the position of the mesh-point
a_dir = mesh_point - a_orig
# If the mesh-point is equal to the starting point, return flag for boundary vertex.
if la.norm(a_dir)==0:
return mesh_point, True
# Unitize projection vector
a_dir /= la.norm(a_dir)
# Initialize variables
edge_point = mesh_point
is_boundary_point = False
prev_projection_param = 0
# Find the required edge-point by computing intersections between the edge-segments of the face and the asymptotic-segment.
# Different intersection events need to be considered.
edges = mesh.face_edges[face_index]
for e_idx in edges:
e = mesh.edge_vertices[e_idx]
e_orig = mesh.V[e[0]]
e_dir = mesh.V[e[1]]-e_orig
is_boundary_edge = np.any(mesh.edge_faces[e_idx]== -1)
edge_param, projection_param, intersection = intersection_event(e_orig, e_dir, a_orig, a_dir)
# Find the edge-point
if intersection == 1:
continue
elif projection_param>prev_projection_param:
is_boundary_point = is_boundary_edge
prev_projection_param = projection_param
edge_point = e_orig + edge_param * e_dir
return edge_point, is_boundary_point
def intersection_event(a_orig, a_dir, b_orig, b_dir, eps=1e-6):
'''Computes the intersection event between segments A and B.
Try to compute the intersection event.
Inputs:
- a_orig : np.array (3,)
The start position of segment A.
- a_dic : np.array (3,)
The direction of the segment A.
- b_orig : np.array (3,)
The start position of segment B.
- b_dic : np.array (3,)
The direction of the segment B.
- eps : float
The tolerance for determining intersections.
Outputs:
- t : float
The parameter on segment A where the intersection occurred.
- u : float
The parameter on segment B where the intersection occurred.
- E : int
Indicator for the type of intersection event.
Returns 0 for all intersection events.
Returns 1 for collinearity.
'''
d_dir = a_dir - b_dir
d_orig = a_orig - b_orig
d = -np.cross(a_dir, b_dir)
dv = np.linalg.norm(d)**2
if(dv<=eps):
return None, None, 1
t = np.dot(np.cross(d_orig, b_dir), d)/ dv
u = np.dot(np.cross(d_orig, a_dir), d)/ dv
E = (t<0 or t>1) or (u<0 or u>1)
return t,u,E

View File

@@ -0,0 +1 @@
#This file exists only for backward compatibility.

View File

@@ -0,0 +1,101 @@
import time
import pytest
import json
import sys
import igl
import numpy as np
sys.path.append('../')
sys.path.append('../src')
import json
from tracer_utils import intersection_event, find_edge_point,averaged_principal_curvatures, trace
from tracer_helper import Mesh
eps=1e-6
with open('test_data.json', 'r') as infile:
homework_data = json.load(infile)
@pytest.mark.timeout(0.5)
@pytest.mark.parametrize("data", homework_data[0])
def test_intersection_event(data):
ground_truth_t1, ground_truth_u1, ground_truth_E1, a1_orig, a1_dir, b1_orig, b1_dir, epsilon = data
a1_orig = np.array(a1_orig, dtype = float)
a1_dir = np.array(a1_dir, dtype = float)
b1_orig = np.array(b1_orig, dtype = float)
b1_dir = np.array(b1_dir, dtype = float)
student_t1, student_u1, student_E1 = intersection_event(a1_orig, a1_dir, b1_orig, b1_dir, epsilon)
if (ground_truth_t1 == None):
assert ground_truth_t1 == student_t1
assert ground_truth_u1 == student_u1
assert ground_truth_E1 == student_E1
else:
assert np.linalg.norm(ground_truth_t1 - student_t1) < eps
assert np.linalg.norm(ground_truth_u1 - student_u1) < eps
assert np.linalg.norm(ground_truth_E1 - student_E1) < eps
@pytest.mark.timeout(0.5)
def test_find_edge_point():
ground_truth_edge_point, ground_truth_is_boundary_point, v, f, a3_orig, a3_dir = homework_data[1]
ground_truth_edge_point = np.array(ground_truth_edge_point, dtype=float)
v = np.array(v, dtype=float)
f = np.array(f, dtype=int)
a3_orig = np.array(a3_orig, dtype=float)
a3_dir = np.array(a3_dir, dtype=float)
m = Mesh(v, f)
student_edge_point, student_is_boundary_point = find_edge_point(m, a3_orig, a3_dir)
assert np.linalg.norm(ground_truth_edge_point - student_edge_point) < eps
assert ground_truth_is_boundary_point == student_is_boundary_point
@pytest.mark.timeout(0.5)
def test_averaged_principal_curvatures():
ground_truth_k1,ground_truth_k2,ground_truth_v1,ground_truth_v2,ground_truth_n, a4_orig, v, f, num_neighbors, epsilon = homework_data[2]
ground_truth_k1 = np.array(ground_truth_k1, dtype=float)
ground_truth_k2 = np.array(ground_truth_k2, dtype=float)
ground_truth_v1 = np.array(ground_truth_v1, dtype=float)
ground_truth_v2 = np.array(ground_truth_v2, dtype=float)
ground_truth_n = np.array(ground_truth_n, dtype=float)
a4_orig = np.array(a4_orig, dtype=float)
v = np.array(v, dtype=float)
f = np.array(f, dtype=int)
m = Mesh(v, f)
student_k1,student_k2,student_v1,student_v2,student_n = averaged_principal_curvatures(a4_orig, m, num_neighbors, epsilon)
assert np.linalg.norm(ground_truth_k1 - student_k1) < eps
assert np.linalg.norm(ground_truth_k2 - student_k2) < eps
assert np.linalg.norm(ground_truth_v1 - student_v1) < eps
assert np.linalg.norm(ground_truth_v2 - student_v2) < eps
assert np.linalg.norm(ground_truth_n - student_n) < eps
@pytest.mark.timeout(0.5)
def test_trace_1():
ground_truth_P1, ground_truth_A1, ground_truth_PP1, vertex_idx, v, f, num_steps, epsilon, backward_trace, num_neighbors = homework_data[3]
ground_truth_P1 = np.array(ground_truth_P1, dtype=float)
ground_truth_A1 = np.array(ground_truth_A1, dtype=float)
ground_truth_PP1 = np.empty(ground_truth_PP1, dtype=float)
v = np.array(v, dtype=float)
f = np.array(f, dtype=int)
m = Mesh(v, f)
student_P1, student_A1, student_PP1 = trace(vertex_idx, m, num_steps, epsilon, True, backward_trace, num_neighbors)
assert np.linalg.norm(ground_truth_P1 - student_P1) < eps
assert np.linalg.norm(ground_truth_A1 - student_A1) < eps
assert np.linalg.norm(ground_truth_PP1 - student_PP1) < eps
@pytest.mark.timeout(0.5)
def test_trace_2():
ground_truth_P1, ground_truth_A1, ground_truth_PP1, vertex_idx, v, f, num_steps, epsilon, backward_trace, num_neighbors = homework_data[4]
ground_truth_P1 = np.array(ground_truth_P1, dtype=float)
ground_truth_A1 = np.array(ground_truth_A1, dtype=float)
ground_truth_PP1 = np.empty(ground_truth_PP1, dtype=float)
v = np.array(v, dtype=float)
f = np.array(f, dtype=int)
m = Mesh(v, f)
student_P1, student_A1, student_PP1 = trace(vertex_idx, m, num_steps, epsilon, False, backward_trace, num_neighbors)
assert np.linalg.norm(ground_truth_P1 - student_P1) < eps
assert np.linalg.norm(ground_truth_A1 - student_A1) < eps
assert np.linalg.norm(ground_truth_PP1 - student_PP1) < eps

File diff suppressed because one or more lines are too long