Log in to post a comment.
const seed = 'Change me, empty seed means random every run'; //type=string
const sceneType = 0; //min=0 max=5 step=1 (Platonic solid 1 with platonic solid 2, Double Spiral, Geodesic Polyhedron - frequency 3 - see my turtle in comments in populateScene(), Geodesic Polyhedron - frequency 4 - see my turtle in comments in populateScene(), Ethanol, Caffeine )
const platonicSolid1 = 4; //min=0 max=5 step=1 (None, Tetrahedron, Cube, Octahedron, Dodecahedron, Icosahedron)
const platonicSolid2 = 5; //min=0 max=5 step=1 (None, Tetrahedron, Cube, Octahedron, Dodecahedron, Icosahedron)
const scale = .95; //min=.1 max=3 step=.01 All scene projections will be normalized to fit the canvas (mind radii settings below) then scaled to this setting
const tracksLimit = 3000; //min=50 max=10000 step=50 How many curves are drawn
const trackLengthLimit = 50; //min=1 max=100 step=.1 The maximum length of such a curve
const segmentLength = .2; //min=.05 max=1 step=.01 Step length while drawing
const distanceThreshold = .7; //min=.2 max=2 step=.01
const baseRadius = 50; //min=10 max=80 step=1 This sets the radius of the circumscribing sphere around Platonic solid 1
const subRadius = 30; //min=1 max=80 step=1 This sets the radius of each circumscribing sphere centered around each vertex of Platonic solid 1 spawning and containing Platonic solid 2
const ptRadius = 10; //min=1 max=100 step=1 This sets the radius of each sphere that spawns at each vertex of Platonic solid 2 (or other scene type polyhedra) which will be 'drawn'
const randomizeLocation = 0; //min=0 max=1 step=.01 Scalar of how much the distance of vertices in sceneType solids are randomized
const randomizePtRadius = 0; //min=0 max=1 step=.01 Scalar of how much the radius of 'drawn' spheres at vertices of sceneType solids are randomized
const ccwDistribution = 3; //min=0 max=3 step=1 (CW, CCW, Toggle, Random) Set the 'mode' for a curve that is drawn if a hit on a sphere results clockwise of ccw or other
const ptYaw = 0; //min=-1 max=1 step=.01 This is supposed to rotate around the z-axis but it doesn't. Is does something weird, but beautiful so I left it and did not look into it since any config can be achieved with Pitch and Roll. If you want to help, please let me known in the comments how this Yaw can be fixed
const ptPitch = 0; //min=-1 max=1 step=.01 Rotation around the y-axis (per sphere)
const ptRoll = 0; //min=-1 max=1 step=.01 Rotation around the x-axis (per sphere)
const ptYPRRelToOrigin = 0; //min=0 max=1 step=1 (No, Yes and ignore randomizePtYPR)
const randomizePtYPR = 0; //min=0 max=1 step=.01 Amount of randomization of Yaw, Pitch and Roll to drawn spheres
const randomizeSignYPR = 0; //min=0 max=1 step=1 (No, Yes) Do a sign switch or not per sphere per axis
// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);
// Global code will be evaluated once.
turtlelib_init();
seed == ''? R.seedRandom(): R.seed(seed);
R.seedRandom();
const turtle = new Turtle();
const bins = new PtBin(5, 120);
let tracks = 0;
let trackLengthInSegments = 0;
const trackLengthInSegmentsLimit = trackLengthLimit / segmentLength;
const camZ = -1000;
let currentStringDirection = 0;
const currentPtStringLen = 5;
let currentPtStringIdx;
let currentPtString;
const circles = scaleAndCenterCircles(populateScene(sceneType)).map(c => [V.scale(c[0], scale), c[1] * scale])
.map(c => [...c, V.scale([
(1 - randomizePtYPR + randomizePtYPR * Math.random()) * (ptYPRRelToOrigin == 0? ptYaw : 0),
(1 - randomizePtYPR + randomizePtYPR * Math.random()) * (ptYPRRelToOrigin == 0? ptPitch: .4 * Math.asin((c[0][0]**2+c[0][2]**2) < .1? 1: c[0][0]/ (c[0][0]**2+c[0][2]**2)**.5) ),
(1 - randomizePtYPR + randomizePtYPR * Math.random()) * (ptYPRRelToOrigin == 0? ptRoll : .4 * -Math.asin((c[0][1]**2+c[0][2]**2) < .1? 1: c[0][1]/ (c[0][1]**2+c[0][2]**2)**.5 ) )
], (randomizeSignYPR == 1 && Math.random() < .5? -1: 1) )]);
let pt = getRandomPoint();
resetCurrentPtString(pt);
turtle.jump(pt);
// The walk function will be called until it returns false.
function walk(i) {
const hit = nearestHit([...pt, 0]);
if(hit === false || trackLengthInSegmentsLimit <= trackLengthInSegments) return resetForNextPoint();
trackLengthInSegments++;
if(hit[0][2].every(e => e === 0)) {
pt = V.add(pt, V.trans(V.rot2d(-hit[1].xyAngle - Math.PI/2 + currentStringDirection), [segmentLength, 0]));
} else {
const viewRot = V.rot3d(...hit[0][2]);
const viewRotInv = V.rot3d(...V.scale(hit[0][2], -1));
const sphereLocation = hit[0][0];
const translatedHit = V.trans(viewRotInv, V.sub(hit[1].intersection, sphereLocation));
const thetaRaw = Math.atan2(translatedHit[1], translatedHit[0]); // No Y flip since +Y is down
const xyAngle = thetaRaw < 0 ? thetaRaw + 2 * Math.PI : thetaRaw;
const direction2d = V.trans(V.rot2d(-xyAngle - Math.PI/2 + currentStringDirection), [segmentLength, 0]);
const translatedDirection = V.trans(viewRotInv, [...direction2d, 0]);
pt = V.add(pt, translatedDirection.filter((e,i) => i < 2));
}
if(bins.isNear(pt, currentPtString, distanceThreshold)) return resetForNextPoint();
bins.add(pt);
addToCurrentPtString(pt);
turtle.goto(pt);
return true;
}
function addToCurrentPtString(pt) {
currentPtString[currentPtStringIdx] = pt;
currentPtStringIdx = (currentPtStringIdx+1) % currentPtStringLen;
}
function resetCurrentPtString(pt) {
currentPtString = [pt];
currentPtStringIdx = 1;
currentStringDirection = (() => {
switch(ccwDistribution) {
case 0:
return 0;
case 1:
return Math.PI;
case 2:
return currentStringDirection == 0? Math.PI: 0;
case 3:
default:
return Math.random() < .5? 0: Math.PI;
}
})();
}
function resetForNextPoint() {
trackLengthInSegments = 0;
if(tracks == tracksLimit) return false;
pt = bins.getFarthestPoint(Array.from({length: 10}, (e, i) => getRandomPoint()));//getRandomPoint2();
resetCurrentPtString(pt);
turtle.jump(pt);
tracks++;
return true;
}
function populateScene(objectType) {
const mainRot = V.rot3d(R.getAngle(), R.getAngle(), R.getAngle());
const platonicSolids = [[0, 0],[3, 3],[4, 3],[3, 4],[5, 3],[3, 5]];
switch(objectType) {
case 0:
const dode = getPlatonicVertices(...platonicSolids[platonicSolid1]);//, (.3 + .7 * Math.random()) * subRadius);
const scaffoldDode = getPlatonicVertices(...platonicSolids[platonicSolid2])
.map(pt => V.scale(pt, (1 - randomizeLocation + randomizeLocation * Math.random()) * baseRadius))
.map(pt => V.trans(mainRot, pt));
return scaffoldDode
.flatMap(pt => {
const m = V.rot3d(R.getAngle(), R.getAngle(), R.getAngle());
const useDode = dode.map(dp => V.trans(m, dp)).map(pt => V.scale(pt, (1 - randomizeLocation + randomizeLocation * Math.random()) * subRadius));
return useDode.map(dp => [V.add(dp, pt), (1 - randomizePtRadius + randomizePtRadius * Math.random()) * ptRadius])
});
case 1: // taken from https://turtletoy.net/turtle/a65148a632
const spiralPts = [[20,64.64101615137756,-42.67949192431122],[18.85584300518942,56.05127235638158,-53.87681649998427],[39.303835928600385,58.69727960790524,-37.54779922716785],[24.915494037931897,73.6355411765698,-18.894939587458595],[-2.6230467805500455,75.59405924387198,-26.050935047800905],[-13.118635801773426,61.77762907391342,-49.10616765792733],[1.0569978093995451,43.756493302774075,-66.96448697810683],[28.40881905620065,33.522026884731744,-66.85210063065783],[51.692818058384184,36.09751262972621,-49.242364077350544],[58.6734128048943,48.92481687856923,-23.743938636269647],[46.56932534511413,65.00924536357165,-2.2544310063962647],[21.0678781989349,76.8935198297574,6.596496454525874],[-7.614829237942829,79.63654338410066,0.11239880348102511],[-29.223061002501332,72.10781667662742,-18.61314173353879],[-36.87138441266605,56.7153111658985,-42.70661191656214],[-28.658530355907292,38.10638338990985,-64.23839974284779],[-7.509131769587377,21.487610561924562,-76.69336134911899],[20.275496156277082,11.109745426018598,-76.58634692059908],[47.089268924152435,9.268132537459945,-64.00522412010649],[66.07816779118019,15.949899107285942,-42.18138205066145],[72.70382245049207,29.08458360968421,-16.377429329975147],[65.55939640983219,45.22493081191722,7.526246837781871],[46.38833066000707,60.44043914258446,24.393602037195258],[19.43600235533305,71.20038079314081,30.866509778439063],[-9.634263405561011,75.07105322673945,25.912829410046633],[-34.98637685429788,71.12035081278907,10.855652889032989],[-51.759774192354215,59.98836017642486,-11.057873498526172],[-56.92541552649035,43.66083257554834,-35.400769523390046],[-49.72435847051073,25.014219982771785,-57.46081482738897],[-31.669503889299463,7.244666312654778,-73.10619913619085],[-6.1480826736603476,-6.713664611189171,-79.48022623008777],[22.262618018821655,-14.679632785975741,-75.42437651931002],[48.628262804345525,-15.556239266761631,-61.58945173384772],[68.4923537349464,-9.45980315109037,-40.23998734388634],[78.5809513274364,2.352310115788464,-14.814553498080915],[77.27595927958609,17.731902399877722,10.674996205422332],[64.8067096746822,34.01306614891902,32.29842399836929],[43.1437660185706,48.44584573708944,46.81415287391828],[15.639097180541196,58.62087378195501,52.14378955926221],[-13.527833148413102,62.82252821411779,47.64743754015343],[-39.99920408615304,60.26540589798938,34.17766070089064],[-59.88869895174932,51.18385769400308,13.910559302938942],[-70.33946821988488,36.77222341903962,-10.006214835969908],[-69.91329836882261,18.98778206664764,-33.93427183710628],[-58.768167851884485,0.25296563725780946,-54.278705704609564],[-38.60288226812699,-16.900429830964992,-68.0010166582401],[-12.388865312098744,-30.192491713012043,-73.04055996744927],[16.06977814387207,-37.912134267474414,-68.5884201158726],[42.68160192035804,-39.150709375755426,-55.185679051605575],[63.64355910134452,-33.917264960830586,-34.62818567717001],[75.96636501711598,-23.12816025123204,-9.704637574641222],[77.883160475659,-8.472330199863762,16.19898858083369],[69.08449529108559,7.828691432680273,39.57301393071932],[50.753309095981386,23.3304100190341,57.26941763700509],[25.39611240174971,35.70354824098015,66.93492080264282],[-3.5052980962946645,43.05535602050013,67.33442298580493],[-31.97504716300387,44.19087284670065,58.52120359289364],[-56.09198827327983,38.77896386048263,41.83121880663878],[-72.53272146168004,27.400934401682107,19.70226851227844],[-79.03550511040108,11.474228171156007,-4.658961381426315],[-74.7228040774787,-6.939073695653557,-27.718089234030362],[-60.235830958535196,-25.415408443534815,-46.104943840914785],[-37.65858958930332,-41.506262248249854,-57.087669127054],[-10.242741183923926,-53.083882333602666,-58.96739861352849],[18.0395314015973,-58.647465865822156,-51.33246761201378],[43.05153146722443,-57.54815060954182,-35.13862667302175],[61.08622698862029,-50.0977967526662,-12.595361647092936],[69.41271153800234,-37.54172703830148,13.131469814285495],[66.69904058313567,-21.89695973545548,38.36279045238436],[53.24202829071945,-5.670940094687651,59.439988750052315],[30.964274337226392,8.50108503823837,73.27274664519497],[3.169937081045499,18.252612234547207,77.82518719280338],[-25.922868930434753,21.85677652972115,72.4584976932305],[-51.808025161377984,18.516832235217766,58.07755584534381],[-70.39384182007133,8.52411661699793,37.04101012233228],[-78.67439101062827,-6.748085664416727,12.837394144613343],[-75.26473447196881,-25.024401536736093,-10.438094736532243],[-60.70136335152506,-43.46721986962158,-28.739110978214754],[-37.43720167395641,-59.13141903756545,-38.75453558026367],[-9.513974570968232,-69.46807109456428,-38.51783941181389],[18.070168758314722,-72.79590551443374,-27.824809805134993],[40.21008501132812,-68.65206879894893,-8.366749519551988],[52.6338175961844,-57.95212500519597,16.46776870343779],[52.766678239633904,-42.901503093827294,42.1319375472919],[40.349202150229615,-26.651899123833356,63.73069679054901],[17.655431996806566,-12.734766202404757,76.9810412209066],[-10.784469958093235,-4.356293338318727,79.1498367074287],[-38.97399016942632,-3.682127413824904,69.767064753542],[-60.657147163551464,-11.263380734553103,50.92961637443399],[-70.74231828561403,-25.758035730982,27.056024925437928],[-66.64774782925247,-44.06389972106656,4.054578819211435],[-49.223482195106925,-61.91039687329237,-12.00501623931492],[-22.92747824409266,-74.85164617666562,-16.478249214352218],[4.961916554187223,-79.48162818010044,-7.617219891991102],[26.1017150375651,-74.57847307697682,12.51901686250142],[33.53417846133209,-61.8110105601991,38.14236944367224],[24.235004663970365,-45.65132807707586,61.06224537603195],[0.9027869781606488,-32.27026532314603,73.19695023934767],[-27.959348652083406,-27.472854177899087,69.73885035823369],[-50.378789548691984,-34.14897312296741,51.921290340622676],[-55.680437350376835,-50.18939255991319,27.940996513426967],[-40.48261128366531,-68.18029084933261,10.610968287373048],[-13.12534371309647,-78.12162582907192,11.168084032900126],[7.6418829393986965,-73.4529406837552,30.76134760251789],[3.672159862768896,-58.24893833400573,54.71356686319618],[-22.64005530463407,-49.17714383391406,58.89848531324368],[-35.43380774131995,-60.76327017450906,38.10862734127092],[-14.487921132245084,-67.77987128537278,39.949826804414684],[-18.154078970201322,-58.20625769136785,51.79246814744841],[-3.4691543111078857,-71.27341453231199,36.16713888002928],[-26.095394563841356,-72.79308658253825,20.498699302177908],[-45.92998075075145,-56.68522253347791,32.82096618832839],[-38.83089067204455,-41.574054880008696,56.247252649700044],[-12.411455427507908,-40.063064296851394,68.12415995065133],[12.997726645800043,-51.639502637736356,59.702732910023],[21.747499688917742,-67.62780178711213,36.790267075591686],[10.031677948776178,-78.43579950319594,12.13169330272136],[-15.42713902307517,-78.45434569241766,-2.626902772806054],[-42.80647487861355,-67.56098828887086,-1.7596782128271191],[-60.96611368085252,-50.00297461884995,13.521216327993411],[-63.39067541635114,-32.004794516667005,36.84167321017277],[-49.59207758814057,-19.310880161180734,59.73018557902074],[-24.30045833490844,-15.440969145487742,74.63936976341745],[4.7136449140831225,-20.968857086903995,77.05889709201162],[29.239220148551443,-33.76142672814138,66.37182069994716],[42.87333029564964,-49.888718501557975,45.52990518093523],[42.439088092257535,-64.83450473881956,19.88460712573406],[28.406115499881405,-74.65862026581428,-4.3763215117902],[4.41060388560297,-76.85787460379407,-21.757646911638762],[-23.863243968695414,-70.79004640853043,-28.622987634453093],[-50.09493094788902,-57.64754114848482,-23.816460153876385],[-68.70271872695417,-40.05354549657579,-8.695388927870024],[-75.91571120731543,-21.418735787574462,13.34161509990863],[-70.38086813957136,-5.212504505303717,37.67398015896498],[-53.2528920654834,5.703910552169587,59.427073686746866],[-27.81503532711845,9.56987634311788,74.39574525268749],[1.248084756843795,5.977131767079362,79.76641086617889],[28.762995943763595,-4.136287039745594,74.53546313147294],[49.991862331588976,-18.72293098808424,59.583718945749936],[61.41500125692214,-35.03098110750079,37.42964868527258],[61.25881993123989,-50.09719752103283,11.73016722150301],[49.70578912910418,-61.241556667146966,-13.37013239394446],[28.78237847744099,-66.48694929607726,-33.92715478511347],[1.9621990429090583,-64.84316661191652,-46.81338969496977],[-26.429254571971924,-56.4252356896351,-50.176082317919466],[-51.911567051498984,-42.39623724045917,-43.67722999524806],[-70.53509621284735,-24.755729620745687,-28.49445823942034],[-79.45704790954107,-6.0140798222491565,-7.09772662555194],[-77.33310382857974,11.19481439780617,17.15370975945837],[-64.47404392059497,24.503869495551534,40.52910986342248],[-42.76172642205654,32.15150119633332,59.47858096208344],[-15.340303667281011,33.221210404596754,71.14064704935788],[13.85815951968012,27.756977091570178,73.73932037484727],[40.6884477508411,16.737897465466492,66.81502640221645],[61.3816166283775,1.9253267306315736,51.26929938823107],[73.06889183227317,-14.397128346600967,29.21648721242427],[74.17175723460784,-29.74954762867696,3.6728945159232564],[64.6065229919916,-41.803374531668624,-21.873935344957587],[45.78263619777179,-48.703336444368986,-43.95358247128824],[20.395968486256788,-49.32109047611957,-59.59378160045731],[-7.9521445131562905,-43.4065034329957,-66.72806758347151],[-35.255611250547325,-31.618493208812282,-64.47712315491623],[-57.65753540698546,-15.43205707549086,-53.267553467712325],[-71.9825966340002,3.066220630777731,-34.771646936320934],[-76.17621851743581,21.46587166624029,-11.677427195573294],[-69.59179335376378,37.36519010119449,12.680566259579942],[-53.08646480225029,48.70434049421995,34.78090862256157],[-28.910823226236392,54.05360351827462,51.40354731783184],[-0.40668198145828627,52.81893384333141,60.08275830784105],[28.452428138452824,45.332299422013314,59.45929965049871],[53.61323840649094,32.81569480866684,49.48456985772348],[71.5164645082859,17.22007996115093,31.44552121795605],[79.6128283446358,0.957698981197765,7.801050726442931],[76.74573181615224,-13.436887188697678,-18.1520646791234],[63.34695688095029,-23.672114740934145,-42.74075432799572],[41.405009292950204,-28.0392177312727,-62.4451397011989],[14.208714856282898,-25.67877242450524,-74.42238723712238],[-14.112124546803235,-16.72962905744077,-76.94752845044621],[-39.187284678251096,-2.3359196216017026,-69.70549864112004],[-57.067546385209546,15.498965128804372,-53.87992597268186],[-64.85010506926773,34.19521691409577,-32.01782159130149],[-61.170456911016544,50.98240099230879,-7.675774953921348],[-46.478458699203514,63.33536142469009,15.110890453652864],[-23.03451207668213,69.39327245244625,32.46458731270772],[5.386329269802139,68.2952664503676,41.31245414211575],[34.0618788828662,60.37019226215942,39.93970209535392],[58.088698135566204,47.13772382304107,28.35019276724908],[73.23178621487361,31.101783421906628,8.35173617070465],[76.7225812282945,15.356063164221654,-16.66742335012183],[67.851491578688,3.049026021302943,-42.27123393363114],[48.22969769085231,-3.2059261031103015,-63.74649426048386],[21.63025909666089,-1.8719502837739563,-76.99744773394266],[-6.61181318926128,7.1283267262626575,-79.40685832640395],[-30.580287452548863,22.287976756535887,-70.48465591364439],[-44.98779697463311,40.70881842293832,-52.14260839230441],[-46.39533412189046,58.62002793510183,-28.480315715336893],[-34.166634293300184,72.16062109396695,-5.047319718874989],[-10.895572810888972,78.28887249140774,12.333992225636582],[17.896150331449295,75.6254313409787,18.98701253806973],[44.86418704113244,65.0012499599202,12.728685759311444],[62.627738753293954,49.50173930177996,-5.226584703836815],[65.89739492624196,33.87506141477466,-30.16599142028248],[53.398549329965824,23.317491216339505,-54.81664225825852],[28.92197834731158,21.84612152909884,-71.31789520189514],[0.8726629000703456,30.686068713330826,-73.87546579392394],[-20.03149104333341,47.27199212004834,-61.35208542577056],[-24.69343678599151,65.50018166875861,-38.72908986156877],[-10.162368796977383,77.65896769444112,-16.30329232085353],[17.19992257336846,77.9056554983026,-5.904668977505134],[42.467671545126294,66.21402167656109,-14.56671836891811],[48.96362218388274,50.527556146912275,-38.0726825208582],[30.765774675450373,43.955568787932904,-59.341112218485364],[4.521110136158547,54.60200257889876,-58.29386887322235],[3.6980404920306498,71.16705924460693,-36.353422858945294],[27.996323063530024,65.98801563666179,-35.52164915733734],[20,64.64101615137756,-42.67949192431122]];
return spiralPts.map(pt => [pt, (1 - randomizePtRadius + randomizePtRadius * Math.random()) * ptRadius]);
case 2: // taken from
return [[0,-80,0],[53.49,-43.674,48.99],[-35.094,-44.63,61.731],[-67.038,-39.187,-10.838],[-9.448,-34.868,-68.429],[58.09,-37.641,-31.453],[12.229,45.132,68.429],[-65.371,42.359,31.453],[-44.49,36.326,-48.99],[27.813,35.37,-61.731],[69.82,40.813,10.838],[0,80,0],[29.784,-72.956,28.284],[-19.373,-73.912,35.64],[-39.044,-68.469,-6.257],[-5.794,-64.15,-39.508],[34.427,-66.923,-18.16],[11.415,-52.076,64.317],[-61.237,-49.047,29.563],[-42.07,-42.459,-46.046],[26.347,-41.416,-58.021],[65.545,-47.359,10.187],[41.173,0,71.281],[-14.369,0,79.015],[-62.569,0,56.569],[-80.869,0,12.515],[-66.426,0,-36.319],[-31.465,0,-71.281],[10.661,0,-79.015],[50.569,0,-56.569],[77.161,0,-12.515],[76.135,0,36.319],[-32.779,51.527,58.021],[-63.088,45.584,-10.187],[-8.958,40.867,-64.317],[54.805,43.895,-29.563],[50.021,50.484,46.046],[6.721,74.414,39.508],[-36.854,71.641,18.16],[-26.784,65.608,-28.284],[16.946,64.652,-35.64],[39.971,70.095,6.257],[15.043,-79.395,14.641],[43,-60.811,40],[-9.725,-79.947,18.449],[-28.109,-61.915,50.403],[-20.326,-76.805,-3.239],[-54.945,-55.63,-8.849],[-3.115,-74.311,-20.451],[-7.922,-50.642,-55.872],[18.124,-75.912,-9.4],[47.976,-53.845,-25.682],[34.054,-49.761,58.735],[-12.375,-50.316,65.339],[-50.497,-48.802,47.324],[-66.741,-45.64,9.707],[-56.06,-42.346,-29.487],[-26.206,-39.837,-59.341],[8.514,-39.315,-65.548],[43.209,-40.926,-46.381],[63.989,-43.898,-11.024],[62.113,-47.402,30.675],[49.944,-23.418,62.976],[28.079,23.818,73.155],[-1.005,23.977,77.205],[-26.204,-23.839,73.697],[-51.443,-23.377,61.944],[-67.297,22.755,46.09],[-76.879,21.849,23.023],[-77.332,-20.979,0.878],[-69.768,-19.975,-24.692],[-57.701,19.191,-44.669],[-39.395,18.472,-62.976],[-21.306,-18.072,-73.155],[0.751,-17.913,-77.205],[19.841,18.051,-73.697],[40.737,18.512,-61.944],[56.591,-19.135,-46.09],[70.516,-20.041,-23.023],[77.077,20.91,-0.878],[76.542,21.914,24.692],[68.25,-22.699,44.669],[-10.9,50.333,65.548],[-51.44,48.722,46.381],[-66.69,45.751,11.024],[-55.357,42.246,-30.675],[-27.297,39.888,-58.735],[9.673,39.333,-65.339],[42.265,40.847,-47.324],[64.355,44.009,-9.707],[62.621,47.303,29.487],[32.768,49.812,59.341],[9.776,62.495,55.872],[3.363,80.237,20.451],[-52.83,59.292,25.682],[-18.774,78.636,9.4],[-37,52.326,-40],[-14.239,75.153,-14.641],[23.255,51.223,-50.403],[9.075,74.601,-18.449],[56.799,57.507,8.849],[20.575,77.743,3.239],[5.628,-77.028,33.439],[-4.573,-66.387,52.215],[21.919,-65.951,48.373],[-31.035,-74.572,15.37],[-52.109,-61.847,12.174],[-42.336,-64.328,34.061],[-22.865,-69.229,-23.94],[-25.032,-55.4,-44.691],[-42.401,-57.369,-27.322],[14.501,-68.383,-30.166],[31.519,-55.955,-39.795],[11.011,-54.691,-50.947],[33.771,-73.203,5.296],[50.195,-62.745,20.096],[51.807,-59.995,-4.165],[14.369,0,79.015],[-1.412,-28.19,76.091],[28.021,-28,71.985],[-41.173,0,71.281],[-50.94,27.484,60.833],[-25.385,28.036,72.749],[-76.135,0,36.319],[-75.796,-25.704,22.338],[-66.048,-26.786,45.725],[-77.161,0,-12.515],[-68.653,23.528,-24.689],[-76.267,24.728,1.236],[-50.569,0,-56.569],[-38.619,-21.789,-62.285],[-57.179,-22.648,-43.725],[-10.661,0,-79.015],[1.06,21.151,-76.091],[-21.357,21.341,-71.985],[31.465,0,-71.281],[40.51,-21.856,-60.833],[19.291,-21.305,-72.749],[66.426,0,-36.319],[69.702,23.637,-22.338],[55.617,22.555,-45.725],[80.869,0,12.515],[75.317,-25.812,24.689],[75.915,-24.613,-1.236],[62.569,0,56.569],[48.832,27.552,62.285],[67.392,26.693,43.725],[-16.24,76.583,30.166],[-36.602,64.979,39.795],[-13.337,66.243,50.947],[-33.107,71.763,-5.296],[-46.55,58.188,-20.096],[-52.623,60.939,4.165],[-4.964,67.938,-33.439],[3.757,54.547,-52.215],[-18.274,54.983,-48.373],[29.296,70.394,-15.37],[49.784,59.087,-12.174],[37.253,56.605,-34.061],[25.014,75.737,23.94],[29.611,65.534,44.691],[46.98,63.564,27.322]]
//.map(pt => V.trans(mainRot, pt))
.map(pt => [pt, ptRadius]);
case 3: // taken from https://turtletoy.net/turtle/8454c9ffb9#baseShape=0,frequency=4,splitMethod=0,vertexDots=1,edgeLines=1,xAxisRotation=0,yAxisRotation=0,zAxisRotation=0
return [[0,-80,0],[53.49,-43.674,48.99],[-35.094,-44.63,61.731],[-67.038,-39.187,-10.838],[-9.448,-34.868,-68.429],[58.09,-37.641,-31.453],[12.229,45.132,68.429],[-65.371,42.359,31.453],[-44.49,36.326,-48.99],[27.813,35.37,-61.731],[69.82,40.813,10.838],[0,80,0],[29.784,-72.956,28.284],[-19.373,-73.912,35.64],[-39.044,-68.469,-6.257],[-5.794,-64.15,-39.508],[34.427,-66.923,-18.16],[11.415,-52.076,64.317],[-61.237,-49.047,29.563],[-42.07,-42.459,-46.046],[26.347,-41.416,-58.021],[65.545,-47.359,10.187],[41.173,0,71.281],[-14.369,0,79.015],[-62.569,0,56.569],[-80.869,0,12.515],[-66.426,0,-36.319],[-31.465,0,-71.281],[10.661,0,-79.015],[50.569,0,-56.569],[77.161,0,-12.515],[76.135,0,36.319],[-32.779,51.527,58.021],[-63.088,45.584,-10.187],[-8.958,40.867,-64.317],[54.805,43.895,-29.563],[50.021,50.484,46.046],[6.721,74.414,39.508],[-36.854,71.641,18.16],[-26.784,65.608,-28.284],[16.946,64.652,-35.64],[39.971,70.095,6.257],[15.043,-79.395,14.641],[43,-60.811,40],[-9.725,-79.947,18.449],[-28.109,-61.915,50.403],[-20.326,-76.805,-3.239],[-54.945,-55.63,-8.849],[-3.115,-74.311,-20.451],[-7.922,-50.642,-55.872],[18.124,-75.912,-9.4],[47.976,-53.845,-25.682],[34.054,-49.761,58.735],[-12.375,-50.316,65.339],[-50.497,-48.802,47.324],[-66.741,-45.64,9.707],[-56.06,-42.346,-29.487],[-26.206,-39.837,-59.341],[8.514,-39.315,-65.548],[43.209,-40.926,-46.381],[63.989,-43.898,-11.024],[62.113,-47.402,30.675],[49.944,-23.418,62.976],[28.079,23.818,73.155],[-1.005,23.977,77.205],[-26.204,-23.839,73.697],[-51.443,-23.377,61.944],[-67.297,22.755,46.09],[-76.879,21.849,23.023],[-77.332,-20.979,0.878],[-69.768,-19.975,-24.692],[-57.701,19.191,-44.669],[-39.395,18.472,-62.976],[-21.306,-18.072,-73.155],[0.751,-17.913,-77.205],[19.841,18.051,-73.697],[40.737,18.512,-61.944],[56.591,-19.135,-46.09],[70.516,-20.041,-23.023],[77.077,20.91,-0.878],[76.542,21.914,24.692],[68.25,-22.699,44.669],[-10.9,50.333,65.548],[-51.44,48.722,46.381],[-66.69,45.751,11.024],[-55.357,42.246,-30.675],[-27.297,39.888,-58.735],[9.673,39.333,-65.339],[42.265,40.847,-47.324],[64.355,44.009,-9.707],[62.621,47.303,29.487],[32.768,49.812,59.341],[9.776,62.495,55.872],[3.363,80.237,20.451],[-52.83,59.292,25.682],[-18.774,78.636,9.4],[-37,52.326,-40],[-14.239,75.153,-14.641],[23.255,51.223,-50.403],[9.075,74.601,-18.449],[56.799,57.507,8.849],[20.575,77.743,3.239],[5.628,-77.028,33.439],[-4.573,-66.387,52.215],[21.919,-65.951,48.373],[-31.035,-74.572,15.37],[-52.109,-61.847,12.174],[-42.336,-64.328,34.061],[-22.865,-69.229,-23.94],[-25.032,-55.4,-44.691],[-42.401,-57.369,-27.322],[14.501,-68.383,-30.166],[31.519,-55.955,-39.795],[11.011,-54.691,-50.947],[33.771,-73.203,5.296],[50.195,-62.745,20.096],[51.807,-59.995,-4.165],[14.369,0,79.015],[-1.412,-28.19,76.091],[28.021,-28,71.985],[-41.173,0,71.281],[-50.94,27.484,60.833],[-25.385,28.036,72.749],[-76.135,0,36.319],[-75.796,-25.704,22.338],[-66.048,-26.786,45.725],[-77.161,0,-12.515],[-68.653,23.528,-24.689],[-76.267,24.728,1.236],[-50.569,0,-56.569],[-38.619,-21.789,-62.285],[-57.179,-22.648,-43.725],[-10.661,0,-79.015],[1.06,21.151,-76.091],[-21.357,21.341,-71.985],[31.465,0,-71.281],[40.51,-21.856,-60.833],[19.291,-21.305,-72.749],[66.426,0,-36.319],[69.702,23.637,-22.338],[55.617,22.555,-45.725],[80.869,0,12.515],[75.317,-25.812,24.689],[75.915,-24.613,-1.236],[62.569,0,56.569],[48.832,27.552,62.285],[67.392,26.693,43.725],[-16.24,76.583,30.166],[-36.602,64.979,39.795],[-13.337,66.243,50.947],[-33.107,71.763,-5.296],[-46.55,58.188,-20.096],[-52.623,60.939,4.165],[-4.964,67.938,-33.439],[3.757,54.547,-52.215],[-18.274,54.983,-48.373],[29.296,70.394,-15.37],[49.784,59.087,-12.174],[37.253,56.605,-34.061],[25.014,75.737,23.94],[29.611,65.534,44.691],[46.98,63.564,27.322],[7.486,-80.414,7.384],[22.527,-76.91,21.648],[36.66,-67.566,34.437],[48.655,-52.799,44.879],[-4.823,-80.699,9.304],[-14.61,-77.691,27.278],[-23.909,-68.632,43.393],[-31.869,-53.865,56.551],[-10.282,-79.073,-1.634],[-29.966,-73.247,-4.789],[-47.414,-62.562,-7.619],[-61.52,-47.794,-9.929],[-1.602,-77.782,-10.314],[-4.518,-69.72,-30.238],[-6.931,-57.744,-48.101],[-8.762,-42.977,-62.687],[9.221,-78.611,-4.741],[26.567,-71.984,-13.899],[41.594,-60.837,-22.11],[53.495,-46.07,-28.814],[44.286,-47.154,54.346],[23.014,-51.419,62.078],[-0.474,-51.707,65.41],[-24.005,-47.937,64.106],[-43.317,-47.207,55.017],[-56.5,-49.408,38.789],[-64.655,-47.769,19.811],[-67.518,-42.747,-0.571],[-62,-41.161,-20.344],[-49.368,-42.767,-38.105],[-34.307,-41.466,-53.166],[-17.885,-37.621,-64.458],[-0.499,-37.37,-67.59],[17.496,-40.674,-62.339],[34.958,-41.509,-52.67],[50.966,-39.642,-39.267],[61.53,-41.074,-21.429],[65.358,-46.021,-0.422],[64.478,-47.838,20.615],[58.441,-46.018,40.19],[52.396,-34.094,56.625],[46.173,-11.941,67.898],[35.082,12.043,73.046],[20.382,34.96,71.604],[5.733,35.078,73.652],[-7.777,12.162,79.006],[-20.575,-12.126,77.232],[-31.088,-34.78,68.491],[-43.816,-34.437,62.547],[-57.753,-11.783,59.936],[-65.77,11.624,51.918],[-67.146,33.088,39.216],[-72.029,32.414,27.55],[-79.835,10.949,17.972],[-80.009,-10.727,6.773],[-72.956,-30.531,-5.037],[-69.191,-29.783,-17.969],[-68.82,-9.98,-30.856],[-62.684,9.779,-40.959],[-51.596,28.085,-47.367],[-42.338,27.55,-56.625],[-35.744,9.244,-67.898],[-26.63,-9.142,-73.046],[-15.557,-26.684,-71.604],[-4.342,-26.566,-73.652],[5.77,-9.023,-79.006],[15.37,9.059,-77.232],[24.012,26.864,-68.491],[34.617,27.207,-62.547],[46.084,9.402,-59.936],[54.101,-9.561,-51.918],[57.948,-28.556,-39.216],[64.953,-29.23,-27.55],[74.629,-10.236,-17.972],[78.002,10.458,-6.773],[74.348,31.113,5.037],[74.016,31.86,17.969],[77.272,11.205,30.856],[73.113,-11.406,40.959],[61.654,-33.559,47.367],[0.643,48.216,67.59],[-22.127,51.441,62.339],[-42.62,50.606,52.67],[-59.068,45.944,39.267],[-66.681,44.512,21.429],[-65.462,46.094,0.422],[-59.679,44.278,-20.615],[-50.251,39.568,-40.19],[-36.095,38.432,-54.346],[-18.215,40.697,-62.078],[0.371,40.409,-65.41],[18.854,37.649,-64.106],[35.216,38.379,-55.017],[48.839,42.708,-38.789],[60.024,44.347,-19.811],[67.663,42.839,0.571],[66.917,44.425,20.344],[56.965,49.349,38.105],[41.904,50.649,53.166],[22.802,47.965,64.458],[11.096,54.425,62.687],[8.306,69.192,48.101],[5.061,78.101,30.238],[1.665,80.849,10.314],[-59.606,51.332,28.814],[-45.192,66.099,22.11],[-27.989,75.836,13.899],[-9.387,80.021,4.741],[-41.102,44.603,-44.879],[-32.213,59.37,-34.437],[-20.769,70.91,-21.648],[-7.281,78.218,-7.384],[25.759,43.537,-56.551],[20.311,58.304,-43.393],[13.188,70.13,-27.278],[4.658,77.932,-9.304],[63.854,49.608,9.929],[48.788,64.375,7.619],[30.509,74.574,4.789],[10.345,79.559,1.634],[17.972,-75.873,31.208],[-6.93,-76.372,34.927],[-12.223,-71.041,44.406],[3.38,-60.02,58.9],[16.941,-59.823,56.958],[26.23,-70.345,38.746],[-25.616,-75.145,25.792],[-35.532,-72.298,4.608],[-45.976,-65.948,2.991],[-57.255,-56.189,21.096],[-52.421,-57.31,32.158],[-31.228,-69.912,35.23],[-31.161,-69.626,-15.268],[-14.35,-67.367,-32.08],[-15.618,-60.347,-42.557],[-33.894,-49.403,-45.862],[-42.673,-50.293,-37.083],[-41.203,-63.494,-16.972],[4.303,-66.944,-35.228],[24.61,-68.394,-24.434],[33.295,-61.979,-29.293],[29.177,-49.04,-49.44],[18.917,-48.469,-55.077],[2.734,-59.959,-45.719],[34.501,-70.804,-6.504],[32.202,-73.96,16.979],[40.522,-68.587,24.454],[58.593,-55.602,15.306],[59.236,-54.36,3.044],[43.466,-64.193,-11.284],[28.248,0,76.085],[0,0,80],[-8.007,-14.366,78.706],[5.149,-40.922,71.247],[19.992,-40.781,69.164],[35.177,-14.225,72.697],[-28.248,0,76.085],[-52.729,0,64.721],[-57.705,13.917,59.573],[-42.524,40.182,60.31],[-29.613,40.591,66.357],[-20.239,14.326,77.01],[-70.428,0,47.023],[-79.611,0,24.721],[-79.563,-12.934,17.685],[-69.633,-37.882,26.336],[-64.63,-38.686,38.204],[-65.371,-13.737,51.907],[-80,0,0],[-72.558,0,-24.721],[-68.478,11.792,-30.957],[-66.869,34.902,-17.697],[-70.641,35.792,-4.542],[-79.735,12.682,6.978],[-59.015,0,-47.023],[-41.316,0,-64.721],[-35.456,-10.928,-67.776],[-40.858,-32.379,-54.971],[-50.276,-33.016,-45.553],[-62.614,-11.565,-40.617],[-21.195,0,-76.085],[0,0,-80],[5.948,10.671,-78.706],[-3.935,31.277,-71.247],[-15.402,31.418,-69.164],[-26.738,10.812,-72.697],[21.195,0,-76.085],[41.316,0,-64.721],[46.109,-11.12,-59.573],[33.884,-32.017,-60.31],[23.06,-31.608,-66.357],[15.132,-10.711,-77.01],[59.015,0,-47.023],[72.558,0,-24.721],[74.456,12.103,-17.685],[63.08,34.317,-26.336],[55.99,33.514,-38.204],[53.775,11.3,-51.907],[80,0,0],[79.611,0,24.721],[76.917,-13.245,30.957],[71.459,-37.297,17.697],[71.854,-36.407,4.542],[77.676,-12.355,-6.978],[70.428,0,47.023],[52.729,0,64.721],[45.779,14.109,67.776],[50.248,39.82,54.971],[59.666,39.183,45.553],[72.937,13.472,40.617],[-4.912,76.413,35.228],[-26.973,74.962,24.434],[-37.165,69.182,29.293],[-35.139,59.062,49.44],[-23.274,59.633,55.077],[-3.247,71.202,45.719],[-35.353,72.552,6.504],[-30.215,69.396,-16.979],[-36.969,62.574,-24.454],[-55.323,52.5,-15.306],[-58.564,53.743,-3.044],[-45.345,66.968,11.284],[-15.985,67.484,-31.208],[6.078,66.984,-34.927],[10.344,60.12,-44.406],[-2.708,48.082,-58.9],[-13.672,48.279,-56.958],[-22.677,60.816,-38.746],[23.252,68.212,-25.792],[34.923,71.059,-4.608],[45.463,65.213,-2.991],[52.898,51.913,-21.096],[46.459,50.792,-32.158],[27.358,61.249,-35.23],[32.998,73.73,15.268],[16.186,75.99,32.08],[18.327,70.814,42.557],[40.272,58.699,45.862],[49.051,57.809,37.083],[43.912,67.667,16.972],[10.518,-79.003,24.261],[2.735,-80.638,16.74],[-2.172,-79.276,26.182],[-16.529,-64.813,51.798],[-20.6,-56.904,58.533],[-8.517,-59.038,59.317],[28.215,-58.513,54.046],[39.088,-56.077,49.932],[32.872,-64.017,44.608],[0.619,-72.713,43.326],[8.831,-67.032,50.897],[13.841,-72.468,41.382],[-20.603,-77.984,17.065],[-15.319,-79.312,7.694],[-25.834,-76.433,6.121],[-54.088,-59.262,1.678],[-61.455,-51.318,0.434],[-59.999,-54.229,11.041],[-46.832,-57.22,41.066],[-39.821,-56.028,49.423],[-35.693,-63.798,42.635],[-42.101,-69.006,13.933],[-47.929,-63.876,23.395],[-37.047,-70.402,25.004],[-21.823,-73.623,-13.714],[-11.715,-76.427,-11.984],[-13.138,-72.392,-22.399],[-16.52,-53.453,-50.761],[-17.269,-45.675,-58.265],[-25.844,-47.9,-52.494],[-49.672,-50.274,-28.665],[-56.147,-49.412,-19.387],[-49.023,-57.053,-18.258],[-24.242,-62.872,-34.715],[-33.949,-57.011,-36.438],[-33.027,-63.98,-25.929],[5.828,-71.947,-25.541],[7.477,-75.97,-15.101],[16.426,-72.737,-19.965],[39.993,-55.415,-33.051],[46.045,-47.773,-36.444],[37.718,-48.798,-43.484],[9.824,-47.273,-58.782],[0.384,-45.373,-61.405],[1.509,-53.103,-53.919],[23.344,-62.787,-35.388],[21.381,-55.924,-45.915],[12.861,-62.076,-41.029],[26.08,-75.273,-2.071],[16.823,-78.573,2.651],[24.718,-76.991,10.06],[47.145,-62.436,30.335],[53.279,-54.713,35.742],[56.642,-55.681,25.619],[58.465,-52.366,-7.664],[56.496,-49.492,-18.563],[50.335,-57.407,-15.066],[42.379,-68.869,12.844],[51.667,-62.117,8.061],[43.373,-67.322,0.572],[21.554,12.133,77.025],[13.79,24.256,76.184],[6.764,12.174,79.075],[-13.985,-26.297,75.628],[-19.579,-37.822,70.608],[-7.038,-39.895,71.584],[31.499,-39.538,66.163],[42.697,-37.271,61.809],[39.493,-25.974,68.141],[6.577,-14.386,78.804],[13.56,-28.529,75.055],[21.621,-14.337,76.718],[-34.171,-12.061,73.385],[-39.53,-23.959,68.726],[-46.988,-11.942,67.436],[-59.864,25.362,53.985],[-60.376,36.341,46.96],[-51.888,38.753,54.265],[-18.348,39.791,69.998],[-6.106,37.94,72.495],[-13.386,26.3,75.711],[-46.93,14.112,67.122],[-38.879,28.184,67.708],[-33.891,14.254,73.176],[-72.71,11.431,41.714],[-73.239,22.618,35.018],[-77.518,11.199,30.038],[-77.375,-23.537,11.722],[-73.226,-33.737,5.375],[-72.127,-36.244,16.219],[-59.057,-38.28,47.096],[-51.846,-36.875,55.49],[-59.488,-25.379,54.362],[-77.265,-13.235,29.802],[-72.088,-26.627,34.499],[-72.368,-13.514,41.684],[-78.202,-10.485,-5.89],[-74.46,-20.744,-12.066],[-74.305,-10.227,-18.834],[-63.667,21.519,-35.019],[-57.375,31.004,-38.263],[-62.687,33.326,-28.022],[-72.417,35.584,6.205],[-72.897,34.483,17.29],[-77.365,23.56,12.248],[-73.999,12.09,-18.902],[-73.382,24.452,-11.888],[-77.957,12.399,-5.73],[-54.697,9.583,-51.245],[-48.964,19.054,-54.541],[-45.431,9.399,-60.511],[-30.115,-20.078,-68.383],[-24.043,-29.186,-67.286],[-32.779,-31.114,-61.56],[-57.283,-32.73,-37.056],[-63.815,-31.677,-27.514],[-63.954,-21.539,-34.544],[-45.186,-11.115,-60.385],[-48.32,-22.49,-53.733],[-54.616,-11.337,-50.956],[-16.114,-9.071,-77.025],[-10.343,-18.193,-76.184],[-5.017,-9.03,-79.075],[10.511,19.765,-75.628],[15.001,28.978,-70.608],[5.372,30.453,-71.584],[-24.546,30.811,-66.163],[-33.829,29.529,-61.809],[-30.545,20.088,-68.141],[-4.884,10.682,-78.804],[-10.215,21.49,-75.055],[-16.183,10.731,-76.718],[25.905,9.143,-73.385],[30.505,18.489,-68.726],[36.44,9.261,-67.436],[48.859,-20.7,-53.985],[50.604,-30.459,-46.96],[42.304,-31.595,-54.265],[14.09,-30.558,-69.998],[4.645,-28.86,-72.495],[10.058,-19.762,-75.711],[36.438,-10.957,-67.122],[30.119,-21.834,-67.708],[25.713,-10.814,-73.176],[62.161,-9.773,-41.714],[64.214,-19.831,-35.018],[69.252,-10.005,-30.038],[74.047,22.525,-11.722],[71.765,33.063,-5.375],[67.869,34.105,-16.219],[49.473,32.068,-47.096],[42.074,29.925,-55.49],[48.482,20.684,-54.362],[69.087,11.834,-29.802],[63.328,23.392,-34.499],[61.876,11.555,-41.684],[79.949,10.719,5.89],[77.907,21.705,12.066],[79.745,10.976,18.834],[72.616,-24.543,35.019],[66.244,-35.796,38.263],[69.639,-37.022,28.022],[70.751,-34.765,-6.205],[68.319,-32.317,-17.29],[73.891,-22.502,-12.248],[79.437,-12.978,18.902],[76.728,-25.567,11.888],[79.651,-12.669,5.73],[66.325,-11.62,51.245],[60.119,-23.395,54.541],[57.059,-11.805,60.511],[38.973,25.984,68.383],[30.986,37.614,67.286],[41.333,39.234,61.56],[65.837,37.618,37.056],[70.757,35.123,27.514],[72.813,24.523,34.544],[56.725,13.953,60.385],[59.147,27.529,53.733],[66.155,13.732,50.956],[-6.414,79.185,25.541],[-7.912,80.398,15.101],[-17.704,78.395,19.965],[-45.277,62.737,33.051],[-52.8,54.78,36.444],[-44.415,57.461,43.484],[-12.258,58.985,58.782],[-0.483,57.18,61.405],[-1.848,65.048,53.919],[-26.663,71.712,35.388],[-25.409,66.46,45.915],[-15.005,72.423,41.029],[-26.284,75.859,2.071],[-16.657,77.795,-2.651],[-23.803,74.141,-10.06],[-42.071,55.716,-30.335],[-46.586,47.84,-35.742],[-51.45,50.577,-25.619],[-60.17,53.893,7.664],[-60.571,53.061,18.563],[-53.262,60.745,15.066],[-40.386,65.63,-12.844],[-50.128,60.267,-8.061],[-43.28,67.177,-0.572],[-9.603,72.129,-24.261],[-2.568,75.73,-16.74],[1.969,71.856,-26.182],[13.602,53.338,-51.798],[16.526,45.649,-58.533],[6.812,47.22,-59.317],[-23.023,47.745,-54.046],[-32.396,46.476,-49.932],[-27.798,54.135,-44.608],[-0.526,61.787,-43.326],[-7.292,55.353,-50.897],[-11.848,62.032,-41.382],[19.326,73.148,-17.065],[14.883,77.056,-7.694],[25.247,74.699,-6.121],[53.749,58.89,-1.678],[61.355,51.235,-0.434],[57.566,52.029,-11.041],[40.136,49.038,-41.066],[33.066,46.525,-49.423],[30.408,54.353,-42.635],[39.957,65.493,-13.933],[43.901,58.508,-23.395],[33.729,64.097,-25.004],[22.975,77.509,13.714],[12.254,79.941,11.984],[14.29,78.74,22.399],[19.996,64.698,50.761],[21.505,56.878,58.265],[31.487,58.359,52.494],[55.315,55.985,28.665],[60.383,53.14,19.387],[52.499,61.098,18.258],[27.617,71.627,34.715],[38.928,65.373,36.438],[36.403,70.519,25.929]]
//.map(pt => V.trans(mainRot, pt))
.map(pt => [pt, ptRadius]);
case 4: //asked chatgpt for a model of ethanol
const ethanol = [[[-4.009, 0.000, 0.000], 4.019],[[3.740, 0.000, 0.000], 4.019],[[6.246, 7.005, 0.000], 3.812],[[-6.079, 2.637, 4.571], 1.932],[[-6.079, 2.637, -4.571], 1.932],[[-6.079, -5.275, 0.000], 1.932],[[5.817, -2.637, 4.571], 1.932],[[5.817, -2.637, -4.571], 1.932],[[2.878, 9.574, 0.000], 1.932]];
return ethanol.map(cpt => [V.trans(mainRot, V.scale(cpt[0], 8)), (1 - randomizePtRadius + randomizePtRadius * Math.random()) * cpt[1] * ptRadius]);
case 5: //asked chatgpt for a model of caffeine
const caffeine = [[[0.000, 0.000, 0.000], 1.797],[[0.000, 3.149, 0.000], 1.749],[[2.684, 4.796, 0.000], 1.702],[[2.684, 7.586, 0.000], 1.702],[[5.358, 3.149, 0.000], 1.749],[[5.358, 0.000, 0.000], 1.797],[[8.069, -1.399, 0.000], 1.702],[[2.684, -1.517, 0.000], 1.749],[[-2.684, -1.517, 0.000], 1.797],[[-2.684, 1.517, 0.000], 1.749],[[-2.334, 4.902, 0.000], 1.797],[[7.955, 4.902, 0.000], 1.797],[[0.000, -3.501, 2.334], 1.797],[[0.000, -2.101, 0.000], 0.864],[[-4.201, 5.836, 1.167], 0.864],[[-1.167, 6.536, -1.167], 0.864],[[-1.634, 3.968, 1.867], 0.864],[[9.093, 3.968, 1.167], 0.864],[[8.403, 6.536, -1.167], 0.864],[[6.769, 5.836, 1.867], 0.864],[[1.167, -2.334, 4.201], 0.864],[[-1.167, -4.201, 3.735], 0.864],[[0.467, -5.369, 1.167], 0.864]];
return caffeine.map(cpt => [V.trans(mainRot, V.scale(cpt[0], 8)), (1 - randomizePtRadius + randomizePtRadius * Math.random()) * cpt[1] * ptRadius]);
}
}
function getRandomPoint() {
let pt;
do {
pt = [Math.random() * 200 - 100, Math.random() * 200 - 100];
hit = nearestHit([...pt, 0])
} while(hit === false);
return pt;
}
function scaleAndCenterCircles(unscaledCircles) {
const circlesMinMax = unscaledCircles.reduce((a, c) => [
[Math.min(a[0][0], c[0][0] - c[1]), Math.min(a[0][1], c[0][1] - c[1])],
[Math.max(a[1][0], c[0][0] + c[1]), Math.max(a[1][1], c[0][1] + c[1])]
], [[Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], [Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER]]);
const scale = Math.min(200 / (circlesMinMax[1][0] - circlesMinMax[0][0]), 200 / (circlesMinMax[1][1] - circlesMinMax[0][1]));
const minMaxDiff = circlesMinMax.map(e => V.scale(e, scale)).map(e => e.map(ee => 100 - Math.abs(ee))).map((e, i, a) => -(a[0][i] - a[1][i]) / 2);
return unscaledCircles.map(c => [V.add(V.scale(c[0], scale), [...minMaxDiff, 0]), c[1] * scale]);
}
function nearestHit(location) {
return hits = circles.map(circle => [circle, raySphereIntersection(V.add(location, [0,0,camZ]), [0,0,1], ...circle)])
.filter(cIntersect => cIntersect[1] !== false)
.sort((a, b) => a[1].t < b[1].t? -1: 1)[0] ?? false;
}
function PtBin(size = 10, max = 100) {
class PtBin {
constructor(size = 10, max = 120) {
this.size = size;
this.max = Math.ceil(max / this.size) * this.size;
const diff = Math.ceil(this.max / this.size);
this.bins = Array.from({length: diff * 2}, (e, i) => Array.from({length: diff * 2}, () => []));
this.pts = [];
this.neighBors = Array.from({length: 3}).flatMap((i, c) => Array.from({length: 3}, (e, r) => [c - 1, r - 1]));
}
getFarthestPoint(candidates) {
const info = candidates.map(cpt => [cpt, this.proxInfo(cpt, [], 50)])
.filter(cinfo => cinfo[1].length > 0)
.map(cinfo => [cinfo[0], V.lenSq(V.sub(cinfo[0], cinfo[1].sort((a, b) => a[1] < b[1]? -1: 1)[0][0]))]);
if(info.length == candidates.length) {
return info.sort((a, b) => a[1] < b[1]? 1: -1)[0][0];
}
return candidates.map(cpt => {
return this.pts.map(pt => [cpt, V.lenSq(V.sub(cpt, pt))])
.sort((a, b) => a[1] < b[1]? -1: 1)[0] ?? [cpt, Number.MAX_SAFE_INTEGER]
}).sort((a, b) => a[1] < b[1]? 1: -1)[0][0];
}
getColRow(pt) {
return [((pt[0] + this.max) / this.size) | 0, ((pt[1] + this.max) / this.size) | 0]
}
add(pt, ifNotNearDistance = null) {
if(pt[0] < -this.max ||this.max < pt[0] || pt[1] < -this.max || this.max < pt[1]) {
return null;
}
if(ifNotNearDistance !== null && this.isNear(pt, ifNotNearDistance)) {
return false;
}
this.pts.push(pt);
const bin = this.getColRow(pt);
this.bins[bin[0]][bin[1]].push(pt);
return true;
}
proxInfo(ckPt, exclude = [], distance = .1) {
const binCol = this.getColRow(ckPt);
const dSq = distance**2;
return this.neighBors.map(n => V.add(binCol, n))
.filter(pt => 0 <= pt[0] && pt[0] < this.bins.length && 0 < pt[1] && pt[1] < this.bins.length)
.flatMap(bin =>
this.bins[bin[0]][bin[1]]
.filter(pt => !exclude.some(p => p[0] == pt[0] && p[1] == pt[1]))
.map(pt => [pt, V.dist(pt, ckPt)])
.filter(dPt => dPt[1] <= distance) //maybe compare to distSq? dont now if build-in Math.hypot is faster but going with that
);
}
ptsNear(ckPt, exclude = [], distance = .1) {
return this.proxInfo(ckPt, exclude, distance).sort((a, b) => a[1] < b[1]? -1: 1).map(dPt => dPt[0]);
}
isNear(ckPt, exclude = [], distance = .1) {
return this.proxInfo(ckPt, exclude, distance).length > 0;
}
}
return new PtBin(size, max);
}
function raySphereIntersection(rayOrigin, rayDirection, sphereLocation, sphereRadius) {
// Vector from sphere center to ray origin
const originToCenter = V.sub(rayOrigin, sphereLocation);
// Coefficients for quadratic equation: at^2 + bt + c = 0
const a = V.dot(rayDirection, rayDirection);
const b = 2 * V.dot(originToCenter, rayDirection);
const c = V.dot(originToCenter, originToCenter) - sphereRadius ** 2;
// Reject if ray starts inside the sphere
if(c < 0) return false;
// Discriminant
const discriminant = b * b - 4 * a * c;
if (discriminant < 0) return false; // No intersection
const sqrtDisc = Math.sqrt(discriminant);
const t1 = (-b - sqrtDisc) / (2 * a);
const t2 = (-b + sqrtDisc) / (2 * a);
// Both intersections are behind the ray origin
if (t1 <= 0 && t2 <= 0) return false;
const closest = Math.min(t1, t2);
const intersection = V.add(rayOrigin, V.scale(rayDirection, closest));
const v = V.sub(intersection, sphereLocation);
const normal = V.norm(v);
const angle = Math.acos(V.dot(V.scale(V.norm(rayDirection), -1), normal)); // angle in radians
const thetaRaw = Math.atan2(v[1], v[0]); // No Y flip since +Y is down
const xyAngle = thetaRaw < 0 ? thetaRaw + 2 * Math.PI : thetaRaw;
return {
t: closest,
intersection: intersection,
normal: normal,
angleAtSurface: angle,
xyAngle: xyAngle
};
}
function getPlatonicVertices(p, q, r = 1) {
if(p == 0 && q == 0) return [[0,0,0]];
return ((phi = (1 + Math.sqrt(5)) / 2) => {
switch (`${p},${q}`) {
case '3,3': // Tetrahedron
return [[1, 1, 1],[-1, -1, 1],[-1, 1, -1],[1, -1, -1]];
case '4,3': // Cube
return Array.from({length: 2}).flatMap((e, x) => Array.from({length: 2}).flatMap((e, y) => Array.from({length: 2}).map((e, z) => [x==0?-1:x, y==0?-1:y, z==0?-1:z])));
case '3,4': // Octahedron
return [[1, 0, 0],[-1, 0, 0],[0, 1, 0],[0, -1, 0],[0, 0, 1],[0, 0, -1],];
case '5,3': // Dodecahedron
return [[1, 1, 1],[1, 1, -1],[1, -1, 1],[1, -1, -1],[-1, 1, 1],[-1, 1, -1],[-1, -1, 1],[-1, -1, -1],[0, 1 / phi, phi],[0, 1 / phi, -phi],[0, -1 / phi, phi],[0, -1 / phi, -phi],[1 / phi, phi, 0],[1 / phi, -phi, 0],[-1 / phi, phi, 0],[-1 / phi, -phi, 0],[phi, 0, 1 / phi],[phi, 0, -1 / phi],[-phi, 0, 1 / phi],[-phi, 0, -1 / phi]];
case '3,5': // Icosahedron
return [[0, 1, phi],[0, 1, -phi],[0, -1, phi],[0, -1, -phi],[1, phi, 0],[1, -phi, 0],[-1, phi, 0],[-1, -phi, 0],[phi, 0, 1],[phi, 0, -1],[-phi, 0, 1],[-phi, 0, -1]];
default:
throw new Error(`Unsupported SchlΓ€fli symbol {${p},${q}}.`);
}
})().map(v => V.scale(V.norm(v), r));
}
// Below is automatically maintained by Turtlelib 1.0
// Changes below this comment might interfere with its correct functioning.
function turtlelib_init() {
turtlelib_ns_c6665b0e9b_Jurgen_Vector_Math();
turtlelib_ns_c5f8fa95ed_Jurgen_Intersection();
turtlelib_ns_13b81fd40e_Jurgen_Randomness();
turtlelib_ns_13b81fd40e_Jurgen_Randomness();
}
// Turtlelib Jurgen Vector Math v 4 - start - {"id":"c6665b0e9b","package":"Jurgen","name":"Vector Math","version":"4"}
function turtlelib_ns_c6665b0e9b_Jurgen_Vector_Math() {
/////////////////////////////////////////////////////////
// Vector functions - Created by Jurgen Westerhof 2024 //
/////////////////////////////////////////////////////////
class Vector {
static add (a,b) { return a.map((v,i)=>v+b[i]); }
static sub (a,b) { return a.map((v,i)=>v-b[i]); }
static mul (a,b) { return a.map((v,i)=>v*b[i]); }
static div (a,b) { return a.map((v,i)=>v/b[i]); }
static scale(a,s) { return a.map(v=>v*s); }
static det(m) { return m.length == 1? m[0][0]: m.length == 2 ? m[0][0]*m[1][1]-m[0][1]*m[1][0]: m[0].reduce((r,e,i) => r+(-1)**(i+2)*e*this.det(m.slice(1).map(c => c.filter((_,j) => i != j))),0); }
static angle(a) { return Math.PI - Math.atan2(a[1], -a[0]); } //compatible with turtletoy heading
static rot2d(angle) { return [[Math.cos(angle), -Math.sin(angle)], [Math.sin(angle), Math.cos(angle)]]; }
static rot3d(yaw,pitch,roll) { return [[Math.cos(yaw)*Math.cos(pitch), Math.cos(yaw)*Math.sin(pitch)*Math.sin(roll)-Math.sin(yaw)*Math.cos(roll), Math.cos(yaw)*Math.sin(pitch)*Math.cos(roll)+Math.sin(yaw)*Math.sin(roll)],[Math.sin(yaw)*Math.cos(pitch), Math.sin(yaw)*Math.sin(pitch)*Math.sin(roll)+Math.cos(yaw)*Math.cos(roll), Math.sin(yaw)*Math.sin(pitch)*Math.cos(roll)-Math.cos(yaw)*Math.sin(roll)],[-Math.sin(pitch), Math.cos(pitch)*Math.sin(roll), Math.cos(pitch)*Math.cos(roll)]]; }
static trans(matrix,a) { return a.map((v,i) => a.reduce((acc, cur, ci) => acc + cur * matrix[ci][i], 0)); }
//Mirror vector a in a ray through [0,0] with direction mirror
static mirror2d(a,mirror) { return [Math.atan2(...mirror)].map(angle => this.trans(this.rot2d(angle), this.mul([-1,1], this.trans(this.rot2d(-angle), a)))).pop(); }
static equals(a,b) { return !a.some((e, i) => e != b[i]); }
static approx(a,b,p) { return this.len(this.sub(a,b)) < (p === undefined? .001: p); }
static norm (a) { return this.scale(a,1/this.len(a)); }
static len (a) { return Math.hypot(...a); }
static lenSq (a) { return a.reduce((a,c)=>a+c**2,0); }
static lerp (a,b,t) { return a.map((v, i) => v*(1-t) + b[i]*t); }
static dist (a,b) { return Math.hypot(...this.sub(a,b)); }
static dot (a,b) { return a.reduce((a,c,i) => a+c*b[i], 0); }
static cross(...ab) { return ab[0].map((e, i) => ab.map(v => v.filter((ee, ii) => ii != i))).map((m,i) => (i%2==0?-1:1)*this.det(m)); }
static elementSum(b){ return b.reduce((a,c) => a + c, 0); }
static clamp(a,min,max) { return a.map((e,i) => Math.min(Math.max(e, min[i]), max[i])) };
static rotateClamp(a,min,max) { return a.map((e,i) => {const d = max[i]-min[i];if(d == 0) return min[i];while(e < min[i]) { e+=d; }while(e > max[i]) { e-=d; }return e;});
}
}
this.V = Vector;
}
// Turtlelib Jurgen Vector Math v 4 - end
// Turtlelib Jurgen Intersection v 4 - start - {"id":"c5f8fa95ed","package":"Jurgen","name":"Intersection","version":"4"}
function turtlelib_ns_c5f8fa95ed_Jurgen_Intersection() {
///////////////////////////////////////////////////////////////
// Intersection functions - Created by Jurgen Westerhof 2024 //
///////////////////////////////////////////////////////////////
class Intersection {
//a-start, a-direction, b-start, b-direction
//returns false on no intersection or [[intersection:x,y], scalar a-direction, scalar b-direction
static info(as, ad, bs, bd) { const d = V.sub(bs, as), det = -V.det([bd, ad]); if(det === 0) return false; const res = [V.det([d, bd]) / det, V.det([d, ad]) / det]; return [V.add(as, V.scale(ad, res[0])), ...res]; }
static ray(a, b, c, d) { return this.info(a, b, c, d); }
static segment(a,b,c,d, inclusiveStart = true, inclusiveEnd = true) { const i = this.info(a, V.sub(b, a), c, V.sub(d, c)); return i === false? false: ( (inclusiveStart? 0<=i[1] && 0<=i[2]: 0<i[1] && 0<i[2]) && (inclusiveEnd? i[1]<=1 && i[2]<=1: i[1]<1 && i[2]<1) )?i[0]:false;}
static tour(tour, segmentStart, segmentDirection) { return tour.map((e, i, a) => [i, this.info(e, V.sub(a[(i+1)%a.length], e), segmentStart, segmentDirection)]).filter(e => e[1] !== false && 0 <= e[1][1] && e[1][1] <= 1).filter(e => 0 <= e[1][2]).map(e => ({position: e[1][0],tourIndex: e[0],tourSegmentPortion: e[1][1],segmentPortion: e[1][2],}));}
static inside(tour, pt) { return tour.map((e,i,a) => this.segment(e, a[(i+1)%a.length], pt, [Number.MAX_SAFE_INTEGER, 0], true, false)).filter(e => e !== false).length % 2 == 1; }
static circles(centerA, radiusA, centerB, radiusB) {const result = {intersect_count: 0,intersect_occurs: true,one_is_in_other: false,are_equal: false,point_1: [null, null],point_2: [null, null],};const dx = centerB[0] - centerA[0];const dy = centerB[1] - centerA[1];const dist = Math.hypot(dy, dx);if (dist > radiusA + radiusB) {result.intersect_occurs = false;}if (dist < Math.abs(radiusA - radiusB) && !N.approx(dist, Math.abs(radiusA - radiusB))) {result.intersect_occurs = false;result.one_is_in_other = true;}if (V.approx(centerA, centerB) && radiusA === radiusB) {result.are_equal = true;}if (result.intersect_occurs) {const centroid = (radiusA**2 - radiusB**2 + dist * dist) / (2.0 * dist);const x2 = centerA[0] + (dx * centroid) / dist;const y2 = centerA[1] + (dy * centroid) / dist;const prec = 10000;const h = (Math.round(radiusA**2 * prec)/prec - Math.round(centroid**2 * prec)/prec)**.5;const rx = -dy * (h / dist);const ry = dx * (h / dist);result.point_1 = [x2 + rx, y2 + ry];result.point_2 = [x2 - rx, y2 - ry];if (result.are_equal) {result.intersect_count = Infinity;} else if (V.equals(result.point_1, result.point_2)) {result.intersect_count = 1;} else {result.intersect_count = 2;}}return result;}
}
this.Intersection = Intersection;
}
// Turtlelib Jurgen Intersection v 4 - end
// Turtlelib Jurgen Randomness v 2 - start - {"id":"13b81fd40e","package":"Jurgen","name":"Randomness","version":"2"}
function turtlelib_ns_13b81fd40e_Jurgen_Randomness() {
///////////////////////////////////////////////////////////////
// Pseudorandom functions - Created by Jurgen Westerhof 2024 //
///////////////////////////////////////////////////////////////
class Random {
static #apply(seed) {
// Seedable random number generator by David Bau: http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html
!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=s&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=s&f+1],c=c*d+h[s&(h[f]=h[g=s&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&"object"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:"string"==e?a:a+"\0"}function l(a,b){for(var c,d=a+"",e=0;e<d.length;)b[s&e]=s&(c^=19*b[s&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return o?n(o.randomBytes(d)):(a.crypto.getRandomValues(c=new Uint8Array(d)),n(c))}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o,p=c.pow(d,e),q=c.pow(2,f),r=2*q,s=d-1,t=c["seed"+i]=function(a,f,g){var h=[];f=1==f?{entropy:!0}:f||{};var o=l(k(f.entropy?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(f.pass||g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=p,c=0;q>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=r;)a/=2,b/=2,c>>>=1;return(a+c)/b},o,"global"in f?f.global:this==c)};if(l(c[i](),b),g&&g.exports){g.exports=t;try{o=require("crypto")}catch(u){}}else h&&h.amd&&h(function(){return t})}(this,[],Math,256,6,52,"object"==typeof module&&module,"function"==typeof define&&define,"random");
Math.seedrandom(seed);
}
static seedRandom() { this.#apply(new Date().getMilliseconds()); }
static seedDaily() { this.#apply(new Date().toDateString()); }
static seed(seed) { this.#apply(seed); }
static getInt(min, max) { if(max == undefined) {max = min + 1; min = 0; } const [mi, ma] = [Math.min(min, max), Math.max(min, max)]; return (mi + Math.random() * (ma - mi)) | 0;}
static get(min, max) {if(min == undefined) {return Math.random();}if(max == undefined) {max = min;min = 0;}const [mi, ma] = [Math.min(min, max), Math.max(min, max)];return mi + Math.random() * (ma - mi);}
static fraction(whole) { return this.get(0, whole); }
static getAngle(l = 1) { return l * this.get(0, 2*Math.PI); }
// Standard Normal variate using Box-Muller transform.
static getGaussian(mean=.5, stdev=.1) {const u = 1 - this.get(); /* Converting [0,1) to (0,1] */const v = this.get();const z = ( -2.0 * Math.log( u ) )**.5 * Math.cos( 2.0 * Math.PI * v );/* Transform to the desired mean and standard deviation: */return z * stdev + mean;}
static skew(value, skew = 0) { /*skew values (from 0 to 1) by a skew from -1 to 1, respectively right and left skewed (resp more values to left or to right), 0 is not skewed*/return (skew < 0)? value - (this.skew(1-value, -skew) - (1-value)): Math.pow(value, 1-Math.abs(skew));}
static getNormalDistributed(skew = 0) { /*skew values (from 0 to 1) by a skew from -1 to 1, respectively right and left skewed (resp more values to left or to right), 0 is not skewed*/let v = -1;while(v < 0 || 1 <= v) { v = this.getGaussian(.5, .1) };return this.skew(v, skew);}
}
this.R = Random;
}
// Turtlelib Jurgen Randomness v 2 - end
// Turtlelib Jurgen Randomness v 2 - start - {"id":"13b81fd40e","package":"Jurgen","name":"Randomness","version":"2"}
function turtlelib_ns_13b81fd40e_Jurgen_Randomness() {
///////////////////////////////////////////////////////////////
// Pseudorandom functions - Created by Jurgen Westerhof 2024 //
///////////////////////////////////////////////////////////////
class Random {
static #apply(seed) {
// Seedable random number generator by David Bau: http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html
!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=s&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=s&f+1],c=c*d+h[s&(h[f]=h[g=s&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&"object"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:"string"==e?a:a+"\0"}function l(a,b){for(var c,d=a+"",e=0;e<d.length;)b[s&e]=s&(c^=19*b[s&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return o?n(o.randomBytes(d)):(a.crypto.getRandomValues(c=new Uint8Array(d)),n(c))}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o,p=c.pow(d,e),q=c.pow(2,f),r=2*q,s=d-1,t=c["seed"+i]=function(a,f,g){var h=[];f=1==f?{entropy:!0}:f||{};var o=l(k(f.entropy?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(f.pass||g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=p,c=0;q>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=r;)a/=2,b/=2,c>>>=1;return(a+c)/b},o,"global"in f?f.global:this==c)};if(l(c[i](),b),g&&g.exports){g.exports=t;try{o=require("crypto")}catch(u){}}else h&&h.amd&&h(function(){return t})}(this,[],Math,256,6,52,"object"==typeof module&&module,"function"==typeof define&&define,"random");
Math.seedrandom(seed);
}
static seedRandom() { this.#apply(new Date().getMilliseconds()); }
static seedDaily() { this.#apply(new Date().toDateString()); }
static seed(seed) { this.#apply(seed); }
static getInt(min, max) { if(max == undefined) {max = min + 1; min = 0; } const [mi, ma] = [Math.min(min, max), Math.max(min, max)]; return (mi + Math.random() * (ma - mi)) | 0;}
static get(min, max) {if(min == undefined) {return Math.random();}if(max == undefined) {max = min;min = 0;}const [mi, ma] = [Math.min(min, max), Math.max(min, max)];return mi + Math.random() * (ma - mi);}
static fraction(whole) { return this.get(0, whole); }
static getAngle(l = 1) { return l * this.get(0, 2*Math.PI); }
// Standard Normal variate using Box-Muller transform.
static getGaussian(mean=.5, stdev=.1) {const u = 1 - this.get(); /* Converting [0,1) to (0,1] */const v = this.get();const z = ( -2.0 * Math.log( u ) )**.5 * Math.cos( 2.0 * Math.PI * v );/* Transform to the desired mean and standard deviation: */return z * stdev + mean;}
static skew(value, skew = 0) { /*skew values (from 0 to 1) by a skew from -1 to 1, respectively right and left skewed (resp more values to left or to right), 0 is not skewed*/return (skew < 0)? value - (this.skew(1-value, -skew) - (1-value)): Math.pow(value, 1-Math.abs(skew));}
static getNormalDistributed(skew = 0) { /*skew values (from 0 to 1) by a skew from -1 to 1, respectively right and left skewed (resp more values to left or to right), 0 is not skewed*/let v = -1;while(v < 0 || 1 <= v) { v = this.getGaussian(.5, .1) };return this.skew(v, skew);}
}
this.R = Random;
}
// Turtlelib Jurgen Randomness v 2 - end