From 3d1b04a5712b6db80fae13d7208ef12da06612d2 Mon Sep 17 00:00:00 2001 From: sth-v Date: Sat, 26 Sep 2026 03:21:33 +0300 Subject: [PATCH 1/2] case18-19 --- examples/ssx/_case_19_data.py | 3619 +++++++++++++++++++++++++++++++++ examples/ssx/case_18.py | 201 ++ examples/ssx/case_19.py | 18 + 3 files changed, 3838 insertions(+) create mode 100644 examples/ssx/_case_19_data.py create mode 100644 examples/ssx/case_18.py create mode 100644 examples/ssx/case_19.py diff --git a/examples/ssx/_case_19_data.py b/examples/ssx/_case_19_data.py new file mode 100644 index 00000000..5fcf49fd --- /dev/null +++ b/examples/ssx/_case_19_data.py @@ -0,0 +1,3619 @@ +import numpy as np +from mmcore.nurbs._nurbs_eval import NURBSSurfaceTuple + + +surf1 = NURBSSurfaceTuple( + order_u=4, + order_v=3, + knot_u=np.array([ 0. , 0. , 0. , 0. , 1.27763961, + 2.52081559, 3.72960848, 4.90410589, 6.04440335, 6.60175934, + 7.15060524, 7.69095565, 8.2228259 , 8.74623203, 9.26119091, + 9.76772021, 10.26583853, 10.75556542, 11.23692145, 11.70992828, + 12.17460875, 12.63098693, 13.07908824, 13.51893954, 13.95056921, + 14.37400732, 14.78928569, 15.19643804, 15.5955002 , 15.98651018, + 16.36950839, 16.74453787, 17.11164441, 17.47087687, 17.82228738, + 18.16593162, 18.50186914, 18.83016371, 19.15088361, 19.46410211, + 19.76989786, 20.06835539, 20.3595656 , 20.64362637, 20.92064314, + 21.19072961, 21.45400846, 21.71061215, 21.96068371, 22.2043777 , + 22.44186113, 22.67331444, 22.89893256, 23.11892592, 23.33352148, + 23.54296378, 23.7475158 , 23.94745986, 24.14309817, 24.33475336, + 24.52276851, 24.70750701, 24.88935187, 25.06870463, 25.24598375, + 25.42162253, 25.59606645, 25.7697702 , 25.94319428, 26.11680143, + 26.2910529 , 26.4664049 , 26.6433051 , 26.82218955, 27.00348003, + 27.18758175, 27.3748817 , 27.56574743, 27.76052631, 27.95954522, + 28.16311063, 28.37150896, 28.58500717, 28.80385357, 29.02827873, + 29.25849643, 29.49470476, 29.7370871 , 29.98581318, 30.24104008, + 30.50291317, 30.77156704, 31.04712635, 31.32970661, 31.61941494, + 31.91635072, 32.22060629, 32.53226746, 32.85141405, 33.17812042, + 33.51245588, 33.85448509, 34.20426845, 34.56186244, 34.92731991, + 35.30069035, 35.68202021, 36.07135307, 36.46872986, 36.8741891 , + 37.28776705, 37.70949785, 38.13941372, 38.57754508, 39.02392065, + 39.4785676 , 39.94151164, 40.41277712, 40.89238713, 41.38036357, + 41.87672723, 42.38149787, 42.89469426, 43.4163343 , 43.94643499, + 44.48501257, 45.03208248, 45.03208248, 45.03208248, 45.03208248]), + knot_v=np.array([ 0. , 0. , 0. , 5.66429155, 5.66429155, + 11.32858311, 11.32858311, 16.99287466, 16.99287466, 22.65716622, + 22.65716622, 22.65716622]), + control_points=np.array([[[-138.85817919, 42.39394798, 0. ], + [-138.85817919, 42.39394798, -3.606 ], + [-140.07651949, 39. , -3.606 ], + [-141.2948598 , 35.60605202, -3.606 ], + [-141.2948598 , 35.60605202, -0. ], + [-141.2948598 , 35.60605202, 3.606 ], + [-140.07651949, 39. , 3.606 ], + [-138.85817919, 42.39394798, 3.606 ], + [-138.85817919, 42.39394798, 0. ]], + + [[-138.44936989, 42.24719533, -0.00000015], + [-138.45147434, 42.24795079, -3.60600014], + [-139.67781871, 38.85687612, -3.60600013], + [-140.90416309, 35.46580145, -3.60600012], + [-140.90205863, 35.46504599, -0.00000012], + [-140.89995417, 35.46429053, 3.60599988], + [-139.6736098 , 38.8553652 , 3.60599986], + [-138.44726543, 42.24643987, 3.60599985], + [-138.44936989, 42.24719533, -0.00000015]], + + [[-137.64317111, 41.95457435, -0.00079606], + [-137.64958586, 41.95689356, -3.60679198], + [-138.89232396, 38.57176644, -3.60677647], + [-140.13506206, 35.18663932, -3.60676096], + [-140.12864731, 35.18432011, -0.00076503], + [-140.12223256, 35.1820009 , 3.60523089], + [-138.87949447, 38.56712802, 3.60521538], + [-137.63675637, 41.95225513, 3.60519986], + [-137.64317111, 41.95457435, -0.00079606]], + + [[-136.45135425, 41.5117569 , -0.00450446], + [-136.46467349, 41.51664023, -3.6104792 ], + [-137.73367208, 38.14126547, -3.61038314], + [-139.00267067, 34.76589071, -3.61028708], + [-138.98935143, 34.76100738, -0.00431233], + [-138.97603219, 34.75612405, 3.60166241], + [-137.7070336 , 38.13149881, 3.60156634], + [-136.43803501, 41.50687356, 3.60147028], + [-136.45135425, 41.5117569 , -0.00450446]], + + [[-135.29409728, 41.07122389, -0.01071759], + [-135.31469461, 41.07887635, -3.61665361], + [-136.61137464, 37.71403366, -3.61641027], + [-137.90805466, 34.34919098, -3.61616693], + [-137.88745733, 34.34153852, -0.01023091], + [-137.86686 , 34.33388606, 3.59570511], + [-136.57017997, 37.69872875, 3.59546177], + [-135.27349995, 41.06357143, 3.59521843], + [-135.29409728, 41.07122389, -0.01071759]], + + [[-134.17064145, 40.6326427 , -0.01945037], + [-134.19892427, 40.64329382, -3.62532705], + [-135.5248352 , 37.28985624, -3.62485804], + [-136.85074613, 33.93641866, -3.62438902], + [-136.82246332, 33.92576754, -0.01851233], + [-136.7941805 , 33.91511641, 3.58736435], + [-135.46826957, 37.26855399, 3.58689533], + [-134.14235863, 40.62199157, 3.58642632], + [-134.17064145, 40.6326427 , -0.01945037]], + + [[-133.25616336, 40.26615997, -0.02890553], + [-133.29126498, 40.27954217, -3.6347121 ], + [-134.64311049, 36.93649196, -3.63397644], + [-135.994956 , 33.59344175, -3.63324078], + [-135.95985438, 33.58005954, -0.0274342 ], + [-135.92475276, 33.56667734, 3.57837237], + [-134.57290725, 36.90972755, 3.57763671], + [-133.22106174, 40.25277776, 3.57690105], + [-133.25616336, 40.26615997, -0.02890553]], + + [[-132.54143871, 39.97374105, -0.03777731], + [-132.58224128, 39.98945533, -3.64351322], + [-133.95576975, 36.65527489, -3.64250878], + [-135.32929822, 33.32109445, -3.64150434], + [-135.28849565, 33.30538017, -0.03576843], + [-135.24769308, 33.2896659 , 3.56996748], + [-133.87416461, 36.62384634, 3.56896304], + [-132.50063613, 39.95802678, 3.5679586 ], + [-132.54143871, 39.97374105, -0.03777731]], + + [[-132.01789501, 39.75653106, -0.04502082], + [-132.06306472, 39.77405691, -3.65069638], + [-133.45320311, 36.44676659, -3.64946239], + [-134.8433415 , 33.11947628, -3.64822841], + [-134.79817179, 33.10195043, -0.04255285], + [-134.75300209, 33.08442458, 3.5631227 ], + [-133.3628637 , 36.4117149 , 3.56188872], + [-131.97272531, 39.73900522, 3.56065474], + [-132.01789501, 39.75653106, -0.04502082]], + + [[-131.50282171, 39.53977036, -0.0529056 ], + [-131.55248681, 39.55918772, -3.65851242], + [-132.95972291, 36.23909153, -3.65701699], + [-134.36695902, 32.91899534, -3.65552157], + [-134.31729393, 32.89957799, -0.04991475], + [-134.26762884, 32.88016063, 3.55569207], + [-132.86039273, 36.20025682, 3.55419664], + [-131.45315662, 39.52035301, 3.55270122], + [-131.50282171, 39.53977036, -0.0529056 ]], + + [[-130.99604627, 39.32337522, -0.06143704], + [-131.05034179, 39.34476945, -3.66696598], + [-132.47518921, 36.03219209, -3.6651744 ], + [-133.90003663, 32.71961473, -3.66338281], + [-133.84574112, 32.6982205 , -0.05785386], + [-133.7914456 , 32.67682627, 3.54767509], + [-132.36659818, 35.98940363, 3.5458835 ], + [-130.94175076, 39.301981 , 3.54409191], + [-130.99604627, 39.32337522, -0.06143704]], + + [[-130.49781435, 39.10744077, -0.07061341], + [-130.55687844, 39.13090134, -3.67605462], + [-131.99986262, 35.82618309, -3.67392933], + [-133.44284681, 32.52146485, -3.67180405], + [-133.38378272, 32.49800428, -0.06636283], + [-133.32471862, 32.47454371, 3.53907838], + [-131.88173444, 35.77926195, 3.53695309], + [-130.43875026, 39.08398019, 3.5348278 ], + [-130.49781435, 39.10744077, -0.07061341]], + + [[-130.00784927, 38.89183722, -0.08044226], + [-130.0718283 , 38.91746017, -3.68578498], + [-131.53350595, 35.62096628, -3.68328506], + [-132.9951836 , 32.32447239, -3.68078514], + [-132.93120457, 32.29884945, -0.07544243], + [-132.86722553, 32.2732265 , 3.52990028], + [-131.40554788, 35.56972039, 3.52740037], + [-129.94387023, 38.86621428, 3.52490045], + [-130.00784927, 38.89183722, -0.08044226]], + + [[-129.52608861, 38.67652102, -0.09092883], + [-129.59513581, 38.70440868, -3.69616133], + [-131.07608965, 35.41652839, -3.69324223], + [-132.5570435 , 32.12864811, -3.69032312], + [-132.4879963 , 32.10076045, -0.08509062], + [-132.4189491 , 32.07287279, 3.52014188], + [-130.93799526, 35.36075307, 3.51722277], + [-129.45704142, 38.64863335, 3.51430367], + [-129.52608861, 38.67652102, -0.09092883]], + + [[-129.05288638, 38.46163894, -0.10206823], + [-129.12715731, 38.49189825, -3.70717788], + [-130.62797909, 35.21303828, -3.70379151], + [-132.12880086, 31.9341783 , -3.70040514], + [-132.05452992, 31.90391899, -0.09529549], + [-131.98025899, 31.87365968, 3.50981415], + [-130.47943721, 35.15251966, 3.50642778], + [-128.97861544, 38.43137963, 3.50304141], + [-129.05288638, 38.46163894, -0.10206823]], + + [[-128.58782888, 38.24699049, -0.11387334], + [-128.66749009, 38.2797372 , -3.71884628], + [-130.18881321, 35.01033776, -3.71493997], + [-131.71013632, 31.74093831, -3.71103367], + [-131.63047511, 31.70819161, -0.10606072], + [-131.55081389, 31.67544491, 3.49891222], + [-130.02949078, 34.94484435, 3.49500591], + [-128.50816766, 38.21424379, 3.49109961], + [-128.58782888, 38.24699049, -0.11387334]], + + [[-128.13096666, 38.03257911, -0.12634778], + [-128.21619125, 38.06793623, -3.73116895], + [-129.75867406, 34.80846523, -3.7266854 ], + [-131.30115688, 31.54899424, -3.72220186], + [-131.21593229, 31.51363711, -0.11738069], + [-131.13070769, 31.47827999, 3.48744049], + [-129.58822488, 34.73775099, 3.48295694], + [-128.04574207, 37.99722199, 3.47847339], + [-128.13096666, 38.03257911, -0.12634778]], + + [[-127.68250502, 37.81848634, -0.13948963], + [-127.77347056, 37.85658356, -3.74414271], + [-129.33778845, 34.60753422, -3.73901987], + [-130.90210634, 31.35848488, -3.73389702], + [-130.8111408 , 31.32038767, -0.12924393], + [-130.72017526, 31.28229045, 3.47540915], + [-129.15585737, 34.53133978, 3.4702863 ], + [-127.59153948, 37.78038912, 3.46516345], + [-127.68250502, 37.81848634, -0.13948963]], + + [[-127.2421 , 37.60452917, -0.15331361], + [-127.33899595, 37.64550684, -3.7577807 ], + [-128.92586953, 34.40741302, -3.75195046], + [-130.5127431 , 31.1693192 , -3.74612022], + [-130.41584715, 31.12834152, -0.14165312], + [-130.3189512 , 31.08736385, 3.46281397], + [-128.73207762, 34.32545767, 3.45698373], + [-127.14520404, 37.56355149, 3.45115348], + [-127.2421 , 37.60452917, -0.15331361]], + + [[-126.80992062, 37.39076773, -0.16781986], + [-126.91294212, 37.43477447, -3.77208152], + [-128.52311356, 34.20820137, -3.76546995], + [-130.133285 , 30.98162827, -3.75885837], + [-130.03026349, 30.93762153, -0.15459671], + [-129.92724199, 30.89361478, 3.44966496], + [-128.31707055, 34.12018788, 3.44305338], + [-126.70689912, 37.34676098, 3.4364418 ], + [-126.80992062, 37.39076773, -0.16781986]], + + [[-126.38576478, 37.17707858, -0.18302097], + [-126.4951181 , 37.22427451, -3.7870559 ], + [-128.12937192, 34.00983113, -3.77958198], + [-129.76362574, 30.79538776, -3.77210805], + [-129.65427242, 30.74819183, -0.16807312], + [-129.54491911, 30.7009959 , 3.43596181], + [-127.91066529, 33.91543927, 3.42848788], + [-126.27641147, 37.12988265, 3.42101396], + [-126.38576478, 37.17707858, -0.18302097]], + + [[-125.96984144, 36.96354214, -0.1989156 ], + [-126.08573829, 37.01409669, -3.80270068], + [-127.7448797 , 33.81242747, -3.79427647], + [-129.40402112, 30.61075824, -3.78585226], + [-129.28812427, 30.56020369, -0.18206718], + [-129.17222743, 30.50964914, 3.4217179 ], + [-127.51308601, 33.71131837, 3.41329369], + [-125.85394459, 36.91298759, 3.40486947], + [-125.96984144, 36.96354214, -0.1989156 ]], + + [[-125.56194127, 36.75002611, -0.21551791], + [-125.68460536, 36.80412206, -3.81902778], + [-127.36948529, 33.61592216, -3.80955683], + [-129.05436521, 30.42772227, -3.80008589], + [-128.93170111, 30.37362632, -0.19657602], + [-128.80903702, 30.31953037, 3.40693385], + [-127.12415709, 33.50773027, 3.39746291], + [-125.43927717, 36.69593016, 3.38799196], + [-125.56194127, 36.75002611, -0.21551791]], + + [[-125.16199123, 36.53645882, -0.23283912], + [-125.29165711, 36.5942926 , -3.83604601], + [-127.00316755, 33.42030912, -3.8254227 ], + [-128.71467799, 30.24632564, -3.81479939], + [-128.58501211, 30.18849186, -0.2115925 ], + [-128.45534623, 30.13065809, 3.39161438], + [-126.74383579, 33.30464157, 3.38099107], + [-125.03232535, 36.47862505, 3.37036776], + [-125.16199123, 36.53645882, -0.23283912]], + + [[-124.77017297, 36.32290638, -0.25087903], + [-124.90708145, 36.38468647, -3.85375273], + [-126.64613837, 33.22571237, -3.84186219], + [-128.38519529, 30.06673827, -3.82997166], + [-128.2482868 , 30.00495818, -0.22709796], + [-128.11137831, 29.94317809, 3.37577575], + [-126.3723214 , 33.10215219, 3.36388521], + [-124.63326448, 36.2611263 , 3.35199467], + [-124.77017297, 36.32290638, -0.25087903]], + + [[-124.38618387, 36.1091676 , -0.26966054], + [-124.53059141, 36.17512063, -3.87216775], + [-126.29817014, 33.03201787, -3.85888333], + [-128.06574888, 29.8889151 , -3.8455989 ], + [-127.92134134, 29.82296207, -0.24309168], + [-127.77693381, 29.75700904, 3.35941553], + [-126.00935507, 32.9001118 , 3.34613111], + [-124.24177633, 36.04321456, 3.33284668], + [-124.38618387, 36.1091676 , -0.26966054]], + + [[-124.01018213, 35.89528968, -0.28918601], + [-124.1623525 , 35.96565702, -3.89129044], + [-125.95945633, 32.83934361, -3.87647408], + [-127.75656017, 29.7130302 , -3.86165772], + [-127.6043898 , 29.64266286, -0.25955328], + [-127.45221943, 29.57229552, 3.34255115], + [-125.65511559, 32.69860893, 3.32773479], + [-123.85801176, 35.82492234, 3.31291843], + [-124.01018213, 35.89528968, -0.28918601]], + + [[-123.64192033, 35.68108647, -0.30947954], + [-123.80213323, 35.75613034, -3.91114115], + [-125.629826 , 32.6476036 , -3.89464055], + [-127.45751876, 29.53907687, -3.87813995], + [-127.29730585, 29.464033 , -0.27647834], + [-127.13709294, 29.38898912, 3.32518327], + [-125.30940018, 32.49751586, 3.30868267], + [-123.48170742, 35.6060426 , 3.29218207], + [-123.64192033, 35.68108647, -0.30947954]], + + [[-123.281561 , 35.46660277, -0.33054447], + [-123.45010367, 35.54660281, -3.93171957], + [-125.30947778, 32.45692634, -3.91336858], + [-127.16885189, 29.36724986, -3.8950176 ], + [-127.00030922, 29.28724982, -0.2938425 ], + [-126.83176655, 29.20724978, 3.3073326 ], + [-124.97239244, 32.29692625, 3.28898162], + [-123.11301833, 35.38660273, 3.27063063], + [-123.281561 , 35.46660277, -0.33054447]], + + [[-122.92884041, 35.25162543, -0.35241013], + [-123.10601761, 35.33688625, -3.95305042], + [-124.99823223, 32.26721858, -3.93266532], + [-126.89044686, 29.19755091, -3.91228022], + [-126.71326965, 29.11229008, -0.31163993], + [-126.53609245, 29.02702926, 3.28900035], + [-124.64387783, 32.09669693, 3.26861525], + [-122.7516632 , 35.1663646 , 3.24823015], + [-122.92884041, 35.25162543, -0.35241013]], + + [[-122.58399829, 35.03624033, -0.37507656], + [-122.7701204 , 35.12708603, -3.9751294 ], + [-124.69635602, 32.07865987, -3.95251 ], + [-126.62259164, 29.0302337 , -3.92989061], + [-126.43646952, 28.93938799, -0.32983777], + [-126.25034741, 28.84854228, 3.27021506], + [-124.3241118 , 31.89696845, 3.24759567], + [-122.39787618, 34.94539462, 3.22497628], + [-122.58399829, 35.03624033, -0.37507656]], + + [[-122.24670615, 34.82017682, -0.39858155], + [-122.44210355, 34.91696187, -3.99798857], + [-124.40361671, 31.89112536, -3.97291289], + [-126.36512987, 28.86528886, -3.94783721], + [-126.16973247, 28.7685038 , -0.34843019], + [-125.97433507, 28.67171875, 3.25097683], + [-124.01282191, 31.69755526, 3.22590115], + [-122.05130876, 34.72339176, 3.20082547], + [-122.24670615, 34.82017682, -0.39858155]], + + [[-121.91700691, 34.60337991, -0.42294253], + [-122.12202124, 34.70648619, -4.02163959], + [-124.12011138, 31.70469178, -3.99386362], + [-126.11820153, 28.70289738, -3.96608766], + [-125.91318719, 28.5997911 , -0.3673906 ], + [-125.70817286, 28.49668482, 3.23130645], + [-123.71008272, 31.49847923, 3.20353049], + [-121.71199257, 34.50027363, 3.17575452], + [-121.91700691, 34.60337991, -0.42294253]], + + [[-121.59501319, 34.38584553, -0.4481705 ], + [-121.80999397, 34.49568224, -4.04608738], + [-123.8459904 , 31.51948627, -4.01534409], + [-125.88198683, 28.54329031, -3.98460079], + [-125.66700605, 28.43345361, -0.38668392], + [-125.45202527, 28.3236169 , 3.21123296], + [-123.41602884, 31.29981287, 3.18048966], + [-121.38003241, 34.27600883, 3.14974637], + [-121.59501319, 34.38584553, -0.4481705 ]], + + [[-121.28028883, 34.16717822, -0.47432459], + [-121.50561129, 34.28419716, -4.07138281], + [-123.58094119, 31.33531802, -4.03737374], + [-125.65627109, 28.38643888, -4.00336466], + [-125.43094863, 28.26941995, -0.40630644], + [-125.20562617, 28.15240102, 3.19075179], + [-123.13029627, 31.10128015, 3.15674271], + [-121.05496637, 34.05015929, 3.12273363], + [-121.28028883, 34.16717822, -0.47432459]], + + [[-120.97331383, 33.94760603, -0.501391 ], + [-121.20934869, 34.07228388, -4.09750554], + [-123.32542204, 31.15253461, -4.05990727], + [-125.44149539, 28.23278533, -4.022309 ], + [-125.20546053, 28.10810748, -0.42619446], + [-124.96942567, 27.98342963, 3.16992008], + [-122.85335232, 30.90317891, 3.13232181], + [-120.73727896, 33.82292818, 3.09472355], + [-120.97331383, 33.94760603, -0.501391 ]], + + [[-120.67360907, 33.72667566, -0.52943933], + [-120.92075373, 33.8595394 , -4.12451509], + [-123.07908201, 30.97092427, -4.08296592], + [-125.23741028, 28.08230914, -4.04141674], + [-124.99026562, 27.9494454 , -0.44634099], + [-124.74312096, 27.81658166, 3.14873477], + [-122.58479269, 30.70519679, 3.1071856 ], + [-120.42646441, 33.59381192, 3.06563642], + [-120.67360907, 33.72667566, -0.52943933]], + + [[-120.38111977, 33.50419409, -0.5585125 ], + [-120.63978558, 33.64581712, -4.15244412], + [-122.84193328, 30.79051701, -4.10654333], + [-125.04408098, 27.9352169 , -4.06064255], + [-124.78541518, 27.79359387, -0.46671093], + [-124.52674937, 27.65197084, 3.12722069], + [-122.32460167, 30.50727095, 3.0813199 ], + [-120.12245397, 33.36257106, 3.03541912], + [-120.38111977, 33.50419409, -0.5585125 ]], + + [[-120.09626236, 33.28033641, -0.58860416], + [-120.36685239, 33.43132544, -4.18127731], + [-122.61435257, 30.61164791, -4.13059007], + [-124.86185276, 27.79197039, -4.07990282], + [-124.59126273, 27.64098135, -0.48722968], + [-124.32067271, 27.48999232, 3.10544347], + [-122.07317252, 30.30966984, 3.05475623], + [-119.82567234, 33.12934737, 3.00406899], + [-120.09626236, 33.28033641, -0.58860416]], + + [[-119.81847658, 33.05449387, -0.61981519], + [-120.10142485, 33.21552498, -4.21110112], + [-122.39592827, 30.43404139, -4.15513775], + [-124.69043169, 27.6525578 , -4.09917437], + [-124.40748342, 27.49152669, -0.50788844], + [-124.12453515, 27.33049558, 3.08339749], + [-121.83003173, 30.11197917, 3.02743411], + [-119.53552831, 32.89346277, 2.97147074], + [-119.81847658, 33.05449387, -0.61981519]], + + [[-119.54805575, 32.82670271, -0.65216267], + [-119.84379009, 32.99849833, -4.24192061], + [-122.18692399, 30.25795643, -4.1801457 ], + [-124.53005788, 27.51741453, -4.11837078], + [-124.23432353, 27.3456189 , -0.52861284], + [-123.93858919, 27.17382328, 3.0611451 ], + [-121.59545529, 29.91436518, 2.99937018], + [-119.2523214 , 32.65490708, 2.93759527], + [-119.54805575, 32.82670271, -0.65216267]], + + [[-119.28482371, 32.59659924, -0.68572097], + [-119.59378374, 32.77994942, -4.27379446], + [-121.98722007, 30.083354 , -4.20561296], + [-124.38065641, 27.38675858, -4.13743145], + [-124.07169638, 27.2034084 , -0.54935795], + [-123.76273635, 27.02005822, 3.03871555], + [-121.36930002, 29.71665364, 2.97053404], + [-118.97586368, 32.41324906, 2.90235253], + [-119.28482371, 32.59659924, -0.68572097]], + + [[-119.02885178, 32.36399151, -0.7205439 ], + [-119.35147509, 32.5597504 , -4.30676046], + [-121.79687824, 29.91035019, -4.23151627], + [-124.24228139, 27.26094999, -4.15627209], + [-123.91965808, 27.06519109, -0.57005553], + [-123.59703477, 26.8694322 , 3.01616102], + [-121.15163162, 29.5188324 , 2.94091684], + [-118.70622847, 32.16823261, 2.86567266], + [-119.02885178, 32.36399151, -0.7205439 ]], + + [[-118.78013902, 32.1285992 , -0.75670076], + [-119.11686071, 32.33769308, -4.34086981], + [-121.61588553, 29.73901102, -4.25783816], + [-124.11491034, 27.14032896, -4.17480651], + [-123.77818865, 26.93123509, -0.59063746], + [-123.44146696, 26.72214122, 2.99353159], + [-120.94244215, 29.32082327, 2.91049994], + [-118.44341733, 31.91950533, 2.82746829], + [-118.78013902, 32.1285992 , -0.75670076]], + + [[-118.5386371 , 31.89004633, -0.7942803 ], + [-118.88988941, 32.11348407, -4.37619058], + [-121.44417987, 29.56935737, -4.28456794], + [-123.99847033, 27.02523066, -4.19294531], + [-123.64721802, 26.80179292, -0.61103502], + [-123.29596571, 26.57835518, 2.97087526], + [-120.74167525, 29.12248188, 2.87925262], + [-118.18738479, 31.66660859, 2.78762998], + [-118.5386371 , 31.89004633, -0.7942803 ]], + + [[-118.30457441, 31.64819545, -0.83333681], + [-118.67076444, 31.88705751, -4.41275712], + [-121.28186889, 29.4015955 , -4.31166413], + [-123.89297335, 26.91613349, -4.21057114], + [-123.52678332, 26.67727144, -0.63115084], + [-123.16059329, 26.43840939, 2.94826947], + [-120.54948884, 28.92387139, 2.84717648], + [-117.93838438, 31.4093334 , 2.74608349], + [-118.30457441, 31.64819545, -0.83333681]], + + [[-118.0778363 , 31.40250725, -0.87399358], + [-118.45936185, 31.65797485, -4.45066694], + [-121.1287933 , 29.23567027, -4.33912622], + [-123.79822475, 26.81336569, -4.22758551], + [-123.4166992 , 26.55789808, -0.65091215], + [-123.03517365, 26.30243048, 2.92576121], + [-120.3657422 , 28.72473506, 2.81422049], + [-117.69631075, 31.14703964, 2.70267978], + [-118.0778363 , 31.40250725, -0.87399358]], + + [[-117.85872431, 31.1528315 , -0.91631456], + [-118.25593947, 31.42616416, -4.48996074], + [-120.98504464, 29.07180738, -4.3669065 ], + [-123.71414982, 26.7174506 , -4.24385226], + [-123.31693466, 26.44411794, -0.67020607], + [-122.9197195 , 26.17078528, 2.90344011], + [-120.19061433, 28.52514206, 2.78038587], + [-117.46150915, 30.87949883, 2.65733162], + [-117.85872431, 31.1528315 , -0.91631456]], + + [[-117.64716301, 30.89852673, -0.96045179], + [-118.06039701, 31.19110005, -4.53075964], + [-120.85042813, 28.90992304, -4.39500839], + [-123.64045924, 26.62874604, -4.25925714], + [-123.22722524, 26.33617272, -0.6889493 ], + [-122.81399124, 26.04359939, 2.88135855], + [-120.02396012, 28.3247764 , 2.7456073 ], + [-117.23392901, 30.6059534 , 2.60985605], + [-117.64716301, 30.89852673, -0.96045179]], + + [[-117.44365764, 30.63957391, -1.00645487], + [-117.87316232, 30.95283474, -4.57308871], + [-120.72507722, 28.75034043, -4.42336378], + [-123.57699211, 26.54784612, -4.27363885], + [-123.14748743, 26.23458529, -0.70700501], + [-122.71798274, 25.92132446, 2.85962883], + [-119.86606785, 28.12381877, 2.7099039 ], + [-117.01415295, 30.32631308, 2.56017897], + [-117.44365764, 30.63957391, -1.00645487]], + + [[-117.24827282, 30.37535819, -1.05448168], + [-117.6942452 , 30.71086984, -4.61707216], + [-120.60879317, 28.5930041 , -4.45196873], + [-123.52334115, 26.47513837, -4.2868653 ], + [-123.07736877, 26.13962672, -0.72427482], + [-122.6313964 , 25.80411508, 2.83831565], + [-119.71684842, 27.92198081, 2.67321222], + [-116.80230045, 30.03984654, 2.5081088 ], + [-117.24827282, 30.37535819, -1.05448168]], + + [[-117.06137109, 30.10553716, -1.10464917], + [-117.5239196 , 30.46495875, -4.66279534], + [-120.50151314, 28.4380319 , -4.4807885 ], + [-123.47910668, 26.41110505, -4.29878165], + [-123.01655816, 26.05168346, -0.74063547], + [-122.55400964, 25.69226187, 2.8175107 ], + [-119.57641611, 27.71918872, 2.63550385], + [-116.59882257, 29.74611557, 2.45349701], + [-117.06137109, 30.10553716, -1.10464917]], + + [[-116.88338348, 29.82980702, -1.1570708 ], + [-117.36250834, 30.2148854 , -4.71034041], + [-120.40314818, 28.28554136, -4.50978609], + [-123.44378803, 26.35619732, -4.30923178], + [-122.96466317, 25.97111895, -0.75596216], + [-122.48553832, 25.58604057, 2.79730745], + [-119.44489847, 27.51538461, 2.59675313], + [-116.40425862, 29.44472864, 2.39619882], + [-116.88338348, 29.82980702, -1.1570708 ]], + + [[-116.71471631, 29.54771533, -1.21189463], + [-117.21029939, 29.96029478, -4.7598208 ], + [-120.3135363 , 28.13554811, -4.53894327], + [-123.41677321, 26.31080144, -4.31806574], + [-122.92119013, 25.89822199, -0.77013957], + [-122.42560705, 25.48564253, 2.7777866 ], + [-119.32237014, 27.3103892 , 2.55690907], + [-116.21913323, 29.13513587, 2.33603154], + [-116.71471631, 29.54771533, -1.21189463]], + + [[-116.55609826, 29.25929042, -1.26917838], + [-117.06785734, 29.7012561 , -4.81126953], + [-120.23261795, 27.9882768 , -4.56819913], + [-123.39737855, 26.27529749, -4.32512874], + [-122.88561947, 25.8333318 , -0.78303759], + [-122.37386038, 25.39136611, 2.75905356], + [-119.20909978, 27.10434542, 2.51598317], + [-116.04433917, 28.81732473, 2.27291277], + [-116.55609826, 29.25929042, -1.26917838]], + + [[-116.40796816, 28.963945 , -1.32910636], + [-116.93547305, 29.43727477, -4.86483483], + [-120.16012112, 27.84358534, -4.59756469], + [-123.38476919, 26.24989591, -4.33029454], + [-122.8572643 , 25.77656615, -0.79456607], + [-122.32975941, 25.30323638, 2.74116241], + [-119.10511134, 26.89692581, 2.47389226], + [-115.88046327, 28.49061523, 2.20662212], + [-116.40796816, 28.963945 , -1.32910636]], + + [[-116.27126999, 28.66202914, -1.3916758 ], + [-116.81387671, 29.16867983, -4.92050015], + [-120.09596294, 27.70172289, -4.62697091], + [-123.37804917, 26.23476596, -4.33344167], + [-122.83544246, 25.72811528, -0.80461732], + [-122.29283574, 25.2214646 , 2.72420703], + [-119.01074951, 26.68842153, 2.43067779], + [-115.72866328, 28.15537846, 2.13714855], + [-116.27126999, 28.66202914, -1.3916758 ]], + + [[-116.14649554, 28.35282487, -1.45710806], + [-116.70338504, 28.8948332 , -4.97845151], + [-120.03979426, 27.56235525, -4.65646949], + [-123.37620349, 26.2298773 , -4.33448747], + [-122.819314 , 25.68786897, -0.81314402], + [-122.2624245 , 25.14586064, 2.70819943], + [-118.92601528, 26.47833859, 2.38621741], + [-115.58960605, 27.81081655, 2.06423539], + [-116.14649554, 28.35282487, -1.45710806]], + + [[-116.03485771, 28.03733703, -1.52526222], + [-116.60494561, 28.61660385, -5.03855807], + [-119.99155357, 27.42583452, -4.68596783], + [-123.37816152, 26.2350652 , -4.3333776 ], + [-122.80807362, 25.65579838, -0.82008176], + [-122.23798572, 25.07653156, 2.69321408], + [-118.85137776, 26.26730089, 2.34062385], + [-115.46476981, 27.45807022, 1.98803362], + [-116.03485771, 28.03733703, -1.52526222]], + + [[-115.93704111, 27.71537285, -1.59624681], + [-116.51903196, 28.3337746 , -5.10091561], + [-119.9509115 , 27.2918508 , -4.71551337], + [-123.38279104, 26.24992699, -4.33011113], + [-122.80080019, 25.63152523, -0.82544232], + [-122.21880933, 25.01312347, 2.67922648], + [-118.7869298 , 26.05504728, 2.29382424], + [-115.35505026, 27.09697109, 1.90842199], + [-115.93704111, 27.71537285, -1.59624681]], + + [[-115.85399426, 27.38751246, -1.67000252], + [-116.44635047, 28.04678743, -5.16547753], + [-119.9176535 , 27.1603205 , -4.74510772], + [-123.38895653, 26.27385356, -4.32473791], + [-122.79660032, 25.61457858, -0.82926289], + [-122.20424412, 24.9553036 , 2.66621213], + [-118.73294109, 25.84177054, 2.24584231], + [-115.26163806, 26.72823748, 1.8254725 ], + [-115.85399426, 27.38751246, -1.67000252]], + + [[-115.78657819, 27.05430661, -1.74646954], + [-116.38753382, 27.75603146, -5.23220374], + [-119.89154387, 27.03101802, -4.77478578], + [-123.39555392, 26.30600458, -4.31736782], + [-122.79459828, 25.60427973, -0.83163362], + [-122.19364264, 24.90255488, 2.65410058], + [-118.68963259, 25.62756832, 2.19668262], + [-115.18562255, 26.35258176, 1.73926466], + [-115.78657819, 27.05430661, -1.74646954]], + + [[-115.73567775, 26.71703383, -1.8254101 ], + [-116.34324439, 27.46250415, -5.30090623], + [-119.87239867, 26.90387189, -4.80454889], + [-123.40155295, 26.34523962, -4.30819155], + [-122.79398631, 25.5997693 , -0.83269541], + [-122.18641967, 24.85429897, 2.64280072], + [-118.65726539, 25.41293124, 2.14644337], + [-115.12811111, 25.97156351, 1.65008603], + [-115.73567775, 26.71703383, -1.8254101 ]], + + [[-115.70191432, 26.37635829, -1.90671504], + [-116.31392951, 27.16664317, -5.37151645], + [-119.86000336, 26.77845824, -4.83448289], + [-123.40607722, 26.39027331, -4.29744932], + [-122.79406203, 25.59998842, -0.83264792], + [-122.18204684, 24.80970354, 2.63215349], + [-118.63597298, 25.19788847, 2.09511993], + [-115.08989913, 25.5860734 , 1.55808637], + [-115.70191432, 26.37635829, -1.90671504]], + + [[-115.68587491, 26.03325711, -1.9901947 ], + [-116.30002672, 26.86914076, -5.44390195], + [-119.85422701, 26.6543858 , -4.86467296], + [-123.40842729, 26.43963084, -4.28544398], + [-122.79427548, 25.60374719, -0.83173672], + [-122.18012366, 24.76786354, 2.62197053], + [-118.62592337, 24.9826185 , 2.04274154], + [-115.07172309, 25.19737346, 1.46351256], + [-115.68587491, 26.03325711, -1.9901947 ]], + + [[-115.68795274, 25.6897798 , -2.07537683], + [-116.30182931, 26.57160202, -5.51769159], + [-119.85498271, 26.53156943, -4.89513247], + [-123.40813611, 26.49153684, -4.27257335], + [-122.79425954, 25.60971462, -0.8302586 ], + [-122.18038298, 24.72789241, 2.61205616], + [-118.62722957, 24.76792499, 1.98949704], + [-115.07407617, 24.80795758, 1.36693792], + [-115.68795274, 25.6897798 , -2.07537683]], + + [[-115.70827877, 25.3468696 , -2.16203966], + [-116.3194306 , 26.27466381, -5.59273605], + [-119.86222074, 26.40948073, -4.92598775], + [-123.40501088, 26.54429765, -4.25923944], + [-122.79385905, 25.61650343, -0.82854305], + [-122.18270723, 24.68870922, 2.60215334], + [-118.63991709, 24.5538923 , 1.93540504], + [-115.09712695, 24.41907539, 1.26865673], + [-115.70827877, 25.3468696 , -2.16203966]], + + [[-115.74676383, 25.00617653, -2.24976695], + [-116.35276208, 25.97957406, -5.66872045], + [-119.87595117, 26.28783825, -4.95730934], + [-123.39914025, 26.59610244, -4.24589822], + [-122.793142 , 25.62270491, -0.82694472], + [-122.18714375, 24.64930738, 2.59200878], + [-118.66395466, 24.34104319, 1.88059767], + [-115.14076558, 24.032779 , 1.16918655], + [-115.74676383, 25.00617653, -2.24976695]], + + [[-115.80318736, 24.66859976, -2.33831659], + [-116.40167004, 25.68693499, -5.7454821 ], + [-119.89627447, 26.16611487, -4.98923661], + [-123.3908789 , 26.64529475, -4.23299112], + [-122.79239622, 25.62695952, -0.82582562], + [-122.19391354, 24.60862429, 2.58133989], + [-118.69930911, 24.12944441, 1.8250944 ], + [-115.20470468, 23.65026453, 1.06884891], + [-115.80318736, 24.66859976, -2.33831659]], + + [[-115.87695968, 24.33600775, -2.42717383], + [-116.46570731, 25.39820123, -5.8226213 ], + [-119.92328555, 26.04419125, -5.02180753], + [-123.38086379, 26.69018126, -4.22099375], + [-122.79211615, 25.62798777, -0.82554629], + [-122.20336851, 24.56579428, 2.56990118], + [-118.74579028, 23.91980427, 1.76908741], + [-115.28821204, 23.27381426, 0.96827364], + [-115.87695968, 24.33600775, -2.42717383]], + + [[-115.9674858 , 24.00909222, -2.51611464], + [-116.54444484, 25.11382532, -5.89998796], + [-119.95718642, 25.92161015, -5.05515318], + [-123.369928 , 26.72939498, -4.2103184 ], + [-122.79296896, 25.62466188, -0.82644507], + [-122.21600992, 24.51992878, 2.55742825], + [-118.80326834, 23.71214395, 1.71259347], + [-115.39052677, 22.90435912, 0.86775868], + [-115.9674858 , 24.00909222, -2.51611464]], + + [[-116.07398729, 23.68885613, -2.60482167], + [-116.63731286, 24.83455061, -5.97734752], + [-119.99820102, 25.79812761, -5.08935384], + [-123.35908918, 26.7617046 , -4.20136016], + [-122.79576361, 25.61601012, -0.82883431], + [-122.23243804, 24.47031565, 2.54369154], + [-118.87154988, 23.50673865, 1.65569786], + [-115.51066172, 22.54316166, 0.76770417], + [-116.07398729, 23.68885613, -2.60482167]], + + [[-116.19540832, 23.37646323, -2.69291316], + [-116.74351173, 24.56128915, -6.05440324], + [-120.04650403, 25.67369835, -5.12443622], + [-123.34949633, 26.78610756, -4.1944692 ], + [-122.80139293, 25.60128164, -0.83297912], + [-122.25328952, 24.41645572, 2.52851097], + [-118.95029722, 23.30404651, 1.59854395], + [-115.64730492, 22.19163731, 0.66857693], + [-116.19540832, 23.37646323, -2.69291316]], + + [[-116.33093114, 23.07210422, -2.78026925], + [-116.86245653, 24.29413008, -6.1310811 ], + [-120.10239614, 25.54802525, -5.16050056], + [-123.34233576, 26.80192042, -4.18992002], + [-122.81081037, 25.57989455, -0.83910818], + [-122.27928498, 24.35786869, 2.51170366], + [-119.03934536, 23.10397352, 1.54112313], + [-115.79940575, 21.85007835, 0.57054259], + [-116.33093114, 23.07210422, -2.78026925]], + + [[-116.47947484, 22.7764118 , -2.86663737], + [-116.99333285, 24.03357659, -6.20718423], + [-120.16607647, 25.42111885, -5.19756194], + [-123.33882009, 26.80866111, -4.18793965], + [-122.82496209, 25.55149632, -0.84739279], + [-122.31110408, 24.29433153, 2.49315407], + [-119.13836046, 22.90678928, 1.48353178], + [-115.96561684, 21.51924702, 0.47390949], + [-116.47947484, 22.7764118 , -2.86663737]], + + [[-116.64033355, 22.48914786, -2.95201374], + [-117.13565336, 23.7793901 , -6.2827284 ], + [-120.23788898, 25.2927389 , -5.23571038], + [-123.34012459, 26.80608769, -4.18869236], + [-122.84480478, 25.51584545, -0.8579777 ], + [-122.34948497, 24.2256032 , 2.47273695], + [-119.24724935, 22.7122544 , 1.42571893], + [-116.14501374, 21.19890561, 0.37870091], + [-116.64033355, 22.48914786, -2.95201374]], + + [[-116.81238918, 22.21080212, -3.03617785], + [-117.28855923, 23.5319976 , -6.35753163], + [-120.3179608 , 25.16307366, -5.27491057], + [-123.34736236, 26.79414972, -4.1922895 ], + [-122.87119231, 25.47295424, -0.87093571], + [-122.39502226, 24.15175876, 2.45041807], + [-119.36562069, 22.5206827 , 1.36779701], + [-116.33621913, 20.88960664, 0.28517594], + [-116.81238918, 22.21080212, -3.03617785]], + + [[-116.99482533, 21.94122605, -3.11909392], + [-117.45144545, 23.2912847 , -6.4315685 ], + [-120.40649099, 25.03213869, -5.31517634], + [-123.36153653, 26.77299269, -4.19878419], + [-122.90491641, 25.42293404, -0.8863096 ], + [-122.44829628, 24.0728754 , 2.42616498], + [-119.49325074, 22.3320214 , 1.30977282], + [-116.53820521, 20.59116741, 0.19338067], + [-116.99482533, 21.94122605, -3.11909392]], + + [[-117.18706471, 21.67999612, -3.20081548], + [-117.62390845, 23.05690557, -6.50488873], + [-120.50373666, 24.89988372, -5.35654299], + [-123.38356486, 26.74286187, -4.20819725], + [-122.94672112, 25.36595241, -0.904124 ], + [-122.50987738, 23.98904296, 2.39994924], + [-119.63004917, 22.14606481, 1.2516035 ], + [-116.75022097, 20.30308666, 0.10325776], + [-117.18706471, 21.67999612, -3.20081548]], + + [[-117.38851239, 21.42680361, -3.28136609], + [-117.80551633, 22.82862793, -6.57751143], + [-120.60988601, 24.76636709, -5.39901278], + [-123.41425568, 26.70410625, -4.22051413], + [-122.99725174, 25.30228193, -0.92436879], + [-122.58024779, 23.9004576 , 2.37177656], + [-119.77587812, 21.96271844, 1.19327791], + [-116.97150845, 20.02497928, 0.01477926], + [-117.38851239, 21.42680361, -3.28136609]], + + [[-117.59849325, 21.18147558, -3.36072856], + [-117.99574922, 22.60635287, -6.64941491], + [-120.72500963, 24.63177151, -5.44254678], + [-123.45427004, 26.65719015, -4.23567866], + [-123.05701407, 25.23231286, -0.9469923 ], + [-122.6597581 , 23.80743556, 2.34169405], + [-119.93049768, 21.78201692, 1.13482592], + [-117.20123727, 19.75659828, -0.0720422 ], + [-117.59849325, 21.18147558, -3.36072856]], + + [[-117.81649199, 20.94367245, -3.43894115], + [-118.1942148 , 22.38983989, -6.72062382], + [-120.84918291, 24.49623328, -5.48711796], + [-123.50415103, 26.60262667, -4.25361209], + [-123.12642823, 25.15645924, -0.97192942], + [-122.74870542, 23.7102918 , 2.30975325], + [-120.0937373 , 21.60389841, 1.07624739], + [-117.43876919, 19.49750501, -0.15725848], + [-117.81649199, 20.94367245, -3.43894115]], + + [[-118.04229295, 20.71280824, -3.51612971], + [-118.40077976, 22.17862707, -6.79124063], + [-120.98258584, 24.35976241, -5.53273981], + [-123.56439191, 26.54089775, -4.274239 ], + [-123.20590511, 25.07507892, -0.99912808], + [-122.8474183 , 23.60926008, 2.27598284], + [-120.26561222, 21.42812475, 1.01748202], + [-117.68380615, 19.24698941, -0.24101879], + [-118.04229295, 20.71280824, -3.51612971]], + + [[-118.27565674, 20.48842796, -3.59238557], + [-118.61527853, 21.97237114, -6.86133558], + [-121.12533356, 24.22244046, -5.57940241], + [-123.63538859, 26.47250978, -4.29746923], + [-123.2957668 , 24.9885666 , -1.02851922], + [-122.95614501, 23.50462342, 2.24043079], + [-120.44608998, 21.25455411, 0.95849761], + [-117.93603496, 19.00448479, -0.32343557], + [-118.27565674, 20.48842796, -3.59238557]], + + [[-118.51615838, 20.27030256, -3.66772767], + [-118.83736179, 21.77093744, -6.93091096], + [-121.27736449, 24.08449185, -5.62704472], + [-123.71736719, 26.39804625, -4.32317848], + [-123.39616379, 24.89741137, -1.05999518], + [-123.07496038, 23.39677649, 2.20318811], + [-120.63495768, 21.08322209, 0.89932187], + [-118.19495498, 18.76966768, -0.40454437], + [-118.51615838, 20.27030256, -3.66772767]], + + [[-118.76372762, 20.05792099, -3.74227621], + [-119.06699523, 21.57393065, -7.00006155], + [-121.43878104, 23.94596137, -5.67566477], + [-123.81056686, 26.31799209, -4.35126799], + [-123.50729926, 24.80198243, -1.09348265], + [-123.20403165, 23.28597277, 2.16430269], + [-120.83224584, 20.91394205, 0.83990591], + [-118.46046002, 18.54191133, -0.48449087], + [-118.76372762, 20.05792099, -3.74227621]], + + [[-119.01835738, 19.85080968, -3.81614777], + [-119.30419669, 21.38098463, -7.06887954], + [-121.60969589, 23.8068915 , -5.72526206], + [-123.91519509, 26.23279838, -4.38164458], + [-123.62935578, 24.70262343, -1.12891281], + [-123.34351647, 23.17244848, 2.12381896], + [-121.03801726, 20.7465416 , 0.78020148], + [-118.73251806, 18.32063473, -0.563416 ], + [-119.01835738, 19.85080968, -3.81614777]], + + [[-119.27966466, 19.64883387, -3.88934167], + [-119.54862401, 21.19204657, -7.13734761], + [-121.78992209, 23.6675411 , -5.77575592], + [-124.03122016, 26.14303562, -4.41416424], + [-123.76226081, 24.59982293, -1.1661583 ], + [-123.49330147, 23.05661023, 2.08184763], + [-121.25200339, 20.5811157 , 0.72025595], + [-119.01070532, 18.10562118, -0.64133573], + [-119.27966466, 19.64883387, -3.88934167]], + + [[-119.5480374 , 19.45131521, -3.96206024], + [-119.80064977, 21.00655053, -7.20563889], + [-121.97977388, 23.52777183, -5.8272085 ], + [-124.15889799, 26.04899312, -4.44877812], + [-123.90628562, 24.4937578 , -1.20519947], + [-123.65367326, 22.93852247, 2.03837918], + [-121.47454914, 20.41730118, 0.6599488 ], + [-119.29542503, 17.89607988, -0.71848158], + [-119.5480374 , 19.45131521, -3.96206024]], + + [[-119.82293972, 19.25830834, -4.03424234], + [-120.05977425, 20.8246135 , -7.27368005], + [-122.17888906, 23.38793771, -5.87950002], + [-124.29800387, 25.95126193, -4.48531999], + [-124.06116934, 24.38495677, -1.24588229], + [-123.82433481, 22.81865161, 1.99355542], + [-121.70522 , 20.2553274 , 0.59937539], + [-119.58610519, 17.69200318, -0.79480464], + [-119.82293972, 19.25830834, -4.03424234]], + + [[-120.10485792, 19.06916669, -4.1060912 ], + [-120.3264543 , 20.64568841, -7.34164705], + [-122.38761244, 23.24787022, -5.93270281], + [-124.44877059, 25.85005203, -4.52375857], + [-124.22717421, 24.27353031, -1.28820272], + [-124.00557784, 22.69700858, 1.94735313], + [-121.94441969, 20.09482677, 0.53840889], + [-119.88326154, 17.49264496, -0.87053535], + [-120.10485792, 19.06916669, -4.1060912 ]], + + [[-120.39349153, 18.88383727, -4.17759321], + [-120.60040201, 20.46978253, -7.40951251], + [-122.60570396, 23.10780571, -5.98673705], + [-124.6110059 , 25.7458289 , -4.56396159], + [-124.40409541, 24.15988364, -1.33204229], + [-124.19718493, 22.57393839, 1.89987701], + [-122.19188299, 19.93591521, 0.47710155], + [-120.18658104, 17.29789202, -0.94567391], + [-120.39349153, 18.88383727, -4.17759321]], + + [[-120.68903016, 18.70195865, -4.24885468], + [-120.88178899, 20.29660751, -7.47736304], + [-122.83326665, 22.96773392, -6.04161445], + [-124.78474431, 25.63886033, -4.60586586], + [-124.59198548, 24.04421147, -1.37735749], + [-124.39922664, 22.44956261, 1.85115087], + [-122.44774898, 19.7784362 , 0.41540228], + [-120.49627132, 17.10730979, -1.02034632], + [-120.68903016, 18.70195865, -4.24885468]], + + [[-120.99148243, 18.52332273, -4.31992786], + [-121.17061377, 20.12601536, -7.54523513], + [-123.07026074, 22.8277354 , -6.09731153], + [-124.96990771, 25.52945545, -4.64938793], + [-124.79077637, 23.92676281, -1.42408065], + [-124.61164503, 22.32407018, 1.80122662], + [-122.71199806, 19.62235013, 0.35330302], + [-120.81235109, 16.92063009, -1.09462059], + [-120.99148243, 18.52332273, -4.31992786]], + + [[-121.30095655, 18.34768629, -4.39088255], + [-121.4669682 , 19.95782032, -7.6131829 ], + [-123.31671583, 22.68784292, -6.15382281], + [-125.16646346, 25.41786552, -4.69446272], + [-125.00045181, 23.80773148, -1.47216237], + [-124.83444017, 22.19759745, 1.75013799], + [-122.98469254, 19.46757485, 0.2907779 ], + [-121.13494491, 16.73755225, -1.16858219], + [-121.30095655, 18.34768629, -4.39088255]], + + [[-121.61731644, 18.17495945, -4.4617289 ], + [-121.7707081 , 19.79197977, -7.68120409], + [-123.572457 , 22.5481936 , -6.21109883], + [-125.37420591, 25.30440742, -4.74099356], + [-125.22081424, 23.6873871 , -1.52151836], + [-125.06742258, 22.07036679, 1.69795683], + [-123.26567367, 19.31415296, 0.22785157], + [-121.46392477, 16.55793914, -1.2422537 ], + [-121.61731644, 18.17495945, -4.4617289 ]], + + [[-121.9410148 , 18.00475726, -4.53260239], + [-122.08225461, 19.62816349, -7.74941784], + [-123.83778522, 22.40866548, -6.26919649], + [-125.59331583, 25.18916746, -4.78897514], + [-125.45207603, 23.56576122, -1.5721597 ], + [-125.31083622, 21.94235498, 1.64465575], + [-123.55530561, 19.161853 , 0.1644344 ], + [-121.799775 , 16.38135102, -1.31578695], + [-121.9410148 , 18.00475726, -4.53260239]], + + [[-122.27156011, 17.8372078 , -4.60342767], + [-122.40111944, 19.46653149, -7.81774116], + [-124.11222463, 22.26953989, -6.32800391], + [-125.82332982, 25.07254829, -4.83826666], + [-125.69377049, 23.44322459, -1.62395317], + [-125.56421116, 21.8139009 , 1.59036032], + [-123.85310597, 19.0108925 , 0.10062308], + [-122.14200078, 16.2078841 , -1.38911417], + [-122.27156011, 17.8372078 , -4.60342767]], + + [[-122.60959469, 17.671869 , -4.67437118], + [-122.72790664, 19.30669109, -7.88632489], + [-124.39623363, 22.13061202, -6.38761249], + [-126.06456063, 24.95453295, -4.8889001 ], + [-125.94624868, 23.31971087, -1.67694638], + [-125.82793673, 21.68488878, 1.53500734], + [-124.15960974, 18.86096785, 0.03629494], + [-122.49128275, 16.03704692, -1.46241746], + [-122.60959469, 17.671869 , -4.67437118]], + + [[-122.95476002, 17.50882114, -4.74538121], + [-123.0622549 , 19.14875033, -7.95511021], + [-124.68944033, 21.99209558, -6.44793632], + [-126.31662576, 24.83544084, -4.94076243], + [-126.20913088, 23.19551164, -1.73103344], + [-126.10163601, 21.55558245, 1.47869556], + [-124.47445058, 18.7122372 , -0.02847833], + [-122.84726515, 15.86889195, -1.53565221], + [-122.95476002, 17.50882114, -4.74538121]], + + [[-123.30725603, 17.34787012, -4.81652355], + [-123.40434139, 18.99254998, -8.02415224], + [-124.99193534, 21.85396386, -6.50899005], + [-126.5795293 , 24.71537775, -4.99382785], + [-126.48244394, 23.0706979 , -1.78619917], + [-126.38535858, 21.42601804, 1.42142952], + [-124.79776463, 18.56460415, -0.09373268], + [-123.21017067, 15.70319027, -1.60889487], + [-123.30725603, 17.34787012, -4.81652355]], + + [[-123.66738502, 17.18880439, -4.88787742], + [-123.75444504, 18.83791022, -8.09352027], + [-125.30390869, 21.7161578 , -6.57080517], + [-126.85337235, 24.59440538, -5.04809007], + [-126.76631233, 22.94529955, -1.84244722], + [-126.67925231, 21.29619373, 1.36319563], + [-125.12978866, 18.41794615, -0.15951947], + [-123.580325 , 15.53969857, -1.68223457], + [-123.66738502, 17.18880439, -4.88787742]], + + [[-124.03479615, 17.0317057 , -4.95939141], + [-124.11220964, 18.68493428, -8.16315711], + [-125.62498377, 21.57886233, -6.63330247], + [-127.13775791, 24.47279038, -5.10344783], + [-127.06034442, 22.8195618 , -1.89968213], + [-126.98293093, 21.16633322, 1.30408357], + [-125.47015679, 18.27240517, -0.22577107], + [-123.95738266, 15.37847711, -1.75562571], + [-124.03479615, 17.0317057 , -4.95939141]], + + [[-124.4098303 , 16.8763588 , -5.03114907], + [-124.47795191, 18.53343453, -8.23313733], + [-125.95538542, 21.44199477, -6.69652238], + [-127.43281892, 24.350555 , -5.15990743], + [-127.3646973 , 22.69347928, -1.95791917], + [-127.29657569, 21.03640355, 1.24406908], + [-125.81914218, 18.12784331, -0.29254587], + [-124.34170868, 15.21928308, -1.82916081], + [-124.4098303 , 16.8763588 , -5.03114907]], + + [[-124.79248333, 16.72270969, -5.1031634 ], + [-124.85165382, 18.38337804, -8.30346747], + [-126.29504268, 21.30560242, -6.76044689], + [-127.73843155, 24.2278268 , -5.21742632], + [-127.67926106, 22.56715846, -2.01712225], + [-127.62009057, 20.90649011, 1.18318182], + [-126.1767017 , 17.98426573, -0.35983875], + [-124.73331284, 15.06204135, -1.90285933], + [-124.79248333, 16.72270969, -5.1031634 ]], + + [[-125.1828386 , 16.57067259, -5.17546302], + [-125.23338291, 18.23469926, -8.37416975], + [-126.64396306, 21.16969666, -6.82507386], + [-128.0545432 , 24.10469406, -5.27597797], + [-128.00399888, 22.44066739, -2.07727124], + [-127.95345457, 20.77664072, 1.12143549], + [-126.54287442, 17.84164332, -0.4276604 ], + [-125.13229428, 14.90664592, -1.97675629], + [-125.1828386 , 16.57067259, -5.17546302]], + + [[-125.58086278, 16.42021204, -5.24805376], + [-125.62309311, 18.08738025, -8.44524452], + [-127.00205188, 21.03432616, -6.89038282], + [-128.38101065, 23.98127207, -5.33552113], + [-128.33878033, 22.31410386, -2.13833037], + [-128.29655 , 20.64693565, 1.0588604 ], + [-126.91759123, 17.69998974, -0.4960013 ], + [-125.53863246, 14.75304383, -2.05086299], + [-125.58086278, 16.42021204, -5.24805376]], + + [[-125.98673995, 16.27121614, -5.32097965], + [-126.02095177, 17.94132673, -8.51672998], + [-127.36941299, 20.89946366, -6.95638976], + [-128.71787422, 23.8576006 , -5.39604954], + [-128.68366241, 22.18749001, -2.20029921], + [-128.6494506 , 20.51737942, 0.99545113], + [-127.30098937, 17.55924248, -0.56488909], + [-125.95252814, 14.60110555, -2.12522932], + [-125.98673995, 16.27121614, -5.32097965]], + + [[-126.40032471, 16.12369808, -5.39422451], + [-126.42680382, 17.7965657 , -8.58860567], + [-127.74585454, 20.76518872, -7.02305793], + [-129.06490526, 23.73381175, -5.4575102 ], + [-129.03842615, 22.06094412, -2.26312904], + [-129.01194704, 20.3880765 , 0.93125211], + [-127.69289632, 17.41945347, -0.63429562], + [-126.3738456 , 14.45083045, -2.19984336], + [-126.40032471, 16.12369808, -5.39422451]], + + [[-126.82192461, 15.97751328, -5.46785145], + [-126.84093919, 17.65296816, -8.66092927], + [-128.13159941, 20.63143153, -7.09042442], + [-129.42225962, 23.60989489, -5.51991958], + [-129.40324504, 21.93444001, -2.32684176], + [-129.38423045, 20.25898513, 0.86623605], + [-128.09357024, 17.28052177, -0.70426879], + [-126.80291002, 14.3020584 , -2.27477364], + [-126.82192461, 15.97751328, -5.46785145]], + + [[-127.25133633, 15.83270046, -5.54183282], + [-127.2631468 , 17.51058393, -8.7336697 ], + [-128.52640692, 20.49828416, -7.15844506], + [-129.78966705, 23.48598439, -5.58322042], + [-129.77785658, 21.80810092, -2.39138355], + [-129.76604612, 20.13021746, 0.80045332], + [-128.50278599, 17.14251723, -0.77477131], + [-127.23952587, 14.154817 , -2.34999595], + [-127.25133633, 15.83270046, -5.54183282]], + + [[-127.68886925, 15.68912699, -5.61622893], + [-127.69371997, 17.36929343, -8.80688261], + [-128.93050948, 20.3656767 , -7.2271578 ], + [-130.167299 , 23.36205997, -5.64743299], + [-130.16244827, 21.68189353, -2.45677931], + [-130.15759754, 20.00172709, 0.73387436], + [-128.92080803, 17.00534382, -0.84585045], + [-127.68401852, 14.00896055, -2.42557526], + [-127.68886925, 15.68912699, -5.61622893]], + + [[-128.13421438, 15.54686651, -5.6909941 ], + [-128.13234414, 17.22917913, -8.88051963], + [-129.34357117, 20.2337252 , -7.29650407], + [-130.55479821, 23.23827127, -5.7124885 ], + [-130.55666846, 21.55595864, -2.52296296], + [-130.5585387 , 19.87364601, 0.66656257], + [-129.34731166, 16.86909995, -0.917453 ], + [-128.13608462, 13.86455388, -2.50146857], + [-128.13421438, 15.54686651, -5.6909941 ]], + + [[-128.58787275, 15.40573609, -5.76621811], + [-128.57950292, 17.09007001, -8.95466607], + [-129.7660095 , 20.10230386, -7.36655209], + [-130.95251607, 23.11453771, -5.77843811], + [-130.9608859 , 21.43020379, -2.58999014], + [-130.96925573, 19.74586986, 0.59845782], + [-129.78274915, 16.73363601, -0.98965616], + [-128.59624258, 13.72140216, -2.57777014], + [-128.58787275, 15.40573609, -5.76621811]], + + [[-129.04931557, 15.26587759, -5.84181887], + [-129.0346656 , 16.95211434, -9.02923808], + [-130.19728633, 19.97158535, -7.43721134], + [-131.35990705, 22.99105635, -5.8451846 ], + [-131.37455702, 21.30481961, -2.65776539], + [-131.38920699, 19.61858287, 0.52965382], + [-130.22658627, 16.59911186, -1.06237292], + [-129.06396554, 13.57964085, -2.65439966], + [-129.04931557, 15.26587759, -5.84181887]], + + [[-129.51912839, 15.12709184, -5.9178977 ], + [-129.49840058, 16.81512344, -9.10433284], + [-130.63790489, 19.841421 , -7.5085633 ], + [-131.7774092 , 22.86771856, -5.91279376], + [-131.79813701, 21.17968696, -2.72635862], + [-131.81886482, 19.49165536, 0.46007652], + [-130.67936051, 16.4653578 , -1.13569302], + [-129.5398562 , 13.43906025, -2.73146256], + [-129.51912839, 15.12709184, -5.9178977 ]], + + [[-129.9969902 , 14.98945803, -5.99440649], + [-129.97038266, 16.67918258, -9.17990038], + [-131.08752404, 19.71191909, -7.58055088], + [-132.20466542, 22.7446556 , -5.98120139], + [-132.23127297, 21.05493105, -2.7957075 ], + [-132.25788051, 19.3652065 , 0.38978639], + [-131.14073913, 16.33246999, -1.20956311], + [-130.02359775, 13.29973348, -2.8089126 ], + [-129.9969902 , 14.98945803, -5.99440649]], + + [[-130.48306386, 14.85291015, -6.07137602], + [-130.45076432, 16.54423321, -9.25596871], + [-131.54625681, 19.58304948, -7.65319158], + [-132.6417493 , 22.62186575, -6.05041445], + [-132.67404884, 20.93054269, -2.86582177], + [-132.70634838, 19.23921963, 0.31877092], + [-131.61085589, 16.20040336, -1.28400621], + [-130.51536341, 13.16158709, -2.88678334], + [-130.48306386, 14.85291015, -6.07137602]], + + [[-130.97737139, 14.71742735, -6.14881342], + [-130.93955962, 16.41026079, -9.33254268], + [-132.01408692, 19.45482162, -7.72648161], + [-133.08861423, 22.49938244, -6.12042053], + [-133.126426 , 20.80654901, -2.93669127], + [-133.16423778, 19.11371557, 0.24703799], + [-132.08971047, 16.06915474, -1.35902309], + [-131.01518317, 13.02459392, -2.96508416], + [-130.97737139, 14.71742735, -6.14881342]], + + [[-131.47996599, 14.58298095, -6.22673052], + [-131.43681376, 16.27724258, -9.40963195], + [-132.4910292 , 19.32723534, -7.80042232], + [-133.54524465, 22.37722811, -6.19121269], + [-133.58839688, 20.68296649, -3.00831126], + [-133.63154912, 18.98870487, 0.17459017], + [-132.57733367, 15.9387121 , -1.43461946], + [-131.52311823, 12.88871933, -3.04382908], + [-131.47996599, 14.58298095, -6.22673052]], + + [[-131.99085795, 14.44955604, -6.30513191], + [-131.94252994, 16.14516898, -9.48723916], + [-132.97705991, 19.20030137, -7.87500896], + [-134.01158987, 22.25543377, -6.26277876], + [-134.05991788, 20.55982082, -3.08067151], + [-134.10824588, 18.86420787, 0.10143574], + [-133.07371592, 15.80907548, -1.51079446], + [-132.03918595, 12.75394309, -3.12302465], + [-131.99085795, 14.44955604, -6.30513191]], + + [[-132.50994297, 14.31716597, -6.38400502], + [-132.4565981 , 16.01405809, -9.56535007], + [-133.47204696, 19.07405568, -7.95022089], + [-134.48749583, 22.13405327, -6.33509172], + [-134.5408407 , 20.43716115, -3.15374668], + [-134.59418557, 18.74026903, 0.02759837], + [-133.5787367 , 15.68027144, -1.5875308 ], + [-132.56328784, 12.62027385, -3.20265998], + [-132.50994297, 14.31716597, -6.38400502]], + + [[-133.03756712, 14.18571295, -6.46340481], + [-132.97935468, 15.88381745, -9.64401743], + [-133.97629029, 18.94842622, -8.02610259], + [-134.9732259 , 22.01303499, -6.40818775], + [-135.03143833, 20.31493048, -3.22757512], + [-135.08965077, 18.61682598, -0.04696249], + [-134.09271516, 15.55221721, -1.66487734], + [-133.09577955, 12.48760844, -3.28279218], + [-133.03756712, 14.18571295, -6.46340481]], + + [[-133.57325884, 14.05530313, -6.5432631 ], + [-133.51032634, 15.75455639, -9.72317216], + [-134.48930971, 18.82353434, -8.10258137], + [-135.46829308, 21.89251229, -6.48199058], + [-135.53122558, 20.19325903, -3.30208152], + [-135.59415807, 18.49400576, -0.12217246], + [-134.6151747 , 15.42502781, -1.74276325], + [-133.63619133, 12.35604986, -3.36335404], + [-133.57325884, 14.05530313, -6.5432631 ]], + + [[-133.9333281 , 13.96962944, -6.59644992], + [-133.86736371, 15.66960392, -9.77591118], + [-134.83481561, 18.74132492, -8.15361722], + [-135.80226751, 21.81304591, -6.53132326], + [-135.8682319 , 20.11307144, -3.35186201], + [-135.93419628, 18.41309696, -0.17240075], + [-134.96674438, 15.34137596, -1.79469471], + [-133.99929248, 12.26965496, -3.41698867], + [-133.9333281 , 13.96962944, -6.59644992]], + + [[-134.11475138, 13.92694164, -6.62312981], + [-134.04729259, 15.62726774, -9.8023713 ], + [-135.00906071, 18.7003261 , -8.17924149], + [-135.97082883, 21.77338447, -6.55611168], + [-136.03828761, 20.07305836, -3.37687019], + [-136.1057464 , 18.37273226, -0.1976287 ], + [-135.14397828, 15.2996739 , -1.82075851], + [-134.18221016, 12.22661553, -3.44388832], + [-134.11475138, 13.92694164, -6.62312981]]]), + weights=np.array([[1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ]]) +) + + +surf2 = NURBSSurfaceTuple( + order_u=4, + order_v=3, + knot_u=np.array([ 0. , 0. , 0. , 0. , 0.71652462, + 1.43304924, 2.11836037, 2.80367151, 3.13470301, 3.46573451, + 3.78906448, 4.11239444, 4.74372964, 5.05177696, 5.35982428, + 5.66029662, 5.96076895, 6.2537151 , 6.54666124, 7.11760651, + 7.39566254, 7.67371857, 7.94441958, 8.2151206 , 8.47853336, + 8.74194611, 9.25434001, 9.50339989, 9.75245978, 9.99446832, + 10.23647686, 10.47152749, 10.70657812, 10.93647333, 11.16296751, + 11.38608911, 11.60586793, 11.82233513, 12.03552331, 12.24546661, + 12.45220079, 12.65576328, 12.85619329, 13.05353192, 13.24782221, + 13.43910925, 13.62744031, 13.81286492, 13.99543494, 14.17520475, + 14.35223128, 14.52657416, 14.69829579, 14.86746151, 15.03413964, + 15.19840161, 15.36032205, 15.51997887, 15.67745334, 15.83283015, + 15.98619747, 16.13764699, 16.28727391, 16.43517694, 16.58145831, + 16.72622365, 16.86958197, 17.01164551, 17.15252959, 17.29235247, + 17.4312351 , 17.5693009 , 17.70667552, 17.84348649, 17.97986292, + 18.11593516, 18.25183444, 18.38769249, 18.52364115, 18.65981202, + 18.79633603, 18.93334311, 19.07096183, 19.20931904, 19.34853959, + 19.488746 , 19.63005825, 19.77259351, 19.91646598, 20.06178669, + 20.2086634 , 20.35720048, 20.50749883, 20.65965586, 20.81376547, + 20.96991799, 21.12820031, 21.28869583, 21.45148454, 21.61664312, + 21.78424499, 21.95436041, 22.12705656, 22.30239767, 22.4804451 , + 22.66125744, 22.84489066, 23.03139818, 23.22083098, 23.41323773, + 23.60866487, 24.00875555, 24.42143391, 24.84700146, 25.28573315, + 25.73787988, 26.20367092, 26.44349342, 26.68331592, 27.16398738, + 27.64465883, 28.58258593, 29.49780935, 30.39109547, 31.26326852, + 32.11521399, 32.94788191, 33.76228976, 34.55952488, 35.34074636, + 36.10718586, 36.86014759, 37.60100689, 38.33120745, 39.05225695, + 39.76572106, 40.47321577, 40.82480697, 41.17639818, 41.52667708, + 41.70181653, 41.87695598, 42.22677591, 42.40168587, 42.57659584, + 42.75170466, 42.92681349, 43.27703113, 43.45276571, 43.62850028, + 43.97996943, 44.33353479, 44.68710016, 45.04359158, 45.40008299, + 45.76031009, 46.12053718, 46.48528472, 46.85003225, 47.22005626, + 47.59008027, 47.96610496, 48.34212965, 49.10756076, 49.49762184, + 49.88768293, 50.28570799, 50.68373305, 51.09030421, 51.49687537, + 51.49687537, 51.49687537, 51.49687537]), + knot_v=np.array([ 0. , 0. , 0. , 5.6635867, 5.6635867, + 11.3271734, 11.3271734, 16.9907601, 16.9907601, 22.6543468, + 22.6543468, 22.6543468]), + control_points=np.array([[[-108.30665828, 13.30821768, 0. ], + [-108.30665828, 13.30821768, 3.60555128], + [-111.07651949, 11. , 3.60555128], + [-113.84638071, 8.69178232, 3.60555128], + [-113.84638071, 8.69178232, 0. ], + [-113.84638071, 8.69178232, -3.60555128], + [-111.07651949, 11. , -3.60555128], + [-108.30665828, 13.30821768, -3.60555128], + [-108.30665828, 13.30821768, 0. ]], + + [[-108.4530993 , 13.48394723, 0. ], + [-108.4530993 , 13.48394723, 3.60555128], + [-111.22942133, 11.18348261, 3.60555128], + [-114.00574337, 8.88301798, 3.60555128], + [-114.00574337, 8.88301798, 0. ], + [-114.00574337, 8.88301798, -3.60555128], + [-111.22942133, 11.18348261, -3.60555128], + [-108.4530993 , 13.48394723, -3.60555128], + [-108.4530993 , 13.48394723, 0. ]], + + [[-108.74407396, 13.83611518, 0. ], + [-108.74407396, 13.83611518, 3.6055516 ], + [-111.53365833, 11.55169664, 3.6055516 ], + [-114.32324269, 9.2672781 , 3.6055516 ], + [-114.32324269, 9.2672781 , 0. ], + [-114.32324269, 9.2672781 , -3.6055516 ], + [-111.53365833, 11.55169664, -3.6055516 ], + [-108.74407396, 13.83611518, -3.6055516 ], + [-108.74407396, 13.83611518, 0. ]], + + [[-109.16831154, 14.35903771, 0. ], + [-109.16831154, 14.35903771, 3.60555298], + [-111.97860688, 12.10013716, 3.60555298], + [-114.78890222, 9.8412366 , 3.60555298], + [-114.78890222, 9.8412366 , 0. ], + [-114.78890222, 9.8412366 , -3.60555298], + [-111.97860688, 12.10013716, -3.60555298], + [-109.16831154, 14.35903771, -3.60555298], + [-109.16831154, 14.35903771, 0. ]], + + [[-109.57993801, 14.87623778, 0. ], + [-109.57993801, 14.87623778, 3.60555517], + [-112.41179029, 12.64441014, 3.60555517], + [-115.24364256, 10.41258251, 3.60555517], + [-115.24364256, 10.41258251, 0. ], + [-115.24364256, 10.41258251, -3.60555517], + [-112.41179029, 12.64441014, -3.60555517], + [-109.57993801, 14.87623778, -3.60555517], + [-109.57993801, 14.87623778, 0. ]], + + [[-109.91026226, 15.29972185, 0. ], + [-109.91026226, 15.29972185, 3.60555757], + [-112.76069935, 13.09170719, 3.60555757], + [-115.61113644, 10.88369253, 3.60555757], + [-115.61113644, 10.88369253, 0. ], + [-115.61113644, 10.88369253, -3.60555757], + [-112.76069935, 13.09170719, -3.60555757], + [-109.91026226, 15.29972185, -3.60555757], + [-109.91026226, 15.29972185, 0. ]], + + [[-110.1683579 , 15.63596228, 0. ], + [-110.1683579 , 15.63596228, 3.60555981], + [-113.03415154, 13.44794772, 3.60555981], + [-115.89994517, 11.25993316, 3.60555981], + [-115.89994517, 11.25993316, 0. ], + [-115.89994517, 11.25993316, -3.60555981], + [-113.03415154, 13.44794772, -3.60555981], + [-110.1683579 , 15.63596228, -3.60555981], + [-110.1683579 , 15.63596228, 0. ]], + + [[-110.35546553, 15.88238766, 0. ], + [-110.35546553, 15.88238766, 3.60556161], + [-113.23281286, 13.70958492, 3.60556161], + [-116.1101602 , 11.53678217, 3.60556161], + [-116.1101602 , 11.53678217, 0. ], + [-116.1101602 , 11.53678217, -3.60556161], + [-113.23281286, 13.70958492, -3.60556161], + [-110.35546553, 15.88238766, -3.60556161], + [-110.35546553, 15.88238766, 0. ]], + + [[-110.53933973, 16.12727522, 0. ], + [-110.53933973, 16.12727522, 3.60556354], + [-113.42847546, 13.97016737, 3.60556354], + [-116.31761118, 11.81305952, 3.60556354], + [-116.31761118, 11.81305952, 0. ], + [-116.31761118, 11.81305952, -3.60556354], + [-113.42847546, 13.97016737, -3.60556354], + [-110.53933973, 16.12727522, -3.60556354], + [-110.53933973, 16.12727522, 0. ]], + + [[-110.77738791, 16.4479702 , 0. ], + [-110.77738791, 16.4479702 , 3.60556625], + [-113.6823757 , 14.31221099, 3.60556625], + [-116.5873635 , 12.17645178, 3.60556625], + [-116.5873635 , 12.17645178, 0. ], + [-116.5873635 , 12.17645178, -3.60556625], + [-113.6823757 , 14.31221099, -3.60556625], + [-110.77738791, 16.4479702 , -3.60556625], + [-110.77738791, 16.4479702 , 0. ]], + + [[-111.00913521, 16.76573676, 0. ], + [-111.00913521, 16.76573676, 3.60556919], + [-113.93046298, 14.65236663, 3.60556919], + [-116.85179075, 12.5389965 , 3.60556919], + [-116.85179075, 12.5389965 , 0. ], + [-116.85179075, 12.5389965 , -3.60556919], + [-113.93046298, 14.65236663, -3.60556919], + [-111.00913521, 16.76573676, -3.60556919], + [-111.00913521, 16.76573676, 0. ]], + + [[-111.23427038, 17.08027359, 0. ], + [-111.23427038, 17.08027359, 3.60557234], + [-114.17244527, 14.99043167, 3.60557234], + [-117.11062016, 12.90058976, 3.60557234], + [-117.11062016, 12.90058976, 0. ], + [-117.11062016, 12.90058976, -3.60557234], + [-114.17244527, 14.99043167, -3.60557234], + [-111.23427038, 17.08027359, -3.60557234], + [-111.23427038, 17.08027359, 0. ]], + + [[-111.39784863, 17.31175896, 0. ], + [-111.39784863, 17.31175896, 3.60557476], + [-114.34876144, 15.23993607, 3.60557476], + [-117.29967424, 13.16811317, 3.60557476], + [-117.29967424, 13.16811317, 0. ], + [-117.29967424, 13.16811317, -3.60557476], + [-114.34876144, 15.23993607, -3.60557476], + [-111.39784863, 17.31175896, -3.60557476], + [-111.39784863, 17.31175896, 0. ]], + + [[-111.5581976 , 17.5416924 , 0. ], + [-111.5581976 , 17.5416924 , 3.60557726], + [-114.52211067, 15.48850407, 3.60557726], + [-117.48602375, 13.43531575, 3.60557726], + [-117.48602375, 13.43531575, 0. ], + [-117.48602375, 13.43531575, -3.60557726], + [-114.52211067, 15.48850407, -3.60557726], + [-111.5581976 , 17.5416924 , -3.60557726], + [-111.5581976 , 17.5416924 , 0. ]], + + [[-111.71391323, 17.76804047, 0. ], + [-111.71391323, 17.76804047, 3.60557982], + [-114.69097685, 15.73396014, 3.60557982], + [-117.66804047, 13.69987981, 3.60557982], + [-117.66804047, 13.69987981, 0. ], + [-117.66804047, 13.69987981, -3.60557982], + [-114.69097685, 15.73396014, -3.60557982], + [-111.71391323, 17.76804047, -3.60557982], + [-111.71391323, 17.76804047, 0. ]], + + [[-111.86635529, 17.99275896, 0. ], + [-111.86635529, 17.99275896, 3.60558246], + [-114.85683618, 15.97844928, 3.60558246], + [-117.84731707, 13.96413961, 3.60558246], + [-117.84731707, 13.96413961, 0. ], + [-117.84731707, 13.96413961, -3.60558246], + [-114.85683618, 15.97844928, -3.60558246], + [-111.86635529, 17.99275896, -3.60558246], + [-111.86635529, 17.99275896, 0. ]], + + [[-112.06268354, 18.28638653, 0. ], + [-112.06268354, 18.28638653, 3.605586 ], + [-115.07118301, 16.29901459, 3.605586 ], + [-118.07968249, 14.31164266, 3.605586 ], + [-118.07968249, 14.31164266, 0. ], + [-118.07968249, 14.31164266, -3.605586 ], + [-115.07118301, 16.29901459, -3.605586 ], + [-112.06268354, 18.28638653, -3.605586 ], + [-112.06268354, 18.28638653, 0. ]], + + [[-112.25247476, 18.57665464, 0. ], + [-112.25247476, 18.57665464, 3.60558966], + [-115.27952732, 16.61763177, 3.60558966], + [-118.30657988, 14.65860891, 3.60558966], + [-118.30657988, 14.65860891, 0. ], + [-118.30657988, 14.65860891, -3.60558966], + [-115.27952732, 16.61763177, -3.60558966], + [-112.25247476, 18.57665464, -3.60558966], + [-112.25247476, 18.57665464, 0. ]], + + [[-112.43552859, 18.86338665, 0. ], + [-112.43552859, 18.86338665, 3.60559342], + [-115.48169219, 16.93428561, 3.60559342], + [-118.5278558 , 15.00518457, 3.60559342], + [-118.5278558 , 15.00518457, 0. ], + [-118.5278558 , 15.00518457, -3.60559342], + [-115.48169219, 16.93428561, -3.60559342], + [-112.43552859, 18.86338665, -3.60559342], + [-112.43552859, 18.86338665, 0. ]], + + [[-112.56768567, 19.07382923, 0. ], + [-112.56768567, 19.07382923, 3.60559623], + [-115.62826873, 17.16767915, 3.60559623], + [-118.6888518 , 15.26152907, 3.60559623], + [-118.6888518 , 15.26152907, 0. ], + [-118.6888518 , 15.26152907, -3.60559623], + [-115.62826873, 17.16767915, -3.60559623], + [-112.56768567, 19.07382923, -3.60559623], + [-112.56768567, 19.07382923, 0. ]], + + [[-112.69648018, 19.28243808, 0. ], + [-112.69648018, 19.28243808, 3.60559909], + [-115.77175817, 17.40007876, 3.60559909], + [-118.84703616, 15.51771944, 3.60559909], + [-118.84703616, 15.51771944, 0. ], + [-118.84703616, 15.51771944, -3.60559909], + [-115.77175817, 17.40007876, -3.60559909], + [-112.69648018, 19.28243808, -3.60559909], + [-112.69648018, 19.28243808, 0. ]], + + [[-112.82080286, 19.48738403, 0. ], + [-112.82080286, 19.48738403, 3.60560195], + [-115.91092306, 17.6294809 , 3.60560195], + [-119.00104325, 15.77157777, 3.60560195], + [-119.00104325, 15.77157777, 0. ], + [-119.00104325, 15.77157777, -3.60560195], + [-115.91092306, 17.6294809 , -3.60560195], + [-112.82080286, 19.48738403, -3.60560195], + [-112.82080286, 19.48738403, 0. ]], + + [[-112.94171617, 19.69038282, 0. ], + [-112.94171617, 19.69038282, 3.60560483], + [-116.04695025, 17.85784218, 3.60560483], + [-119.15218433, 16.02530155, 3.60560483], + [-119.15218433, 16.02530155, 0. ], + [-119.15218433, 16.02530155, -3.60560483], + [-116.04695025, 17.85784218, -3.60560483], + [-112.94171617, 19.69038282, -3.60560483], + [-112.94171617, 19.69038282, 0. ]], + + [[-113.09629441, 19.95486135, 0. ], + [-113.09629441, 19.95486135, 3.60560865], + [-116.22177181, 18.15694076, 3.60560865], + [-119.34724922, 16.35902017, 3.60560865], + [-119.34724922, 16.35902017, 0. ], + [-119.34724922, 16.35902017, -3.60560865], + [-116.22177181, 18.15694076, -3.60560865], + [-113.09629441, 19.95486135, -3.60560865], + [-113.09629441, 19.95486135, 0. ]], + + [[-113.24413022, 20.21537372, 0. ], + [-113.24413022, 20.21537372, 3.6056125 ], + [-116.39038095, 18.45401454, 3.6056125 ], + [-119.53663167, 16.69265535, 3.6056125 ], + [-119.53663167, 16.69265535, 0. ], + [-119.53663167, 16.69265535, -3.6056125 ], + [-116.39038095, 18.45401454, -3.6056125 ], + [-113.24413022, 20.21537372, -3.6056125 ], + [-113.24413022, 20.21537372, 0. ]], + + [[-113.38512222, 20.47185252, 0. ], + [-113.38512222, 20.47185252, 3.60561638], + [-116.55269319, 18.74925679, 3.60561638], + [-119.72026416, 17.02666107, 3.60561638], + [-119.72026416, 17.02666107, 0. ], + [-119.72026416, 17.02666107, -3.60561638], + [-116.55269319, 18.74925679, -3.60561638], + [-113.38512222, 20.47185252, -3.60561638], + [-113.38512222, 20.47185252, 0. ]], + + [[-113.48593944, 20.65934644, 0. ], + [-113.48593944, 20.65934644, 3.60561925], + [-116.66952716, 18.96652241, 3.60561925], + [-119.85311488, 17.27369838, 3.60561925], + [-119.85311488, 17.27369838, 0. ], + [-119.85311488, 17.27369838, -3.60561925], + [-116.66952716, 18.96652241, -3.60561925], + [-113.48593944, 20.65934644, -3.60561925], + [-113.48593944, 20.65934644, 0. ]], + + [[-113.58333163, 20.84468624, 0. ], + [-113.58333163, 20.84468624, 3.60562212], + [-116.78318676, 19.1828032 , 3.60562212], + [-119.98304189, 17.52092017, 3.60562212], + [-119.98304189, 17.52092017, 0. ], + [-119.98304189, 17.52092017, -3.60562212], + [-116.78318676, 19.1828032 , -3.60562212], + [-113.58333163, 20.84468624, -3.60562212], + [-113.58333163, 20.84468624, 0. ]], + + [[-113.67641325, 21.02612716, 0. ], + [-113.67641325, 21.02612716, 3.60562497], + [-116.89262728, 19.39611451, 3.60562497], + [-120.10884131, 17.76610186, 3.60562497], + [-120.10884131, 17.76610186, 0. ], + [-120.10884131, 17.76610186, -3.60562497], + [-116.89262728, 19.39611451, -3.60562497], + [-113.67641325, 21.02612716, -3.60562497], + [-113.67641325, 21.02612716, 0. ]], + + [[-113.7660192 , 21.20522779, 0. ], + [-113.7660192 , 21.20522779, 3.60562781], + [-116.9988163 , 19.60834227, 3.60562781], + [-120.2316134 , 18.01145675, 3.60562781], + [-120.2316134 , 18.01145675, 0. ], + [-120.2316134 , 18.01145675, -3.60562781], + [-116.9988163 , 19.60834227, -3.60562781], + [-113.7660192 , 21.20522779, -3.60562781], + [-113.7660192 , 21.20522779, 0. ]], + + [[-113.8515788 , 21.38078189, 0. ], + [-113.8515788 , 21.38078189, 3.60563063], + [-117.10106296, 19.81811546, 3.60563063], + [-120.35054712, 18.25544903, 3.60563063], + [-120.35054712, 18.25544903, 0. ], + [-120.35054712, 18.25544903, -3.60563063], + [-117.10106296, 19.81811546, -3.60563063], + [-113.8515788 , 21.38078189, -3.60563063], + [-113.8515788 , 21.38078189, 0. ]], + + [[-113.9334739 , 21.55351269, 0. ], + [-113.9334739 , 21.55351269, 3.60563343], + [-117.1998086 , 20.02636564, 3.60563343], + [-120.4661433 , 18.49921859, 3.60563343], + [-120.4661433 , 18.49921859, 0. ], + [-120.4661433 , 18.49921859, -3.60563343], + [-117.1998086 , 20.02636564, -3.60563343], + [-113.9334739 , 21.55351269, -3.60563343], + [-113.9334739 , 21.55351269, 0. ]], + + [[-114.0113463 , 21.72255677, 0. ], + [-114.0113463 , 21.72255677, 3.60563621], + [-117.29459593, 20.23210554, 3.60563621], + [-120.57784557, 18.74165432, 3.60563621], + [-120.57784557, 18.74165432, 0. ], + [-120.57784557, 18.74165432, -3.60563621], + [-117.29459593, 20.23210554, -3.60563621], + [-114.0113463 , 21.72255677, -3.60563621], + [-114.0113463 , 21.72255677, 0. ]], + + [[-114.08540626, 21.88826115, 0. ], + [-114.08540626, 21.88826115, 3.60563895], + [-117.38565356, 20.43581648, 3.60563895], + [-120.68590087, 18.9833718 , 3.60563895], + [-120.68590087, 18.9833718 , 0. ], + [-120.68590087, 18.9833718 , -3.60563895], + [-117.38565356, 20.43581648, -3.60563895], + [-114.08540626, 21.88826115, -3.60563895], + [-114.08540626, 21.88826115, 0. ]], + + [[-114.1556948 , 22.05061291, 0. ], + [-114.1556948 , 22.05061291, 3.60564167], + [-117.47300353, 20.6375499 , 3.60564167], + [-120.79031225, 19.22448689, 3.60564167], + [-120.79031225, 19.22448689, 0. ], + [-120.79031225, 19.22448689, -3.60564167], + [-117.47300353, 20.6375499 , -3.60564167], + [-114.1556948 , 22.05061291, -3.60564167], + [-114.1556948 , 22.05061291, 0. ]], + + [[-114.22219016, 22.20944143, 0. ], + [-114.22219016, 22.20944143, 3.60564436], + [-117.55658537, 20.83716168, 3.60564436], + [-120.89098057, 19.46488194, 3.60564436], + [-120.89098057, 19.46488194, 0. ], + [-120.89098057, 19.46488194, -3.60564436], + [-117.55658537, 20.83716168, -3.60564436], + [-114.22219016, 22.20944143, -3.60564436], + [-114.22219016, 22.20944143, 0. ]], + + [[-114.28498566, 22.36483868, 0. ], + [-114.28498566, 22.36483868, 3.60564702], + [-117.63647862, 21.03483849, 3.60564702], + [-120.98797157, 19.7048383 , 3.60564702], + [-120.98797157, 19.7048383 , 0. ], + [-120.98797157, 19.7048383 , -3.60564702], + [-117.63647862, 21.03483849, -3.60564702], + [-114.28498566, 22.36483868, -3.60564702], + [-114.28498566, 22.36483868, 0. ]], + + [[-114.34410289, 22.51672584, 0. ], + [-114.34410289, 22.51672584, 3.60564965], + [-117.71267 , 21.23055901, 3.60564965], + [-121.08123711, 19.94439218, 3.60564965], + [-121.08123711, 19.94439218, 0. ], + [-121.08123711, 19.94439218, -3.60564965], + [-117.71267 , 21.23055901, -3.60564965], + [-114.34410289, 22.51672584, -3.60564965], + [-114.34410289, 22.51672584, 0. ]], + + [[-114.39953286, 22.66492031, 0. ], + [-114.39953286, 22.66492031, 3.60565224], + [-117.78509932, 21.42416417, 3.60565224], + [-121.17066577, 20.18340802, 3.60565224], + [-121.17066577, 20.18340802, 0. ], + [-121.17066577, 20.18340802, -3.60565224], + [-117.78509932, 21.42416417, -3.60565224], + [-114.39953286, 22.66492031, -3.60565224], + [-114.39953286, 22.66492031, 0. ]], + + [[-114.45135535, 22.8094577 , 0. ], + [-114.45135535, 22.8094577 , 3.6056548 ], + [-117.85381569, 21.61577834, 3.6056548 ], + [-121.25627603, 20.42209898, 3.6056548 ], + [-121.25627603, 20.42209898, 0. ], + [-121.25627603, 20.42209898, -3.6056548 ], + [-117.85381569, 21.61577834, -3.6056548 ], + [-114.45135535, 22.8094577 , -3.6056548 ], + [-114.45135535, 22.8094577 , 0. ]], + + [[-114.49962084, 22.95029368, 0. ], + [-114.49962084, 22.95029368, 3.60565732], + [-117.91882584, 21.80542808, 3.60565732], + [-121.33803085, 20.66056249, 3.60565732], + [-121.33803085, 20.66056249, 0. ], + [-121.33803085, 20.66056249, -3.60565732], + [-117.91882584, 21.80542808, -3.60565732], + [-114.49962084, 22.95029368, -3.60565732], + [-114.49962084, 22.95029368, 0. ]], + + [[-114.54435422, 23.08728825, 0. ], + [-114.54435422, 23.08728825, 3.60565981], + [-117.98009434, 21.99300954, 3.60565981], + [-121.41583445, 20.89873082, 3.60565981], + [-121.41583445, 20.89873082, 0. ], + [-121.41583445, 20.89873082, -3.60565981], + [-117.98009434, 21.99300954, -3.60565981], + [-114.54435422, 23.08728825, -3.60565981], + [-114.54435422, 23.08728825, 0. ]], + + [[-114.58562875, 23.22042376, 0. ], + [-114.58562875, 23.22042376, 3.60566226], + [-118.03764323, 22.17858222, 3.60566226], + [-121.48965771, 21.13674069, 3.60566226], + [-121.48965771, 21.13674069, 0. ], + [-121.48965771, 21.13674069, -3.60566226], + [-118.03764323, 22.17858222, -3.60566226], + [-114.58562875, 23.22042376, -3.60566226], + [-114.58562875, 23.22042376, 0. ]], + + [[-114.62352603, 23.34971132, 0. ], + [-114.62352603, 23.34971132, 3.60566467], + [-118.09150117, 22.36225531, 3.60566467], + [-121.55947631, 21.37479929, 3.60566467], + [-121.55947631, 21.37479929, 0. ], + [-121.55947631, 21.37479929, -3.60566467], + [-118.09150117, 22.36225531, -3.60566467], + [-114.62352603, 23.34971132, -3.60566467], + [-114.62352603, 23.34971132, 0. ]], + + [[-114.65805451, 23.47487663, 0. ], + [-114.65805451, 23.47487663, 3.60566705], + [-118.1415819 , 22.54372407, 3.60566705], + [-121.62510929, 21.61257152, 3.60566705], + [-121.62510929, 21.61257152, 0. ], + [-121.62510929, 21.61257152, -3.60566705], + [-118.1415819 , 22.54372407, -3.60566705], + [-114.65805451, 23.47487663, -3.60566705], + [-114.65805451, 23.47487663, 0. ]], + + [[-114.68935236, 23.59608075, 0. ], + [-114.68935236, 23.59608075, 3.60566939], + [-118.18797619, 22.7233072 , 3.60566939], + [-121.68660001, 21.85053364, 3.60566939], + [-121.68660001, 21.85053364, 0. ], + [-121.68660001, 21.85053364, -3.60566939], + [-118.18797619, 22.7233072 , -3.60566939], + [-114.68935236, 23.59608075, -3.60566939], + [-114.68935236, 23.59608075, 0. ]], + + [[-114.71747698, 23.71318756, 0. ], + [-114.71747698, 23.71318756, 3.60567168], + [-118.23065004, 22.900899 , 3.60567168], + [-121.7438231 , 22.08861045, 3.60567168], + [-121.7438231 , 22.08861045, 0. ], + [-121.7438231 , 22.08861045, -3.60567168], + [-118.23065004, 22.900899 , -3.60567168], + [-114.71747698, 23.71318756, -3.60567168], + [-114.71747698, 23.71318756, 0. ]], + + [[-114.74250458, 23.82607777, 0. ], + [-114.74250458, 23.82607777, 3.60567395], + [-118.26958293, 23.07639967, 3.60567395], + [-121.79666129, 22.32672157, 3.60567395], + [-121.79666129, 22.32672157, 0. ], + [-121.79666129, 22.32672157, -3.60567395], + [-118.26958293, 23.07639967, -3.60567395], + [-114.74250458, 23.82607777, -3.60567395], + [-114.74250458, 23.82607777, 0. ]], + + [[-114.76454956, 23.93478048, 0. ], + [-114.76454956, 23.93478048, 3.60567617], + [-118.30480278, 23.24993728, 3.60567617], + [-121.84505601, 22.56509408, 3.60567617], + [-121.84505601, 22.56509408, 0. ], + [-121.84505601, 22.56509408, -3.60567617], + [-118.30480278, 23.24993728, -3.60567617], + [-114.76454956, 23.93478048, -3.60567617], + [-114.76454956, 23.93478048, 0. ]], + + [[-114.78369894, 24.03915416, 0. ], + [-114.78369894, 24.03915416, 3.60567835], + [-118.33628158, 23.42135823, 3.60567835], + [-121.88886421, 22.80356231, 3.60567835], + [-121.88886421, 22.80356231, 0. ], + [-121.88886421, 22.80356231, -3.60567835], + [-118.33628158, 23.42135823, -3.60567835], + [-114.78369894, 24.03915416, -3.60567835], + [-114.78369894, 24.03915416, 0. ]], + + [[-114.80009512, 24.13933691, 0. ], + [-114.80009512, 24.13933691, 3.6056805 ], + [-118.36407036, 23.59096646, 3.6056805 ], + [-121.9280456 , 23.04259602, 3.6056805 ], + [-121.9280456 , 23.04259602, 0. ], + [-121.9280456 , 23.04259602, -3.6056805 ], + [-118.36407036, 23.59096646, -3.6056805 ], + [-114.80009512, 24.13933691, -3.6056805 ], + [-114.80009512, 24.13933691, 0. ]], + + [[-114.81381856, 24.23505108, 0. ], + [-114.81381856, 24.23505108, 3.60568261], + [-118.38810243, 23.75835127, 3.60568261], + [-121.9623863 , 23.28165145, 3.60568261], + [-121.9623863 , 23.28165145, 0. ], + [-121.9623863 , 23.28165145, -3.60568261], + [-118.38810243, 23.75835127, -3.60568261], + [-114.81381856, 24.23505108, -3.60568261], + [-114.81381856, 24.23505108, 0. ]], + + [[-114.82502729, 24.32646461, 0. ], + [-114.82502729, 24.32646461, 3.60568468], + [-118.40842976, 23.92384812, 3.60568468], + [-121.99183222, 23.52123162, 3.60568468], + [-121.99183222, 23.52123162, 0. ], + [-121.99183222, 23.52123162, -3.60568468], + [-118.40842976, 23.92384812, -3.60568468], + [-114.82502729, 24.32646461, -3.60568468], + [-114.82502729, 24.32646461, 0. ]], + + [[-114.83384165, 24.41345472, 0. ], + [-114.83384165, 24.41345472, 3.60568672], + [-118.4250264 , 24.08727239, 3.60568672], + [-122.01621115, 23.76109005, 3.60568672], + [-122.01621115, 23.76109005, 0. ], + [-122.01621115, 23.76109005, -3.60568672], + [-118.4250264 , 24.08727239, -3.60568672], + [-114.83384165, 24.41345472, -3.60568672], + [-114.83384165, 24.41345472, 0. ]], + + [[-114.8404124 , 24.49610283, 0. ], + [-114.8404124 , 24.49610283, 3.60568871], + [-118.43790786, 24.24879219, 3.60568871], + [-122.03540332, 24.00148156, 3.60568871], + [-122.03540332, 24.00148156, 0. ], + [-122.03540332, 24.00148156, -3.60568871], + [-118.43790786, 24.24879219, -3.60568871], + [-114.8404124 , 24.49610283, -3.60568871], + [-114.8404124 , 24.49610283, 0. ]], + + [[-114.84487925, 24.57430122, 0. ], + [-114.84487925, 24.57430122, 3.60569068], + [-118.44705596, 24.40818592, 3.60569068], + [-122.04923268, 24.24207062, 3.60569068], + [-122.04923268, 24.24207062, 0. ], + [-122.04923268, 24.24207062, -3.60569068], + [-118.44705596, 24.40818592, -3.60569068], + [-114.84487925, 24.57430122, -3.60569068], + [-114.84487925, 24.57430122, 0. ]], + + [[-114.84740347, 24.64814392, 0. ], + [-114.84740347, 24.64814392, 3.60569261], + [-118.45248305, 24.56559522, 3.60569261], + [-122.05756263, 24.48304652, 3.60569261], + [-122.05756263, 24.48304652, 0. ], + [-122.05756263, 24.48304652, -3.60569261], + [-118.45248305, 24.56559522, -3.60569261], + [-114.84740347, 24.64814392, -3.60569261], + [-114.84740347, 24.64814392, 0. ]], + + [[-114.84814303, 24.71765639, 0. ], + [-114.84814303, 24.71765639, 3.6056945 ], + [-118.45418614, 24.72100107, 3.6056945 ], + [-122.06022925, 24.72434576, 3.6056945 ], + [-122.06022925, 24.72434576, 0. ], + [-122.06022925, 24.72434576, -3.6056945 ], + [-118.45418614, 24.72100107, -3.6056945 ], + [-114.84814303, 24.71765639, -3.6056945 ], + [-114.84814303, 24.71765639, 0. ]], + + [[-114.84726025, 24.78290196, 0. ], + [-114.84726025, 24.78290196, 3.60569637], + [-118.45216337, 24.87442816, 3.60569637], + [-122.05706649, 24.96595437, 3.60569637], + [-122.05706649, 24.96595437, 0. ], + [-122.05706649, 24.96595437, -3.60569637], + [-118.45216337, 24.87442816, -3.60569637], + [-114.84726025, 24.78290196, -3.60569637], + [-114.84726025, 24.78290196, 0. ]], + + [[-114.84492123, 24.8439106 , 0. ], + [-114.84492123, 24.8439106 , 3.6056982 ], + [-118.44641772, 25.02577104, 3.6056982 ], + [-122.04791422, 25.20763148, 3.6056982 ], + [-122.04791422, 25.20763148, 0. ], + [-122.04791422, 25.20763148, -3.6056982 ], + [-118.44641772, 25.02577104, -3.6056982 ], + [-114.84492123, 24.8439106 , -3.6056982 ], + [-114.84492123, 24.8439106 , 0. ]], + + [[-114.84128972, 24.90082295, 0. ], + [-114.84128972, 24.90082295, 3.6057 ], + [-118.43694705, 25.17514106, 3.6057 ], + [-122.03260439, 25.44945917, 3.6057 ], + [-122.03260439, 25.44945917, 0. ], + [-122.03260439, 25.44945917, -3.6057 ], + [-118.43694705, 25.17514106, -3.6057 ], + [-114.84128972, 24.90082295, -3.6057 ], + [-114.84128972, 24.90082295, 0. ]], + + [[-114.83652667, 24.95374813, 0. ], + [-114.83652667, 24.95374813, 3.60570177], + [-118.42374657, 25.32253255, 3.60570177], + [-122.01096647, 25.69131697, 3.60570177], + [-122.01096647, 25.69131697, 0. ], + [-122.01096647, 25.69131697, -3.60570177], + [-118.42374657, 25.32253255, -3.60570177], + [-114.83652667, 24.95374813, -3.60570177], + [-114.83652667, 24.95374813, 0. ]], + + [[-114.83079402, 25.00278935, 0. ], + [-114.83079402, 25.00278935, 3.60570351], + [-118.40682868, 25.46784092, 3.60570351], + [-121.98286334, 25.9328925 , 3.60570351], + [-121.98286334, 25.9328925 , 0. ], + [-121.98286334, 25.9328925 , -3.60570351], + [-118.40682868, 25.46784092, -3.60570351], + [-114.83079402, 25.00278935, -3.60570351], + [-114.83079402, 25.00278935, 0. ]], + + [[-114.82423588, 25.04815735, 0. ], + [-114.82423588, 25.04815735, 3.60570522], + [-118.3861745 , 25.61121525, 3.60570522], + [-121.94811313, 26.17427315, 3.60570522], + [-121.94811313, 26.17427315, 0. ], + [-121.94811313, 26.17427315, -3.60570522], + [-118.3861745 , 25.61121525, -3.60570522], + [-114.82423588, 25.04815735, -3.60570522], + [-114.82423588, 25.04815735, 0. ]], + + [[-114.81699937, 25.08998671, 0. ], + [-114.81699937, 25.08998671, 3.60570691], + [-118.36180715, 25.75249666, 3.60570691], + [-121.90661492, 26.41500661, 3.60570691], + [-121.90661492, 26.41500661, 0. ], + [-121.90661492, 26.41500661, -3.60570691], + [-118.36180715, 25.75249666, -3.60570691], + [-114.81699937, 25.08998671, -3.60570691], + [-114.81699937, 25.08998671, 0. ]], + + [[-114.80920223, 25.12853632, 0. ], + [-114.80920223, 25.12853632, 3.60570857], + [-118.33369643, 25.89185792, 3.60570857], + [-121.85819063, 26.65517952, 3.60570857], + [-121.85819063, 26.65517952, 0. ], + [-121.85819063, 26.65517952, -3.60570857], + [-118.33369643, 25.89185792, -3.60570857], + [-114.80920223, 25.12853632, -3.60570857], + [-114.80920223, 25.12853632, 0. ]], + + [[-114.80096195, 25.16399411, 0. ], + [-114.80096195, 25.16399411, 3.60571021], + [-118.30186726, 26.02915614, 3.60571021], + [-121.80277257, 26.89431817, 3.60571021], + [-121.80277257, 26.89431817, 0. ], + [-121.80277257, 26.89431817, -3.60571021], + [-118.30186726, 26.02915614, -3.60571021], + [-114.80096195, 25.16399411, -3.60571021], + [-114.80096195, 25.16399411, 0. ]], + + [[-114.79236873, 25.19661889, 0. ], + [-114.79236873, 25.19661889, 3.60571183], + [-118.26632087, 26.16441003, 3.60571183], + [-121.740273 , 27.13220117, 3.60571183], + [-121.740273 , 27.13220117, 0. ], + [-121.740273 , 27.13220117, -3.60571183], + [-118.26632087, 26.16441003, -3.60571183], + [-114.79236873, 25.19661889, -3.60571183], + [-114.79236873, 25.19661889, 0. ]], + + [[-114.7834867 , 25.2266943 , 0. ], + [-114.7834867 , 25.2266943 , 3.60571342], + [-118.22704016, 26.29768193, 3.60571342], + [-121.67059362, 27.36866956, 3.60571342], + [-121.67059362, 27.36866956, 0. ], + [-121.67059362, 27.36866956, -3.60571342], + [-118.22704016, 26.29768193, -3.60571342], + [-114.7834867 , 25.2266943 , -3.60571342], + [-114.7834867 , 25.2266943 , 0. ]], + + [[-114.77435981, 25.25450023, 0. ], + [-114.77435981, 25.25450023, 3.60571499], + [-118.18402628, 26.42895571, 3.60571499], + [-121.59369276, 27.60341119, 3.60571499], + [-121.59369276, 27.60341119, 0. ], + [-121.59369276, 27.60341119, -3.60571499], + [-118.18402628, 26.42895571, -3.60571499], + [-114.77435981, 25.25450023, -3.60571499], + [-114.77435981, 25.25450023, 0. ]], + + [[-114.76500816, 25.28032327, 0. ], + [-114.76500816, 25.28032327, 3.60571655], + [-118.1372999 , 26.55817483, 3.60571655], + [-121.50959165, 27.83602639, 3.60571655], + [-121.50959165, 27.83602639, 0. ], + [-121.50959165, 27.83602639, -3.60571655], + [-118.1372999 , 26.55817483, -3.60571655], + [-114.76500816, 25.28032327, -3.60571655], + [-114.76500816, 25.28032327, 0. ]], + + [[-114.75541326, 25.30448527, 0. ], + [-114.75541326, 25.30448527, 3.60571808], + [-118.08683361, 26.6854149 , 3.60571808], + [-121.41825396, 28.06634453, 3.60571808], + [-121.41825396, 28.06634453, 0. ], + [-121.41825396, 28.06634453, -3.60571808], + [-118.08683361, 26.6854149 , -3.60571808], + [-114.75541326, 25.30448527, -3.60571808], + [-114.75541326, 25.30448527, 0. ]], + + [[-114.74553571, 25.32728761, 0. ], + [-114.74553571, 25.32728761, 3.6057196 ], + [-118.03264604, 26.81062515, 3.6057196 ], + [-121.31975637, 28.29396269, 3.6057196 ], + [-121.31975637, 28.29396269, 0. ], + [-121.31975637, 28.29396269, -3.6057196 ], + [-118.03264604, 26.81062515, -3.6057196 ], + [-114.74553571, 25.32728761, -3.6057196 ], + [-114.74553571, 25.32728761, 0. ]], + + [[-114.73529913, 25.34904822, 0. ], + [-114.73529913, 25.34904822, 3.6057211 ], + [-117.97472264, 26.93383809, 3.6057211 ], + [-121.21414615, 28.51862796, 3.6057211 ], + [-121.21414615, 28.51862796, 0. ], + [-121.21414615, 28.51862796, -3.6057211 ], + [-117.97472264, 26.93383809, -3.6057211 ], + [-114.73529913, 25.34904822, -3.6057211 ], + [-114.73529913, 25.34904822, 0. ]], + + [[-114.72460465, 25.37006446, 0. ], + [-114.72460465, 25.37006446, 3.60572259], + [-117.91309287, 27.05499495, 3.60572259], + [-121.10158108, 28.73992544, 3.60572259], + [-121.10158108, 28.73992544, 0. ], + [-121.10158108, 28.73992544, -3.60572259], + [-117.91309287, 27.05499495, -3.60572259], + [-114.72460465, 25.37006446, -3.60572259], + [-114.72460465, 25.37006446, 0. ]], + + [[-114.71331225, 25.39064809, 0. ], + [-114.71331225, 25.39064809, 3.60572407], + [-117.84771906, 27.17416946, 3.60572407], + [-120.98212587, 28.95769082, 3.60572407], + [-120.98212587, 28.95769082, 0. ], + [-120.98212587, 28.95769082, -3.60572407], + [-117.84771906, 27.17416946, -3.60572407], + [-114.71331225, 25.39064809, -3.60572407], + [-114.71331225, 25.39064809, 0. ]], + + [[-114.70126715, 25.41107369, 0. ], + [-114.70126715, 25.41107369, 3.60572553], + [-117.77863619, 27.2912997 , 3.60572553], + [-120.85600523, 29.17152572, 3.60572553], + [-120.85600523, 29.17152572, 0. ], + [-120.85600523, 29.17152572, -3.60572553], + [-117.77863619, 27.2912997 , -3.60572553], + [-114.70126715, 25.41107369, -3.60572553], + [-114.70126715, 25.41107369, 0. ]], + + [[-114.68826887, 25.43163149, 0. ], + [-114.68826887, 25.43163149, 3.60572698], + [-117.70576596, 27.40650721, 3.60572698], + [-120.72326304, 29.38138292, 3.60572698], + [-120.72326304, 29.38138292, 0. ], + [-120.72326304, 29.38138292, -3.60572698], + [-117.70576596, 27.40650721, -3.60572698], + [-114.68826887, 25.43163149, -3.60572698], + [-114.68826887, 25.43163149, 0. ]], + + [[-114.67413577, 25.4525273 , 0. ], + [-114.67413577, 25.4525273 , 3.60572842], + [-117.62925681, 27.51956346, 3.60572842], + [-120.58437785, 29.58659962, 3.60572842], + [-120.58437785, 29.58659962, 0. ], + [-120.58437785, 29.58659962, -3.60572842], + [-117.62925681, 27.51956346, -3.60572842], + [-114.67413577, 25.4525273 , -3.60572842], + [-114.67413577, 25.4525273 , 0. ]], + + [[-114.6586161 , 25.47402164, 0. ], + [-114.6586161 , 25.47402164, 3.60572986], + [-117.54897415, 27.6306758 , 3.60572986], + [-120.43933221, 29.78732997, 3.60572986], + [-120.43933221, 29.78732997, 0. ], + [-120.43933221, 29.78732997, -3.60572986], + [-117.54897415, 27.6306758 , -3.60572986], + [-114.6586161 , 25.47402164, -3.60572986], + [-114.6586161 , 25.47402164, 0. ]], + + [[-114.64148098, 25.4962913 , 0. ], + [-114.64148098, 25.4962913 , 3.60573128], + [-117.46498878, 27.73974013, 3.60573128], + [-120.28849657, 29.98318897, 3.60573128], + [-120.28849657, 29.98318897, 0. ], + [-120.28849657, 29.98318897, -3.60573128], + [-117.46498878, 27.73974013, -3.60573128], + [-114.64148098, 25.4962913 , -3.60573128], + [-114.64148098, 25.4962913 , 0. ]], + + [[-114.62246203, 25.51952334, 0. ], + [-114.62246203, 25.51952334, 3.6057327 ], + [-117.37722909, 27.8468475 , 3.6057327 ], + [-120.13199614, 30.17417165, 3.6057327 ], + [-120.13199614, 30.17417165, 0. ], + [-120.13199614, 30.17417165, -3.6057327 ], + [-117.37722909, 27.8468475 , -3.6057327 ], + [-114.62246203, 25.51952334, -3.6057327 ], + [-114.62246203, 25.51952334, 0. ]], + + [[-114.60132025, 25.54383013, 0. ], + [-114.60132025, 25.54383013, 3.60573411], + [-117.28579361, 27.95187609, 3.60573411], + [-119.97026697, 30.35992204, 3.60573411], + [-119.97026697, 30.35992204, 0. ], + [-119.97026697, 30.35992204, -3.60573411], + [-117.28579361, 27.95187609, -3.60573411], + [-114.60132025, 25.54383013, -3.60573411], + [-114.60132025, 25.54383013, 0. ]], + + [[-114.57778674, 25.56932988, 0. ], + [-114.57778674, 25.56932988, 3.60573551], + [-117.19064562, 28.0548789 , 3.60573551], + [-119.80350451, 30.54042793, 3.60573551], + [-119.80350451, 30.54042793, 0. ], + [-119.80350451, 30.54042793, -3.60573551], + [-117.19064562, 28.0548789 , -3.60573551], + [-114.57778674, 25.56932988, -3.60573551], + [-114.57778674, 25.56932988, 0. ]], + + [[-114.55158085, 25.5961204 , 0. ], + [-114.55158085, 25.5961204 , 3.6057369 ], + [-117.09171688, 28.15592219, 3.6057369 ], + [-119.63185291, 30.71572399, 3.6057369 ], + [-119.63185291, 30.71572399, 0. ], + [-119.63185291, 30.71572399, -3.6057369 ], + [-117.09171688, 28.15592219, -3.6057369 ], + [-114.55158085, 25.5961204 , -3.6057369 ], + [-114.55158085, 25.5961204 , 0. ]], + + [[-114.52247474, 25.62422268, 0. ], + [-114.52247474, 25.62422268, 3.60573829], + [-116.98911724, 28.25489452, 3.60573829], + [-119.45575974, 30.88556636, 3.60573829], + [-119.45575974, 30.88556636, 0. ], + [-119.45575974, 30.88556636, -3.60573829], + [-116.98911724, 28.25489452, -3.60573829], + [-114.52247474, 25.62422268, -3.60573829], + [-114.52247474, 25.62422268, 0. ]], + + [[-114.49019719, 25.65368238, 0. ], + [-114.49019719, 25.65368238, 3.60573968], + [-116.8827662 , 28.35187697, 3.60573968], + [-119.27533521, 31.05007156, 3.60573968], + [-119.27533521, 31.05007156, 0. ], + [-119.27533521, 31.05007156, -3.60573968], + [-116.8827662 , 28.35187697, -3.60573968], + [-114.49019719, 25.65368238, -3.60573968], + [-114.49019719, 25.65368238, 0. ]], + + [[-114.45452046, 25.68448756, 0. ], + [-114.45452046, 25.68448756, 3.60574105], + [-116.77270225, 28.4468329 , 3.60574105], + [-119.09088404, 31.20917825, 3.60574105], + [-119.09088404, 31.20917825, 0. ], + [-119.09088404, 31.20917825, -3.60574105], + [-116.77270225, 28.4468329 , -3.60574105], + [-114.45452046, 25.68448756, -3.60574105], + [-114.45452046, 25.68448756, 0. ]], + + [[-114.41519645, 25.71663154, 0. ], + [-114.41519645, 25.71663154, 3.60574243], + [-116.65886316, 28.5398128 , 3.60574243], + [-118.90252987, 31.36299406, 3.60574243], + [-118.90252987, 31.36299406, 0. ], + [-118.90252987, 31.36299406, -3.60574243], + [-116.65886316, 28.5398128 , -3.60574243], + [-114.41519645, 25.71663154, -3.60574243], + [-114.41519645, 25.71663154, 0. ]], + + [[-114.37205822, 25.75003331, 0. ], + [-114.37205822, 25.75003331, 3.60574379], + [-116.54137681, 28.63071376, 3.60574379], + [-118.7106954 , 31.51139421, 3.60574379], + [-118.7106954 , 31.51139421, 0. ], + [-118.7106954 , 31.51139421, -3.60574379], + [-116.54137681, 28.63071376, -3.60574379], + [-114.37205822, 25.75003331, -3.60574379], + [-114.37205822, 25.75003331, 0. ]], + + [[-114.3248857 , 25.78465164, 0. ], + [-114.3248857 , 25.78465164, 3.60574515], + [-116.42016646, 28.71960298, 3.60574515], + [-118.51544721, 31.65455432, 3.60574515], + [-118.51544721, 31.65455432, 0. ], + [-118.51544721, 31.65455432, -3.60574515], + [-116.42016646, 28.71960298, -3.60574515], + [-114.3248857 , 25.78465164, -3.60574515], + [-114.3248857 , 25.78465164, 0. ]], + + [[-114.27346611, 25.82043009, 0. ], + [-114.27346611, 25.82043009, 3.60574651], + [-116.29515678, 28.8065284 , 3.60574651], + [-118.31684745, 31.79262672, 3.60574651], + [-118.31684745, 31.79262672, 0. ], + [-118.31684745, 31.79262672, -3.60574651], + [-116.29515678, 28.8065284 , -3.60574651], + [-114.27346611, 25.82043009, -3.60574651], + [-114.27346611, 25.82043009, 0. ]], + + [[-114.2176977 , 25.85723533, 0. ], + [-114.2176977 , 25.85723533, 3.60574786], + [-116.16649536, 28.8913874 , 3.60574786], + [-118.11529303, 31.92553947, 3.60574786], + [-118.11529303, 31.92553947, 0. ], + [-118.11529303, 31.92553947, -3.60574786], + [-116.16649536, 28.8913874 , -3.60574786], + [-114.2176977 , 25.85723533, -3.60574786], + [-114.2176977 , 25.85723533, 0. ]], + + [[-114.157409 , 25.89498617, 0. ], + [-114.157409 , 25.89498617, 3.60574919], + [-116.03411187, 28.97423301, 3.60574919], + [-117.91081474, 32.05347985, 3.60574919], + [-117.91081474, 32.05347985, 0. ], + [-117.91081474, 32.05347985, -3.60574919], + [-116.03411187, 28.97423301, -3.60574919], + [-114.157409 , 25.89498617, -3.60574919], + [-114.157409 , 25.89498617, 0. ]], + + [[-114.09243654, 25.93359205, 0. ], + [-114.09243654, 25.93359205, 3.60575052], + [-115.89793855, 29.05510119, 3.60575052], + [-117.70344057, 32.17661033, 3.60575052], + [-117.70344057, 32.17661033, 0. ], + [-117.70344057, 32.17661033, -3.60575052], + [-115.89793855, 29.05510119, -3.60575052], + [-114.09243654, 25.93359205, -3.60575052], + [-114.09243654, 25.93359205, 0. ]], + + [[-114.02275846, 25.97288628, 0. ], + [-114.02275846, 25.97288628, 3.60575185], + [-115.75815695, 29.13388895, 3.60575185], + [-117.49355544, 32.29489162, 3.60575185], + [-117.49355544, 32.29489162, 0. ], + [-117.49355544, 32.29489162, -3.60575185], + [-115.75815695, 29.13388895, -3.60575185], + [-114.02275846, 25.97288628, -3.60575185], + [-114.02275846, 25.97288628, 0. ]], + + [[-113.94814712, 26.01282197, 0. ], + [-113.94814712, 26.01282197, 3.60575316], + [-115.6145068 , 29.2107407 , 3.60575316], + [-117.28086647, 32.40865943, 3.60575316], + [-117.28086647, 32.40865943, 0. ], + [-117.28086647, 32.40865943, -3.60575316], + [-115.6145068 , 29.2107407 , -3.60575316], + [-113.94814712, 26.01282197, -3.60575316], + [-113.94814712, 26.01282197, 0. ]], + + [[-113.8686693 , 26.05319753, 0. ], + [-113.8686693 , 26.05319753, 3.60575445], + [-115.46727407, 29.28550268, 3.60575445], + [-117.06587883, 32.51780784, 3.60575445], + [-117.06587883, 32.51780784, 0. ], + [-117.06587883, 32.51780784, -3.60575445], + [-115.46727407, 29.28550268, -3.60575445], + [-113.8686693 , 26.05319753, -3.60575445], + [-113.8686693 , 26.05319753, 0. ]], + + [[-113.78414826, 26.0939478 , 0. ], + [-113.78414826, 26.0939478 , 3.60575574], + [-115.31624978, 29.35828564, 3.60575574], + [-116.8483513 , 32.62262349, 3.60575574], + [-116.8483513 , 32.62262349, 0. ], + [-116.8483513 , 32.62262349, -3.60575574], + [-115.31624978, 29.35828564, -3.60575574], + [-113.78414826, 26.0939478 , -3.60575574], + [-113.78414826, 26.0939478 , 0. ]], + + [[-113.6945863 , 26.1349219 , 0. ], + [-113.6945863 , 26.1349219 , 3.60575701], + [-115.16153795, 29.42903742, 3.60575701], + [-116.62848959, 32.72315294, 3.60575701], + [-116.62848959, 32.72315294, 0. ], + [-116.62848959, 32.72315294, -3.60575701], + [-115.16153795, 29.42903742, -3.60575701], + [-113.6945863 , 26.1349219 , -3.60575701], + [-113.6945863 , 26.1349219 , 0. ]], + + [[-113.59985625, 26.17603517, 0. ], + [-113.59985625, 26.17603517, 3.60575826], + [-115.00299711, 29.49781942, 3.60575826], + [-116.40613797, 32.81960366, 3.60575826], + [-116.40613797, 32.81960366, 0. ], + [-116.40613797, 32.81960366, -3.60575826], + [-115.00299711, 29.49781942, -3.60575826], + [-113.59985625, 26.17603517, -3.60575826], + [-113.59985625, 26.17603517, 0. ]], + + [[-113.50009293, 26.21709822, 0. ], + [-113.50009293, 26.21709822, 3.60575949], + [-114.84090235, 29.56451515, 3.60575949], + [-116.18171177, 32.91193209, 3.60575949], + [-116.18171177, 32.91193209, 0. ], + [-116.18171177, 32.91193209, -3.60575949], + [-114.84090235, 29.56451515, -3.60575949], + [-113.50009293, 26.21709822, -3.60575949], + [-113.50009293, 26.21709822, 0. ]], + + [[-113.39510468, 26.25806689, 0. ], + [-113.39510468, 26.25806689, 3.60576071], + [-114.67497418, 29.62924279, 3.60576071], + [-115.95484368, 33.00041869, 3.60576071], + [-115.95484368, 33.00041869, 0. ], + [-115.95484368, 33.00041869, -3.60576071], + [-114.67497418, 29.62924279, -3.60576071], + [-113.39510468, 26.25806689, -3.60576071], + [-113.39510468, 26.25806689, 0. ]], + + [[-113.28495206, 26.29879716, 0. ], + [-113.28495206, 26.29879716, 3.6057619 ], + [-114.50533588, 29.69194932, 3.6057619 ], + [-115.7257197 , 33.08510147, 3.6057619 ], + [-115.7257197 , 33.08510147, 0. ], + [-115.7257197 , 33.08510147, -3.6057619 ], + [-114.50533588, 29.69194932, -3.6057619 ], + [-113.28495206, 26.29879716, -3.6057619 ], + [-113.28495206, 26.29879716, 0. ]], + + [[-113.1696214 , 26.33918427, 0. ], + [-113.1696214 , 26.33918427, 3.60576306], + [-114.33197429, 29.75264045, 3.60576306], + [-115.49432718, 33.16609664, 3.60576306], + [-115.49432718, 33.16609664, 0. ], + [-115.49432718, 33.16609664, -3.60576306], + [-114.33197429, 29.75264045, -3.60576306], + [-113.1696214 , 26.33918427, -3.60576306], + [-113.1696214 , 26.33918427, 0. ]], + + [[-113.04918103, 26.37910361, 0. ], + [-113.04918103, 26.37910361, 3.60576419], + [-114.1549859 , 29.81128634, 3.60576419], + [-115.26079077, 33.24346906, 3.60576419], + [-115.26079077, 33.24346906, 0. ], + [-115.26079077, 33.24346906, -3.60576419], + [-114.1549859 , 29.81128634, -3.60576419], + [-113.04918103, 26.37910361, -3.60576419], + [-113.04918103, 26.37910361, 0. ]], + + [[-112.92347525, 26.41850851, 0. ], + [-112.92347525, 26.41850851, 3.6057653 ], + [-113.97413452, 29.86796299, 3.6057653 ], + [-115.02479378, 33.31741746, 3.6057653 ], + [-115.02479378, 33.31741746, 0. ], + [-115.02479378, 33.31741746, -3.6057653 ], + [-113.97413452, 29.86796299, -3.6057653 ], + [-112.92347525, 26.41850851, -3.6057653 ], + [-112.92347525, 26.41850851, 0. ]], + + [[-112.79269072, 26.45724923, 0. ], + [-112.79269072, 26.45724923, 3.60576637], + [-113.7896721 , 29.92259099, 3.60576637], + [-114.78665347, 33.38793275, 3.60576637], + [-114.78665347, 33.38793275, 0. ], + [-114.78665347, 33.38793275, -3.60576637], + [-113.7896721 , 29.92259099, -3.60576637], + [-112.79269072, 26.45724923, -3.60576637], + [-112.79269072, 26.45724923, 0. ]], + + [[-112.60994077, 26.50835621, 0. ], + [-112.60994077, 26.50835621, 3.60576776], + [-113.53665923, 29.99332929, 3.60576776], + [-114.46337769, 33.47830237, 3.60576776], + [-114.46337769, 33.47830237, 0. ], + [-114.46337769, 33.47830237, -3.60576776], + [-113.53665923, 29.99332929, -3.60576776], + [-112.60994077, 26.50835621, -3.60576776], + [-112.60994077, 26.50835621, 0. ]], + + [[-112.36856695, 26.57010644, 0. ], + [-112.36856695, 26.57010644, 3.60576939], + [-113.21109301, 30.07653954, 3.60576939], + [-114.05361906, 33.58297264, 3.60576939], + [-114.05361906, 33.58297264, 0. ], + [-114.05361906, 33.58297264, -3.60576939], + [-113.21109301, 30.07653954, -3.60576939], + [-112.36856695, 26.57010644, -3.60576939], + [-112.36856695, 26.57010644, 0. ]], + + [[-112.06077272, 26.63976955, 0. ], + [-112.06077272, 26.63976955, 3.60577114], + [-112.80840845, 30.16760013, 3.60577114], + [-113.55604418, 33.69543071, 3.60577114], + [-113.55604418, 33.69543071, 0. ], + [-113.55604418, 33.69543071, -3.60577114], + [-112.80840845, 30.16760013, -3.60577114], + [-112.06077272, 26.63976955, -3.60577114], + [-112.06077272, 26.63976955, 0. ]], + + [[-111.73297395, 26.70498072, 0. ], + [-111.73297395, 26.70498072, 3.60577266], + [-112.3909015 , 30.25059033, 3.60577266], + [-113.04882905, 33.79619994, 3.60577266], + [-113.04882905, 33.79619994, 0. ], + [-113.04882905, 33.79619994, -3.60577266], + [-112.3909015 , 30.25059033, -3.60577266], + [-111.73297395, 26.70498072, -3.60577266], + [-111.73297395, 26.70498072, 0. ]], + + [[-111.38537 , 26.76526989, 0. ], + [-111.38537 , 26.76526989, 3.60577392], + [-111.9585045 , 30.32552891, 3.60577392], + [-112.53163901, 33.88578792, 3.60577392], + [-112.53163901, 33.88578792, 0. ], + [-112.53163901, 33.88578792, -3.60577392], + [-111.9585045 , 30.32552891, -3.60577392], + [-111.38537 , 26.76526989, -3.60577392], + [-111.38537 , 26.76526989, 0. ]], + + [[-111.01817496, 26.82021723, 0. ], + [-111.01817496, 26.82021723, 3.60577488], + [-111.51116674, 30.39241967, 3.60577488], + [-112.00415852, 33.96462212, 3.60577488], + [-112.00415852, 33.96462212, 0. ], + [-112.00415852, 33.96462212, -3.60577488], + [-111.51116674, 30.39241967, -3.60577488], + [-111.01817496, 26.82021723, -3.60577488], + [-111.01817496, 26.82021723, 0. ]], + + [[-110.63182565, 26.8694316 , 0. ], + [-110.63182565, 26.8694316 , 3.60577549], + [-111.04909722, 30.45123736, 3.60577549], + [-111.46636879, 34.03304313, 3.60577549], + [-111.46636879, 34.03304313, 0. ], + [-111.46636879, 34.03304313, -3.60577549], + [-111.04909722, 30.45123736, -3.60577549], + [-110.63182565, 26.8694316 , -3.60577549], + [-110.63182565, 26.8694316 , 0. ]], + + [[-110.36541233, 26.89780916, 0. ], + [-110.36541233, 26.89780916, 3.60577564], + [-110.73564027, 30.48460108, 3.60577564], + [-111.1058682 , 34.07139301, 3.60577564], + [-111.1058682 , 34.07139301, 0. ], + [-111.1058682 , 34.07139301, -3.60577564], + [-110.73564027, 30.48460108, -3.60577564], + [-110.36541233, 26.89780916, -3.60577564], + [-110.36541233, 26.89780916, 0. ]], + + [[-110.22919606, 26.91099117, 0. ], + [-110.22919606, 26.91099117, 3.60577564], + [-110.57651949, 30.5 , 3.60577564], + [-110.92384293, 34.08900883, 3.60577564], + [-110.92384293, 34.08900883, 0. ], + [-110.92384293, 34.08900883, -3.60577564], + [-110.57651949, 30.5 , -3.60577564], + [-110.22919606, 26.91099117, -3.60577564], + [-110.22919606, 26.91099117, 0. ]], + + [[-109.87998438, 26.94478702, 0. ], + [-109.87998438, 26.94478702, 3.60577564], + [-110.25753728, 30.53086998, 3.60577564], + [-110.63509019, 34.11695293, 3.60577564], + [-110.63509019, 34.11695293, 0. ], + [-110.63509019, 34.11695293, -3.60577564], + [-110.25753728, 30.53086998, -3.60577564], + [-109.87998438, 26.94478702, -3.60577564], + [-109.87998438, 26.94478702, 0. ]], + + [[-109.18877015, 27.02046672, 0. ], + [-109.18877015, 27.02046672, 3.6057763 ], + [-109.62815642, 30.59980847, 3.6057763 ], + [-110.06754269, 34.17915022, 3.6057763 ], + [-110.06754269, 34.17915022, 0. ], + [-110.06754269, 34.17915022, -3.6057763 ], + [-109.62815642, 30.59980847, -3.6057763 ], + [-109.18877015, 27.02046672, -3.6057763 ], + [-109.18877015, 27.02046672, 0. ]], + + [[-108.1608545 , 27.16104 , 0. ], + [-108.1608545 , 27.16104 , 3.60577909], + [-108.69858522, 30.72698094, 3.60577909], + [-109.23631594, 34.29292188, 3.60577909], + [-109.23631594, 34.29292188, 0. ], + [-109.23631594, 34.29292188, -3.60577909], + [-108.69858522, 30.72698094, -3.60577909], + [-108.1608545 , 27.16104 , -3.60577909], + [-108.1608545 , 27.16104 , 0. ]], + + [[-107.15476139, 27.32766147, 0. ], + [-107.15476139, 27.32766147, 3.60578337], + [-107.79534801, 30.87662237, 3.60578337], + [-108.43593463, 34.42558327, 3.60578337], + [-108.43593463, 34.42558327, 0. ], + [-108.43593463, 34.42558327, -3.60578337], + [-107.79534801, 30.87662237, -3.60578337], + [-107.15476139, 27.32766147, -3.60578337], + [-107.15476139, 27.32766147, 0. ]], + + [[-106.17041568, 27.520798 , 0. ], + [-106.17041568, 27.520798 , 3.60578892], + [-106.91841282, 31.04874368, 3.60578892], + [-107.66640996, 34.57668937, 3.60578892], + [-107.66640996, 34.57668937, 0. ], + [-107.66640996, 34.57668937, -3.60578892], + [-106.91841282, 31.04874368, -3.60578892], + [-106.17041568, 27.520798 , -3.60578892], + [-106.17041568, 27.520798 , 0. ]], + + [[-105.20783884, 27.74094304, 0. ], + [-105.20783884, 27.74094304, 3.60579552], + [-106.06778795, 31.24334988, 3.60579552], + [-106.92773706, 34.74575673, 3.60579552], + [-106.92773706, 34.74575673, 0. ], + [-106.92773706, 34.74575673, -3.60579552], + [-106.06778795, 31.24334988, -3.60579552], + [-105.20783884, 27.74094304, -3.60579552], + [-105.20783884, 27.74094304, 0. ]], + + [[-104.2671436 , 27.98861284, 0. ], + [-104.2671436 , 27.98861284, 3.60580298], + [-105.24350571, 31.46044019, 3.60580298], + [-106.21986781, 34.93226754, 3.60580298], + [-106.21986781, 34.93226754, 0. ], + [-106.21986781, 34.93226754, -3.60580298], + [-105.24350571, 31.46044019, -3.60580298], + [-104.2671436 , 27.98861284, -3.60580298], + [-104.2671436 , 27.98861284, 0. ]], + + [[-103.34853405, 28.264331 , 0. ], + [-103.34853405, 28.264331 , 3.60581113], + [-104.44560914, 31.70000174, 3.60581113], + [-105.54268424, 35.13567249, 3.60581113], + [-105.54268424, 35.13567249, 0. ], + [-105.54268424, 35.13567249, -3.60581113], + [-104.44560914, 31.70000174, -3.60581113], + [-103.34853405, 28.264331 , -3.60581113], + [-103.34853405, 28.264331 , 0. ]], + + [[-102.45203469, 28.56873084, 0. ], + [-102.45203469, 28.56873084, 3.60581984], + [-103.67391096, 31.96210572, 3.60581984], + [-104.89578723, 35.3554806 , 3.60581984], + [-104.89578723, 35.3554806 , 0. ], + [-104.89578723, 35.3554806 , -3.60581984], + [-103.67391096, 31.96210572, -3.60581984], + [-102.45203469, 28.56873084, -3.60581984], + [-102.45203469, 28.56873084, 0. ]], + + [[-101.57834103, 28.9022442 , 0. ], + [-101.57834103, 28.9022442 , 3.60582896], + [-102.92871259, 32.24665213, 3.60582896], + [-104.27908416, 35.59106005, 3.60582896], + [-104.27908416, 35.59106005, 0. ], + [-104.27908416, 35.59106005, -3.60582896], + [-102.92871259, 32.24665213, -3.60582896], + [-101.57834103, 28.9022442 , -3.60582896], + [-101.57834103, 28.9022442 , 0. ]], + + [[-100.72754826, 29.26554562, 0. ], + [-100.72754826, 29.26554562, 3.60583839], + [-102.20970521, 32.55376537, 3.60583839], + [-103.69186217, 35.84198512, 3.60583839], + [-103.69186217, 35.84198512, 0. ], + [-103.69186217, 35.84198512, -3.60583839], + [-102.20970521, 32.55376537, -3.60583839], + [-100.72754826, 29.26554562, -3.60583839], + [-100.72754826, 29.26554562, 0. ]], + + [[ -99.90052717, 29.65901246, 0. ], + [ -99.90052717, 29.65901246, 3.60584803], + [-101.51713768, 32.88335211, 3.60584803], + [-103.13374818, 36.10769176, 3.60584803], + [-103.13374818, 36.10769176, 0. ], + [-103.13374818, 36.10769176, -3.60584803], + [-101.51713768, 32.88335211, -3.60584803], + [ -99.90052717, 29.65901246, -3.60584803], + [ -99.90052717, 29.65901246, 0. ]], + + [[ -99.09777293, 30.08317306, 0. ], + [ -99.09777293, 30.08317306, 3.60585781], + [-100.85083623, 33.23550195, 3.60585781], + [-102.60389953, 36.38783085, 3.60585781], + [-102.60389953, 36.38783085, 0. ], + [-102.60389953, 36.38783085, -3.60585781], + [-100.85083623, 33.23550195, -3.60585781], + [ -99.09777293, 30.08317306, -3.60585781], + [ -99.09777293, 30.08317306, 0. ]], + + [[ -98.32030959, 30.53826031, 0. ], + [ -98.32030959, 30.53826031, 3.60586765], + [-100.21096682, 33.61013591, 3.60586765], + [-102.10162405, 36.68201151, 3.60586765], + [-102.10162405, 36.68201151, 0. ], + [-102.10162405, 36.68201151, -3.60586765], + [-100.21096682, 33.61013591, -3.60586765], + [ -98.32030959, 30.53826031, -3.60586765], + [ -98.32030959, 30.53826031, 0. ]], + + [[ -97.56885993, 31.0246246 , 0. ], + [ -97.56885993, 31.0246246 , 3.60587749], + [ -99.59735344, 34.00737159, 3.60587749], + [-101.62584695, 36.99011857, 3.60587749], + [-101.62584695, 36.99011857, 0. ], + [-101.62584695, 36.99011857, -3.60587749], + [ -99.59735344, 34.00737159, -3.60587749], + [ -97.56885993, 31.0246246 , -3.60587749], + [ -97.56885993, 31.0246246 , 0. ]], + + [[ -96.84476019, 31.54213518, 0. ], + [ -96.84476019, 31.54213518, 3.60588727], + [ -99.01024386, 34.42705424, 3.60588727], + [-101.17572753, 37.31197331, 3.60588727], + [-101.17572753, 37.31197331, 0. ], + [-101.17572753, 37.31197331, -3.60588727], + [ -99.01024386, 34.42705424, -3.60588727], + [ -96.84476019, 31.54213518, -3.60588727], + [ -96.84476019, 31.54213518, 0. ]], + + [[ -96.1488279 , 32.09088984, 0. ], + [ -96.1488279 , 32.09088984, 3.60589696], + [ -98.4494072 , 34.8693539 , 3.60589696], + [-100.74998651, 37.64781796, 3.60589696], + [-100.74998651, 37.64781796, 0. ], + [-100.74998651, 37.64781796, -3.60589696], + [ -98.4494072 , 34.8693539 , -3.60589696], + [ -96.1488279 , 32.09088984, -3.60589696], + [ -96.1488279 , 32.09088984, 0. ]], + + [[ -95.59271997, 32.57451777, 0. ], + [ -95.59271997, 32.57451777, 3.60590492], + [ -98.00346985, 35.25721987, 3.60590492], + [-100.41421972, 37.93992198, 3.60590492], + [-100.41421972, 37.93992198, 0. ], + [-100.41421972, 37.93992198, -3.60590492], + [ -98.00346985, 35.25721987, -3.60590492], + [ -95.59271997, 32.57451777, -3.60590492], + [ -95.59271997, 32.57451777, 0. ]], + + [[ -95.16345056, 32.97640922, 0. ], + [ -95.16345056, 32.97640922, 3.6059112 ], + [ -97.66018006, 35.57862772, 3.6059112 ], + [-100.15690956, 38.18084622, 3.6059112 ], + [-100.15690956, 38.18084622, 0. ], + [-100.15690956, 38.18084622, -3.6059112 ], + [ -97.66018006, 35.57862772, -3.6059112 ], + [ -95.16345056, 32.97640922, -3.6059112 ], + [ -95.16345056, 32.97640922, 0. ]], + + [[ -94.84988748, 33.2847366 , 0. ], + [ -94.84988748, 33.2847366 , 3.60591585], + [ -97.40979458, 35.8248418 , 3.60591585], + [ -99.96970169, 38.364947 , 3.60591585], + [ -99.96970169, 38.364947 , 0. ], + [ -99.96970169, 38.364947 , -3.60591585], + [ -97.40979458, 35.8248418 , -3.60591585], + [ -94.84988748, 33.2847366 , -3.60591585], + [ -94.84988748, 33.2847366 , 0. ]], + + [[ -94.59495959, 33.54806598, 0. ], + [ -94.59495959, 33.54806598, 3.60591968], + [ -97.20646104, 36.03488329, 3.60591968], + [ -99.81796248, 38.5217006 , 3.60591968], + [ -99.81796248, 38.5217006 , 0. ], + [ -99.81796248, 38.5217006 , -3.60591968], + [ -97.20646104, 36.03488329, -3.60591968], + [ -94.59495959, 33.54806598, -3.60591968], + [ -94.59495959, 33.54806598, 0. ]], + + [[ -94.39512076, 33.76229421, 0. ], + [ -94.39512076, 33.76229421, 3.60592272], + [ -97.04715857, 36.20566016, 3.60592272], + [ -99.69919638, 38.6490261 , 3.60592272], + [ -99.69919638, 38.6490261 , 0. ], + [ -99.69919638, 38.6490261 , -3.60592272], + [ -97.04715857, 36.20566016, -3.60592272], + [ -94.39512076, 33.76229421, -3.60592272], + [ -94.39512076, 33.76229421, 0. ]], + + [[ -94.19801472, 33.9789032 , 0. ], + [ -94.19801472, 33.9789032 , 3.60592574], + [ -96.89008071, 36.37828426, 3.60592574], + [ -99.58214669, 38.77766532, 3.60592574], + [ -99.58214669, 38.77766532, 0. ], + [ -99.58214669, 38.77766532, -3.60592574], + [ -96.89008071, 36.37828426, -3.60592574], + [ -94.19801472, 33.9789032 , -3.60592574], + [ -94.19801472, 33.9789032 , 0. ]], + + [[ -94.00497408, 34.19912012, 0. ], + [ -94.00497408, 34.19912012, 3.60592872], + [ -96.73628894, 36.55373091, 3.60592872], + [ -99.46760381, 38.9083417 , 3.60592872], + [ -99.46760381, 38.9083417 , 0. ], + [ -99.46760381, 38.9083417 , -3.60592872], + [ -96.73628894, 36.55373091, -3.60592872], + [ -94.00497408, 34.19912012, -3.60592872], + [ -94.00497408, 34.19912012, 0. ]], + + [[ -93.81611383, 34.4228172 , 0. ], + [ -93.81611383, 34.4228172 , 3.60593167], + [ -96.58583044, 36.73194624, 3.60593167], + [ -99.35554705, 39.04107528, 3.60593167], + [ -99.35554705, 39.04107528, 0. ], + [ -99.35554705, 39.04107528, -3.60593167], + [ -96.58583044, 36.73194624, -3.60593167], + [ -93.81611383, 34.4228172 , -3.60593167], + [ -93.81611383, 34.4228172 , 0. ]], + + [[ -93.67656562, 34.59231797, 0. ], + [ -93.67656562, 34.59231797, 3.60593387], + [ -96.47464828, 36.86699515, 3.60593387], + [ -99.27273095, 39.14167232, 3.60593387], + [ -99.27273095, 39.14167232, 0. ], + [ -99.27273095, 39.14167232, -3.60593387], + [ -96.47464828, 36.86699515, -3.60593387], + [ -93.67656562, 34.59231797, -3.60593387], + [ -93.67656562, 34.59231797, 0. ]], + + [[ -93.53905718, 34.76361774, 0. ], + [ -93.53905718, 34.76361774, 3.60593604], + [ -96.36507224, 37.00350097, 3.60593604], + [ -99.1910873 , 39.2433842 , 3.60593604], + [ -99.1910873 , 39.2433842 , 0. ], + [ -99.1910873 , 39.2433842 , -3.60593604], + [ -96.36507224, 37.00350097, -3.60593604], + [ -93.53905718, 34.76361774, -3.60593604], + [ -93.53905718, 34.76361774, 0. ]], + + [[ -93.35853328, 34.99429206, 0. ], + [ -93.35853328, 34.99429206, 3.60593892], + [ -96.22118029, 37.18737025, 3.60593892], + [ -99.0838273 , 39.38044845, 3.60593892], + [ -99.0838273 , 39.38044845, 0. ], + [ -99.0838273 , 39.38044845, -3.60593892], + [ -96.22118029, 37.18737025, -3.60593892], + [ -93.35853328, 34.99429206, -3.60593892], + [ -93.35853328, 34.99429206, 0. ]], + + [[ -93.18222971, 35.22838587, 0. ], + [ -93.18222971, 35.22838587, 3.60594176], + [ -96.08057571, 37.37406497, 3.60594176], + [ -98.97892172, 39.51974407, 3.60594176], + [ -98.97892172, 39.51974407, 0. ], + [ -98.97892172, 39.51974407, -3.60594176], + [ -96.08057571, 37.37406497, -3.60594176], + [ -93.18222971, 35.22838587, -3.60594176], + [ -93.18222971, 35.22838587, 0. ]], + + [[ -93.01026902, 35.46571041, 0. ], + [ -93.01026902, 35.46571041, 3.60594455], + [ -95.94332389, 37.56349045, 3.60594455], + [ -98.87637877, 39.66127049, 3.60594455], + [ -98.87637877, 39.66127049, 0. ], + [ -98.87637877, 39.66127049, -3.60594455], + [ -95.94332389, 37.56349045, -3.60594455], + [ -93.01026902, 35.46571041, -3.60594455], + [ -93.01026902, 35.46571041, 0. ]], + + [[ -92.84109795, 35.70533358, 0. ], + [ -92.84109795, 35.70533358, 3.60594732], + [ -95.80821345, 37.75487139, 3.60594732], + [ -98.77532895, 39.80440919, 3.60594732], + [ -98.77532895, 39.80440919, 0. ], + [ -98.77532895, 39.80440919, -3.60594732], + [ -95.80821345, 37.75487139, -3.60594732], + [ -92.84109795, 35.70533358, -3.60594732], + [ -92.84109795, 35.70533358, 0. ]], + + [[ -92.63481199, 36.00925145, 0. ], + [ -92.63481199, 36.00925145, 3.60595073], + [ -95.64328073, 37.99786387, 3.60595073], + [ -98.65174947, 39.98647629, 3.60595073], + [ -98.65174947, 39.98647629, 0. ], + [ -98.65174947, 39.98647629, -3.60595073], + [ -95.64328073, 37.99786387, -3.60595073], + [ -92.63481199, 36.00925145, -3.60595073], + [ -92.63481199, 36.00925145, 0. ]], + + [[ -92.39638822, 36.37966127, 0. ], + [ -92.39638822, 36.37966127, 3.60595472], + [ -95.45231135, 38.29454774, 3.60595472], + [ -98.50823448, 40.20943422, 3.60595472], + [ -98.50823448, 40.20943422, 0. ], + [ -98.50823448, 40.20943422, -3.60595472], + [ -95.45231135, 38.29454774, -3.60595472], + [ -92.39638822, 36.37966127, -3.60595472], + [ -92.39638822, 36.37966127, 0. ]], + + [[ -92.16634715, 36.75682965, 0. ], + [ -92.16634715, 36.75682965, 3.60595861], + [ -95.26766511, 38.5972848 , 3.60595861], + [ -98.36898307, 40.43773996, 3.60595861], + [ -98.36898307, 40.43773996, 0. ], + [ -98.36898307, 40.43773996, -3.60595861], + [ -95.26766511, 38.5972848 , -3.60595861], + [ -92.16634715, 36.75682965, -3.60595861], + [ -92.16634715, 36.75682965, 0. ]], + + [[ -91.94539765, 37.13951427, 0. ], + [ -91.94539765, 37.13951427, 3.60596239], + [ -95.08988358, 38.9051975 , 3.60596239], + [ -98.23436952, 40.67088073, 3.60596239], + [ -98.23436952, 40.67088073, 0. ], + [ -98.23436952, 40.67088073, -3.60596239], + [ -95.08988358, 38.9051975 , -3.60596239], + [ -91.94539765, 37.13951427, -3.60596239], + [ -91.94539765, 37.13951427, 0. ]], + + [[ -91.73291273, 37.52867885, 0. ], + [ -91.73291273, 37.52867885, 3.60596606], + [ -94.91844483, 39.21917985, 3.60596606], + [ -98.10397693, 40.90968084, 3.60596606], + [ -98.10397693, 40.90968084, 0. ], + [ -98.10397693, 40.90968084, -3.60596606], + [ -94.91844483, 39.21917985, -3.60596606], + [ -91.73291273, 37.52867885, -3.60596606], + [ -91.73291273, 37.52867885, 0. ]], + + [[ -91.52958294, 37.92293081, 0. ], + [ -91.52958294, 37.92293081, 3.6059696 ], + [ -94.75389781, 39.53822461, 3.6059696 ], + [ -97.97821267, 41.15351841, 3.6059696 ], + [ -97.97821267, 41.15351841, 0. ], + [ -97.97821267, 41.15351841, -3.6059696 ], + [ -94.75389781, 39.53822461, -3.6059696 ], + [ -91.52958294, 37.92293081, -3.6059696 ], + [ -91.52958294, 37.92293081, 0. ]], + + [[ -91.33462586, 38.32364899, 0. ], + [ -91.33462586, 38.32364899, 3.60597301], + [ -94.59560997, 39.86356236, 3.60597301], + [ -97.85659409, 41.40347573, 3.60597301], + [ -97.85659409, 41.40347573, 0. ], + [ -97.85659409, 41.40347573, -3.60597301], + [ -94.59560997, 39.86356236, -3.60597301], + [ -91.33462586, 38.32364899, -3.60597301], + [ -91.33462586, 38.32364899, 0. ]], + + [[ -91.14888115, 38.72895101, 0. ], + [ -91.14888115, 38.72895101, 3.60597627], + [ -94.44427236, 40.19377502, 3.60597627], + [ -97.73966356, 41.65859904, 3.60597627], + [ -97.73966356, 41.65859904, 0. ], + [ -97.73966356, 41.65859904, -3.60597627], + [ -94.44427236, 40.19377502, -3.60597627], + [ -91.14888115, 38.72895101, -3.60597627], + [ -91.14888115, 38.72895101, 0. ]], + + [[ -90.97147278, 39.14055796, 0. ], + [ -90.97147278, 39.14055796, 3.60597939], + [ -94.29918906, 40.53037087, 3.60597939], + [ -97.62690535, 41.92018378, 3.60597939], + [ -97.62690535, 41.92018378, 0. ], + [ -97.62690535, 41.92018378, -3.60597939], + [ -94.29918906, 40.53037087, -3.60597939], + [ -90.97147278, 39.14055796, -3.60597939], + [ -90.97147278, 39.14055796, 0. ]], + + [[ -90.80319982, 39.5564347 , 0. ], + [ -90.80319982, 39.5564347 , 3.60598233], + [ -94.16103823, 40.87178704, 3.60598233], + [ -97.51887664, 42.18713939, 3.60598233], + [ -97.51887664, 42.18713939, 0. ], + [ -97.51887664, 42.18713939, -3.60598233], + [ -94.16103823, 40.87178704, -3.60598233], + [ -90.80319982, 39.5564347 , -3.60598233], + [ -90.80319982, 39.5564347 , 0. ]], + + [[ -90.64322155, 39.97843021, 0. ], + [ -90.64322155, 39.97843021, 3.60598512], + [ -94.02916206, 41.21963673, 3.60598512], + [ -97.41510257, 42.46084326, 3.60598512], + [ -97.41510257, 42.46084326, 0. ], + [ -97.41510257, 42.46084326, -3.60598512], + [ -94.02916206, 41.21963673, -3.60598512], + [ -90.64322155, 39.97843021, -3.60598512], + [ -90.64322155, 39.97843021, 0. ]], + + [[ -90.4922681 , 40.40439789, 0. ], + [ -90.4922681 , 40.40439789, 3.6059877 ], + [ -93.90420024, 41.57224059, 3.6059877 ], + [ -97.31613238, 42.74008328, 3.6059877 ], + [ -97.31613238, 42.74008328, 0. ], + [ -97.31613238, 42.74008328, -3.6059877 ], + [ -93.90420024, 41.57224059, -3.6059877 ], + [ -90.4922681 , 40.40439789, -3.6059877 ], + [ -90.4922681 , 40.40439789, 0. ]], + + [[ -90.30136793, 40.98211526, 0. ], + [ -90.30136793, 40.98211526, 3.6059909 ], + [ -93.74548454, 42.05252905, 3.6059909 ], + [ -97.18960116, 43.12294284, 3.6059909 ], + [ -97.18960116, 43.12294284, 0. ], + [ -97.18960116, 43.12294284, -3.6059909 ], + [ -93.74548454, 42.05252905, -3.6059909 ], + [ -90.30136793, 40.98211526, -3.6059909 ], + [ -90.30136793, 40.98211526, 0. ]], + + [[ -90.1284285 , 41.56722463, 0. ], + [ -90.1284285 , 41.56722463, 3.60599366], + [ -93.60070498, 42.54220561, 3.60599366], + [ -97.07298146, 43.5171866 , 3.60599366], + [ -97.07298146, 43.5171866 , 0. ], + [ -97.07298146, 43.5171866 , -3.60599366], + [ -93.60070498, 42.54220561, -3.60599366], + [ -90.1284285 , 41.56722463, -3.60599366], + [ -90.1284285 , 41.56722463, 0. ]], + + [[ -89.97295732, 42.15857425, 0. ], + [ -89.97295732, 42.15857425, 3.60599591], + [ -93.46969051, 43.04049325, 3.60599591], + [ -96.9664237 , 43.92241225, 3.60599591], + [ -96.9664237 , 43.92241225, 0. ], + [ -96.9664237 , 43.92241225, -3.60599591], + [ -93.46969051, 43.04049325, -3.60599591], + [ -89.97295732, 42.15857425, -3.60599591], + [ -89.97295732, 42.15857425, 0. ]], + + [[ -89.86395629, 42.60948351, 0. ], + [ -89.86395629, 42.60948351, 3.60599735], + [ -93.37741375, 43.422186 , 3.60599735], + [ -96.89087122, 44.23488849, 3.60599735], + [ -96.89087122, 44.23488849, 0. ], + [ -96.89087122, 44.23488849, -3.60599735], + [ -93.37741375, 43.422186 , -3.60599735], + [ -89.86395629, 42.60948351, -3.60599735], + [ -89.86395629, 42.60948351, 0. ]], + + [[ -89.76354227, 43.06350049, 0. ], + [ -89.76354227, 43.06350049, 3.6059985 ], + [ -93.2920136 , 43.808282 , 3.6059985 ], + [ -96.82048493, 44.55306351, 3.6059985 ], + [ -96.82048493, 44.55306351, 0. ], + [ -96.82048493, 44.55306351, -3.6059985 ], + [ -93.2920136 , 43.808282 , -3.6059985 ], + [ -89.76354227, 43.06350049, -3.6059985 ], + [ -89.76354227, 43.06350049, 0. ]], + + [[ -89.67098781, 43.52352518, 0. ], + [ -89.67098781, 43.52352518, 3.60599935], + [ -93.21293433, 44.20129069, 3.60599935], + [ -96.75488085, 44.8790562 , 3.60599935], + [ -96.75488085, 44.8790562 , 0. ], + [ -96.75488085, 44.8790562 , -3.60599935], + [ -93.21293433, 44.20129069, -3.60599935], + [ -89.67098781, 43.52352518, -3.60599935], + [ -89.67098781, 43.52352518, 0. ]], + + [[ -89.58685463, 43.98635094, 0. ], + [ -89.58685463, 43.98635094, 3.60599988], + [ -93.14071898, 44.5985095 , 3.60599988], + [ -96.69458333, 45.21066806, 3.60599988], + [ -96.69458333, 45.21066806, 0. ], + [ -96.69458333, 45.21066806, -3.60599988], + [ -93.14071898, 44.5985095 , -3.60599988], + [ -89.58685463, 43.98635094, -3.60599988], + [ -89.58685463, 43.98635094, 0. ]], + + [[ -89.53630082, 44.29665922, 0. ], + [ -89.53630082, 44.29665922, 3.606 ], + [ -93.09712777, 44.86604629, 3.606 ], + [ -96.65795472, 45.43543337, 3.606 ], + [ -96.65795472, 45.43543337, 0. ], + [ -96.65795472, 45.43543337, -3.606 ], + [ -93.09712777, 44.86604629, -3.606 ], + [ -89.53630082, 44.29665922, -3.606 ], + [ -89.53630082, 44.29665922, 0. ]], + + [[ -89.51245115, 44.45168179, 0. ], + [ -89.51245115, 44.45168179, 3.606 ], + [ -93.07651949, 45. , 3.606 ], + [ -96.64058784, 45.54831821, 3.606 ], + [ -96.64058784, 45.54831821, 0. ], + [ -96.64058784, 45.54831821, -3.606 ], + [ -93.07651949, 45. , -3.606 ], + [ -89.51245115, 44.45168179, -3.606 ], + [ -89.51245115, 44.45168179, 0. ]]]), + weights=np.array([[1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ], + [1. , 0.70710678, 1. , 0.70710678, 1. , + 0.70710678, 1. , 0.70710678, 1. ]]) +) diff --git a/examples/ssx/case_18.py b/examples/ssx/case_18.py new file mode 100644 index 00000000..ab10ae96 --- /dev/null +++ b/examples/ssx/case_18.py @@ -0,0 +1,201 @@ +import time + +import numpy as np +from mmcore.nurbs._nurbs_eval import NURBSSurfaceTuple + + +s1 = NURBSSurfaceTuple( + order_u=3, + order_v=2, + knot_u=np.array([ 0. , 0. , 0. , 10.05800403, 10.05800403, + 20.11600806, 20.11600806, 30.1740121 , 30.1740121 , 40.23201613, + 40.23201613, 40.23201613]), + knot_v=np.array([ 0., 0., 32., 32.]), + control_points=np.array([[[-20., 12., 27.], + [-16., 7., -5.]], + + [[-20., 12., 27.], + [-21., 3., -5.]], + + [[-20., 12., 27.], + [-25., 8., -5.]], + + [[-20., 12., 27.], + [-29., 13., -5.]], + + [[-20., 12., 27.], + [-24., 17., -5.]], + + [[-20., 12., 27.], + [-19., 21., -5.]], + + [[-20., 12., 27.], + [-15., 16., -5.]], + + [[-20., 12., 27.], + [-11., 11., -5.]], + + [[-20., 12., 27.], + [-16., 7., -5.]]]), + weights=np.array([[1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ]]) +) + + +s2 = NURBSSurfaceTuple( + order_u=3, + order_v=2, + knot_u=np.array([ 0. , 0. , 0. , 10.05800403, 10.05800403, + 20.11600806, 20.11600806, 30.1740121 , 30.1740121 , 40.23201613, + 40.23201613, 40.23201613]), + knot_v=np.array([ 0., 0., 32., 32.]), + control_points=np.array([[[-16., 17., -5.], + [-12., 22., 27.]], + + [[-16., 17., -5.], + [-17., 26., 27.]], + + [[-16., 17., -5.], + [-21., 21., 27.]], + + [[-16., 17., -5.], + [-25., 16., 27.]], + + [[-16., 17., -5.], + [-20., 12., 27.]], + + [[-16., 17., -5.], + [-15., 8., 27.]], + + [[-16., 17., -5.], + [-11., 13., 27.]], + + [[-16., 17., -5.], + [ -7., 18., 27.]], + + [[-16., 17., -5.], + [-12., 22., 27.]]]), + weights=np.array([[1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ]]) +) + + + + +s2 = NURBSSurfaceTuple( + order_u=3, + order_v=2, + knot_u=np.array([ 0. , 0. , 0. , 10.05800403, 10.05800403, + 20.11600806, 20.11600806, 30.1740121 , 30.1740121 , 40.23201613, + 40.23201613, 40.23201613]), + knot_v=np.array([ 0., 0., 32., 32.]), + control_points=np.array([[[-20., 12., 27.], + [-16., 7., -5.]], + + [[-20., 12., 27.], + [-21., 3., -5.]], + + [[-20., 12., 27.], + [-25., 8., -5.]], + + [[-20., 12., 27.], + [-29., 13., -5.]], + + [[-20., 12., 27.], + [-24., 17., -5.]], + + [[-20., 12., 27.], + [-19., 21., -5.]], + + [[-20., 12., 27.], + [-15., 16., -5.]], + + [[-20., 12., 27.], + [-11., 11., -5.]], + + [[-20., 12., 27.], + [-16., 7., -5.]]]), + weights=np.array([[1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ]]) +) + + +s3 = NURBSSurfaceTuple( + order_u=3, + order_v=2, + knot_u=np.array([ 0. , 0. , 0. , 10.05800403, 10.05800403, + 20.11600806, 20.11600806, 30.1740121 , 30.1740121 , 40.23201613, + 40.23201613, 40.23201613]), + knot_v=np.array([ 0., 0., 32., 32.]), + control_points=np.array([[[-16. , 17. , -5. ], + [-12.9454394 , 22.62758025, 27. ]], + + [[-16. , 17. , -5. ], + [-18.57301965, 25.68214086, 27. ]], + + [[-16. , 17. , -5. ], + [-21.62758025, 20.0545606 , 27. ]], + + [[-16. , 17. , -5. ], + [-24.68214086, 14.42698035, 27. ]], + + [[-16. , 17. , -5. ], + [-19.0545606 , 11.37241975, 27. ]], + + [[-16. , 17. , -5. ], + [-13.42698035, 8.31785914, 27. ]], + + [[-16. , 17. , -5. ], + [-10.37241975, 13.9454394 , 27. ]], + + [[-16. , 17. , -5. ], + [ -7.31785914, 19.57301965, 27. ]], + + [[-16. , 17. , -5. ], + [-12.9454394 , 22.62758025, 27. ]]]), + weights=np.array([[1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ], + [0.70710678, 0.70710678], + [1. , 1. ]]) +) + +from mmcore.numeric.intersection.ssx import nurbs_ssx + +if __name__ == "__main__": + start1=time.perf_counter() + result= nurbs_ssx( s1, s2, atol=1e-3) + end1=time.perf_counter() + print( result) + print( end1-start1,'secs.' ) + start2=time.perf_counter() + result = nurbs_ssx(s1, s2, atol=1e-3) + end2=time.perf_counter() + print( result) + print(end2 - start2, 'secs.') + diff --git a/examples/ssx/case_19.py b/examples/ssx/case_19.py new file mode 100644 index 00000000..a6f57804 --- /dev/null +++ b/examples/ssx/case_19.py @@ -0,0 +1,18 @@ +import os +import sys + +import numpy as np + +sys.path.append(os.path.abspath(os.path.dirname(__file__))) +from _case_19_data import surf1,surf2 + +from mmcore.numeric.intersection.ssx import nurbs_ssx +if __name__ == "__main__": + import time + start=time.perf_counter() + result= nurbs_ssx( surf1, surf2, atol=1e-3) + end=time.perf_counter() + print( result) + print(f'{end-start} secs.') + + From 9ffabdb6c13d2b75619724fc6554eb19a8cd22e1 Mon Sep 17 00:00:00 2001 From: sth-v Date: Sat, 26 Sep 2026 04:37:45 +0300 Subject: [PATCH 2/2] Filter NURBS SSX candidates with padded hull bounds before tracing --- .../reviews/2026-09-26-ssx-broad-phase.md | 116 ++++++++ mmcore/numeric/algorithms/_gjk.cpp | 11 +- mmcore/numeric/algorithms/cygjk.pxd | 7 +- mmcore/numeric/algorithms/cygjk.pyx | 70 +++++ mmcore/numeric/intersection/ssx/_nssx5.py | 7 + .../intersection/ssx/_ssx_broad_phase.py | 187 ++++++++++++ .../intersection/ssx/_ssx_hull_refine.py | 186 ++++++++++++ tests/test_gjk_separating_axis.py | 119 ++++++++ tests/test_ssx_broad_phase.py | 270 ++++++++++++++++++ tests/test_ssx_hull_refinement.py | 212 ++++++++++++++ tools/benchmark_ssx_broad_phase.py | 179 ++++++++++++ 11 files changed, 1359 insertions(+), 5 deletions(-) create mode 100644 docs/superpowers/reviews/2026-09-26-ssx-broad-phase.md create mode 100644 mmcore/numeric/intersection/ssx/_ssx_broad_phase.py create mode 100644 mmcore/numeric/intersection/ssx/_ssx_hull_refine.py create mode 100644 tests/test_gjk_separating_axis.py create mode 100644 tests/test_ssx_broad_phase.py create mode 100644 tests/test_ssx_hull_refinement.py create mode 100644 tools/benchmark_ssx_broad_phase.py diff --git a/docs/superpowers/reviews/2026-09-26-ssx-broad-phase.md b/docs/superpowers/reviews/2026-09-26-ssx-broad-phase.md new file mode 100644 index 00000000..675787e4 --- /dev/null +++ b/docs/superpowers/reviews/2026-09-26-ssx-broad-phase.md @@ -0,0 +1,116 @@ +# NURBS SSX broad-phase performance + +The broad phase now rejects separated patch pairs before calling `bez_ssx`. +The original patches, parameter domains, pair order, and requested `atol` +are retained for every surviving solve. + +## Measurements + +Diagnostic runs on the same local Python 3.14 environment at `atol=1e-3`: + +| Fixture | Bézier patches | Original calls | Filtered calls | Before | After | +|---|---:|---:|---:|---:|---:| +| `nurbs_nurbs_intersection_2.py` | 108 × 108 | 2,485 | 446 | 117.5 s | 47.3 s | +| `case_19.py` | 492 × 664 | 7,426 | 290 | 651.2 s | 111.4 s | + +These are individual diagnostic timings, not general speed guarantees. +The returned branch arrays, points, singularities and overlap regions were +byte-identical to each baseline. Existing completion/reason status was also +unchanged. In particular, this performance change does not resolve case19's +existing `depth_limit` and `unresolved_multiplicity` reports. + +For the reported example, 2,039 complete-empty patch solves consumed 69.3 s. +Boundary CSX alone took 109.9 s across the original candidate list. Tree +construction and traversal took only about 11 ms; decomposition took 43 ms. + +## What changed + +The existing `lbvh.py` tree is already built top-down, by median splitting +along the largest centroid span. Its 2,485 reported pairs exactly match the +overlapping leaf AABBs. A different split strategy with the same leaf boxes +would change traversal cost, but not which pairs reach the narrow phase. + +The new sequence keeps that tree and adds: + +1. Cached PCA directions for participating patches. Six frame axes and nine + cross axes supply the usual OBB test directions, but intervals are measured + over the actual control points rather than the looser fitted boxes. +2. A native GJK direction proposal for remaining hull pairs. The old Boolean + API is unchanged. Every proposed axis is checked again against the full + control nets; a Boolean negative alone never deletes a candidate. +3. Up to two levels of lazy homogeneous subdivision when the original hulls + remain too loose. An original pair is rejected only if all tested child + combinations are separated. Children are not sent to `bez_ssx`. + +The split axis uses control-net curvature, with an edge-length fallback. +That choice controls efficiency only: either partition covers the parent. +For case19, fixed `u` subdivision barely helped; subdividing the more curved +direction reduced the hull-filter survivors from 1,634 to 483, then 290. + +| Case19 stage | Remaining original pairs | +|---|---:| +| Padded AABB traversal | 7,426 | +| Full-control support intervals on OBB directions | 2,222 | +| Verified GJK directions | 1,634 | +| Two child-hull levels | 290 | + +The entire added filter took about 0.12 s in the measured case19 run. +All 216 pairs producing geometry, and both incomplete pairs, survived. + +## Geometric and resource handling + +Both hulls retain an `atol` cushion: a projection gap must exceed +`2*atol` plus arithmetic allowance. This is a conservative Euclidean contact +margin; it does not require retaining every false positive admitted by the +old world-axis expanded boxes. The backend still receives the original +`atol`, without adjustment. + +Positive rational weights are already required by the NURBS API. Bounds use +Cartesian controls. Child hulls are computed in homogeneous coordinates with +normalized positive weights, and their exclusion margin includes subdivision +roundoff. Failed fitting, unusable directions, or unsafe child arithmetic +retain candidates. A failed split keeps the original node as its enclosure. + +The GJK diagnostic exposed seven case19 hull pairs less than `2*atol` apart +despite a Boolean "separated" result. The verified direction filter retains +all seven. Gauss-map separation stays in the narrow phase: it classifies +possible loops, rather than proving the surfaces spatially disjoint. + +Projection temporaries are chunked across pairs and controls. Large native +control products skip GJK's quadratic cache; large split work skips refinement. +Refinement has comparison limits per level. Any parent with an untested +descendant survives. Initial control caches remain proportional to the +participating input data. + +Aggregate allowances are still computed from the original AABB candidates. +Pruning does not reduce the resources available to surviving geometry. +An older native extension can still use the projection/refinement filters; +rebuilding adds the optional GJK direction stage. + +## Reproduction and checks + +The benchmark bypasses only the new filters for its baseline, keeping the +same narrow-phase code and dependency versions: + +```sh +.venv/bin/python tools/benchmark_ssx_broad_phase.py examples/ssx/nurbs_nurbs_intersection_2.py --baseline --output /tmp/ssx-before.json +.venv/bin/python tools/benchmark_ssx_broad_phase.py examples/ssx/nurbs_nurbs_intersection_2.py --output /tmp/ssx-after.json +``` + +Use `case_19.py` for the larger fixture. `--no-gjk`, `--no-refinement`, and +`--repeat` isolate stage costs. JSON includes candidate counts, wall/CPU time, +returned geometry counts, status reasons, and a complete geometry digest. + +New tests use analytic separation/contact constructions at model-space +tolerance, including nongauge rational weights, transformed parameter charts, +collapsed patches, invalid direction proposals, and interrupted refinement. +They also verify that a curved empty pair is excluded before the full solver. +Existing geometry tests were not loosened. Full validation is recorded in +the pull request. + +Algorithm references: [OBBTree](https://ai.stanford.edu/~latombe/cs326/2002/pqp.pdf) +describes the 15-axis box test; [van den Bergen's GJK paper](https://solid.sourceforge.net/jgt98convex.pdf) +distinguishes a separating support-plane lower bound from an unconverged +simplex distance. [PBRT's BVH chapter](https://www.pbr-book.org/4ed/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies) +provides the hierarchy-construction comparison. Here, measurements favor +tighter leaf enclosures over rebuilding the tree. diff --git a/mmcore/numeric/algorithms/_gjk.cpp b/mmcore/numeric/algorithms/_gjk.cpp index 380c1305..e366001e 100644 --- a/mmcore/numeric/algorithms/_gjk.cpp +++ b/mmcore/numeric/algorithms/_gjk.cpp @@ -219,7 +219,8 @@ template bool gjk_collision_detection(const std::vector>& vertices1, const std::vector>& vertices2, T tol, - size_t maxIter = 0) + size_t maxIter = 0, + Vec3* separatingAxis = nullptr) { if (vertices1.empty() || vertices2.empty()) throw std::invalid_argument("Input vertex sets cannot be empty"); @@ -290,7 +291,13 @@ bool gjk_collision_detection(const std::vector>& vertices1, } if (dot(newPoint, d) < 0) + { + // Optional proposal only. A caller using model-space padding + // must independently verify both complete hulls along this axis. + if (separatingAxis != nullptr) + *separatingAxis = d; return false; // support point failed to pass origin + } simplex.push_back(newPoint); @@ -304,4 +311,4 @@ bool gjk_collision_detection(const std::vector>& vertices1, // measured 200/200 false negatives at max_iter 1-2. "Unknown => not // separated" keeps every caller's `if (!gjk(...)) prune;` sound. return true; -} \ No newline at end of file +} diff --git a/mmcore/numeric/algorithms/cygjk.pxd b/mmcore/numeric/algorithms/cygjk.pxd index 04294679..98a0772f 100644 --- a/mmcore/numeric/algorithms/cygjk.pxd +++ b/mmcore/numeric/algorithms/cygjk.pxd @@ -20,6 +20,7 @@ cdef extern from "_gjk.cpp" nogil: # Use "*" to include the custom C++ header/c bool gjk_collision_detection(const vector[Vec3[double]]& vertices1, const vector[Vec3[double]]& vertices2, double tol, size_t max_iter); - - - \ No newline at end of file + bool gjk_collision_detection_with_axis "gjk_collision_detection"( + const vector[Vec3[double]]& vertices1, + const vector[Vec3[double]]& vertices2, + double tol, size_t max_iter, Vec3[double]* separating_axis) except + diff --git a/mmcore/numeric/algorithms/cygjk.pyx b/mmcore/numeric/algorithms/cygjk.pyx index 68525889..4676c5aa 100644 --- a/mmcore/numeric/algorithms/cygjk.pyx +++ b/mmcore/numeric/algorithms/cygjk.pyx @@ -10,6 +10,8 @@ # distutils: language = c++ cimport cython +from libc.math cimport fabs, isfinite, sqrt +from operator import index as _index cimport mmcore.numeric.algorithms.cygjk @cython.boundscheck(False) @@ -33,3 +35,71 @@ def gjk(double[:,:] v1, double[:,:] v2, double tol=1e-6, int max_iter=25): return result + + +def gjk_separating_axis(const double[:, :] v1, const double[:, :] v2, + double tol=1e-12, max_iter=25): + """Propose a unit separating direction, or return ``None``. + + The direction comes from GJK's first negative support test. It is not + a separation certificate: callers must project every original control + point onto it and verify their model-space padding and roundoff margin. + ``tol`` is a numerical search parameter, not a geometric padding. + Searches reporting contact/overlap or exhausting iterations return ``None``. + + Inputs must be finite, nonempty float64 buffers of shape ``(n, 3)``; + read-only and strided buffers are supported. Uniform internal scaling + prevents overflow without changing the direction's coordinate frame. + ``max_iter`` must be a positive integer, keeping the search bounded. + """ + if v1 is None or v2 is None: + raise ValueError("vertex buffers must be nonempty arrays of shape (n, 3)") + if v1.shape[0] == 0 or v2.shape[0] == 0 or v1.shape[1] != 3 or v2.shape[1] != 3: + raise ValueError("vertex buffers must be nonempty arrays of shape (n, 3)") + if not isfinite(tol) or tol < 0.0: + raise ValueError("tol must be finite and nonnegative") + requested_iterations = _index(max_iter) + if requested_iterations <= 0: + raise ValueError("max_iter must be a positive integer") + cdef size_t iterations = requested_iterations + cdef vector[Vec3[double]] first = vector[Vec3[double]](v1.shape[0]) + cdef vector[Vec3[double]] second = vector[Vec3[double]](v2.shape[0]) + cdef Py_ssize_t i, coordinate + cdef double value, scale = 0.0 + cdef Vec3[double] direction + for i in range(v1.shape[0]): + for coordinate in range(3): + value = v1[i, coordinate] + if not isfinite(value): + raise ValueError("vertex coordinates must be finite") + first[i][coordinate] = value + scale = max(scale, fabs(value)) + for i in range(v2.shape[0]): + for coordinate in range(3): + value = v2[i, coordinate] + if not isfinite(value): + raise ValueError("vertex coordinates must be finite") + second[i][coordinate] = value + scale = max(scale, fabs(value)) + if scale == 0.0: + return None + for i in range(v1.shape[0]): + for coordinate in range(3): + first[i][coordinate] /= scale + for i in range(v2.shape[0]): + for coordinate in range(3): + second[i][coordinate] /= scale + if gjk_collision_detection_with_axis(first, second, tol, iterations, &direction): + return None + scale = 0.0 + for coordinate in range(3): + if not isfinite(direction[coordinate]): + return None + scale = max(scale, fabs(direction[coordinate])) + if scale == 0.0: + return None + for coordinate in range(3): + direction[coordinate] /= scale + scale = sqrt(direction[0] * direction[0] + direction[1] * direction[1] + + direction[2] * direction[2]) + return (direction[0] / scale, direction[1] / scale, direction[2] / scale) diff --git a/mmcore/numeric/intersection/ssx/_nssx5.py b/mmcore/numeric/intersection/ssx/_nssx5.py index 9091b364..76d5e64a 100644 --- a/mmcore/numeric/intersection/ssx/_nssx5.py +++ b/mmcore/numeric/intersection/ssx/_nssx5.py @@ -61,6 +61,7 @@ bez_ssx, SSXSingularity, _dist_point_polyline, ) from mmcore.numeric.intersection.ssx._ssx_substrate import SSXBranch, SSXPoint +from mmcore.numeric.intersection.ssx._ssx_broad_phase import _filter_patch_pairs from mmcore.numeric.intersection.ssx._ssx5_overlap import ( SSXOverlapRegion, _point_in_polygon, _dist_point_polyline_2d, ) @@ -1403,6 +1404,12 @@ def _patch_aabb(patch): for a, b in bvh_intersect(tree1, tree2, exact=False))) agg = _make_aggregate(kwargs, len(candidates)) + # Keep the existing AABB selection and candidate-scaled allowances. + # Stronger padded hull bounds save whole Bezier solves without + # reducing the resources available to their surviving geometry. + if (agg.remaining_cells > 0 and agg.remaining_csx_calls > 0 + and agg.remaining_output_items > 0): + candidates = _filter_patch_pairs(patches1, patches2, candidates, atol) forward = {k: kwargs[k] for k in _FORWARD_KWARGS if k in kwargs} raw = _RawResults() diff --git a/mmcore/numeric/intersection/ssx/_ssx_broad_phase.py b/mmcore/numeric/intersection/ssx/_ssx_broad_phase.py new file mode 100644 index 00000000..18c909c2 --- /dev/null +++ b/mmcore/numeric/intersection/ssx/_ssx_broad_phase.py @@ -0,0 +1,187 @@ +"""Cheap, tolerance-padded control-hull exclusions for NURBS patch pairs. + +PCA/OBB directions and GJK only propose separating axes. An exclusion +always comes from projections of both complete Cartesian control nets. +Positive rational weights, validated by the NURBS entry point, put each +surface inside its control hull. Ambiguous arithmetic retains the pair. +""" +from dataclasses import dataclass + +import numpy as np + +from mmcore.numeric.algorithms import cygjk + +# Source checkouts with an older native extension still get the axis filter. +# A rebuilt extension adds the optional, independently checked GJK proposal. +_gjk_axis = getattr(cygjk, 'gjk_separating_axis', None) +_ROUNDOFF = 128. * np.finfo(float).eps +_PROJECTION_ENTRIES = 262144 +_GJK_MAX_CONTROL_PRODUCT = 65536 # bound the native driver's quadratic cache + + +@dataclass +class _PatchBounds: + offsets: np.ndarray + origins: np.ndarray + axes: np.ndarray + coordinate_scale: np.ndarray + lookup: np.ndarray + + +def _prepare_patches(patches, indices): + """Cache only participating patches; decomposition preserves degree.""" + indices = np.unique(indices) + points = np.stack([np.asarray(patches[i].control_points, dtype=float) + .reshape(-1, 3) for i in indices]) + # Half first avoids overflow in min+max. The origin need not be exact: + # the same stored origin is used for every control point in a patch. + origins = .5*points.min(axis=1) + .5*points.max(axis=1) + offsets = points - origins[:, None, :] + scale = np.max(np.abs(offsets), axis=(1, 2)) + finite = np.isfinite(offsets).all(axis=(1, 2)) & np.isfinite(scale) + axes = np.zeros((len(indices), 3, 3)) + if np.any(finite): + scaled = offsets[finite] / np.maximum(scale[finite, None, None], + np.finfo(float).tiny) + scaled -= scaled.mean(axis=1, keepdims=True) + covariance = np.einsum('nki,nkj->nij', scaled, scaled) + try: + _, vectors = np.linalg.eigh(covariance) + axes[finite] = vectors.transpose(0, 2, 1) + except np.linalg.LinAlgError: + # Failed fitting provides no axes, not an exclusion. + pass + lookup = np.full(len(patches), -1, dtype=np.intp) + lookup[indices] = np.arange(len(indices)) + return _PatchBounds(offsets, origins, axes, + np.max(np.abs(points), axis=1), lookup) + + +def _separated_on_axes(first, second, delta, axes, coordinate_scale, atol): + """Check complete support intervals, including projection roundoff. + + The local offsets and origin difference avoid subtracting two large + projected world coordinates. The error cushion also includes their + subtractions at the original coordinate scale. Axis-fitting accuracy + is immaterial: every finite nonzero direction is a valid test axis. + """ + lengths = np.linalg.norm(axes, axis=-1) + valid = np.isfinite(lengths) & (lengths > np.finfo(float).tiny) + axes = axes / np.where(valid, lengths, 1.)[..., None] + def interval(points, shift=None): + # Also chunk the control axis: even one unusually high-degree pair + # must not allocate an unrestricted controls-by-directions tensor. + block = max(1, _PROJECTION_ENTRIES // (len(points)*axes.shape[1])) + low = np.full(axes.shape[:2], np.inf) + high = np.full(axes.shape[:2], -np.inf) + for begin in range(0, points.shape[1], block): + projection = np.einsum('npi,nai->npa', points[:, begin:begin+block], axes) + if shift is not None: + projection += shift[:, None, :] + low = np.minimum(low, projection.min(axis=1)) + high = np.maximum(high, projection.max(axis=1)) + return low, high + + low_a, high_a = interval(first) + low_b, high_b = interval(second, np.einsum('ni,nai->na', delta, axes)) + valid &= (np.isfinite(low_a) & np.isfinite(high_a) + & np.isfinite(low_b) & np.isfinite(high_b)) + # Multiply by epsilon before summing, so a finite world magnitude does + # not overflow merely while computing its (much smaller) error bound. + error = np.einsum('ni,nai->na', + np.maximum(1., coordinate_scale)*_ROUNDOFF, np.abs(axes)) + clearance = np.nextafter(2.*atol + error, np.inf) + gap = np.maximum(low_b-high_a, low_a-high_b) + return np.any(valid & np.isfinite(gap) & (gap > clearance), axis=1) + + +def _filter_hull_pairs(patches1, patches2, pairs, atol, *, stats=None, + use_gjk=True): + """Retain possibly contacting AABB candidates in their original order. + + Both hulls have an ``atol`` cushion. A PCA frame is cached once per + participating patch. Its six face directions and nine cross directions + supply inexpensive OBB-style axes, but projections use the actual + controls rather than the looser fitted boxes. GJK may propose one more + axis; neither its Boolean verdict nor an unconverged distance is used. + """ + if stats is not None: + stats.update(input_pairs=len(pairs), axis_rejected=0, gjk_rejected=0, + gjk_calls=0, candidate_pairs=len(pairs), cached_patches=(0, 0)) + if len(pairs) == 0 or not np.isfinite(atol) or atol < 0.: + return list(pairs) + indices = np.asarray(pairs, dtype=np.intp) + with np.errstate(over='ignore', invalid='ignore', divide='ignore', under='ignore'): + first = _prepare_patches(patches1, indices[:, 0]) + second = _prepare_patches(patches2, indices[:, 1]) + ai = first.lookup[indices[:, 0]] + bi = second.lookup[indices[:, 1]] + if stats is not None: + stats['cached_patches'] = (len(first.origins), len(second.origins)) + # Keep projection temporaries bounded for high-degree control nets. + count = max(first.offsets.shape[1], second.offsets.shape[1]) + batch_size = max(1, min(1024, _PROJECTION_ENTRIES // (15*count))) + keep = np.ones(len(pairs), dtype=bool) + for begin in range(0, len(pairs), batch_size): + end = min(begin+batch_size, len(pairs)) + a, b = ai[begin:end], bi[begin:end] + fa, fb = first.axes[a], second.axes[b] + cross = np.cross(fa[:, :, None, :], fb[:, None, :, :]).reshape(-1, 9, 3) + axes = np.concatenate((fa, fb, cross), axis=1) + delta = second.origins[b]-first.origins[a] + scale = np.maximum(first.coordinate_scale[a], second.coordinate_scale[b]) + keep[begin:end] = ~_separated_on_axes( + first.offsets[a], second.offsets[b], delta, axes, scale, atol) + if stats is not None: + stats['axis_rejected'] = int(np.count_nonzero(~keep)) + + product = first.offsets.shape[1]*second.offsets.shape[1] + if use_gjk and _gjk_axis is not None and product <= _GJK_MAX_CONTROL_PRODUCT: + for index in np.flatnonzero(keep): + a, b = ai[index], bi[index] + delta = second.origins[b]-first.origins[a] + pa, pb = first.offsets[a], second.offsets[b]+delta + if not (np.isfinite(pa).all() and np.isfinite(pb).all()): + continue + if stats is not None: + stats['gjk_calls'] += 1 + axis = _gjk_axis(pa, pb, tol=1e-12, max_iter=25) + if axis is None: + continue + axis = np.asarray(axis, dtype=float) + if axis.shape != (3,) or not np.isfinite(axis).all(): + continue + scale = np.maximum(first.coordinate_scale[a], second.coordinate_scale[b]) + separated = _separated_on_axes( + first.offsets[a:a+1], second.offsets[b:b+1], delta[None, :], + axis[None, None, :], scale[None, :], atol)[0] + if separated: + keep[index] = False + if stats is not None: + stats['gjk_rejected'] += 1 + if stats is not None: + stats['candidate_pairs'] = int(np.count_nonzero(keep)) + return [pair for pair, retained in zip(pairs, keep) if retained] + + +def _filter_patch_pairs(patches1, patches2, pairs, atol, *, stats=None, + use_gjk=True, refine=True): + """Filter whole patch owners, with bounded refinement of loose hulls. + + Refinement subdivides bounds only. The surviving original patch pair, + its domain, requested accuracy, and narrow-phase allowance stay intact. + """ + kept = _filter_hull_pairs(patches1, patches2, pairs, atol, + stats=stats, use_gjk=use_gjk) + if refine and kept and np.isfinite(atol) and atol >= 0.: + from mmcore.numeric.intersection.ssx._ssx_hull_refine import _refine_patch_pairs + + def filter_children(first, second, candidates, clearance): + return _filter_hull_pairs(first, second, candidates, clearance, + use_gjk=use_gjk) + + kept = _refine_patch_pairs(patches1, patches2, kept, atol, + filter_hulls=filter_children, stats=stats) + if stats is not None: + stats['candidate_pairs'] = len(kept) + return kept diff --git a/mmcore/numeric/intersection/ssx/_ssx_hull_refine.py b/mmcore/numeric/intersection/ssx/_ssx_hull_refine.py new file mode 100644 index 00000000..407f769e --- /dev/null +++ b/mmcore/numeric/intersection/ssx/_ssx_hull_refine.py @@ -0,0 +1,186 @@ +"""Bounded, private child hulls for excluding original NURBS patch pairs. + +Subdivision only tightens enclosures. Surviving pairs still identify the +original patches, so neither the narrow-phase domains nor its tolerance change. +""" +from dataclasses import dataclass + +import numpy as np + + +_PAIR_BATCH_SIZE = 1024 +_MAX_CHILD_PAIRS = 65536 +_MAX_SPLIT_WORK = 262144 +_ROUNDOFF = 128. * np.finfo(float).eps + + +@dataclass(frozen=True) +class _HullPatch: + control_points: np.ndarray + weights: np.ndarray + + +def _split_hull(patch): + """Return two positive-weight midpoint hulls, or decline refinement. + + Normalizing all weights by their maximum preserves rational geometry and + prevents multiplying Cartesian coordinates by weights larger than one. + Subnormal normalized weights are declined before homogeneous arithmetic. + """ + points = np.asarray(patch.control_points, dtype=float) + weights = np.asarray(patch.weights, dtype=float) + if (points.ndim != 3 or points.shape[-1] != 3 + or weights.shape != points.shape[:2] + or not weights.size or not np.isfinite(points).all() + or not np.isfinite(weights).all() or np.any(weights <= 0.)): + return None + with np.errstate(over='ignore', invalid='ignore', divide='ignore', under='ignore'): + weights = weights / weights.max() + if not np.isfinite(weights).all() or np.any(weights < np.finfo(float).tiny): + return None + degree = np.array(points.shape[:2], dtype=int) - 1 + if not np.any(degree > 0): + return None + scaled = points / max(1., float(np.max(np.abs(points)))) + curvature = np.zeros(2) + for axis in range(2): + if degree[axis] >= 2: + difference = np.diff(scaled, n=2, axis=axis) + curvature[axis] = (degree[axis] * (degree[axis] - 1) + * np.max(np.linalg.norm(difference, axis=-1))) + if np.any(curvature > 0.): + axis = int(np.argmax(curvature)) + else: + lengths = [float(np.max(np.linalg.norm(np.diff(scaled, axis=a), axis=-1))) + if degree[a] else -1. for a in range(2)] + axis = int(np.argmax(lengths)) + # Midpoint de Casteljau is quadratic in the split degree. A large + # single-span input must not spend unbounded setup work here before + # the narrow phase can apply its own allowance. + if points.shape[axis] * weights.size > _MAX_SPLIT_WORK: + return None + homogeneous = np.concatenate((points * weights[..., None], weights[..., None]), axis=-1) + if not np.isfinite(homogeneous).all(): + return None + work = np.moveaxis(homogeneous, axis, 0) + left, right = [work[0].copy()], [work[-1].copy()] + while len(work) > 1: + # Half before addition also handles finite coordinates near the + # largest representable value without overflowing their sum. + work = .5 * work[:-1] + .5 * work[1:] + left.append(work[0].copy()) + right.append(work[-1].copy()) + children = [] + for controls in (left, right[::-1]): + net = np.moveaxis(np.stack(controls), 0, axis) + child_weights = net[..., -1] + if (not np.isfinite(net).all() + or np.any(child_weights < np.finfo(float).tiny)): + return None + child_points = net[..., :3] / child_weights[..., None] + if not np.isfinite(child_points).all(): + return None + children.append(_HullPatch(child_points, child_weights)) + return tuple(children) + + +def _refine_patch_pairs(patches1, patches2, pairs, atol, *, filter_hulls, + stats=None, max_depth=2): + """Return an ordered subset of original pairs, using at most two levels. + + ``filter_hulls`` must conservatively retain possible contacts at its + supplied tolerance. Failed construction leaves that node unsplit; + exhausted comparison capacity retains every affected original parent. + """ + original = list(pairs) + depth_limit = min(2, max(0, int(max_depth))) + if stats is not None: + stats.update(refinement_input_pairs=len(original), refinement_rejected=0, + refinement_depth=0, refinement_child_pairs=0, + refinement_cached_children=0, refinement_fallback_pairs=0) + if not original or depth_limit == 0 or not np.isfinite(atol) or atol < 0.: + return original + + nodes, lookups = [], [] + coordinate_scale, max_degree = 1., 0 + for side, patches in enumerate((patches1, patches2)): + ids = dict.fromkeys(pair[side] for pair in original) + lookup = {index: i for i, index in enumerate(ids)} + side_nodes = [patches[index] for index in ids] + for patch in side_nodes: + points = np.asarray(patch.control_points, dtype=float) + if not np.isfinite(points).all(): + return original + coordinate_scale = max(coordinate_scale, float(np.max(np.abs(points)))) + max_degree = max(max_degree, max(points.shape[:2]) - 1) + nodes.append(side_nodes) + lookups.append(lookup) + active = [(lookups[0][a], lookups[1][b], owner) + for owner, (a, b) in enumerate(original)] + caches = [{}, {}] + protected = set() + cached_children = comparisons = completed_depth = 0 + + def children(side, index): + nonlocal cached_children + if index not in caches[side]: + split = _split_hull(nodes[side][index]) + if split is None: + caches[side][index] = (index,) + else: + start = len(nodes[side]) + nodes[side].extend(split) + caches[side][index] = (start, start + 1) + cached_children += 2 + return caches[side][index] + + for depth in range(1, depth_limit + 1): + # This cushion is used only for hull exclusions. The caller sends + # original patches and its original atol to the actual SSX solver. + error = (_ROUNDOFF * (max_degree + 3) * depth) * coordinate_scale + child_atol = float(atol) + error + if not np.isfinite(child_atol): + protected.update(owner for _, _, owner in active) + break + pending, next_active = [], [] + level_comparisons = 0 + + def flush(): + if not pending: + return + candidate_pairs = [(a, b) for a, b, _ in pending] + try: + kept = set(filter_hulls(nodes[0], nodes[1], candidate_pairs, child_atol)) + except (ArithmeticError, ValueError, np.linalg.LinAlgError): + protected.update(owner for _, _, owner in pending) + else: + next_active.extend(item for item in pending if item[:2] in kept) + pending.clear() + + for position, (a, b, owner) in enumerate(active): + if owner in protected: + continue + ca, cb = children(0, a), children(1, b) + count = len(ca) * len(cb) + if level_comparisons + count > _MAX_CHILD_PAIRS: + protected.update(item[2] for item in active[position:]) + break + pending.extend((aa, bb, owner) for aa in ca for bb in cb) + level_comparisons += count + if len(pending) >= _PAIR_BATCH_SIZE: + flush() + flush() + comparisons += level_comparisons + completed_depth = depth + active = [item for item in next_active if item[2] not in protected] + if not active: + break + retained = protected | {owner for _, _, owner in active} + result = [pair for owner, pair in enumerate(original) if owner in retained] + if stats is not None: + stats.update(refinement_rejected=len(original) - len(result), + refinement_depth=completed_depth, + refinement_child_pairs=comparisons, + refinement_cached_children=cached_children, + refinement_fallback_pairs=len(protected)) + return result diff --git a/tests/test_gjk_separating_axis.py b/tests/test_gjk_separating_axis.py new file mode 100644 index 00000000..f4225472 --- /dev/null +++ b/tests/test_gjk_separating_axis.py @@ -0,0 +1,119 @@ +"""GJK directions are proposals; a caller still verifies its model-space gap.""" +import numpy as np +import pytest + +import mmcore.numeric.algorithms.cygjk as cygjk + + +ATOL = 1e-3 +BOX = np.array([[0., 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], + [0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]]) +TET = np.array([[0., 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + +def _proposal(first, second, **kwargs): + propose = getattr(cygjk, "gjk_separating_axis", None) + assert callable(propose), "the native GJK axis-proposal API is missing" + return propose(first, second, **kwargs) + + +def _support_gap(first, second, axis): + """Independently check all vertices along the proposed direction.""" + assert isinstance(axis, tuple) and len(axis) == 3 + direction = np.asarray(axis, dtype=float) + assert np.all(np.isfinite(direction)) + direction /= np.max(np.abs(direction)) + direction /= np.linalg.norm(direction) + origin = first[0] + a = (first - origin) @ direction + b = (second - origin) @ direction + return max(float(b.min() - a.max()), float(a.min() - b.max())) + + +@pytest.mark.parametrize("translation", [0., 1e6]) +@pytest.mark.parametrize("swap", [False, True]) +def test_direction_separates_rotated_hulls_with_overlapping_aabbs(translation, swap): + c = np.sqrt(.5) + rotation = np.array([[c, -c, 0.], [c, c, 0.], [0., 0., 1.]]) + first = BOX @ rotation.T + translation + second = first + 1.1 * rotation[:, 0] + assert np.all(first.max(0) >= second.min(0)) + assert np.all(second.max(0) >= first.min(0)) + if swap: + first, second = second, first + assert _support_gap(first, second, _proposal(first, second)) > 2 * ATOL + + +@pytest.mark.parametrize("shift", [0., .5, 1.]) +def test_overlap_and_exact_face_contact_have_no_proposal(shift): + assert _proposal(BOX, BOX + [shift, 0., 0.]) is None + + +def test_exhausted_search_does_not_invent_an_axis(): + # The first tetrahedron has x+y+z <= 1, the other >= 1.25. + # One iteration is insufficient to find their oblique separator. + second = -TET + .75 + assert _proposal(TET, second, max_iter=1) is None + assert _support_gap(TET, second, _proposal(TET, second, max_iter=25)) > 2 * ATOL + + +@pytest.mark.parametrize("points", [ + np.zeros((1, 3)), + np.array([[0., 0., 0.], [1., 0., 0.]]), + np.array([[0., 0., 0.], [1., 0., 0.], [0., 1., 0.]]), +]) +def test_degenerate_hulls_return_only_useful_directions(points): + assert _proposal(points, points) is None + separated = points + [0., 0., 1.] + assert _support_gap(points, separated, _proposal(points, separated)) > 2 * ATOL + + +def test_sub_tolerance_direction_is_not_a_padded_separation_verdict(): + second = BOX + [1. + .25 * ATOL, 0., 0.] + axis = _proposal(BOX, second) + gap = _support_gap(BOX, second, axis) + assert 0. < gap < ATOL + assert not gap > 2 * ATOL + + +def test_large_finite_input_cannot_overflow_the_support_search(): + first = BOX * 1e300 + second = first + [2e300, 0., 0.] + assert _support_gap(first, second, _proposal(first, second)) > 2 * ATOL + + +def test_readonly_and_noncontiguous_inputs_are_supported(): + first = BOX[::-1] + second = (BOX + [2., 0., 0.])[::-1] + first.setflags(write=False) + second.setflags(write=False) + assert _support_gap(first, second, _proposal(first, second)) > 2 * ATOL + + +@pytest.mark.parametrize("bad", [ + None, np.empty((0, 3)), np.zeros((2, 2)), np.zeros((2, 4)), np.zeros(3), + np.array([[np.nan, 0., 0.]]), np.array([[0., np.inf, 0.]]), +]) +@pytest.mark.parametrize("side", [0, 1]) +def test_invalid_vertices_are_rejected_before_native_access(bad, side): + inputs = [BOX, BOX] + inputs[side] = bad + with pytest.raises(ValueError): + _proposal(*inputs) + + +@pytest.mark.parametrize("limit", [0, -1]) +def test_nonpositive_iteration_limits_are_rejected(limit): + with pytest.raises(ValueError): + _proposal(BOX, BOX, max_iter=limit) + + +def test_fractional_iteration_limit_is_rejected(): + with pytest.raises(TypeError): + _proposal(BOX, BOX, max_iter=1.5) + + +@pytest.mark.parametrize("tolerance", [-1., np.nan, np.inf]) +def test_invalid_numerical_tolerance_is_rejected(tolerance): + with pytest.raises(ValueError): + _proposal(BOX, BOX, tol=tolerance) diff --git a/tests/test_ssx_broad_phase.py b/tests/test_ssx_broad_phase.py new file mode 100644 index 00000000..67a93fa1 --- /dev/null +++ b/tests/test_ssx_broad_phase.py @@ -0,0 +1,270 @@ +"""Analytic exclusion/retention contracts for the NURBS patch broad phase. + +The oracle is known geometry, not agreement with another numerical SSX run. +All geometric distances use the requested model-space CAD tolerance. These +checks deliberately retain uncertain convex-hull overlap: a broad phase may +prove separation, but cannot decide whether the surfaces intersect. +""" + +import numpy as np +import pytest + +from mmcore.nurbs._nurbs_eval import NURBSSurfaceTuple +from mmcore.numeric.intersection.ssx import _ssx_broad_phase as broad_phase + + +ATOL = 1e-3 + + +def _patch(points, weights=None): + points = np.asarray(points, dtype=float) + nu, nv = points.shape[:2] + if weights is None: + weights = np.ones((nu, nv)) + return NURBSSurfaceTuple( + nu, nv, + np.r_[np.zeros(nu), np.ones(nu)], + np.r_[np.zeros(nv), np.ones(nv)], + points, np.asarray(weights, dtype=float), + ) + + +def _plane(center=(0., 0., 0.), u=(1., 0., 0.), v=(0., 1., 0.)): + center, u, v = map(lambda value: np.asarray(value, dtype=float), (center, u, v)) + return _patch([[center - u - v, center - u + v], + [center + u - v, center + u + v]]) + + +def _slanted(gap=0.): + tangent = np.array([1., 0., 1.]) / np.sqrt(2.) + normal = np.array([-1., 0., 1.]) / np.sqrt(2.) + return _plane(center=gap * normal, u=tangent) + + +def _kept(first, second, *, atol=ATOL, use_gjk=False): + return broad_phase._filter_patch_pairs( + [first], [second], [(0, 0)], atol, use_gjk=use_gjk, + ) + + +def _aabbs_overlap(first, second, atol=ATOL): + a = first.control_points.reshape(-1, 3) + b = second.control_points.reshape(-1, 3) + return bool(np.all(a.max(0) + 2 * atol >= b.min(0)) + and np.all(b.max(0) + 2 * atol >= a.min(0))) + + +def _tangent_paraboloid(): + # z = x**2 + y**2 for x,y in [-1,1], in tensor Bernstein form. + coordinates = [-1., 0., 1.] + squares = [1., -1., 1.] + return _patch([[[x, y, squares[i] + squares[j]] + for j, y in enumerate(coordinates)] + for i, x in enumerate(coordinates)]) + + +def _contact_pair(kind): + plane = _plane() + if kind == 'crossing': + return plane, _plane(u=(1., 0., 0.), v=(0., 0., 1.)) + if kind == 'tangent_point': + return plane, _tangent_paraboloid() + if kind == 'area_overlap': + return plane, _plane(center=(.75, .25, 0.)) + if kind == 'shared_edge': + return plane, _plane(center=(2., 0., 0.)) + if kind == 'shared_corner': + return plane, _plane(center=(2., 2., 0.)) + if kind == 'collapsed_line': + return plane, _plane(u=(1., 0., 0.), v=(0., 0., 0.)) + if kind == 'collapsed_point': + return plane, _plane(u=(0., 0., 0.), v=(0., 0., 0.)) + if kind == 'coincident_points': + point = _plane(u=(0., 0., 0.), v=(0., 0., 0.)) + return point, point + raise AssertionError(kind) + + +def test_slanted_disjoint_patches_are_rejected_despite_overlapping_aabbs(): + first, second = _slanted(), _slanted(.25) + assert _aabbs_overlap(first, second) + assert _kept(first, second) == [] + + +@pytest.mark.parametrize('kind', [ + 'crossing', 'tangent_point', 'area_overlap', 'shared_edge', + 'shared_corner', 'collapsed_line', 'collapsed_point', 'coincident_points', +]) +def test_actual_contacts_and_degenerate_patches_are_retained(kind): + first, second = _contact_pair(kind) + assert _aabbs_overlap(first, second) + assert _kept(first, second) == [(0, 0)] + + +@pytest.mark.parametrize('gap_in_atol, retain', [ + (.5, True), (1.9, True), (2., True), (2.1, False), (4., False), +]) +def test_normal_gap_uses_model_space_two_sided_margin(gap_in_atol, retain): + first, second = _slanted(), _slanted(gap_in_atol * ATOL) + assert _aabbs_overlap(first, second) + assert _kept(first, second) == ([(0, 0)] if retain else []) + + +def test_nonuniform_rational_weights_preserve_a_known_tangent_contact(): + # The true rational curve has midpoint x=z=7/12. Its homogeneous XYZ + # control hull has x+z <= 1, so treating weighted coordinates as Cartesian + # would incorrectly discard its tangent plane x+z=7/6. + points = np.array([[[1., -1., 0.], [1., 1., 0.]], + [[1., -1., 1.], [1., 1., 1.]], + [[0., -1., 1.], [0., 1., 1.]]]) + weights = np.array([[1., 1.], [.2, .2], [1., 1.]]) + rational = _patch(points, weights) + midpoint = np.einsum('i,ij,ijd->d', [.25, .5, .25], weights, points) + midpoint /= np.einsum('i,ij->', [.25, .5, .25], weights) + witness = np.array([7. / 12., 0., 7. / 12.]) + assert np.linalg.norm(midpoint - witness) <= ATOL + unweighted_midpoint = np.einsum('i,ijd->d', [.25, .5, .25], points) / 2. + assert np.linalg.norm(unweighted_midpoint - witness) > 10 * ATOL + tangent = _plane(center=witness, u=np.array([-1., 0., 1.]) / np.sqrt(2.)) + assert _kept(rational, tangent) == [(0, 0)] + + +def _map_patch(patch, *, rotation=None, translation=None, scale=1., chart=None): + points = patch.control_points.copy() + weights = patch.weights.copy() + if chart == 'transpose': + points, weights = points.swapaxes(0, 1), weights.T + elif chart == 'reverse_u': + points, weights = points[::-1], weights[::-1] + elif chart == 'reverse_v': + points, weights = points[:, ::-1], weights[:, ::-1] + points *= scale + if rotation is not None: + points = points @ rotation.T + if translation is not None: + points += translation + return _patch(points, weights) + + +def _rotation(): + # Rodrigues rotation about an oblique axis avoids axis-aligned fixtures. + axis = np.array([1., 2., 3.]) / np.sqrt(14.) + x, y, z = axis + skew = np.array([[0., -z, y], [z, 0., -x], [-y, x, 0.]]) + angle = .83 + return np.eye(3) * np.cos(angle) + (1 - np.cos(angle)) * np.outer(axis, axis) + np.sin(angle) * skew + + +@pytest.mark.parametrize('variant', [ + 'swap', 'transpose_first', 'transpose_second', 'reverse_u', 'reverse_v', + 'rotation', 'translation', 'small_units', 'large_units', 'combined', +]) +def test_exclusion_and_contact_are_invariant_to_representation(variant): + for gap, retain in ((.25, False), (1.9 * ATOL, True)): + first, second = _slanted(), _slanted(gap) + atol = ATOL + if variant == 'swap': + first, second = second, first + elif variant.startswith('transpose_'): + if variant.endswith('first'): + first = _map_patch(first, chart='transpose') + else: + second = _map_patch(second, chart='transpose') + elif variant in ('reverse_u', 'reverse_v'): + first = _map_patch(first, chart=variant) + else: + options = {} + if variant in ('rotation', 'combined'): + options['rotation'] = _rotation() + if variant in ('translation', 'combined'): + options['translation'] = np.array([1.e6, -2.e6, 3.e6]) + if variant in ('small_units', 'large_units', 'combined'): + scale = .01 if variant == 'small_units' else 1000. + options['scale'] = scale + atol *= scale + first, second = (_map_patch(patch, **options) for patch in (first, second)) + assert _kept(first, second, atol=atol) == ([(0, 0)] if retain else []) + + +@pytest.mark.parametrize('proposal', [ + np.array([1., 0., 0.]), np.zeros(3), np.full(3, np.nan), + np.array([np.inf, 0., 0.]), None, +], ids=['wrong_axis', 'zero_axis', 'nan_axis', 'infinite_axis', 'no_axis']) +def test_native_axis_is_only_a_proposal_and_cannot_discard_contact(monkeypatch, proposal): + calls = [] + + def propose(*args, **kwargs): + calls.append(True) + return proposal + + monkeypatch.setattr(broad_phase, '_gjk_axis', propose) + for first, second in [_contact_pair('crossing'), (_slanted(), _slanted(1.9 * ATOL))]: + assert _kept(first, second, use_gjk=True) == [(0, 0)] + assert calls, 'the proposal checks must exercise the optional native path' + + +def test_candidate_order_is_preserved_when_middle_pair_is_excluded(): + patches = [_slanted(), _slanted(.25), _slanted(ATOL)] + pairs = [(2, 0), (1, 0), (0, 0)] + assert broad_phase._filter_patch_pairs( + patches, [_slanted()], pairs, ATOL, use_gjk=False, + ) == [(2, 0), (0, 0)] + + +def test_empty_candidate_list_remains_empty(): + assert broad_phase._filter_patch_pairs([], [], [], ATOL, use_gjk=False) == [] + + +def test_projection_chunks_preserve_extrema_across_control_blocks(monkeypatch): + monkeypatch.setattr(broad_phase, '_PROJECTION_ENTRIES', 15) + for first, second, expected in ( + (_slanted(), _slanted(.25), []), + (_slanted(), _slanted(1.9*ATOL), [(0, 0)]), + (_plane(), _tangent_paraboloid(), [(0, 0)])): + assert _kept(first, second) == expected + + +def test_large_control_product_skips_quadratic_native_search(monkeypatch): + def forbidden(*args, **kwargs): + raise AssertionError('large control products must not enter native GJK') + + monkeypatch.setattr(broad_phase, '_gjk_axis', forbidden) + # Coincident constant patches must survive. Three hundred controls each + # would require a 90,000-entry native cache merely to confirm contact. + patch = _patch(np.zeros((300, 1, 3))) + assert broad_phase._filter_patch_pairs( + [patch], [patch], [(0, 0)], ATOL, refine=False) == [(0, 0)] + + +def test_nurbs_adapter_excludes_curved_empty_pair_before_bezier_solver(monkeypatch): + from mmcore.numeric.intersection.ssx import _nssx5 as adapter + + def forbidden(*args, **kwargs): + raise AssertionError('a separated patch pair reached the full SSX solver') + + monkeypatch.setattr(adapter, 'bez_ssx', forbidden) + curved = _tangent_paraboloid() + curved.control_points[..., 2] += 4*ATOL + plane = _plane() + # The graph z=x²+y²+4*atol is everywhere separated from z=0, + # although their AABBs and unsplit control hulls overlap. + assert _aabbs_overlap(curved, plane) + result = adapter.nurbs_ssx(curved, plane, atol=ATOL) + assert result['branches'] == result['points'] == result['singularities'] == [] + assert result['overlap_regions'] == [] + assert result['complete'] + + +@pytest.mark.parametrize('failure', ['failed_fit', 'nonfinite_axes']) +def test_unusable_axis_fit_retains_uncertain_candidates(monkeypatch, failure): + def unusable_fit(covariance): + if failure == 'failed_fit': + raise np.linalg.LinAlgError('synthetic axis-fit failure') + return np.zeros(covariance.shape[:-1]), np.full(covariance.shape, np.nan) + + monkeypatch.setattr(broad_phase.np.linalg, 'eigh', unusable_fit) + first, second = _slanted(), _slanted(.25) + assert _aabbs_overlap(first, second) + # Separation is real, but unusable directions do not certify it. Retain + # the pair so the narrow phase remains responsible for resolving it. + assert _kept(first, second, use_gjk=False) == [(0, 0)] diff --git a/tests/test_ssx_hull_refinement.py b/tests/test_ssx_hull_refinement.py new file mode 100644 index 00000000..2e3f358e --- /dev/null +++ b/tests/test_ssx_hull_refinement.py @@ -0,0 +1,212 @@ +"""Independent analytic coverage for private rational child-hull exclusions.""" +import numpy as np +import pytest + +from mmcore.nurbs._nurbs_eval import NURBSSurfaceTuple +from mmcore.numeric.intersection.ssx import _ssx_hull_refine as refine + + +ATOL = 1e-3 + + +def _patch(cp, weights=None): + cp = np.asarray(cp, dtype=float) + nu, nv = cp.shape[:2] + return NURBSSurfaceTuple(nu, nv, np.r_[np.zeros(nu), np.ones(nu)], + np.r_[np.zeros(nv), np.ones(nv)], cp, + np.ones((nu, nv)) if weights is None else np.asarray(weights, float)) + + +def _graph(gap, rational=False): + # z=(2u-1)^2 for equal weights, or that same numerator divided by + # the positive quadratic weight polynomial. Adding gap shifts z by gap. + weights = np.array([1., .2 if rational else 1., 1.]) + z = np.array([1., -1., 1.]) / weights + gap + return _patch([[[x, y, z[i]] for y in (-1., 1.)] + for i, x in enumerate((-1., 0., 1.))], + np.repeat(weights[:, None], 2, axis=1)) + + +def _plane(): + return _patch([[[-1., -1., 0.], [-1., 1., 0.]], + [[1., -1., 0.], [1., 1., 0.]]]) + + +def _projection_filter(directions=None, calls=None): + # Independent hull oracle: interval separation along supplied unit axes. + # It is deliberately incomplete but every exclusion is conservative. + axes = np.eye(3) if directions is None else np.asarray(directions, float) + axes = axes / np.linalg.norm(axes, axis=1)[:, None] + + def filter_hulls(first, second, pairs, atol): + if calls is not None: + calls.append((len(pairs), atol)) + result = [] + for i, j in pairs: + a = first[i].control_points.reshape(-1, 3) @ axes.T + b = second[j].control_points.reshape(-1, 3) @ axes.T + gap = np.maximum(a.min(0) - b.max(0), b.min(0) - a.max(0)) + if not np.any(np.isfinite(gap) & (gap > 2 * atol)): + result.append((i, j)) + return result + return filter_hulls + + +@pytest.mark.parametrize('rational', [False, True]) +@pytest.mark.parametrize('depth', [1, 2]) +def test_curved_positive_gap_excludes_only_after_real_subdivision(rational, depth): + first, second = _graph(4 * ATOL, rational), _plane() + oracle = _projection_filter() + assert oracle([first], [second], [(0, 0)], ATOL) == [(0, 0)] + before = first.control_points.copy(), first.weights.copy() + assert refine._refine_patch_pairs([first], [second], [(0, 0)], ATOL, + filter_hulls=oracle, max_depth=depth) == [] + assert np.array_equal(first.control_points, before[0]) + assert np.array_equal(first.weights, before[1]) + + +@pytest.mark.parametrize('rational', [False, True]) +@pytest.mark.parametrize('gap', [0., 1.9 * ATOL, 2 * ATOL]) +def test_real_tangent_and_two_sided_tolerance_contacts_are_retained(rational, gap): + assert refine._refine_patch_pairs([_graph(gap, rational)], [_plane()], [(0, 0)], + ATOL, filter_hulls=_projection_filter()) == [(0, 0)] + + +def test_nongauge_rational_arc_is_separated_from_plane_beyond_its_tangent(): + cp = np.array([[[1., -1., 0.], [1., 1., 0.]], + [[1., -1., 1.], [1., 1., 1.]], + [[0., -1., 1.], [0., 1., 1.]]]) + arc = _patch(cp, [[1., 1.], [.2, .2], [1., 1.]]) + normal = np.array([1., 0., 1.]) / np.sqrt(2.) + tangent = np.array([-1., 0., 1.]) / np.sqrt(2.) + center = np.array([7. / 12., 0., 7. / 12.]) + 4 * ATOL * normal + v = np.array([0., 1., 0.]) + plane = _patch([[center - tangent - v, center - tangent + v], + [center + tangent - v, center + tangent + v]]) + oracle = _projection_filter([normal]) + assert oracle([arc], [plane], [(0, 0)], ATOL) == [(0, 0)] + assert refine._refine_patch_pairs([arc], [plane], [(0, 0)], ATOL, + filter_hulls=oracle) == [] + + +@pytest.mark.parametrize('variant', ['rotate', 'translate', 'small_units', 'large_units', + 'swap', 'transpose', 'reverse']) +def test_original_pair_decisions_survive_geometry_and_chart_changes(variant): + angle = .71 + rotation = np.array([[np.cos(angle), 0., np.sin(angle)], [0., 1., 0.], + [-np.sin(angle), 0., np.cos(angle)]]) + for gap, keep in [(4 * ATOL, False), (1.9 * ATOL, True)]: + original = [_graph(gap, True), _plane()] + atol, axes = ATOL, np.eye(3) + transformed = [] + for patch in original: + points, weights = patch.control_points.copy(), patch.weights.copy() + if variant == 'rotate': + points = points @ rotation.T + axes = rotation.T + elif variant == 'translate': + points += [1.e6, -2.e6, 3.e6] + elif variant in ('small_units', 'large_units'): + scale = .01 if variant == 'small_units' else 1000. + points *= scale + atol = ATOL * scale + elif variant == 'transpose': + points, weights = points.swapaxes(0, 1), weights.T + elif variant == 'reverse': + points, weights = points[::-1], weights[::-1] + transformed.append(_patch(points, weights)) + if variant == 'swap': + transformed.reverse() + result = refine._refine_patch_pairs([transformed[0]], [transformed[1]], [(0, 0)], + atol, filter_hulls=_projection_filter(axes)) + assert result == ([(0, 0)] if keep else []) + + +def test_only_original_identifiers_and_order_leave_the_refinement(): + patches = [_graph(0.), _graph(4 * ATOL), _graph(ATOL)] + pairs = [(2, 1), (1, 1), (0, 1), (2, 1)] + result = refine._refine_patch_pairs(patches, [_plane(), _plane()], pairs, ATOL, + filter_hulls=_projection_filter()) + assert result == [(2, 1), (0, 1), (2, 1)] + + +def test_subnormal_normalized_weights_decline_subdivision(): + patch = _graph(4 * ATOL) + weights = patch.weights.copy() + weights[1] = np.finfo(float).tiny / 2. + patch = _patch(patch.control_points, weights) + assert refine._split_hull(patch) is None + assert refine._refine_patch_pairs([patch], [_plane()], [(0, 0)], ATOL, + filter_hulls=_projection_filter()) == [(0, 0)] + + +def test_split_work_limit_leaves_the_original_hull_available(monkeypatch): + monkeypatch.setattr(refine, '_MAX_SPLIT_WORK', 1) + patch = _graph(4*ATOL) + assert refine._split_hull(patch) is None + assert refine._refine_patch_pairs([patch], [_plane()], [(0, 0)], ATOL, + filter_hulls=_projection_filter()) == [(0, 0)] + + +def test_extreme_weight_gauge_is_normalized_before_homogeneous_products(): + patch = _graph(4 * ATOL) + scaled_weights = patch.weights * np.finfo(float).max + patch = _patch(patch.control_points, scaled_weights) + # Some Cartesian controls exceed one: multiplying by these original + # weights would overflow, although their common gauge changes no geometry. + assert refine._refine_patch_pairs([patch], [_plane()], [(0, 0)], ATOL, + filter_hulls=_projection_filter()) == [] + + +def test_comparison_budget_preserves_any_parent_with_untested_descendants(monkeypatch): + monkeypatch.setattr(refine, '_MAX_CHILD_PAIRS', 5) + pairs = [(0, 0), (1, 0)] + result = refine._refine_patch_pairs([_graph(4 * ATOL), _graph(4 * ATOL)], + [_plane()], pairs, ATOL, + filter_hulls=_projection_filter()) + assert result == [(1, 0)] + + +def test_failed_hull_comparison_retains_original_parent(): + def failed(*args): + raise FloatingPointError('synthetic unavailable certificate') + + assert refine._refine_patch_pairs([_graph(4 * ATOL)], [_plane()], [(0, 0)], ATOL, + filter_hulls=failed) == [(0, 0)] + + +def test_zero_depth_preserves_original_pairs_without_callback(): + def forbidden(*args): + raise AssertionError('no hull refinement was requested') + + pairs = [(0, 0)] + assert refine._refine_patch_pairs([_graph(4 * ATOL)], [_plane()], pairs, ATOL, + filter_hulls=forbidden, max_depth=0) == pairs + + +def test_roundoff_cushion_only_inflates_the_exclusion_callback_tolerance(): + calls = [] + first, second = _graph(2 * ATOL, True), _plane() + result = refine._refine_patch_pairs([first], [second], [(0, 0)], ATOL, + filter_hulls=_projection_filter(calls=calls)) + assert result == [(0, 0)] + assert calls and all(tolerance > ATOL for _, tolerance in calls) + assert calls[-1][1] >= calls[0][1] + + +def test_budget_exhaustion_after_one_descendant_keeps_the_same_parent(monkeypatch): + monkeypatch.setattr(refine, '_MAX_CHILD_PAIRS', 5) + calls = [] + oracle = _projection_filter() + + def initially_ambiguous(first, second, pairs, tolerance): + calls.append(len(pairs)) + # An incomplete certificate may retain every first-level child. + # At level two the budget can cover only one of those descendants. + if len(calls) == 1: + return pairs + return oracle(first, second, pairs, tolerance) + + assert refine._refine_patch_pairs([_graph(4 * ATOL)], [_plane()], [(0, 0)], ATOL, + filter_hulls=initially_ambiguous) == [(0, 0)] + assert len(calls) == 2 diff --git a/tools/benchmark_ssx_broad_phase.py b/tools/benchmark_ssx_broad_phase.py new file mode 100644 index 00000000..ccc25611 --- /dev/null +++ b/tools/benchmark_ssx_broad_phase.py @@ -0,0 +1,179 @@ +"""Compare NURBS SSX candidate filtering with the same narrow-phase solver. + +Run from any directory, for example:: + + .venv/bin/python tools/benchmark_ssx_broad_phase.py \ + examples/ssx/nurbs_nurbs_intersection_2.py --baseline + .venv/bin/python tools/benchmark_ssx_broad_phase.py \ + examples/ssx/nurbs_nurbs_intersection_2.py + +Fixture files are trusted Python source. Their data declarations are executed, +stopping before the usual example CLI, result computation, or main guard. +""" +from pathlib import Path +import argparse +import ast +import dataclasses +import hashlib +import json +import statistics +import sys +import time + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +import numpy as np +from mmcore.numeric.intersection.ssx import _nssx5 as adapter + + +def load_surfaces(path, first=None, second=None): + path = Path(path).resolve() + nodes = [] + for node in ast.parse(path.read_text()).body: + if isinstance(node, ast.If): + break + if isinstance(node, ast.Import) and any(a.name == 'logging' for a in node.names): + break + if isinstance(node, ast.Assign) and any( + isinstance(t, ast.Name) and t.id in ('args', 'result') for t in node.targets): + break + if isinstance(node, ast.ImportFrom) and node.module == 'examples.ssx.common_helpers': + continue + nodes.append(node) + namespace = {'__name__': 'benchmark_fixture', '__file__': str(path)} + sys.path.insert(0, str(path.parent)) + try: + exec(compile(ast.Module(nodes, type_ignores=[]), str(path), 'exec'), namespace) + finally: + sys.path.pop(0) + if first is None and second is None: + first, second = ('s1', 's2') if 's1' in namespace else ('surf1', 'surf2') + if first is None or second is None: + raise ValueError('provide both --first and --second') + return namespace[first], namespace[second] + + +def geometry_digest(result): + """Hash all returned geometry, excluding work counters and allowances.""" + digest = hashlib.sha256() + + def token(data): + digest.update(len(data).to_bytes(8, 'big')) + digest.update(data) + + def visit(value): + if isinstance(value, np.ndarray): + token(b'array') + token(repr((value.dtype.str, value.shape)).encode()) + token(value.tobytes()) + elif dataclasses.is_dataclass(value): + token(type(value).__qualname__.encode()) + for item in dataclasses.fields(value): + token(item.name.encode()) + visit(getattr(value, item.name)) + elif isinstance(value, dict): + token(b'dict') + token(str(len(value)).encode()) + for key in sorted(value): + visit(key) + visit(value[key]) + elif isinstance(value, (list, tuple)): + token(type(value).__name__.encode()) + token(str(len(value)).encode()) + for item in value: + visit(item) + elif value is None or isinstance(value, (str, bool, int, float, np.generic)): + scalar = value.item() if isinstance(value, np.generic) else value + token(repr((type(scalar).__name__, scalar)).encode()) + else: + raise TypeError(f'unsupported result value: {type(value).__name__}') + + visit({key: result[key] for key in ('branches', 'points', 'singularities', 'overlap_regions')}) + return digest.hexdigest() + + +def run_once(surfaces, atol, *, baseline=False, use_gjk=True, refine=True): + original_filter = adapter._filter_patch_pairs + original_solver = adapter.bez_ssx + original_decompose = adapter.decompose_surface + stats = {'bez_ssx_calls': 0, 'bez_ssx_seconds': 0., 'nonempty_pairs': 0, + 'decomposition_seconds': 0., 'patch_counts': []} + + def decompose(*args, **kwargs): + start = time.perf_counter() + result = original_decompose(*args, **kwargs) + stats['decomposition_seconds'] += time.perf_counter()-start + stats['patch_counts'].append(len(result)) + return result + + def filter_pairs(first, second, pairs, tolerance): + start = time.perf_counter() + if baseline: + result = pairs + stats.update(input_pairs=len(pairs), candidate_pairs=len(pairs)) + else: + result = original_filter(first, second, pairs, tolerance, + stats=stats, use_gjk=use_gjk, refine=refine) + stats['filter_seconds'] = time.perf_counter()-start + return result + + def solve(*args, **kwargs): + start = time.perf_counter() + result = original_solver(*args, **kwargs) + stats['bez_ssx_seconds'] += time.perf_counter()-start + stats['bez_ssx_calls'] += 1 + stats['nonempty_pairs'] += int(any(result[key] for key in + ('branches', 'points', 'singularities', 'overlap_regions'))) + return result + + adapter.decompose_surface = decompose + adapter._filter_patch_pairs = filter_pairs + adapter.bez_ssx = solve + start, cpu_start = time.perf_counter(), time.process_time() + try: + result = adapter.nurbs_ssx(*surfaces, atol=atol) + finally: + adapter.decompose_surface = original_decompose + adapter._filter_patch_pairs = original_filter + adapter.bez_ssx = original_solver + stats.update(seconds=time.perf_counter()-start, cpu_seconds=time.process_time()-cpu_start, + geometry_digest=geometry_digest(result), complete=result['complete'], + reasons=result['status']['reasons'], + branches=len(result['branches']), points=len(result['points']), + singularities=len(result['singularities']), regions=len(result['overlap_regions'])) + return stats + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('fixture', type=Path) + parser.add_argument('--first') + parser.add_argument('--second') + parser.add_argument('--atol', type=float, default=1e-3) + parser.add_argument('--baseline', action='store_true', help='bypass only the new candidate filters') + parser.add_argument('--no-gjk', action='store_true') + parser.add_argument('--no-refinement', action='store_true') + parser.add_argument('--repeat', type=int, default=1) + parser.add_argument('--output', type=Path) + args = parser.parse_args() + if args.repeat < 1: + parser.error('--repeat must be positive') + surfaces = load_surfaces(args.fixture, args.first, args.second) + trials = [] + for _ in range(args.repeat): + trial = run_once(surfaces, args.atol, baseline=args.baseline, + use_gjk=not args.no_gjk, refine=not args.no_refinement) + trials.append(trial) + print(json.dumps(trial), flush=True) + report = dict(fixture=str(args.fixture.resolve()), atol=args.atol, + baseline=args.baseline, use_gjk=not args.no_gjk, + refinement=not args.no_refinement, source=adapter.__file__, + median_seconds=statistics.median(r['seconds'] for r in trials), trials=trials) + if args.output: + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.write_text(json.dumps(report, indent=2)+'\n') + + +if __name__ == '__main__': + main()