potree.js 3.8 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435604366043760438604396044060441604426044360444604456044660447604486044960450604516045260453604546045560456604576045860459604606046160462604636046460465604666046760468604696047060471604726047360474604756047660477604786047960480604816048260483604846048560486604876048860489604906049160492604936049460495604966049760498604996050060501605026050360504605056050660507605086050960510605116051260513605146051560516605176051860519605206052160522605236052460525605266052760528605296053060531605326053360534605356053660537605386053960540605416054260543605446054560546605476054860549605506055160552605536055460555605566055760558605596056060561605626056360564605656056660567605686056960570605716057260573605746057560576605776057860579605806058160582605836058460585605866058760588605896059060591605926059360594605956059660597605986059960600606016060260603606046060560606606076060860609606106061160612606136061460615606166061760618606196062060621606226062360624606256062660627606286062960630606316063260633606346063560636606376063860639606406064160642606436064460645606466064760648606496065060651606526065360654606556065660657606586065960660606616066260663606646066560666606676066860669606706067160672606736067460675606766067760678606796068060681606826068360684606856068660687606886068960690606916069260693606946069560696606976069860699607006070160702607036070460705607066070760708607096071060711607126071360714607156071660717607186071960720607216072260723607246072560726607276072860729607306073160732607336073460735607366073760738607396074060741607426074360744607456074660747607486074960750607516075260753607546075560756607576075860759607606076160762607636076460765607666076760768607696077060771607726077360774607756077660777607786077960780607816078260783607846078560786607876078860789607906079160792607936079460795607966079760798607996080060801608026080360804608056080660807608086080960810608116081260813608146081560816608176081860819608206082160822608236082460825608266082760828608296083060831608326083360834608356083660837608386083960840608416084260843608446084560846608476084860849608506085160852608536085460855608566085760858608596086060861608626086360864608656086660867608686086960870608716087260873608746087560876608776087860879608806088160882608836088460885608866088760888608896089060891608926089360894608956089660897608986089960900609016090260903609046090560906609076090860909609106091160912609136091460915609166091760918609196092060921609226092360924609256092660927609286092960930609316093260933609346093560936609376093860939609406094160942609436094460945609466094760948609496095060951609526095360954609556095660957609586095960960609616096260963609646096560966609676096860969609706097160972609736097460975609766097760978609796098060981609826098360984609856098660987609886098960990609916099260993609946099560996609976099860999610006100161002610036100461005610066100761008610096101061011610126101361014610156101661017610186101961020610216102261023610246102561026610276102861029610306103161032610336103461035610366103761038610396104061041610426104361044610456104661047610486104961050610516105261053610546105561056610576105861059610606106161062610636106461065610666106761068610696107061071610726107361074610756107661077610786107961080610816108261083610846108561086610876108861089610906109161092610936109461095610966109761098610996110061101611026110361104611056110661107611086110961110611116111261113611146111561116611176111861119611206112161122611236112461125611266112761128611296113061131611326113361134611356113661137611386113961140611416114261143611446114561146611476114861149611506115161152611536115461155611566115761158611596116061161611626116361164611656116661167611686116961170611716117261173611746117561176611776117861179611806118161182611836118461185611866118761188611896119061191611926119361194611956119661197611986119961200612016120261203612046120561206612076120861209612106121161212612136121461215612166121761218612196122061221612226122361224612256122661227612286122961230612316123261233612346123561236612376123861239612406124161242612436124461245612466124761248612496125061251612526125361254612556125661257612586125961260612616126261263612646126561266612676126861269612706127161272612736127461275612766127761278612796128061281612826128361284612856128661287612886128961290612916129261293612946129561296612976129861299613006130161302613036130461305613066130761308613096131061311613126131361314613156131661317613186131961320613216132261323613246132561326613276132861329613306133161332613336133461335613366133761338613396134061341613426134361344613456134661347613486134961350613516135261353613546135561356613576135861359613606136161362613636136461365613666136761368613696137061371613726137361374613756137661377613786137961380613816138261383613846138561386613876138861389613906139161392613936139461395613966139761398613996140061401614026140361404614056140661407614086140961410614116141261413614146141561416614176141861419614206142161422614236142461425614266142761428614296143061431614326143361434614356143661437614386143961440614416144261443614446144561446614476144861449614506145161452614536145461455614566145761458614596146061461614626146361464614656146661467614686146961470614716147261473614746147561476614776147861479614806148161482614836148461485614866148761488614896149061491614926149361494614956149661497614986149961500615016150261503615046150561506615076150861509615106151161512615136151461515615166151761518615196152061521615226152361524615256152661527615286152961530615316153261533615346153561536615376153861539615406154161542615436154461545615466154761548615496155061551615526155361554615556155661557615586155961560615616156261563615646156561566615676156861569615706157161572615736157461575615766157761578615796158061581615826158361584615856158661587615886158961590615916159261593615946159561596615976159861599616006160161602616036160461605616066160761608616096161061611616126161361614616156161661617616186161961620616216162261623616246162561626616276162861629616306163161632616336163461635616366163761638616396164061641616426164361644616456164661647616486164961650616516165261653616546165561656616576165861659616606166161662616636166461665616666166761668616696167061671616726167361674616756167661677616786167961680616816168261683616846168561686616876168861689616906169161692616936169461695616966169761698616996170061701617026170361704617056170661707617086170961710617116171261713617146171561716617176171861719617206172161722617236172461725617266172761728617296173061731617326173361734617356173661737617386173961740617416174261743617446174561746617476174861749617506175161752617536175461755617566175761758617596176061761617626176361764617656176661767617686176961770617716177261773617746177561776617776177861779617806178161782617836178461785617866178761788617896179061791617926179361794617956179661797617986179961800618016180261803618046180561806618076180861809618106181161812618136181461815618166181761818618196182061821618226182361824618256182661827618286182961830618316183261833618346183561836618376183861839618406184161842618436184461845618466184761848618496185061851618526185361854618556185661857618586185961860618616186261863618646186561866618676186861869618706187161872618736187461875618766187761878618796188061881618826188361884618856188661887618886188961890618916189261893618946189561896618976189861899619006190161902619036190461905619066190761908619096191061911619126191361914619156191661917619186191961920619216192261923619246192561926619276192861929619306193161932619336193461935619366193761938619396194061941619426194361944619456194661947619486194961950619516195261953619546195561956619576195861959619606196161962619636196461965619666196761968619696197061971619726197361974619756197661977619786197961980619816198261983619846198561986619876198861989619906199161992619936199461995619966199761998619996200062001620026200362004620056200662007620086200962010620116201262013620146201562016620176201862019620206202162022620236202462025620266202762028620296203062031620326203362034620356203662037620386203962040620416204262043620446204562046620476204862049620506205162052620536205462055620566205762058620596206062061620626206362064620656206662067620686206962070620716207262073620746207562076620776207862079620806208162082620836208462085620866208762088620896209062091620926209362094620956209662097620986209962100621016210262103621046210562106621076210862109621106211162112621136211462115621166211762118621196212062121621226212362124621256212662127621286212962130621316213262133621346213562136621376213862139621406214162142621436214462145621466214762148621496215062151621526215362154621556215662157621586215962160621616216262163621646216562166621676216862169621706217162172621736217462175621766217762178621796218062181621826218362184621856218662187621886218962190621916219262193621946219562196621976219862199622006220162202622036220462205622066220762208622096221062211622126221362214622156221662217622186221962220622216222262223622246222562226622276222862229622306223162232622336223462235622366223762238622396224062241622426224362244622456224662247622486224962250622516225262253622546225562256622576225862259622606226162262622636226462265622666226762268622696227062271622726227362274622756227662277622786227962280622816228262283622846228562286622876228862289622906229162292622936229462295622966229762298622996230062301623026230362304623056230662307623086230962310623116231262313623146231562316623176231862319623206232162322623236232462325623266232762328623296233062331623326233362334623356233662337623386233962340623416234262343623446234562346623476234862349623506235162352623536235462355623566235762358623596236062361623626236362364623656236662367623686236962370623716237262373623746237562376623776237862379623806238162382623836238462385623866238762388623896239062391623926239362394623956239662397623986239962400624016240262403624046240562406624076240862409624106241162412624136241462415624166241762418624196242062421624226242362424624256242662427624286242962430624316243262433624346243562436624376243862439624406244162442624436244462445624466244762448624496245062451624526245362454624556245662457624586245962460624616246262463624646246562466624676246862469624706247162472624736247462475624766247762478624796248062481624826248362484624856248662487624886248962490624916249262493624946249562496624976249862499625006250162502625036250462505625066250762508625096251062511625126251362514625156251662517625186251962520625216252262523625246252562526625276252862529625306253162532625336253462535625366253762538625396254062541625426254362544625456254662547625486254962550625516255262553625546255562556625576255862559625606256162562625636256462565625666256762568625696257062571625726257362574625756257662577625786257962580625816258262583625846258562586625876258862589625906259162592625936259462595625966259762598625996260062601626026260362604626056260662607626086260962610626116261262613626146261562616626176261862619626206262162622626236262462625626266262762628626296263062631626326263362634626356263662637626386263962640626416264262643626446264562646626476264862649626506265162652626536265462655626566265762658626596266062661626626266362664626656266662667626686266962670626716267262673626746267562676626776267862679626806268162682626836268462685626866268762688626896269062691626926269362694626956269662697626986269962700627016270262703627046270562706627076270862709627106271162712627136271462715627166271762718627196272062721627226272362724627256272662727627286272962730627316273262733627346273562736627376273862739627406274162742627436274462745627466274762748627496275062751627526275362754627556275662757627586275962760627616276262763627646276562766627676276862769627706277162772627736277462775627766277762778627796278062781627826278362784627856278662787627886278962790627916279262793627946279562796627976279862799628006280162802628036280462805628066280762808628096281062811628126281362814628156281662817628186281962820628216282262823628246282562826628276282862829628306283162832628336283462835628366283762838628396284062841628426284362844628456284662847628486284962850628516285262853628546285562856628576285862859628606286162862628636286462865628666286762868628696287062871628726287362874628756287662877628786287962880628816288262883628846288562886628876288862889628906289162892628936289462895628966289762898628996290062901629026290362904629056290662907629086290962910629116291262913629146291562916629176291862919629206292162922629236292462925629266292762928629296293062931629326293362934629356293662937629386293962940629416294262943629446294562946629476294862949629506295162952629536295462955629566295762958629596296062961629626296362964629656296662967629686296962970629716297262973629746297562976629776297862979629806298162982629836298462985629866298762988629896299062991629926299362994629956299662997629986299963000630016300263003630046300563006630076300863009630106301163012630136301463015630166301763018630196302063021630226302363024630256302663027630286302963030630316303263033630346303563036630376303863039630406304163042630436304463045630466304763048630496305063051630526305363054630556305663057630586305963060630616306263063630646306563066630676306863069630706307163072630736307463075630766307763078630796308063081630826308363084630856308663087630886308963090630916309263093630946309563096630976309863099631006310163102631036310463105631066310763108631096311063111631126311363114631156311663117631186311963120631216312263123631246312563126631276312863129631306313163132631336313463135631366313763138631396314063141631426314363144631456314663147631486314963150631516315263153631546315563156631576315863159631606316163162631636316463165631666316763168631696317063171631726317363174631756317663177631786317963180631816318263183631846318563186631876318863189631906319163192631936319463195631966319763198631996320063201632026320363204632056320663207632086320963210632116321263213632146321563216632176321863219632206322163222632236322463225632266322763228632296323063231632326323363234632356323663237632386323963240632416324263243632446324563246632476324863249632506325163252632536325463255632566325763258632596326063261632626326363264632656326663267632686326963270632716327263273632746327563276632776327863279632806328163282632836328463285632866328763288632896329063291632926329363294632956329663297632986329963300633016330263303633046330563306633076330863309633106331163312633136331463315633166331763318633196332063321633226332363324633256332663327633286332963330633316333263333633346333563336633376333863339633406334163342633436334463345633466334763348633496335063351633526335363354633556335663357633586335963360633616336263363633646336563366633676336863369633706337163372633736337463375633766337763378633796338063381633826338363384633856338663387633886338963390633916339263393633946339563396633976339863399634006340163402634036340463405634066340763408634096341063411634126341363414634156341663417634186341963420634216342263423634246342563426634276342863429634306343163432634336343463435634366343763438634396344063441634426344363444634456344663447634486344963450634516345263453634546345563456634576345863459634606346163462634636346463465634666346763468634696347063471634726347363474634756347663477634786347963480634816348263483634846348563486634876348863489634906349163492634936349463495634966349763498634996350063501635026350363504635056350663507635086350963510635116351263513635146351563516635176351863519635206352163522635236352463525635266352763528635296353063531635326353363534635356353663537635386353963540635416354263543635446354563546635476354863549635506355163552635536355463555635566355763558635596356063561635626356363564635656356663567635686356963570635716357263573635746357563576635776357863579635806358163582635836358463585635866358763588635896359063591635926359363594635956359663597635986359963600636016360263603636046360563606636076360863609636106361163612636136361463615636166361763618636196362063621636226362363624636256362663627636286362963630636316363263633636346363563636636376363863639636406364163642636436364463645636466364763648636496365063651636526365363654636556365663657636586365963660636616366263663636646366563666636676366863669636706367163672636736367463675636766367763678636796368063681636826368363684636856368663687636886368963690636916369263693636946369563696636976369863699637006370163702637036370463705637066370763708637096371063711637126371363714637156371663717637186371963720637216372263723637246372563726637276372863729637306373163732637336373463735637366373763738637396374063741637426374363744637456374663747637486374963750637516375263753637546375563756637576375863759637606376163762637636376463765637666376763768637696377063771637726377363774637756377663777637786377963780637816378263783637846378563786637876378863789637906379163792637936379463795637966379763798637996380063801638026380363804638056380663807638086380963810638116381263813638146381563816638176381863819638206382163822638236382463825638266382763828638296383063831638326383363834638356383663837638386383963840638416384263843638446384563846638476384863849638506385163852638536385463855638566385763858638596386063861638626386363864638656386663867638686386963870638716387263873638746387563876638776387863879638806388163882638836388463885638866388763888638896389063891638926389363894638956389663897638986389963900639016390263903639046390563906639076390863909639106391163912639136391463915639166391763918639196392063921639226392363924639256392663927639286392963930639316393263933639346393563936639376393863939639406394163942639436394463945639466394763948639496395063951639526395363954639556395663957639586395963960639616396263963639646396563966639676396863969639706397163972639736397463975639766397763978639796398063981639826398363984639856398663987639886398963990639916399263993639946399563996639976399863999640006400164002640036400464005640066400764008640096401064011640126401364014640156401664017640186401964020640216402264023640246402564026640276402864029640306403164032640336403464035640366403764038640396404064041640426404364044640456404664047640486404964050640516405264053640546405564056640576405864059640606406164062640636406464065640666406764068640696407064071640726407364074640756407664077640786407964080640816408264083640846408564086640876408864089640906409164092640936409464095640966409764098640996410064101641026410364104641056410664107641086410964110641116411264113641146411564116641176411864119641206412164122641236412464125641266412764128641296413064131641326413364134641356413664137641386413964140641416414264143641446414564146641476414864149641506415164152641536415464155641566415764158641596416064161641626416364164641656416664167641686416964170641716417264173641746417564176641776417864179641806418164182641836418464185641866418764188641896419064191641926419364194641956419664197641986419964200642016420264203642046420564206642076420864209642106421164212642136421464215642166421764218642196422064221642226422364224642256422664227642286422964230642316423264233642346423564236642376423864239642406424164242642436424464245642466424764248642496425064251642526425364254642556425664257642586425964260642616426264263642646426564266642676426864269642706427164272642736427464275642766427764278642796428064281642826428364284642856428664287642886428964290642916429264293642946429564296642976429864299643006430164302643036430464305643066430764308643096431064311643126431364314643156431664317643186431964320643216432264323643246432564326643276432864329643306433164332643336433464335643366433764338643396434064341643426434364344643456434664347643486434964350643516435264353643546435564356643576435864359643606436164362643636436464365643666436764368643696437064371643726437364374643756437664377643786437964380643816438264383643846438564386643876438864389643906439164392643936439464395643966439764398643996440064401644026440364404644056440664407644086440964410644116441264413644146441564416644176441864419644206442164422644236442464425644266442764428644296443064431644326443364434644356443664437644386443964440644416444264443644446444564446644476444864449644506445164452644536445464455644566445764458644596446064461644626446364464644656446664467644686446964470644716447264473644746447564476644776447864479644806448164482644836448464485644866448764488644896449064491644926449364494644956449664497644986449964500645016450264503645046450564506645076450864509645106451164512645136451464515645166451764518645196452064521645226452364524645256452664527645286452964530645316453264533645346453564536645376453864539645406454164542645436454464545645466454764548645496455064551645526455364554645556455664557645586455964560645616456264563645646456564566645676456864569645706457164572645736457464575645766457764578645796458064581645826458364584645856458664587645886458964590645916459264593645946459564596645976459864599646006460164602646036460464605646066460764608646096461064611646126461364614646156461664617646186461964620646216462264623646246462564626646276462864629646306463164632646336463464635646366463764638646396464064641646426464364644646456464664647646486464964650646516465264653646546465564656646576465864659646606466164662646636466464665646666466764668646696467064671646726467364674646756467664677646786467964680646816468264683646846468564686646876468864689646906469164692646936469464695646966469764698646996470064701647026470364704647056470664707647086470964710647116471264713647146471564716647176471864719647206472164722647236472464725647266472764728647296473064731647326473364734647356473664737647386473964740647416474264743647446474564746647476474864749647506475164752647536475464755647566475764758647596476064761647626476364764647656476664767647686476964770647716477264773647746477564776647776477864779647806478164782647836478464785647866478764788647896479064791647926479364794647956479664797647986479964800648016480264803648046480564806648076480864809648106481164812648136481464815648166481764818648196482064821648226482364824648256482664827648286482964830648316483264833648346483564836648376483864839648406484164842648436484464845648466484764848648496485064851648526485364854648556485664857648586485964860648616486264863648646486564866648676486864869648706487164872648736487464875648766487764878648796488064881648826488364884648856488664887648886488964890648916489264893648946489564896648976489864899649006490164902649036490464905649066490764908649096491064911649126491364914649156491664917649186491964920649216492264923649246492564926649276492864929649306493164932649336493464935649366493764938649396494064941649426494364944649456494664947649486494964950649516495264953649546495564956649576495864959649606496164962649636496464965649666496764968649696497064971649726497364974649756497664977649786497964980649816498264983649846498564986649876498864989649906499164992649936499464995649966499764998649996500065001650026500365004650056500665007650086500965010650116501265013650146501565016650176501865019650206502165022650236502465025650266502765028650296503065031650326503365034650356503665037650386503965040650416504265043650446504565046650476504865049650506505165052650536505465055650566505765058650596506065061650626506365064650656506665067650686506965070650716507265073650746507565076650776507865079650806508165082650836508465085650866508765088650896509065091650926509365094650956509665097650986509965100651016510265103651046510565106651076510865109651106511165112651136511465115651166511765118651196512065121651226512365124651256512665127651286512965130651316513265133651346513565136651376513865139651406514165142651436514465145651466514765148651496515065151651526515365154651556515665157651586515965160651616516265163651646516565166651676516865169651706517165172651736517465175651766517765178651796518065181651826518365184651856518665187651886518965190651916519265193651946519565196651976519865199652006520165202652036520465205652066520765208652096521065211652126521365214652156521665217652186521965220652216522265223652246522565226652276522865229652306523165232652336523465235652366523765238652396524065241652426524365244652456524665247652486524965250652516525265253652546525565256652576525865259652606526165262652636526465265652666526765268652696527065271652726527365274652756527665277652786527965280652816528265283652846528565286652876528865289652906529165292652936529465295652966529765298652996530065301653026530365304653056530665307653086530965310653116531265313653146531565316653176531865319653206532165322653236532465325653266532765328653296533065331653326533365334653356533665337653386533965340653416534265343653446534565346653476534865349653506535165352653536535465355653566535765358653596536065361653626536365364653656536665367653686536965370653716537265373653746537565376653776537865379653806538165382653836538465385653866538765388653896539065391653926539365394653956539665397653986539965400654016540265403654046540565406654076540865409654106541165412654136541465415654166541765418654196542065421654226542365424654256542665427654286542965430654316543265433654346543565436654376543865439654406544165442654436544465445654466544765448654496545065451654526545365454654556545665457654586545965460654616546265463654646546565466654676546865469654706547165472654736547465475654766547765478654796548065481654826548365484654856548665487654886548965490654916549265493654946549565496654976549865499655006550165502655036550465505655066550765508655096551065511655126551365514655156551665517655186551965520655216552265523655246552565526655276552865529655306553165532655336553465535655366553765538655396554065541655426554365544655456554665547655486554965550655516555265553655546555565556655576555865559655606556165562655636556465565655666556765568655696557065571655726557365574655756557665577655786557965580655816558265583655846558565586655876558865589655906559165592655936559465595655966559765598655996560065601656026560365604656056560665607656086560965610656116561265613656146561565616656176561865619656206562165622656236562465625656266562765628656296563065631656326563365634656356563665637656386563965640656416564265643656446564565646656476564865649656506565165652656536565465655656566565765658656596566065661656626566365664656656566665667656686566965670656716567265673656746567565676656776567865679656806568165682656836568465685656866568765688656896569065691656926569365694656956569665697656986569965700657016570265703657046570565706657076570865709657106571165712657136571465715657166571765718657196572065721657226572365724657256572665727657286572965730657316573265733657346573565736657376573865739657406574165742657436574465745657466574765748657496575065751657526575365754657556575665757657586575965760657616576265763657646576565766657676576865769657706577165772657736577465775657766577765778657796578065781657826578365784657856578665787657886578965790657916579265793657946579565796657976579865799658006580165802658036580465805658066580765808658096581065811658126581365814658156581665817658186581965820658216582265823658246582565826658276582865829658306583165832658336583465835658366583765838658396584065841658426584365844658456584665847658486584965850658516585265853658546585565856658576585865859658606586165862658636586465865658666586765868658696587065871658726587365874658756587665877658786587965880658816588265883658846588565886658876588865889658906589165892658936589465895658966589765898658996590065901659026590365904659056590665907659086590965910659116591265913659146591565916659176591865919659206592165922659236592465925659266592765928659296593065931659326593365934659356593665937659386593965940659416594265943659446594565946659476594865949659506595165952659536595465955659566595765958659596596065961659626596365964659656596665967659686596965970659716597265973659746597565976659776597865979659806598165982659836598465985659866598765988659896599065991659926599365994659956599665997659986599966000660016600266003660046600566006660076600866009660106601166012660136601466015660166601766018660196602066021660226602366024660256602666027660286602966030660316603266033660346603566036660376603866039660406604166042660436604466045660466604766048660496605066051660526605366054660556605666057660586605966060660616606266063660646606566066660676606866069660706607166072660736607466075660766607766078660796608066081660826608366084660856608666087660886608966090660916609266093660946609566096660976609866099661006610166102661036610466105661066610766108661096611066111661126611366114661156611666117661186611966120661216612266123661246612566126661276612866129661306613166132661336613466135661366613766138661396614066141661426614366144661456614666147661486614966150661516615266153661546615566156661576615866159661606616166162661636616466165661666616766168661696617066171661726617366174661756617666177661786617966180661816618266183661846618566186661876618866189661906619166192661936619466195661966619766198661996620066201662026620366204662056620666207662086620966210662116621266213662146621566216662176621866219662206622166222662236622466225662266622766228662296623066231662326623366234662356623666237662386623966240662416624266243662446624566246662476624866249662506625166252662536625466255662566625766258662596626066261662626626366264662656626666267662686626966270662716627266273662746627566276662776627866279662806628166282662836628466285662866628766288662896629066291662926629366294662956629666297662986629966300663016630266303663046630566306663076630866309663106631166312663136631466315663166631766318663196632066321663226632366324663256632666327663286632966330663316633266333663346633566336663376633866339663406634166342663436634466345663466634766348663496635066351663526635366354663556635666357663586635966360663616636266363663646636566366663676636866369663706637166372663736637466375663766637766378663796638066381663826638366384663856638666387663886638966390663916639266393663946639566396663976639866399664006640166402664036640466405664066640766408664096641066411664126641366414664156641666417664186641966420664216642266423664246642566426664276642866429664306643166432664336643466435664366643766438664396644066441664426644366444664456644666447664486644966450664516645266453664546645566456664576645866459664606646166462664636646466465664666646766468664696647066471664726647366474664756647666477664786647966480664816648266483664846648566486664876648866489664906649166492664936649466495664966649766498664996650066501665026650366504665056650666507665086650966510665116651266513665146651566516665176651866519665206652166522665236652466525665266652766528665296653066531665326653366534665356653666537665386653966540665416654266543665446654566546665476654866549665506655166552665536655466555665566655766558665596656066561665626656366564665656656666567665686656966570665716657266573665746657566576665776657866579665806658166582665836658466585665866658766588665896659066591665926659366594665956659666597665986659966600666016660266603666046660566606666076660866609666106661166612666136661466615666166661766618666196662066621666226662366624666256662666627666286662966630666316663266633666346663566636666376663866639666406664166642666436664466645666466664766648666496665066651666526665366654666556665666657666586665966660666616666266663666646666566666666676666866669666706667166672666736667466675666766667766678666796668066681666826668366684666856668666687666886668966690666916669266693666946669566696666976669866699667006670166702667036670466705667066670766708667096671066711667126671366714667156671666717667186671966720667216672266723667246672566726667276672866729667306673166732667336673466735667366673766738667396674066741667426674366744667456674666747667486674966750667516675266753667546675566756667576675866759667606676166762667636676466765667666676766768667696677066771667726677366774667756677666777667786677966780667816678266783667846678566786667876678866789667906679166792667936679466795667966679766798667996680066801668026680366804668056680666807668086680966810668116681266813668146681566816668176681866819668206682166822668236682466825668266682766828668296683066831668326683366834668356683666837668386683966840668416684266843668446684566846668476684866849668506685166852668536685466855668566685766858668596686066861668626686366864668656686666867668686686966870668716687266873668746687566876668776687866879668806688166882668836688466885668866688766888668896689066891668926689366894668956689666897668986689966900669016690266903669046690566906669076690866909669106691166912669136691466915669166691766918669196692066921669226692366924669256692666927669286692966930669316693266933669346693566936669376693866939669406694166942669436694466945669466694766948669496695066951669526695366954669556695666957669586695966960669616696266963669646696566966669676696866969669706697166972669736697466975669766697766978669796698066981669826698366984669856698666987669886698966990669916699266993669946699566996669976699866999670006700167002670036700467005670066700767008670096701067011670126701367014670156701667017670186701967020670216702267023670246702567026670276702867029670306703167032670336703467035670366703767038670396704067041670426704367044670456704667047670486704967050670516705267053670546705567056670576705867059670606706167062670636706467065670666706767068670696707067071670726707367074670756707667077670786707967080670816708267083670846708567086670876708867089670906709167092670936709467095670966709767098670996710067101671026710367104671056710667107671086710967110671116711267113671146711567116671176711867119671206712167122671236712467125671266712767128671296713067131671326713367134671356713667137671386713967140671416714267143671446714567146671476714867149671506715167152671536715467155671566715767158671596716067161671626716367164671656716667167671686716967170671716717267173671746717567176671776717867179671806718167182671836718467185671866718767188671896719067191671926719367194671956719667197671986719967200672016720267203672046720567206672076720867209672106721167212672136721467215672166721767218672196722067221672226722367224672256722667227672286722967230672316723267233672346723567236672376723867239672406724167242672436724467245672466724767248672496725067251672526725367254672556725667257672586725967260672616726267263672646726567266672676726867269672706727167272672736727467275672766727767278672796728067281672826728367284672856728667287672886728967290672916729267293672946729567296672976729867299673006730167302673036730467305673066730767308673096731067311673126731367314673156731667317673186731967320673216732267323673246732567326673276732867329673306733167332673336733467335673366733767338673396734067341673426734367344673456734667347673486734967350673516735267353673546735567356673576735867359673606736167362673636736467365673666736767368673696737067371673726737367374673756737667377673786737967380673816738267383673846738567386673876738867389673906739167392673936739467395673966739767398673996740067401674026740367404674056740667407674086740967410674116741267413674146741567416674176741867419674206742167422674236742467425674266742767428674296743067431674326743367434674356743667437674386743967440674416744267443674446744567446674476744867449674506745167452674536745467455674566745767458674596746067461674626746367464674656746667467674686746967470674716747267473674746747567476674776747867479674806748167482674836748467485674866748767488674896749067491674926749367494674956749667497674986749967500675016750267503675046750567506675076750867509675106751167512675136751467515675166751767518675196752067521675226752367524675256752667527675286752967530675316753267533675346753567536675376753867539675406754167542675436754467545675466754767548675496755067551675526755367554675556755667557675586755967560675616756267563675646756567566675676756867569675706757167572675736757467575675766757767578675796758067581675826758367584675856758667587675886758967590675916759267593675946759567596675976759867599676006760167602676036760467605676066760767608676096761067611676126761367614676156761667617676186761967620676216762267623676246762567626676276762867629676306763167632676336763467635676366763767638676396764067641676426764367644676456764667647676486764967650676516765267653676546765567656676576765867659676606766167662676636766467665676666766767668676696767067671676726767367674676756767667677676786767967680676816768267683676846768567686676876768867689676906769167692676936769467695676966769767698676996770067701677026770367704677056770667707677086770967710677116771267713677146771567716677176771867719677206772167722677236772467725677266772767728677296773067731677326773367734677356773667737677386773967740677416774267743677446774567746677476774867749677506775167752677536775467755677566775767758677596776067761677626776367764677656776667767677686776967770677716777267773677746777567776677776777867779677806778167782677836778467785677866778767788677896779067791677926779367794677956779667797677986779967800678016780267803678046780567806678076780867809678106781167812678136781467815678166781767818678196782067821678226782367824678256782667827678286782967830678316783267833678346783567836678376783867839678406784167842678436784467845678466784767848678496785067851678526785367854678556785667857678586785967860678616786267863678646786567866678676786867869678706787167872678736787467875678766787767878678796788067881678826788367884678856788667887678886788967890678916789267893678946789567896678976789867899679006790167902679036790467905679066790767908679096791067911679126791367914679156791667917679186791967920679216792267923679246792567926679276792867929679306793167932679336793467935679366793767938679396794067941679426794367944679456794667947679486794967950679516795267953679546795567956679576795867959679606796167962679636796467965679666796767968679696797067971679726797367974679756797667977679786797967980679816798267983679846798567986679876798867989679906799167992679936799467995679966799767998679996800068001680026800368004680056800668007680086800968010680116801268013680146801568016680176801868019680206802168022680236802468025680266802768028680296803068031680326803368034680356803668037680386803968040680416804268043680446804568046680476804868049680506805168052680536805468055680566805768058680596806068061680626806368064680656806668067680686806968070680716807268073680746807568076680776807868079680806808168082680836808468085680866808768088680896809068091680926809368094680956809668097680986809968100681016810268103681046810568106681076810868109681106811168112681136811468115681166811768118681196812068121681226812368124681256812668127681286812968130681316813268133681346813568136681376813868139681406814168142681436814468145681466814768148681496815068151681526815368154681556815668157681586815968160681616816268163681646816568166681676816868169681706817168172681736817468175681766817768178681796818068181681826818368184681856818668187681886818968190681916819268193681946819568196681976819868199682006820168202682036820468205682066820768208682096821068211682126821368214682156821668217682186821968220682216822268223682246822568226682276822868229682306823168232682336823468235682366823768238682396824068241682426824368244682456824668247682486824968250682516825268253682546825568256682576825868259682606826168262682636826468265682666826768268682696827068271682726827368274682756827668277682786827968280682816828268283682846828568286682876828868289682906829168292682936829468295682966829768298682996830068301683026830368304683056830668307683086830968310683116831268313683146831568316683176831868319683206832168322683236832468325683266832768328683296833068331683326833368334683356833668337683386833968340683416834268343683446834568346683476834868349683506835168352683536835468355683566835768358683596836068361683626836368364683656836668367683686836968370683716837268373683746837568376683776837868379683806838168382683836838468385683866838768388683896839068391683926839368394683956839668397683986839968400684016840268403684046840568406684076840868409684106841168412684136841468415684166841768418684196842068421684226842368424684256842668427684286842968430684316843268433684346843568436684376843868439684406844168442684436844468445684466844768448684496845068451684526845368454684556845668457684586845968460684616846268463684646846568466684676846868469684706847168472684736847468475684766847768478684796848068481684826848368484684856848668487684886848968490684916849268493684946849568496684976849868499685006850168502685036850468505685066850768508685096851068511685126851368514685156851668517685186851968520685216852268523685246852568526685276852868529685306853168532685336853468535685366853768538685396854068541685426854368544685456854668547685486854968550685516855268553685546855568556685576855868559685606856168562685636856468565685666856768568685696857068571685726857368574685756857668577685786857968580685816858268583685846858568586685876858868589685906859168592685936859468595685966859768598685996860068601686026860368604686056860668607686086860968610686116861268613686146861568616686176861868619686206862168622686236862468625686266862768628686296863068631686326863368634686356863668637686386863968640686416864268643686446864568646686476864868649686506865168652686536865468655686566865768658686596866068661686626866368664686656866668667686686866968670686716867268673686746867568676686776867868679686806868168682686836868468685686866868768688686896869068691686926869368694686956869668697686986869968700687016870268703687046870568706687076870868709687106871168712687136871468715687166871768718687196872068721687226872368724687256872668727687286872968730687316873268733687346873568736687376873868739687406874168742687436874468745687466874768748687496875068751687526875368754687556875668757687586875968760687616876268763687646876568766687676876868769687706877168772687736877468775687766877768778687796878068781687826878368784687856878668787687886878968790687916879268793687946879568796687976879868799688006880168802688036880468805688066880768808688096881068811688126881368814688156881668817688186881968820688216882268823688246882568826688276882868829688306883168832688336883468835688366883768838688396884068841688426884368844688456884668847688486884968850688516885268853688546885568856688576885868859688606886168862688636886468865688666886768868688696887068871688726887368874688756887668877688786887968880688816888268883688846888568886688876888868889688906889168892688936889468895688966889768898688996890068901689026890368904689056890668907689086890968910689116891268913689146891568916689176891868919689206892168922689236892468925689266892768928689296893068931689326893368934689356893668937689386893968940689416894268943689446894568946689476894868949689506895168952689536895468955689566895768958689596896068961689626896368964689656896668967689686896968970689716897268973689746897568976689776897868979689806898168982689836898468985689866898768988689896899068991689926899368994689956899668997689986899969000690016900269003690046900569006690076900869009690106901169012690136901469015690166901769018690196902069021690226902369024690256902669027690286902969030690316903269033690346903569036690376903869039690406904169042690436904469045690466904769048690496905069051690526905369054690556905669057690586905969060690616906269063690646906569066690676906869069690706907169072690736907469075690766907769078690796908069081690826908369084690856908669087690886908969090690916909269093690946909569096690976909869099691006910169102691036910469105691066910769108691096911069111691126911369114691156911669117691186911969120691216912269123691246912569126691276912869129691306913169132691336913469135691366913769138691396914069141691426914369144691456914669147691486914969150691516915269153691546915569156691576915869159691606916169162691636916469165691666916769168691696917069171691726917369174691756917669177691786917969180691816918269183691846918569186691876918869189691906919169192691936919469195691966919769198691996920069201692026920369204692056920669207692086920969210692116921269213692146921569216692176921869219692206922169222692236922469225692266922769228692296923069231692326923369234692356923669237692386923969240692416924269243692446924569246692476924869249692506925169252692536925469255692566925769258692596926069261692626926369264692656926669267692686926969270692716927269273692746927569276692776927869279692806928169282692836928469285692866928769288692896929069291692926929369294692956929669297692986929969300693016930269303693046930569306693076930869309693106931169312693136931469315693166931769318693196932069321693226932369324693256932669327693286932969330693316933269333693346933569336693376933869339693406934169342693436934469345693466934769348693496935069351693526935369354693556935669357693586935969360693616936269363693646936569366693676936869369693706937169372693736937469375693766937769378693796938069381693826938369384693856938669387693886938969390693916939269393693946939569396693976939869399694006940169402694036940469405694066940769408694096941069411694126941369414694156941669417694186941969420694216942269423694246942569426694276942869429694306943169432694336943469435694366943769438694396944069441694426944369444694456944669447694486944969450694516945269453694546945569456694576945869459694606946169462694636946469465694666946769468694696947069471694726947369474694756947669477694786947969480694816948269483694846948569486694876948869489694906949169492694936949469495694966949769498694996950069501695026950369504695056950669507695086950969510695116951269513695146951569516695176951869519695206952169522695236952469525695266952769528695296953069531695326953369534695356953669537695386953969540695416954269543695446954569546695476954869549695506955169552695536955469555695566955769558695596956069561695626956369564695656956669567695686956969570695716957269573695746957569576695776957869579695806958169582695836958469585695866958769588695896959069591695926959369594695956959669597695986959969600696016960269603696046960569606696076960869609696106961169612696136961469615696166961769618696196962069621696226962369624696256962669627696286962969630696316963269633696346963569636696376963869639696406964169642696436964469645696466964769648696496965069651696526965369654696556965669657696586965969660696616966269663696646966569666696676966869669696706967169672696736967469675696766967769678696796968069681696826968369684696856968669687696886968969690696916969269693696946969569696696976969869699697006970169702697036970469705697066970769708697096971069711697126971369714697156971669717697186971969720697216972269723697246972569726697276972869729697306973169732697336973469735697366973769738697396974069741697426974369744697456974669747697486974969750697516975269753697546975569756697576975869759697606976169762697636976469765697666976769768697696977069771697726977369774697756977669777697786977969780697816978269783697846978569786697876978869789697906979169792697936979469795697966979769798697996980069801698026980369804698056980669807698086980969810698116981269813698146981569816698176981869819698206982169822698236982469825698266982769828698296983069831698326983369834698356983669837698386983969840698416984269843698446984569846698476984869849698506985169852698536985469855698566985769858698596986069861698626986369864698656986669867698686986969870698716987269873698746987569876698776987869879698806988169882698836988469885698866988769888698896989069891698926989369894698956989669897698986989969900699016990269903699046990569906699076990869909699106991169912699136991469915699166991769918699196992069921699226992369924699256992669927699286992969930699316993269933699346993569936699376993869939699406994169942699436994469945699466994769948699496995069951699526995369954699556995669957699586995969960699616996269963699646996569966699676996869969699706997169972699736997469975699766997769978699796998069981699826998369984699856998669987699886998969990699916999269993699946999569996699976999869999700007000170002700037000470005700067000770008700097001070011700127001370014700157001670017700187001970020700217002270023700247002570026700277002870029700307003170032700337003470035700367003770038700397004070041700427004370044700457004670047700487004970050700517005270053700547005570056700577005870059700607006170062700637006470065700667006770068700697007070071700727007370074700757007670077700787007970080700817008270083700847008570086700877008870089700907009170092700937009470095700967009770098700997010070101701027010370104701057010670107701087010970110701117011270113701147011570116701177011870119701207012170122701237012470125701267012770128701297013070131701327013370134701357013670137701387013970140701417014270143701447014570146701477014870149701507015170152701537015470155701567015770158701597016070161701627016370164701657016670167701687016970170701717017270173701747017570176701777017870179701807018170182701837018470185701867018770188701897019070191701927019370194701957019670197701987019970200702017020270203702047020570206702077020870209702107021170212702137021470215702167021770218702197022070221702227022370224702257022670227702287022970230702317023270233702347023570236702377023870239702407024170242702437024470245702467024770248702497025070251702527025370254702557025670257702587025970260702617026270263702647026570266702677026870269702707027170272702737027470275702767027770278702797028070281702827028370284702857028670287702887028970290702917029270293702947029570296702977029870299703007030170302703037030470305703067030770308703097031070311703127031370314703157031670317703187031970320703217032270323703247032570326703277032870329703307033170332703337033470335703367033770338703397034070341703427034370344703457034670347703487034970350703517035270353703547035570356703577035870359703607036170362703637036470365703667036770368703697037070371703727037370374703757037670377703787037970380703817038270383703847038570386703877038870389703907039170392703937039470395703967039770398703997040070401704027040370404704057040670407704087040970410704117041270413704147041570416704177041870419704207042170422704237042470425704267042770428704297043070431704327043370434704357043670437704387043970440704417044270443704447044570446704477044870449704507045170452704537045470455704567045770458704597046070461704627046370464704657046670467704687046970470704717047270473704747047570476704777047870479704807048170482704837048470485704867048770488704897049070491704927049370494704957049670497704987049970500705017050270503705047050570506705077050870509705107051170512705137051470515705167051770518705197052070521705227052370524705257052670527705287052970530705317053270533705347053570536705377053870539705407054170542705437054470545705467054770548705497055070551705527055370554705557055670557705587055970560705617056270563705647056570566705677056870569705707057170572705737057470575705767057770578705797058070581705827058370584705857058670587705887058970590705917059270593705947059570596705977059870599706007060170602706037060470605706067060770608706097061070611706127061370614706157061670617706187061970620706217062270623706247062570626706277062870629706307063170632706337063470635706367063770638706397064070641706427064370644706457064670647706487064970650706517065270653706547065570656706577065870659706607066170662706637066470665706667066770668706697067070671706727067370674706757067670677706787067970680706817068270683706847068570686706877068870689706907069170692706937069470695706967069770698706997070070701707027070370704707057070670707707087070970710707117071270713707147071570716707177071870719707207072170722707237072470725707267072770728707297073070731707327073370734707357073670737707387073970740707417074270743707447074570746707477074870749707507075170752707537075470755707567075770758707597076070761707627076370764707657076670767707687076970770707717077270773707747077570776707777077870779707807078170782707837078470785707867078770788707897079070791707927079370794707957079670797707987079970800708017080270803708047080570806708077080870809708107081170812708137081470815708167081770818708197082070821708227082370824708257082670827708287082970830708317083270833708347083570836708377083870839708407084170842708437084470845708467084770848708497085070851708527085370854708557085670857708587085970860708617086270863708647086570866708677086870869708707087170872708737087470875708767087770878708797088070881708827088370884708857088670887708887088970890708917089270893708947089570896708977089870899709007090170902709037090470905709067090770908709097091070911709127091370914709157091670917709187091970920709217092270923709247092570926709277092870929709307093170932709337093470935709367093770938709397094070941709427094370944709457094670947709487094970950709517095270953709547095570956709577095870959709607096170962709637096470965709667096770968709697097070971709727097370974709757097670977709787097970980709817098270983709847098570986709877098870989709907099170992709937099470995709967099770998709997100071001710027100371004710057100671007710087100971010710117101271013710147101571016710177101871019710207102171022710237102471025710267102771028710297103071031710327103371034710357103671037710387103971040710417104271043710447104571046710477104871049710507105171052710537105471055710567105771058710597106071061710627106371064710657106671067710687106971070710717107271073710747107571076710777107871079710807108171082710837108471085710867108771088710897109071091710927109371094710957109671097710987109971100711017110271103711047110571106711077110871109711107111171112711137111471115711167111771118711197112071121711227112371124711257112671127711287112971130711317113271133711347113571136711377113871139711407114171142711437114471145711467114771148711497115071151711527115371154711557115671157711587115971160711617116271163711647116571166711677116871169711707117171172711737117471175711767117771178711797118071181711827118371184711857118671187711887118971190711917119271193711947119571196711977119871199712007120171202712037120471205712067120771208712097121071211712127121371214712157121671217712187121971220712217122271223712247122571226712277122871229712307123171232712337123471235712367123771238712397124071241712427124371244712457124671247712487124971250712517125271253712547125571256712577125871259712607126171262712637126471265712667126771268712697127071271712727127371274712757127671277712787127971280712817128271283712847128571286712877128871289712907129171292712937129471295712967129771298712997130071301713027130371304713057130671307713087130971310713117131271313713147131571316713177131871319713207132171322713237132471325713267132771328713297133071331713327133371334713357133671337713387133971340713417134271343713447134571346713477134871349713507135171352713537135471355713567135771358713597136071361713627136371364713657136671367713687136971370713717137271373713747137571376713777137871379713807138171382713837138471385713867138771388713897139071391713927139371394713957139671397713987139971400714017140271403714047140571406714077140871409714107141171412714137141471415714167141771418714197142071421714227142371424714257142671427714287142971430714317143271433714347143571436714377143871439714407144171442714437144471445714467144771448714497145071451714527145371454714557145671457714587145971460714617146271463714647146571466714677146871469714707147171472714737147471475714767147771478714797148071481714827148371484714857148671487714887148971490714917149271493714947149571496714977149871499715007150171502715037150471505715067150771508715097151071511715127151371514715157151671517715187151971520715217152271523715247152571526715277152871529715307153171532715337153471535715367153771538715397154071541715427154371544715457154671547715487154971550715517155271553715547155571556715577155871559715607156171562715637156471565715667156771568715697157071571715727157371574715757157671577715787157971580715817158271583715847158571586715877158871589715907159171592715937159471595715967159771598715997160071601716027160371604716057160671607716087160971610716117161271613716147161571616716177161871619716207162171622716237162471625716267162771628716297163071631716327163371634716357163671637716387163971640716417164271643716447164571646716477164871649716507165171652716537165471655716567165771658716597166071661716627166371664716657166671667716687166971670716717167271673716747167571676716777167871679716807168171682716837168471685716867168771688716897169071691716927169371694716957169671697716987169971700717017170271703717047170571706717077170871709717107171171712717137171471715717167171771718717197172071721717227172371724717257172671727717287172971730717317173271733717347173571736717377173871739717407174171742717437174471745717467174771748717497175071751717527175371754717557175671757717587175971760717617176271763717647176571766717677176871769717707177171772717737177471775717767177771778717797178071781717827178371784717857178671787717887178971790717917179271793717947179571796717977179871799718007180171802718037180471805718067180771808718097181071811718127181371814718157181671817718187181971820718217182271823718247182571826718277182871829718307183171832718337183471835718367183771838718397184071841718427184371844718457184671847718487184971850718517185271853718547185571856718577185871859718607186171862718637186471865718667186771868718697187071871718727187371874718757187671877718787187971880718817188271883718847188571886718877188871889718907189171892718937189471895718967189771898718997190071901719027190371904719057190671907719087190971910719117191271913719147191571916719177191871919719207192171922719237192471925719267192771928719297193071931719327193371934719357193671937719387193971940719417194271943719447194571946719477194871949719507195171952719537195471955719567195771958719597196071961719627196371964719657196671967719687196971970719717197271973719747197571976719777197871979719807198171982719837198471985719867198771988719897199071991719927199371994719957199671997719987199972000720017200272003720047200572006720077200872009720107201172012720137201472015720167201772018720197202072021720227202372024720257202672027720287202972030720317203272033720347203572036720377203872039720407204172042720437204472045720467204772048720497205072051720527205372054720557205672057720587205972060720617206272063720647206572066720677206872069720707207172072720737207472075720767207772078720797208072081720827208372084720857208672087720887208972090720917209272093720947209572096720977209872099721007210172102721037210472105721067210772108721097211072111721127211372114721157211672117721187211972120721217212272123721247212572126721277212872129721307213172132721337213472135721367213772138721397214072141721427214372144721457214672147721487214972150721517215272153721547215572156721577215872159721607216172162721637216472165721667216772168721697217072171721727217372174721757217672177721787217972180721817218272183721847218572186721877218872189721907219172192721937219472195721967219772198721997220072201722027220372204722057220672207722087220972210722117221272213722147221572216722177221872219722207222172222722237222472225722267222772228722297223072231722327223372234722357223672237722387223972240722417224272243722447224572246722477224872249722507225172252722537225472255722567225772258722597226072261722627226372264722657226672267722687226972270722717227272273722747227572276722777227872279722807228172282722837228472285722867228772288722897229072291722927229372294722957229672297722987229972300723017230272303723047230572306723077230872309723107231172312723137231472315723167231772318723197232072321723227232372324723257232672327723287232972330723317233272333723347233572336723377233872339723407234172342723437234472345723467234772348723497235072351723527235372354723557235672357723587235972360723617236272363723647236572366723677236872369723707237172372723737237472375723767237772378723797238072381723827238372384723857238672387723887238972390723917239272393723947239572396723977239872399724007240172402724037240472405724067240772408724097241072411724127241372414724157241672417724187241972420724217242272423724247242572426724277242872429724307243172432724337243472435724367243772438724397244072441724427244372444724457244672447724487244972450724517245272453724547245572456724577245872459724607246172462724637246472465724667246772468724697247072471724727247372474724757247672477724787247972480724817248272483724847248572486724877248872489724907249172492724937249472495724967249772498724997250072501725027250372504725057250672507725087250972510725117251272513725147251572516725177251872519725207252172522725237252472525725267252772528725297253072531725327253372534725357253672537725387253972540725417254272543725447254572546725477254872549725507255172552725537255472555725567255772558725597256072561725627256372564725657256672567725687256972570725717257272573725747257572576725777257872579725807258172582725837258472585725867258772588725897259072591725927259372594725957259672597725987259972600726017260272603726047260572606726077260872609726107261172612726137261472615726167261772618726197262072621726227262372624726257262672627726287262972630726317263272633726347263572636726377263872639726407264172642726437264472645726467264772648726497265072651726527265372654726557265672657726587265972660726617266272663726647266572666726677266872669726707267172672726737267472675726767267772678726797268072681726827268372684726857268672687726887268972690726917269272693726947269572696726977269872699727007270172702727037270472705727067270772708727097271072711727127271372714727157271672717727187271972720727217272272723727247272572726727277272872729727307273172732727337273472735727367273772738727397274072741727427274372744727457274672747727487274972750727517275272753727547275572756727577275872759727607276172762727637276472765727667276772768727697277072771727727277372774727757277672777727787277972780727817278272783727847278572786727877278872789727907279172792727937279472795727967279772798727997280072801728027280372804728057280672807728087280972810728117281272813728147281572816728177281872819728207282172822728237282472825728267282772828728297283072831728327283372834728357283672837728387283972840728417284272843728447284572846728477284872849728507285172852728537285472855728567285772858728597286072861728627286372864728657286672867728687286972870728717287272873728747287572876728777287872879728807288172882728837288472885728867288772888728897289072891728927289372894728957289672897728987289972900729017290272903729047290572906729077290872909729107291172912729137291472915729167291772918729197292072921729227292372924729257292672927729287292972930729317293272933729347293572936729377293872939729407294172942729437294472945729467294772948729497295072951729527295372954729557295672957729587295972960729617296272963729647296572966729677296872969729707297172972729737297472975729767297772978729797298072981729827298372984729857298672987729887298972990729917299272993729947299572996729977299872999730007300173002730037300473005730067300773008730097301073011730127301373014730157301673017730187301973020730217302273023730247302573026730277302873029730307303173032730337303473035730367303773038730397304073041730427304373044730457304673047730487304973050730517305273053730547305573056730577305873059730607306173062730637306473065730667306773068730697307073071730727307373074730757307673077730787307973080730817308273083730847308573086730877308873089730907309173092730937309473095730967309773098730997310073101731027310373104731057310673107731087310973110731117311273113731147311573116731177311873119731207312173122731237312473125731267312773128731297313073131731327313373134731357313673137731387313973140731417314273143731447314573146731477314873149731507315173152731537315473155731567315773158731597316073161731627316373164731657316673167731687316973170731717317273173731747317573176731777317873179731807318173182731837318473185731867318773188731897319073191731927319373194731957319673197731987319973200732017320273203732047320573206732077320873209732107321173212732137321473215732167321773218732197322073221732227322373224732257322673227732287322973230732317323273233732347323573236732377323873239732407324173242732437324473245732467324773248732497325073251732527325373254732557325673257732587325973260732617326273263732647326573266732677326873269732707327173272732737327473275732767327773278732797328073281732827328373284732857328673287732887328973290732917329273293732947329573296732977329873299733007330173302733037330473305733067330773308733097331073311733127331373314733157331673317733187331973320733217332273323733247332573326733277332873329733307333173332733337333473335733367333773338733397334073341733427334373344733457334673347733487334973350733517335273353733547335573356733577335873359733607336173362733637336473365733667336773368733697337073371733727337373374733757337673377733787337973380733817338273383733847338573386733877338873389733907339173392733937339473395733967339773398733997340073401734027340373404734057340673407734087340973410734117341273413734147341573416734177341873419734207342173422734237342473425734267342773428734297343073431734327343373434734357343673437734387343973440734417344273443734447344573446734477344873449734507345173452734537345473455734567345773458734597346073461734627346373464734657346673467734687346973470734717347273473734747347573476734777347873479734807348173482734837348473485734867348773488734897349073491734927349373494734957349673497734987349973500735017350273503735047350573506735077350873509735107351173512735137351473515735167351773518735197352073521735227352373524735257352673527735287352973530735317353273533735347353573536735377353873539735407354173542735437354473545735467354773548735497355073551735527355373554735557355673557735587355973560735617356273563735647356573566735677356873569735707357173572735737357473575735767357773578735797358073581735827358373584735857358673587735887358973590735917359273593735947359573596735977359873599736007360173602736037360473605736067360773608736097361073611736127361373614736157361673617736187361973620736217362273623736247362573626736277362873629736307363173632736337363473635736367363773638736397364073641736427364373644736457364673647736487364973650736517365273653736547365573656736577365873659736607366173662736637366473665736667366773668736697367073671736727367373674736757367673677736787367973680736817368273683736847368573686736877368873689736907369173692736937369473695736967369773698736997370073701737027370373704737057370673707737087370973710737117371273713737147371573716737177371873719737207372173722737237372473725737267372773728737297373073731737327373373734737357373673737737387373973740737417374273743737447374573746737477374873749737507375173752737537375473755737567375773758737597376073761737627376373764737657376673767737687376973770737717377273773737747377573776737777377873779737807378173782737837378473785737867378773788737897379073791737927379373794737957379673797737987379973800738017380273803738047380573806738077380873809738107381173812738137381473815738167381773818738197382073821738227382373824738257382673827738287382973830738317383273833738347383573836738377383873839738407384173842738437384473845738467384773848738497385073851738527385373854738557385673857738587385973860738617386273863738647386573866738677386873869738707387173872738737387473875738767387773878738797388073881738827388373884738857388673887738887388973890738917389273893738947389573896738977389873899739007390173902739037390473905739067390773908739097391073911739127391373914739157391673917739187391973920739217392273923739247392573926739277392873929739307393173932739337393473935739367393773938739397394073941739427394373944739457394673947739487394973950739517395273953739547395573956739577395873959739607396173962739637396473965739667396773968739697397073971739727397373974739757397673977739787397973980739817398273983739847398573986739877398873989739907399173992739937399473995739967399773998739997400074001740027400374004740057400674007740087400974010740117401274013740147401574016740177401874019740207402174022740237402474025740267402774028740297403074031740327403374034740357403674037740387403974040740417404274043740447404574046740477404874049740507405174052740537405474055740567405774058740597406074061740627406374064740657406674067740687406974070740717407274073740747407574076740777407874079740807408174082740837408474085740867408774088740897409074091740927409374094740957409674097740987409974100741017410274103741047410574106741077410874109741107411174112741137411474115741167411774118741197412074121741227412374124741257412674127741287412974130741317413274133741347413574136741377413874139741407414174142741437414474145741467414774148741497415074151741527415374154741557415674157741587415974160741617416274163741647416574166741677416874169741707417174172741737417474175741767417774178741797418074181741827418374184741857418674187741887418974190741917419274193741947419574196741977419874199742007420174202742037420474205742067420774208742097421074211742127421374214742157421674217742187421974220742217422274223742247422574226742277422874229742307423174232742337423474235742367423774238742397424074241742427424374244742457424674247742487424974250742517425274253742547425574256742577425874259742607426174262742637426474265742667426774268742697427074271742727427374274742757427674277742787427974280742817428274283742847428574286742877428874289742907429174292742937429474295742967429774298742997430074301743027430374304743057430674307743087430974310743117431274313743147431574316743177431874319743207432174322743237432474325743267432774328743297433074331743327433374334743357433674337743387433974340743417434274343743447434574346743477434874349743507435174352743537435474355743567435774358743597436074361743627436374364743657436674367743687436974370743717437274373743747437574376743777437874379743807438174382743837438474385743867438774388743897439074391743927439374394743957439674397743987439974400744017440274403744047440574406744077440874409744107441174412744137441474415744167441774418744197442074421744227442374424744257442674427744287442974430744317443274433744347443574436744377443874439744407444174442744437444474445744467444774448744497445074451744527445374454744557445674457744587445974460744617446274463744647446574466744677446874469744707447174472744737447474475744767447774478744797448074481744827448374484744857448674487744887448974490744917449274493744947449574496744977449874499745007450174502745037450474505745067450774508745097451074511745127451374514745157451674517745187451974520745217452274523745247452574526745277452874529745307453174532745337453474535745367453774538745397454074541745427454374544745457454674547745487454974550745517455274553745547455574556745577455874559745607456174562745637456474565745667456774568745697457074571745727457374574745757457674577745787457974580745817458274583745847458574586745877458874589745907459174592745937459474595745967459774598745997460074601746027460374604746057460674607746087460974610746117461274613746147461574616746177461874619746207462174622746237462474625746267462774628746297463074631746327463374634746357463674637746387463974640746417464274643746447464574646746477464874649746507465174652746537465474655746567465774658746597466074661746627466374664746657466674667746687466974670746717467274673746747467574676746777467874679746807468174682746837468474685746867468774688746897469074691746927469374694746957469674697746987469974700747017470274703747047470574706747077470874709747107471174712747137471474715747167471774718747197472074721747227472374724747257472674727747287472974730747317473274733747347473574736747377473874739747407474174742747437474474745747467474774748747497475074751747527475374754747557475674757747587475974760747617476274763747647476574766747677476874769747707477174772747737477474775747767477774778747797478074781747827478374784747857478674787747887478974790747917479274793747947479574796747977479874799748007480174802748037480474805748067480774808748097481074811748127481374814748157481674817748187481974820748217482274823748247482574826748277482874829748307483174832748337483474835748367483774838748397484074841748427484374844748457484674847748487484974850748517485274853748547485574856748577485874859748607486174862748637486474865748667486774868748697487074871748727487374874748757487674877748787487974880748817488274883748847488574886748877488874889748907489174892748937489474895748967489774898748997490074901749027490374904749057490674907749087490974910749117491274913749147491574916749177491874919749207492174922749237492474925749267492774928749297493074931749327493374934749357493674937749387493974940749417494274943749447494574946749477494874949749507495174952749537495474955749567495774958749597496074961749627496374964749657496674967749687496974970749717497274973749747497574976749777497874979749807498174982749837498474985749867498774988749897499074991749927499374994749957499674997749987499975000750017500275003750047500575006750077500875009750107501175012750137501475015750167501775018750197502075021750227502375024750257502675027750287502975030750317503275033750347503575036750377503875039750407504175042750437504475045750467504775048750497505075051750527505375054750557505675057750587505975060750617506275063750647506575066750677506875069750707507175072750737507475075750767507775078750797508075081750827508375084750857508675087750887508975090750917509275093750947509575096750977509875099751007510175102751037510475105751067510775108751097511075111751127511375114751157511675117751187511975120751217512275123751247512575126751277512875129751307513175132751337513475135751367513775138751397514075141751427514375144751457514675147751487514975150751517515275153751547515575156751577515875159751607516175162751637516475165751667516775168751697517075171751727517375174751757517675177751787517975180751817518275183751847518575186751877518875189751907519175192751937519475195751967519775198751997520075201752027520375204752057520675207752087520975210752117521275213752147521575216752177521875219752207522175222752237522475225752267522775228752297523075231752327523375234752357523675237752387523975240752417524275243752447524575246752477524875249752507525175252752537525475255752567525775258752597526075261752627526375264752657526675267752687526975270752717527275273752747527575276752777527875279752807528175282752837528475285752867528775288752897529075291752927529375294752957529675297752987529975300753017530275303753047530575306753077530875309753107531175312753137531475315753167531775318753197532075321753227532375324753257532675327753287532975330753317533275333753347533575336753377533875339753407534175342753437534475345753467534775348753497535075351753527535375354753557535675357753587535975360753617536275363753647536575366753677536875369753707537175372753737537475375753767537775378753797538075381753827538375384753857538675387753887538975390753917539275393753947539575396753977539875399754007540175402754037540475405754067540775408754097541075411754127541375414754157541675417754187541975420754217542275423754247542575426754277542875429754307543175432754337543475435754367543775438754397544075441754427544375444754457544675447754487544975450754517545275453754547545575456754577545875459754607546175462754637546475465754667546775468754697547075471754727547375474754757547675477754787547975480754817548275483754847548575486754877548875489754907549175492754937549475495754967549775498754997550075501755027550375504755057550675507755087550975510755117551275513755147551575516755177551875519755207552175522755237552475525755267552775528755297553075531755327553375534755357553675537755387553975540755417554275543755447554575546755477554875549755507555175552755537555475555755567555775558755597556075561755627556375564755657556675567755687556975570755717557275573755747557575576755777557875579755807558175582755837558475585755867558775588755897559075591755927559375594755957559675597755987559975600756017560275603756047560575606756077560875609756107561175612756137561475615756167561775618756197562075621756227562375624756257562675627756287562975630756317563275633756347563575636756377563875639756407564175642756437564475645756467564775648756497565075651756527565375654756557565675657756587565975660756617566275663756647566575666756677566875669756707567175672756737567475675756767567775678756797568075681756827568375684756857568675687756887568975690756917569275693756947569575696756977569875699757007570175702757037570475705757067570775708757097571075711757127571375714757157571675717757187571975720757217572275723757247572575726757277572875729757307573175732757337573475735757367573775738757397574075741757427574375744757457574675747757487574975750757517575275753757547575575756757577575875759757607576175762757637576475765757667576775768757697577075771757727577375774757757577675777757787577975780757817578275783757847578575786757877578875789757907579175792757937579475795757967579775798757997580075801758027580375804758057580675807758087580975810758117581275813758147581575816758177581875819758207582175822758237582475825758267582775828758297583075831758327583375834758357583675837758387583975840758417584275843758447584575846758477584875849758507585175852758537585475855758567585775858758597586075861758627586375864758657586675867758687586975870758717587275873758747587575876758777587875879758807588175882758837588475885758867588775888758897589075891758927589375894758957589675897758987589975900759017590275903759047590575906759077590875909759107591175912759137591475915759167591775918759197592075921759227592375924759257592675927759287592975930759317593275933759347593575936759377593875939759407594175942759437594475945759467594775948759497595075951759527595375954759557595675957759587595975960759617596275963759647596575966759677596875969759707597175972759737597475975759767597775978759797598075981759827598375984759857598675987759887598975990759917599275993759947599575996759977599875999760007600176002760037600476005760067600776008760097601076011760127601376014760157601676017760187601976020760217602276023760247602576026760277602876029760307603176032760337603476035760367603776038760397604076041760427604376044760457604676047760487604976050760517605276053760547605576056760577605876059760607606176062760637606476065760667606776068760697607076071760727607376074760757607676077760787607976080760817608276083760847608576086760877608876089760907609176092760937609476095760967609776098760997610076101761027610376104761057610676107761087610976110761117611276113761147611576116761177611876119761207612176122761237612476125761267612776128761297613076131761327613376134761357613676137761387613976140761417614276143761447614576146761477614876149761507615176152761537615476155761567615776158761597616076161761627616376164761657616676167761687616976170761717617276173761747617576176761777617876179761807618176182761837618476185761867618776188761897619076191761927619376194761957619676197761987619976200762017620276203762047620576206762077620876209762107621176212762137621476215762167621776218762197622076221762227622376224762257622676227762287622976230762317623276233762347623576236762377623876239762407624176242762437624476245762467624776248762497625076251762527625376254762557625676257762587625976260762617626276263762647626576266762677626876269762707627176272762737627476275762767627776278762797628076281762827628376284762857628676287762887628976290762917629276293762947629576296762977629876299763007630176302763037630476305763067630776308763097631076311763127631376314763157631676317763187631976320763217632276323763247632576326763277632876329763307633176332763337633476335763367633776338763397634076341763427634376344763457634676347763487634976350763517635276353763547635576356763577635876359763607636176362763637636476365763667636776368763697637076371763727637376374763757637676377763787637976380763817638276383763847638576386763877638876389763907639176392763937639476395763967639776398763997640076401764027640376404764057640676407764087640976410764117641276413764147641576416764177641876419764207642176422764237642476425764267642776428764297643076431764327643376434764357643676437764387643976440764417644276443764447644576446764477644876449764507645176452764537645476455764567645776458764597646076461764627646376464764657646676467764687646976470764717647276473764747647576476764777647876479764807648176482764837648476485764867648776488764897649076491764927649376494764957649676497764987649976500765017650276503765047650576506765077650876509765107651176512765137651476515765167651776518765197652076521765227652376524765257652676527765287652976530765317653276533765347653576536765377653876539765407654176542765437654476545765467654776548765497655076551765527655376554765557655676557765587655976560765617656276563765647656576566765677656876569765707657176572765737657476575765767657776578765797658076581765827658376584765857658676587765887658976590765917659276593765947659576596765977659876599766007660176602766037660476605766067660776608766097661076611766127661376614766157661676617766187661976620766217662276623766247662576626766277662876629766307663176632766337663476635766367663776638766397664076641766427664376644766457664676647766487664976650766517665276653766547665576656766577665876659766607666176662766637666476665766667666776668766697667076671766727667376674766757667676677766787667976680766817668276683766847668576686766877668876689766907669176692766937669476695766967669776698766997670076701767027670376704767057670676707767087670976710767117671276713767147671576716767177671876719767207672176722767237672476725767267672776728767297673076731767327673376734767357673676737767387673976740767417674276743767447674576746767477674876749767507675176752767537675476755767567675776758767597676076761767627676376764767657676676767767687676976770767717677276773767747677576776767777677876779767807678176782767837678476785767867678776788767897679076791767927679376794767957679676797767987679976800768017680276803768047680576806768077680876809768107681176812768137681476815768167681776818768197682076821768227682376824768257682676827768287682976830768317683276833768347683576836768377683876839768407684176842768437684476845768467684776848768497685076851768527685376854768557685676857768587685976860768617686276863768647686576866768677686876869768707687176872768737687476875768767687776878768797688076881768827688376884768857688676887768887688976890768917689276893768947689576896768977689876899769007690176902769037690476905769067690776908769097691076911769127691376914769157691676917769187691976920769217692276923769247692576926769277692876929769307693176932769337693476935769367693776938769397694076941769427694376944769457694676947769487694976950769517695276953769547695576956769577695876959769607696176962769637696476965769667696776968769697697076971769727697376974769757697676977769787697976980769817698276983769847698576986769877698876989769907699176992769937699476995769967699776998769997700077001770027700377004770057700677007770087700977010770117701277013770147701577016770177701877019770207702177022770237702477025770267702777028770297703077031770327703377034770357703677037770387703977040770417704277043770447704577046770477704877049770507705177052770537705477055770567705777058770597706077061770627706377064770657706677067770687706977070770717707277073770747707577076770777707877079770807708177082770837708477085770867708777088770897709077091770927709377094770957709677097770987709977100771017710277103771047710577106771077710877109771107711177112771137711477115771167711777118771197712077121771227712377124771257712677127771287712977130771317713277133771347713577136771377713877139771407714177142771437714477145771467714777148771497715077151771527715377154771557715677157771587715977160771617716277163771647716577166771677716877169771707717177172771737717477175771767717777178771797718077181771827718377184771857718677187771887718977190771917719277193771947719577196771977719877199772007720177202772037720477205772067720777208772097721077211772127721377214772157721677217772187721977220772217722277223772247722577226772277722877229772307723177232772337723477235772367723777238772397724077241772427724377244772457724677247772487724977250772517725277253772547725577256772577725877259772607726177262772637726477265772667726777268772697727077271772727727377274772757727677277772787727977280772817728277283772847728577286772877728877289772907729177292772937729477295772967729777298772997730077301773027730377304773057730677307773087730977310773117731277313773147731577316773177731877319773207732177322773237732477325773267732777328773297733077331773327733377334773357733677337773387733977340773417734277343773447734577346773477734877349773507735177352773537735477355773567735777358773597736077361773627736377364773657736677367773687736977370773717737277373773747737577376773777737877379773807738177382773837738477385773867738777388773897739077391773927739377394773957739677397773987739977400774017740277403774047740577406774077740877409774107741177412774137741477415774167741777418774197742077421774227742377424774257742677427774287742977430774317743277433774347743577436774377743877439774407744177442774437744477445774467744777448774497745077451774527745377454774557745677457774587745977460774617746277463774647746577466774677746877469774707747177472774737747477475774767747777478774797748077481774827748377484774857748677487774887748977490774917749277493774947749577496774977749877499775007750177502775037750477505775067750777508775097751077511775127751377514775157751677517775187751977520775217752277523775247752577526775277752877529775307753177532775337753477535775367753777538775397754077541775427754377544775457754677547775487754977550775517755277553775547755577556775577755877559775607756177562775637756477565775667756777568775697757077571775727757377574775757757677577775787757977580775817758277583775847758577586775877758877589775907759177592775937759477595775967759777598775997760077601776027760377604776057760677607776087760977610776117761277613776147761577616776177761877619776207762177622776237762477625776267762777628776297763077631776327763377634776357763677637776387763977640776417764277643776447764577646776477764877649776507765177652776537765477655776567765777658776597766077661776627766377664776657766677667776687766977670776717767277673776747767577676776777767877679776807768177682776837768477685776867768777688776897769077691776927769377694776957769677697776987769977700777017770277703777047770577706777077770877709777107771177712777137771477715777167771777718777197772077721777227772377724777257772677727777287772977730777317773277733777347773577736777377773877739777407774177742777437774477745777467774777748777497775077751777527775377754777557775677757777587775977760777617776277763777647776577766777677776877769777707777177772777737777477775777767777777778777797778077781777827778377784777857778677787777887778977790777917779277793777947779577796777977779877799778007780177802778037780477805778067780777808778097781077811778127781377814778157781677817778187781977820778217782277823778247782577826778277782877829778307783177832778337783477835778367783777838778397784077841778427784377844778457784677847778487784977850778517785277853778547785577856778577785877859778607786177862778637786477865778667786777868778697787077871778727787377874778757787677877778787787977880778817788277883778847788577886778877788877889778907789177892778937789477895778967789777898778997790077901779027790377904779057790677907779087790977910779117791277913779147791577916779177791877919779207792177922779237792477925779267792777928779297793077931779327793377934779357793677937779387793977940779417794277943779447794577946779477794877949779507795177952779537795477955779567795777958779597796077961779627796377964779657796677967779687796977970779717797277973779747797577976779777797877979779807798177982779837798477985779867798777988779897799077991779927799377994779957799677997779987799978000780017800278003780047800578006780077800878009780107801178012780137801478015780167801778018780197802078021780227802378024780257802678027780287802978030780317803278033780347803578036780377803878039780407804178042780437804478045780467804778048780497805078051780527805378054780557805678057780587805978060780617806278063780647806578066780677806878069780707807178072780737807478075780767807778078780797808078081780827808378084780857808678087780887808978090780917809278093780947809578096780977809878099781007810178102781037810478105781067810778108781097811078111781127811378114781157811678117781187811978120781217812278123781247812578126781277812878129781307813178132781337813478135781367813778138781397814078141781427814378144781457814678147781487814978150781517815278153781547815578156781577815878159781607816178162781637816478165781667816778168781697817078171781727817378174781757817678177781787817978180781817818278183781847818578186781877818878189781907819178192781937819478195781967819778198781997820078201782027820378204782057820678207782087820978210782117821278213782147821578216782177821878219782207822178222782237822478225782267822778228782297823078231782327823378234782357823678237782387823978240782417824278243782447824578246782477824878249782507825178252782537825478255782567825778258782597826078261782627826378264782657826678267782687826978270782717827278273782747827578276782777827878279782807828178282782837828478285782867828778288782897829078291782927829378294782957829678297782987829978300783017830278303783047830578306783077830878309783107831178312783137831478315783167831778318783197832078321783227832378324783257832678327783287832978330783317833278333783347833578336783377833878339783407834178342783437834478345783467834778348783497835078351783527835378354783557835678357783587835978360783617836278363783647836578366783677836878369783707837178372783737837478375783767837778378783797838078381783827838378384783857838678387783887838978390783917839278393783947839578396783977839878399784007840178402784037840478405784067840778408784097841078411784127841378414784157841678417784187841978420784217842278423784247842578426784277842878429784307843178432784337843478435784367843778438784397844078441784427844378444784457844678447784487844978450784517845278453784547845578456784577845878459784607846178462784637846478465784667846778468784697847078471784727847378474784757847678477784787847978480784817848278483784847848578486784877848878489784907849178492784937849478495784967849778498784997850078501785027850378504785057850678507785087850978510785117851278513785147851578516785177851878519785207852178522785237852478525785267852778528785297853078531785327853378534785357853678537785387853978540785417854278543785447854578546785477854878549785507855178552785537855478555785567855778558785597856078561785627856378564785657856678567785687856978570785717857278573785747857578576785777857878579785807858178582785837858478585785867858778588785897859078591785927859378594785957859678597785987859978600786017860278603786047860578606786077860878609786107861178612786137861478615786167861778618786197862078621786227862378624786257862678627786287862978630786317863278633786347863578636786377863878639786407864178642786437864478645786467864778648786497865078651786527865378654786557865678657786587865978660786617866278663786647866578666786677866878669786707867178672786737867478675786767867778678786797868078681786827868378684786857868678687786887868978690786917869278693786947869578696786977869878699787007870178702787037870478705787067870778708787097871078711787127871378714787157871678717787187871978720787217872278723787247872578726787277872878729787307873178732787337873478735787367873778738787397874078741787427874378744787457874678747787487874978750787517875278753787547875578756787577875878759787607876178762787637876478765787667876778768787697877078771787727877378774787757877678777787787877978780787817878278783787847878578786787877878878789787907879178792787937879478795787967879778798787997880078801788027880378804788057880678807788087880978810788117881278813788147881578816788177881878819788207882178822788237882478825788267882778828788297883078831788327883378834788357883678837788387883978840788417884278843788447884578846788477884878849788507885178852788537885478855788567885778858788597886078861788627886378864788657886678867788687886978870788717887278873788747887578876788777887878879788807888178882788837888478885788867888778888788897889078891788927889378894788957889678897788987889978900789017890278903789047890578906789077890878909789107891178912789137891478915789167891778918789197892078921789227892378924789257892678927789287892978930789317893278933789347893578936789377893878939789407894178942789437894478945789467894778948789497895078951789527895378954789557895678957789587895978960789617896278963789647896578966789677896878969789707897178972789737897478975789767897778978789797898078981789827898378984789857898678987789887898978990789917899278993789947899578996789977899878999790007900179002790037900479005790067900779008790097901079011790127901379014790157901679017790187901979020790217902279023790247902579026790277902879029790307903179032790337903479035790367903779038790397904079041790427904379044790457904679047790487904979050790517905279053790547905579056790577905879059790607906179062790637906479065790667906779068790697907079071790727907379074790757907679077790787907979080790817908279083790847908579086790877908879089790907909179092790937909479095790967909779098790997910079101791027910379104791057910679107791087910979110791117911279113791147911579116791177911879119791207912179122791237912479125791267912779128791297913079131791327913379134791357913679137791387913979140791417914279143791447914579146791477914879149791507915179152791537915479155791567915779158791597916079161791627916379164791657916679167791687916979170791717917279173791747917579176791777917879179791807918179182791837918479185791867918779188791897919079191791927919379194791957919679197791987919979200792017920279203792047920579206792077920879209792107921179212792137921479215792167921779218792197922079221792227922379224792257922679227792287922979230792317923279233792347923579236792377923879239792407924179242792437924479245792467924779248792497925079251792527925379254792557925679257792587925979260792617926279263792647926579266792677926879269792707927179272792737927479275792767927779278792797928079281792827928379284792857928679287792887928979290792917929279293792947929579296792977929879299793007930179302793037930479305793067930779308793097931079311793127931379314793157931679317793187931979320793217932279323793247932579326793277932879329793307933179332793337933479335793367933779338793397934079341793427934379344793457934679347793487934979350793517935279353793547935579356793577935879359793607936179362793637936479365793667936779368793697937079371793727937379374793757937679377793787937979380793817938279383793847938579386793877938879389793907939179392793937939479395793967939779398793997940079401794027940379404794057940679407794087940979410794117941279413794147941579416794177941879419794207942179422794237942479425794267942779428794297943079431794327943379434794357943679437794387943979440794417944279443794447944579446794477944879449794507945179452794537945479455794567945779458794597946079461794627946379464794657946679467794687946979470794717947279473794747947579476794777947879479794807948179482794837948479485794867948779488794897949079491794927949379494794957949679497794987949979500795017950279503795047950579506795077950879509795107951179512795137951479515795167951779518795197952079521795227952379524795257952679527795287952979530795317953279533795347953579536795377953879539795407954179542795437954479545795467954779548795497955079551795527955379554795557955679557795587955979560795617956279563795647956579566795677956879569795707957179572795737957479575795767957779578795797958079581795827958379584795857958679587795887958979590795917959279593795947959579596795977959879599796007960179602796037960479605796067960779608796097961079611796127961379614796157961679617796187961979620796217962279623796247962579626796277962879629796307963179632796337963479635796367963779638796397964079641796427964379644796457964679647796487964979650796517965279653796547965579656796577965879659796607966179662796637966479665796667966779668796697967079671796727967379674796757967679677796787967979680796817968279683796847968579686796877968879689796907969179692796937969479695796967969779698796997970079701797027970379704797057970679707797087970979710797117971279713797147971579716797177971879719797207972179722797237972479725797267972779728797297973079731797327973379734797357973679737797387973979740797417974279743797447974579746797477974879749797507975179752797537975479755797567975779758797597976079761797627976379764797657976679767797687976979770797717977279773797747977579776797777977879779797807978179782797837978479785797867978779788797897979079791797927979379794797957979679797797987979979800798017980279803798047980579806798077980879809798107981179812798137981479815798167981779818798197982079821798227982379824798257982679827798287982979830798317983279833798347983579836798377983879839798407984179842798437984479845798467984779848798497985079851798527985379854798557985679857798587985979860798617986279863798647986579866798677986879869798707987179872798737987479875798767987779878798797988079881798827988379884798857988679887798887988979890798917989279893798947989579896798977989879899799007990179902799037990479905799067990779908799097991079911799127991379914799157991679917799187991979920799217992279923799247992579926799277992879929799307993179932799337993479935799367993779938799397994079941799427994379944799457994679947799487994979950799517995279953799547995579956799577995879959799607996179962799637996479965799667996779968799697997079971799727997379974799757997679977799787997979980799817998279983799847998579986799877998879989799907999179992799937999479995799967999779998799998000080001800028000380004800058000680007800088000980010800118001280013800148001580016800178001880019800208002180022800238002480025800268002780028800298003080031800328003380034800358003680037800388003980040800418004280043800448004580046800478004880049800508005180052800538005480055800568005780058800598006080061800628006380064800658006680067800688006980070800718007280073800748007580076800778007880079800808008180082800838008480085800868008780088800898009080091800928009380094800958009680097800988009980100801018010280103801048010580106801078010880109801108011180112801138011480115801168011780118801198012080121801228012380124801258012680127801288012980130801318013280133801348013580136801378013880139801408014180142801438014480145801468014780148801498015080151801528015380154801558015680157801588015980160801618016280163801648016580166801678016880169801708017180172801738017480175801768017780178801798018080181801828018380184801858018680187801888018980190801918019280193801948019580196801978019880199802008020180202802038020480205802068020780208802098021080211802128021380214802158021680217802188021980220802218022280223802248022580226802278022880229802308023180232802338023480235802368023780238802398024080241802428024380244802458024680247802488024980250802518025280253802548025580256802578025880259802608026180262802638026480265802668026780268802698027080271802728027380274802758027680277802788027980280802818028280283802848028580286802878028880289802908029180292802938029480295802968029780298802998030080301803028030380304803058030680307803088030980310803118031280313803148031580316803178031880319803208032180322803238032480325803268032780328803298033080331803328033380334803358033680337803388033980340803418034280343803448034580346803478034880349803508035180352803538035480355803568035780358803598036080361803628036380364803658036680367803688036980370803718037280373803748037580376803778037880379803808038180382803838038480385803868038780388803898039080391803928039380394803958039680397803988039980400804018040280403804048040580406804078040880409804108041180412804138041480415804168041780418804198042080421804228042380424804258042680427804288042980430804318043280433804348043580436804378043880439804408044180442804438044480445804468044780448804498045080451804528045380454804558045680457804588045980460804618046280463804648046580466804678046880469804708047180472804738047480475804768047780478804798048080481804828048380484804858048680487804888048980490804918049280493804948049580496804978049880499805008050180502805038050480505805068050780508805098051080511805128051380514805158051680517805188051980520805218052280523805248052580526805278052880529805308053180532805338053480535805368053780538805398054080541805428054380544805458054680547805488054980550805518055280553805548055580556805578055880559805608056180562805638056480565805668056780568805698057080571805728057380574805758057680577805788057980580805818058280583805848058580586805878058880589805908059180592805938059480595805968059780598805998060080601806028060380604806058060680607806088060980610806118061280613806148061580616806178061880619806208062180622806238062480625806268062780628806298063080631806328063380634806358063680637806388063980640806418064280643806448064580646806478064880649806508065180652806538065480655806568065780658806598066080661806628066380664806658066680667806688066980670806718067280673806748067580676806778067880679806808068180682806838068480685806868068780688806898069080691806928069380694806958069680697806988069980700807018070280703807048070580706807078070880709807108071180712807138071480715807168071780718807198072080721807228072380724807258072680727807288072980730807318073280733807348073580736807378073880739807408074180742807438074480745807468074780748807498075080751807528075380754807558075680757807588075980760807618076280763807648076580766807678076880769807708077180772807738077480775807768077780778807798078080781807828078380784807858078680787807888078980790807918079280793807948079580796807978079880799808008080180802808038080480805808068080780808808098081080811808128081380814808158081680817808188081980820808218082280823808248082580826808278082880829808308083180832808338083480835808368083780838808398084080841808428084380844808458084680847808488084980850808518085280853808548085580856808578085880859808608086180862808638086480865808668086780868808698087080871808728087380874808758087680877808788087980880808818088280883808848088580886808878088880889808908089180892808938089480895808968089780898808998090080901809028090380904809058090680907809088090980910809118091280913809148091580916809178091880919809208092180922809238092480925809268092780928809298093080931809328093380934809358093680937809388093980940809418094280943809448094580946809478094880949809508095180952809538095480955809568095780958809598096080961809628096380964809658096680967809688096980970809718097280973809748097580976809778097880979809808098180982809838098480985809868098780988809898099080991809928099380994809958099680997809988099981000810018100281003810048100581006810078100881009810108101181012810138101481015810168101781018810198102081021810228102381024810258102681027810288102981030810318103281033810348103581036810378103881039810408104181042810438104481045810468104781048810498105081051810528105381054810558105681057810588105981060810618106281063810648106581066810678106881069810708107181072810738107481075810768107781078810798108081081810828108381084810858108681087810888108981090810918109281093810948109581096810978109881099811008110181102811038110481105811068110781108811098111081111811128111381114811158111681117811188111981120811218112281123811248112581126811278112881129811308113181132811338113481135811368113781138811398114081141811428114381144811458114681147811488114981150811518115281153811548115581156811578115881159811608116181162811638116481165811668116781168811698117081171811728117381174811758117681177811788117981180811818118281183811848118581186811878118881189811908119181192811938119481195811968119781198811998120081201812028120381204812058120681207812088120981210812118121281213812148121581216812178121881219812208122181222812238122481225812268122781228812298123081231812328123381234812358123681237812388123981240812418124281243812448124581246812478124881249812508125181252812538125481255812568125781258812598126081261812628126381264812658126681267812688126981270812718127281273812748127581276812778127881279812808128181282812838128481285812868128781288812898129081291812928129381294812958129681297812988129981300813018130281303813048130581306813078130881309813108131181312813138131481315813168131781318813198132081321813228132381324813258132681327813288132981330813318133281333813348133581336813378133881339813408134181342813438134481345813468134781348813498135081351813528135381354813558135681357813588135981360813618136281363813648136581366813678136881369813708137181372813738137481375813768137781378813798138081381813828138381384813858138681387813888138981390813918139281393813948139581396813978139881399814008140181402814038140481405814068140781408814098141081411814128141381414814158141681417814188141981420814218142281423814248142581426814278142881429814308143181432814338143481435814368143781438814398144081441814428144381444814458144681447814488144981450814518145281453814548145581456814578145881459814608146181462814638146481465814668146781468814698147081471814728147381474814758147681477814788147981480814818148281483814848148581486814878148881489814908149181492814938149481495814968149781498814998150081501815028150381504815058150681507815088150981510815118151281513815148151581516815178151881519815208152181522815238152481525815268152781528815298153081531815328153381534815358153681537815388153981540815418154281543815448154581546815478154881549815508155181552815538155481555815568155781558815598156081561815628156381564815658156681567815688156981570815718157281573815748157581576815778157881579815808158181582815838158481585815868158781588815898159081591815928159381594815958159681597815988159981600816018160281603816048160581606816078160881609816108161181612816138161481615816168161781618816198162081621816228162381624816258162681627816288162981630816318163281633816348163581636816378163881639816408164181642816438164481645816468164781648816498165081651816528165381654816558165681657816588165981660816618166281663816648166581666816678166881669816708167181672816738167481675816768167781678816798168081681816828168381684816858168681687816888168981690816918169281693816948169581696816978169881699817008170181702817038170481705817068170781708817098171081711817128171381714817158171681717817188171981720817218172281723817248172581726817278172881729817308173181732817338173481735817368173781738817398174081741817428174381744817458174681747817488174981750817518175281753817548175581756817578175881759817608176181762817638176481765817668176781768817698177081771817728177381774817758177681777817788177981780817818178281783817848178581786817878178881789817908179181792817938179481795817968179781798817998180081801818028180381804818058180681807818088180981810818118181281813818148181581816818178181881819818208182181822818238182481825818268182781828818298183081831818328183381834818358183681837818388183981840818418184281843818448184581846818478184881849818508185181852818538185481855818568185781858818598186081861818628186381864818658186681867818688186981870818718187281873818748187581876818778187881879818808188181882818838188481885818868188781888818898189081891818928189381894818958189681897818988189981900819018190281903819048190581906819078190881909819108191181912819138191481915819168191781918819198192081921819228192381924819258192681927819288192981930819318193281933819348193581936819378193881939819408194181942819438194481945819468194781948819498195081951819528195381954819558195681957819588195981960819618196281963819648196581966819678196881969819708197181972819738197481975819768197781978819798198081981819828198381984819858198681987819888198981990819918199281993819948199581996819978199881999820008200182002820038200482005820068200782008820098201082011820128201382014820158201682017820188201982020820218202282023820248202582026820278202882029820308203182032820338203482035820368203782038820398204082041820428204382044820458204682047820488204982050820518205282053820548205582056820578205882059820608206182062820638206482065820668206782068820698207082071820728207382074820758207682077820788207982080820818208282083820848208582086820878208882089820908209182092820938209482095820968209782098820998210082101821028210382104821058210682107821088210982110821118211282113821148211582116821178211882119821208212182122821238212482125821268212782128821298213082131821328213382134821358213682137821388213982140821418214282143821448214582146821478214882149821508215182152821538215482155821568215782158821598216082161821628216382164821658216682167821688216982170821718217282173821748217582176821778217882179821808218182182821838218482185821868218782188821898219082191821928219382194821958219682197821988219982200822018220282203822048220582206822078220882209822108221182212822138221482215822168221782218822198222082221822228222382224822258222682227822288222982230822318223282233822348223582236822378223882239822408224182242822438224482245822468224782248822498225082251822528225382254822558225682257822588225982260822618226282263822648226582266822678226882269822708227182272822738227482275822768227782278822798228082281822828228382284822858228682287822888228982290822918229282293822948229582296822978229882299823008230182302823038230482305823068230782308823098231082311823128231382314823158231682317823188231982320823218232282323823248232582326823278232882329823308233182332823338233482335823368233782338823398234082341823428234382344823458234682347823488234982350823518235282353823548235582356823578235882359823608236182362823638236482365823668236782368823698237082371823728237382374823758237682377823788237982380823818238282383823848238582386823878238882389823908239182392823938239482395823968239782398823998240082401824028240382404824058240682407824088240982410824118241282413824148241582416824178241882419824208242182422824238242482425824268242782428824298243082431824328243382434824358243682437824388243982440824418244282443824448244582446824478244882449824508245182452824538245482455824568245782458824598246082461824628246382464824658246682467824688246982470824718247282473824748247582476824778247882479824808248182482824838248482485824868248782488824898249082491824928249382494824958249682497824988249982500825018250282503825048250582506825078250882509825108251182512825138251482515825168251782518825198252082521825228252382524825258252682527825288252982530825318253282533825348253582536825378253882539825408254182542825438254482545825468254782548825498255082551825528255382554825558255682557825588255982560825618256282563825648256582566825678256882569825708257182572825738257482575825768257782578825798258082581825828258382584825858258682587825888258982590825918259282593825948259582596825978259882599826008260182602826038260482605826068260782608826098261082611826128261382614826158261682617826188261982620826218262282623826248262582626826278262882629826308263182632826338263482635826368263782638826398264082641826428264382644826458264682647826488264982650826518265282653826548265582656826578265882659826608266182662826638266482665826668266782668826698267082671826728267382674826758267682677826788267982680826818268282683826848268582686826878268882689826908269182692826938269482695826968269782698826998270082701827028270382704827058270682707827088270982710827118271282713827148271582716827178271882719827208272182722827238272482725827268272782728827298273082731827328273382734827358273682737827388273982740827418274282743827448274582746827478274882749827508275182752827538275482755827568275782758827598276082761827628276382764827658276682767827688276982770827718277282773827748277582776827778277882779827808278182782827838278482785827868278782788827898279082791827928279382794827958279682797827988279982800828018280282803828048280582806828078280882809828108281182812828138281482815828168281782818828198282082821828228282382824828258282682827828288282982830828318283282833828348283582836828378283882839828408284182842828438284482845828468284782848828498285082851828528285382854828558285682857828588285982860828618286282863828648286582866828678286882869828708287182872828738287482875828768287782878828798288082881828828288382884828858288682887828888288982890828918289282893828948289582896828978289882899829008290182902829038290482905829068290782908829098291082911829128291382914829158291682917829188291982920829218292282923829248292582926829278292882929829308293182932829338293482935829368293782938829398294082941829428294382944829458294682947829488294982950829518295282953829548295582956829578295882959829608296182962829638296482965829668296782968829698297082971829728297382974829758297682977829788297982980829818298282983829848298582986829878298882989829908299182992829938299482995829968299782998829998300083001830028300383004830058300683007830088300983010830118301283013830148301583016830178301883019830208302183022830238302483025830268302783028830298303083031830328303383034830358303683037830388303983040830418304283043830448304583046830478304883049830508305183052830538305483055830568305783058830598306083061830628306383064830658306683067830688306983070830718307283073830748307583076830778307883079830808308183082830838308483085830868308783088830898309083091830928309383094830958309683097830988309983100831018310283103831048310583106831078310883109831108311183112831138311483115831168311783118831198312083121831228312383124831258312683127831288312983130831318313283133831348313583136831378313883139831408314183142831438314483145831468314783148831498315083151831528315383154831558315683157831588315983160831618316283163831648316583166831678316883169831708317183172831738317483175831768317783178831798318083181831828318383184831858318683187831888318983190831918319283193831948319583196831978319883199832008320183202832038320483205832068320783208832098321083211832128321383214832158321683217832188321983220832218322283223832248322583226832278322883229832308323183232832338323483235832368323783238832398324083241832428324383244832458324683247832488324983250832518325283253832548325583256832578325883259832608326183262832638326483265832668326783268832698327083271832728327383274832758327683277832788327983280832818328283283832848328583286832878328883289832908329183292832938329483295832968329783298832998330083301833028330383304833058330683307833088330983310833118331283313833148331583316833178331883319833208332183322833238332483325833268332783328833298333083331833328333383334833358333683337833388333983340833418334283343833448334583346833478334883349833508335183352833538335483355833568335783358833598336083361833628336383364833658336683367833688336983370833718337283373833748337583376833778337883379833808338183382833838338483385833868338783388833898339083391833928339383394833958339683397833988339983400834018340283403834048340583406834078340883409834108341183412834138341483415834168341783418834198342083421834228342383424834258342683427834288342983430834318343283433834348343583436834378343883439834408344183442834438344483445834468344783448834498345083451834528345383454834558345683457834588345983460834618346283463834648346583466834678346883469834708347183472834738347483475834768347783478834798348083481834828348383484834858348683487834888348983490834918349283493834948349583496834978349883499835008350183502835038350483505835068350783508835098351083511835128351383514835158351683517835188351983520835218352283523835248352583526835278352883529835308353183532835338353483535835368353783538835398354083541835428354383544835458354683547835488354983550835518355283553835548355583556835578355883559835608356183562835638356483565835668356783568835698357083571835728357383574835758357683577835788357983580835818358283583835848358583586835878358883589835908359183592835938359483595835968359783598835998360083601836028360383604836058360683607836088360983610836118361283613836148361583616836178361883619836208362183622836238362483625836268362783628836298363083631836328363383634836358363683637836388363983640836418364283643836448364583646836478364883649836508365183652836538365483655836568365783658836598366083661836628366383664836658366683667836688366983670836718367283673836748367583676836778367883679836808368183682836838368483685836868368783688836898369083691836928369383694836958369683697836988369983700837018370283703837048370583706837078370883709837108371183712837138371483715837168371783718837198372083721837228372383724837258372683727837288372983730837318373283733837348373583736837378373883739837408374183742837438374483745837468374783748837498375083751837528375383754837558375683757837588375983760837618376283763837648376583766837678376883769837708377183772837738377483775837768377783778837798378083781837828378383784837858378683787837888378983790837918379283793837948379583796837978379883799838008380183802838038380483805838068380783808838098381083811838128381383814838158381683817838188381983820838218382283823838248382583826838278382883829838308383183832838338383483835838368383783838838398384083841838428384383844838458384683847838488384983850838518385283853838548385583856838578385883859838608386183862838638386483865838668386783868838698387083871838728387383874838758387683877838788387983880838818388283883838848388583886838878388883889838908389183892838938389483895838968389783898838998390083901839028390383904839058390683907839088390983910839118391283913839148391583916839178391883919839208392183922839238392483925839268392783928839298393083931839328393383934839358393683937839388393983940839418394283943839448394583946839478394883949839508395183952839538395483955839568395783958839598396083961839628396383964839658396683967839688396983970839718397283973839748397583976839778397883979839808398183982839838398483985839868398783988839898399083991839928399383994839958399683997839988399984000840018400284003840048400584006840078400884009840108401184012840138401484015840168401784018840198402084021840228402384024840258402684027840288402984030840318403284033840348403584036840378403884039840408404184042840438404484045840468404784048840498405084051840528405384054840558405684057840588405984060840618406284063840648406584066840678406884069840708407184072840738407484075840768407784078840798408084081840828408384084840858408684087840888408984090840918409284093840948409584096840978409884099841008410184102841038410484105841068410784108841098411084111841128411384114841158411684117841188411984120841218412284123841248412584126841278412884129841308413184132841338413484135841368413784138841398414084141841428414384144841458414684147841488414984150841518415284153841548415584156841578415884159841608416184162841638416484165841668416784168841698417084171841728417384174841758417684177841788417984180841818418284183841848418584186841878418884189841908419184192841938419484195841968419784198841998420084201842028420384204842058420684207842088420984210842118421284213842148421584216842178421884219842208422184222842238422484225842268422784228842298423084231842328423384234842358423684237842388423984240842418424284243842448424584246842478424884249842508425184252842538425484255842568425784258842598426084261842628426384264842658426684267842688426984270842718427284273842748427584276842778427884279842808428184282842838428484285842868428784288842898429084291842928429384294842958429684297842988429984300843018430284303843048430584306843078430884309843108431184312843138431484315843168431784318843198432084321843228432384324843258432684327843288432984330843318433284333843348433584336843378433884339843408434184342843438434484345843468434784348843498435084351843528435384354843558435684357843588435984360843618436284363843648436584366843678436884369843708437184372843738437484375843768437784378843798438084381843828438384384843858438684387843888438984390843918439284393843948439584396843978439884399844008440184402844038440484405844068440784408844098441084411844128441384414844158441684417844188441984420844218442284423844248442584426844278442884429844308443184432844338443484435844368443784438844398444084441844428444384444844458444684447844488444984450844518445284453844548445584456844578445884459844608446184462844638446484465844668446784468844698447084471844728447384474844758447684477844788447984480844818448284483844848448584486844878448884489844908449184492844938449484495844968449784498844998450084501845028450384504845058450684507845088450984510845118451284513845148451584516845178451884519845208452184522845238452484525845268452784528845298453084531845328453384534845358453684537845388453984540845418454284543845448454584546845478454884549845508455184552845538455484555845568455784558845598456084561845628456384564845658456684567845688456984570845718457284573845748457584576845778457884579845808458184582845838458484585845868458784588845898459084591845928459384594845958459684597845988459984600846018460284603846048460584606846078460884609846108461184612846138461484615846168461784618846198462084621846228462384624846258462684627846288462984630846318463284633846348463584636846378463884639846408464184642846438464484645846468464784648846498465084651846528465384654846558465684657846588465984660846618466284663846648466584666846678466884669846708467184672846738467484675846768467784678846798468084681846828468384684846858468684687846888468984690846918469284693846948469584696846978469884699847008470184702847038470484705847068470784708847098471084711847128471384714847158471684717847188471984720847218472284723847248472584726847278472884729847308473184732847338473484735847368473784738847398474084741847428474384744847458474684747847488474984750847518475284753847548475584756847578475884759847608476184762847638476484765847668476784768847698477084771847728477384774847758477684777847788477984780847818478284783847848478584786847878478884789847908479184792847938479484795847968479784798847998480084801848028480384804848058480684807848088480984810848118481284813848148481584816848178481884819848208482184822848238482484825848268482784828848298483084831848328483384834848358483684837848388483984840848418484284843848448484584846848478484884849848508485184852848538485484855848568485784858848598486084861848628486384864848658486684867848688486984870848718487284873848748487584876848778487884879848808488184882848838488484885848868488784888848898489084891848928489384894848958489684897848988489984900849018490284903849048490584906849078490884909849108491184912849138491484915849168491784918849198492084921849228492384924849258492684927849288492984930849318493284933849348493584936849378493884939849408494184942849438494484945849468494784948849498495084951849528495384954849558495684957849588495984960849618496284963849648496584966849678496884969849708497184972849738497484975849768497784978849798498084981849828498384984849858498684987849888498984990849918499284993849948499584996849978499884999850008500185002850038500485005850068500785008850098501085011850128501385014850158501685017850188501985020850218502285023850248502585026850278502885029850308503185032850338503485035850368503785038850398504085041850428504385044850458504685047850488504985050850518505285053850548505585056850578505885059850608506185062850638506485065850668506785068850698507085071850728507385074850758507685077850788507985080850818508285083850848508585086850878508885089850908509185092850938509485095850968509785098850998510085101851028510385104851058510685107851088510985110851118511285113851148511585116851178511885119851208512185122851238512485125851268512785128851298513085131851328513385134851358513685137851388513985140851418514285143851448514585146851478514885149851508515185152851538515485155851568515785158851598516085161851628516385164851658516685167851688516985170851718517285173851748517585176851778517885179851808518185182851838518485185851868518785188851898519085191851928519385194851958519685197851988519985200852018520285203852048520585206852078520885209852108521185212852138521485215852168521785218852198522085221852228522385224852258522685227852288522985230852318523285233852348523585236852378523885239852408524185242852438524485245852468524785248852498525085251852528525385254852558525685257852588525985260852618526285263852648526585266852678526885269852708527185272852738527485275852768527785278852798528085281852828528385284852858528685287852888528985290852918529285293852948529585296852978529885299853008530185302853038530485305853068530785308853098531085311853128531385314853158531685317853188531985320853218532285323853248532585326853278532885329853308533185332853338533485335853368533785338853398534085341853428534385344853458534685347853488534985350853518535285353853548535585356853578535885359853608536185362853638536485365853668536785368853698537085371853728537385374853758537685377853788537985380853818538285383853848538585386853878538885389853908539185392853938539485395853968539785398853998540085401854028540385404854058540685407854088540985410854118541285413854148541585416854178541885419854208542185422854238542485425854268542785428854298543085431854328543385434854358543685437854388543985440854418544285443854448544585446854478544885449854508545185452854538545485455854568545785458854598546085461854628546385464854658546685467854688546985470854718547285473854748547585476854778547885479854808548185482854838548485485854868548785488854898549085491854928549385494854958549685497854988549985500855018550285503855048550585506855078550885509855108551185512855138551485515855168551785518855198552085521855228552385524855258552685527855288552985530855318553285533855348553585536855378553885539855408554185542855438554485545855468554785548855498555085551855528555385554855558555685557855588555985560855618556285563855648556585566855678556885569855708557185572855738557485575855768557785578855798558085581855828558385584855858558685587855888558985590855918559285593855948559585596855978559885599856008560185602856038560485605856068560785608856098561085611856128561385614856158561685617856188561985620856218562285623856248562585626856278562885629856308563185632856338563485635856368563785638856398564085641856428564385644856458564685647856488564985650856518565285653856548565585656856578565885659856608566185662856638566485665856668566785668856698567085671856728567385674856758567685677856788567985680856818568285683856848568585686856878568885689856908569185692856938569485695856968569785698856998570085701857028570385704857058570685707857088570985710857118571285713857148571585716857178571885719857208572185722857238572485725857268572785728857298573085731857328573385734857358573685737857388573985740857418574285743857448574585746857478574885749857508575185752857538575485755857568575785758857598576085761857628576385764857658576685767857688576985770857718577285773857748577585776857778577885779857808578185782857838578485785857868578785788857898579085791857928579385794857958579685797857988579985800858018580285803858048580585806858078580885809858108581185812858138581485815858168581785818858198582085821858228582385824858258582685827858288582985830858318583285833858348583585836858378583885839858408584185842858438584485845858468584785848858498585085851858528585385854858558585685857858588585985860858618586285863858648586585866858678586885869858708587185872858738587485875858768587785878858798588085881858828588385884858858588685887858888588985890858918589285893858948589585896858978589885899859008590185902859038590485905859068590785908859098591085911859128591385914859158591685917859188591985920859218592285923859248592585926859278592885929859308593185932859338593485935859368593785938859398594085941859428594385944859458594685947859488594985950859518595285953859548595585956859578595885959859608596185962859638596485965859668596785968859698597085971859728597385974859758597685977859788597985980859818598285983859848598585986859878598885989859908599185992859938599485995859968599785998859998600086001860028600386004860058600686007860088600986010860118601286013860148601586016860178601886019860208602186022860238602486025860268602786028860298603086031860328603386034860358603686037860388603986040860418604286043860448604586046860478604886049860508605186052860538605486055860568605786058860598606086061860628606386064860658606686067860688606986070860718607286073860748607586076860778607886079860808608186082860838608486085860868608786088860898609086091860928609386094860958609686097860988609986100861018610286103861048610586106861078610886109861108611186112861138611486115861168611786118861198612086121861228612386124861258612686127861288612986130861318613286133861348613586136861378613886139861408614186142861438614486145861468614786148861498615086151861528615386154861558615686157861588615986160861618616286163861648616586166861678616886169861708617186172861738617486175861768617786178861798618086181861828618386184861858618686187861888618986190861918619286193861948619586196861978619886199862008620186202862038620486205862068620786208862098621086211862128621386214862158621686217862188621986220862218622286223862248622586226862278622886229862308623186232862338623486235862368623786238862398624086241862428624386244862458624686247862488624986250862518625286253862548625586256862578625886259862608626186262862638626486265862668626786268862698627086271862728627386274862758627686277862788627986280862818628286283862848628586286862878628886289862908629186292862938629486295862968629786298862998630086301863028630386304863058630686307863088630986310863118631286313863148631586316863178631886319863208632186322863238632486325863268632786328863298633086331863328633386334863358633686337863388633986340863418634286343863448634586346863478634886349863508635186352863538635486355863568635786358863598636086361863628636386364863658636686367863688636986370863718637286373863748637586376863778637886379863808638186382863838638486385863868638786388863898639086391863928639386394863958639686397863988639986400864018640286403864048640586406864078640886409864108641186412864138641486415864168641786418864198642086421864228642386424864258642686427864288642986430864318643286433864348643586436864378643886439864408644186442864438644486445864468644786448864498645086451864528645386454864558645686457864588645986460864618646286463864648646586466864678646886469864708647186472864738647486475864768647786478864798648086481864828648386484864858648686487864888648986490864918649286493864948649586496864978649886499865008650186502865038650486505865068650786508865098651086511865128651386514865158651686517865188651986520865218652286523865248652586526865278652886529865308653186532865338653486535865368653786538865398654086541865428654386544865458654686547865488654986550865518655286553865548655586556865578655886559865608656186562865638656486565865668656786568865698657086571865728657386574865758657686577865788657986580865818658286583865848658586586865878658886589865908659186592865938659486595865968659786598865998660086601866028660386604866058660686607866088660986610866118661286613866148661586616866178661886619866208662186622866238662486625866268662786628866298663086631866328663386634866358663686637866388663986640866418664286643866448664586646866478664886649866508665186652866538665486655866568665786658866598666086661866628666386664866658666686667866688666986670866718667286673866748667586676866778667886679866808668186682866838668486685866868668786688866898669086691866928669386694866958669686697866988669986700867018670286703867048670586706867078670886709867108671186712867138671486715867168671786718867198672086721867228672386724867258672686727867288672986730867318673286733867348673586736867378673886739867408674186742867438674486745867468674786748867498675086751867528675386754867558675686757867588675986760867618676286763867648676586766867678676886769867708677186772867738677486775867768677786778867798678086781867828678386784867858678686787867888678986790867918679286793867948679586796867978679886799868008680186802868038680486805868068680786808868098681086811868128681386814868158681686817868188681986820868218682286823868248682586826868278682886829868308683186832868338683486835868368683786838868398684086841868428684386844868458684686847868488684986850868518685286853868548685586856868578685886859868608686186862868638686486865868668686786868868698687086871868728687386874868758687686877868788687986880868818688286883868848688586886868878688886889868908689186892868938689486895868968689786898868998690086901869028690386904869058690686907869088690986910869118691286913869148691586916869178691886919869208692186922869238692486925869268692786928869298693086931869328693386934869358693686937869388693986940869418694286943869448694586946869478694886949869508695186952869538695486955869568695786958869598696086961869628696386964869658696686967869688696986970869718697286973869748697586976869778697886979869808698186982869838698486985869868698786988869898699086991869928699386994869958699686997869988699987000870018700287003870048700587006870078700887009870108701187012870138701487015870168701787018870198702087021870228702387024870258702687027870288702987030870318703287033870348703587036870378703887039870408704187042870438704487045870468704787048870498705087051870528705387054870558705687057870588705987060870618706287063870648706587066870678706887069870708707187072870738707487075870768707787078870798708087081870828708387084870858708687087870888708987090870918709287093870948709587096870978709887099871008710187102871038710487105871068710787108871098711087111871128711387114871158711687117871188711987120871218712287123871248712587126871278712887129871308713187132871338713487135871368713787138871398714087141871428714387144871458714687147871488714987150871518715287153871548715587156871578715887159871608716187162871638716487165871668716787168871698717087171871728717387174871758717687177871788717987180871818718287183871848718587186871878718887189871908719187192871938719487195871968719787198871998720087201872028720387204872058720687207872088720987210872118721287213872148721587216872178721887219872208722187222872238722487225872268722787228872298723087231872328723387234872358723687237872388723987240872418724287243872448724587246872478724887249872508725187252872538725487255872568725787258872598726087261872628726387264872658726687267872688726987270872718727287273872748727587276872778727887279872808728187282872838728487285872868728787288872898729087291872928729387294872958729687297872988729987300873018730287303873048730587306873078730887309873108731187312873138731487315873168731787318873198732087321873228732387324873258732687327873288732987330873318733287333873348733587336873378733887339873408734187342873438734487345873468734787348873498735087351873528735387354873558735687357873588735987360873618736287363873648736587366873678736887369873708737187372873738737487375873768737787378873798738087381873828738387384873858738687387873888738987390873918739287393873948739587396873978739887399874008740187402874038740487405874068740787408874098741087411874128741387414874158741687417874188741987420874218742287423874248742587426874278742887429874308743187432874338743487435874368743787438874398744087441874428744387444874458744687447874488744987450874518745287453874548745587456874578745887459874608746187462874638746487465874668746787468874698747087471874728747387474874758747687477874788747987480874818748287483874848748587486874878748887489874908749187492874938749487495874968749787498874998750087501875028750387504875058750687507875088750987510875118751287513875148751587516875178751887519875208752187522875238752487525875268752787528875298753087531875328753387534875358753687537875388753987540875418754287543875448754587546875478754887549875508755187552875538755487555875568755787558875598756087561875628756387564875658756687567875688756987570875718757287573875748757587576875778757887579875808758187582875838758487585875868758787588875898759087591875928759387594875958759687597875988759987600876018760287603876048760587606876078760887609876108761187612876138761487615876168761787618876198762087621876228762387624876258762687627876288762987630876318763287633876348763587636876378763887639876408764187642876438764487645876468764787648876498765087651876528765387654876558765687657876588765987660876618766287663876648766587666876678766887669876708767187672876738767487675876768767787678876798768087681876828768387684876858768687687876888768987690876918769287693876948769587696876978769887699877008770187702877038770487705877068770787708877098771087711877128771387714877158771687717877188771987720877218772287723877248772587726877278772887729877308773187732877338773487735877368773787738877398774087741877428774387744877458774687747877488774987750877518775287753877548775587756877578775887759877608776187762877638776487765877668776787768877698777087771877728777387774877758777687777877788777987780877818778287783877848778587786877878778887789877908779187792877938779487795877968779787798877998780087801878028780387804878058780687807878088780987810878118781287813878148781587816878178781887819878208782187822878238782487825878268782787828878298783087831878328783387834878358783687837878388783987840878418784287843878448784587846878478784887849878508785187852878538785487855878568785787858878598786087861878628786387864878658786687867878688786987870878718787287873878748787587876878778787887879878808788187882878838788487885878868788787888878898789087891878928789387894878958789687897878988789987900879018790287903879048790587906879078790887909879108791187912879138791487915879168791787918879198792087921879228792387924879258792687927879288792987930879318793287933879348793587936879378793887939879408794187942879438794487945879468794787948879498795087951879528795387954879558795687957879588795987960879618796287963879648796587966879678796887969879708797187972879738797487975879768797787978879798798087981879828798387984879858798687987879888798987990879918799287993879948799587996879978799887999880008800188002880038800488005880068800788008880098801088011880128801388014880158801688017880188801988020880218802288023880248802588026880278802888029880308803188032880338803488035880368803788038880398804088041880428804388044880458804688047880488804988050880518805288053880548805588056880578805888059880608806188062880638806488065880668806788068880698807088071880728807388074880758807688077880788807988080880818808288083880848808588086880878808888089880908809188092880938809488095880968809788098880998810088101881028810388104881058810688107881088810988110881118811288113881148811588116881178811888119881208812188122881238812488125881268812788128881298813088131881328813388134881358813688137881388813988140881418814288143881448814588146881478814888149881508815188152881538815488155881568815788158881598816088161881628816388164881658816688167881688816988170881718817288173881748817588176881778817888179881808818188182881838818488185881868818788188881898819088191881928819388194881958819688197881988819988200882018820288203882048820588206882078820888209882108821188212882138821488215882168821788218882198822088221882228822388224882258822688227882288822988230882318823288233882348823588236882378823888239882408824188242882438824488245882468824788248882498825088251882528825388254882558825688257882588825988260882618826288263882648826588266882678826888269882708827188272882738827488275882768827788278882798828088281882828828388284882858828688287882888828988290882918829288293882948829588296882978829888299883008830188302883038830488305883068830788308883098831088311883128831388314883158831688317883188831988320883218832288323883248832588326883278832888329883308833188332883338833488335883368833788338883398834088341883428834388344883458834688347883488834988350883518835288353883548835588356883578835888359883608836188362883638836488365883668836788368883698837088371883728837388374883758837688377883788837988380883818838288383883848838588386883878838888389883908839188392883938839488395883968839788398883998840088401884028840388404884058840688407884088840988410884118841288413884148841588416884178841888419884208842188422884238842488425884268842788428884298843088431884328843388434884358843688437884388843988440884418844288443884448844588446884478844888449884508845188452884538845488455884568845788458884598846088461884628846388464884658846688467884688846988470884718847288473884748847588476884778847888479884808848188482884838848488485884868848788488884898849088491884928849388494884958849688497884988849988500885018850288503885048850588506885078850888509885108851188512885138851488515885168851788518885198852088521885228852388524885258852688527885288852988530885318853288533885348853588536885378853888539885408854188542885438854488545885468854788548885498855088551885528855388554885558855688557885588855988560885618856288563885648856588566885678856888569885708857188572885738857488575885768857788578885798858088581885828858388584885858858688587885888858988590885918859288593885948859588596885978859888599886008860188602886038860488605886068860788608886098861088611886128861388614886158861688617886188861988620886218862288623886248862588626886278862888629886308863188632886338863488635886368863788638886398864088641886428864388644886458864688647886488864988650886518865288653886548865588656886578865888659886608866188662886638866488665886668866788668886698867088671886728867388674886758867688677886788867988680886818868288683886848868588686886878868888689886908869188692886938869488695886968869788698886998870088701887028870388704887058870688707887088870988710887118871288713887148871588716887178871888719887208872188722887238872488725887268872788728887298873088731887328873388734887358873688737887388873988740887418874288743887448874588746887478874888749887508875188752887538875488755887568875788758887598876088761887628876388764887658876688767887688876988770887718877288773887748877588776887778877888779887808878188782887838878488785887868878788788887898879088791887928879388794887958879688797887988879988800888018880288803888048880588806888078880888809888108881188812888138881488815888168881788818888198882088821888228882388824888258882688827888288882988830888318883288833888348883588836888378883888839888408884188842888438884488845888468884788848888498885088851888528885388854888558885688857888588885988860888618886288863888648886588866888678886888869888708887188872888738887488875888768887788878888798888088881888828888388884888858888688887888888888988890888918889288893888948889588896888978889888899889008890188902889038890488905889068890788908889098891088911889128891388914889158891688917889188891988920889218892288923889248892588926889278892888929889308893188932889338893488935889368893788938889398894088941889428894388944889458894688947889488894988950889518895288953889548895588956889578895888959889608896188962889638896488965889668896788968889698897088971889728897388974889758897688977889788897988980889818898288983889848898588986889878898888989889908899188992889938899488995889968899788998889998900089001890028900389004890058900689007890088900989010890118901289013890148901589016890178901889019890208902189022890238902489025890268902789028890298903089031890328903389034890358903689037890388903989040890418904289043890448904589046890478904889049890508905189052890538905489055890568905789058890598906089061890628906389064890658906689067890688906989070890718907289073890748907589076890778907889079890808908189082890838908489085890868908789088890898909089091890928909389094890958909689097890988909989100891018910289103891048910589106891078910889109891108911189112891138911489115891168911789118891198912089121891228912389124891258912689127891288912989130891318913289133891348913589136891378913889139891408914189142891438914489145891468914789148891498915089151891528915389154891558915689157891588915989160891618916289163891648916589166891678916889169891708917189172891738917489175891768917789178891798918089181891828918389184891858918689187891888918989190891918919289193891948919589196891978919889199892008920189202892038920489205892068920789208892098921089211892128921389214892158921689217892188921989220892218922289223892248922589226892278922889229892308923189232892338923489235892368923789238892398924089241892428924389244892458924689247892488924989250892518925289253892548925589256892578925889259892608926189262892638926489265892668926789268892698927089271892728927389274892758927689277892788927989280892818928289283892848928589286892878928889289892908929189292892938929489295892968929789298892998930089301893028930389304893058930689307893088930989310893118931289313893148931589316893178931889319893208932189322893238932489325893268932789328893298933089331893328933389334893358933689337893388933989340893418934289343893448934589346893478934889349893508935189352893538935489355893568935789358893598936089361893628936389364893658936689367893688936989370893718937289373893748937589376893778937889379893808938189382893838938489385893868938789388893898939089391893928939389394893958939689397893988939989400894018940289403894048940589406894078940889409894108941189412894138941489415894168941789418894198942089421894228942389424894258942689427894288942989430894318943289433894348943589436894378943889439894408944189442894438944489445894468944789448894498945089451894528945389454894558945689457894588945989460894618946289463894648946589466894678946889469894708947189472894738947489475894768947789478894798948089481894828948389484894858948689487894888948989490894918949289493894948949589496894978949889499895008950189502895038950489505895068950789508895098951089511895128951389514895158951689517895188951989520895218952289523895248952589526895278952889529895308953189532895338953489535895368953789538895398954089541895428954389544895458954689547895488954989550895518955289553895548955589556895578955889559895608956189562895638956489565895668956789568895698957089571895728957389574895758957689577895788957989580895818958289583895848958589586895878958889589895908959189592895938959489595895968959789598895998960089601896028960389604896058960689607896088960989610896118961289613896148961589616896178961889619896208962189622896238962489625896268962789628896298963089631896328963389634896358963689637896388963989640896418964289643896448964589646896478964889649896508965189652896538965489655896568965789658896598966089661896628966389664896658966689667896688966989670896718967289673896748967589676896778967889679896808968189682896838968489685896868968789688896898969089691896928969389694896958969689697896988969989700897018970289703897048970589706897078970889709897108971189712897138971489715897168971789718897198972089721897228972389724897258972689727897288972989730897318973289733897348973589736897378973889739897408974189742897438974489745897468974789748897498975089751897528975389754897558975689757897588975989760897618976289763897648976589766897678976889769897708977189772897738977489775897768977789778897798978089781897828978389784897858978689787897888978989790897918979289793897948979589796897978979889799898008980189802898038980489805898068980789808898098981089811898128981389814898158981689817898188981989820898218982289823898248982589826898278982889829898308983189832898338983489835898368983789838898398984089841898428984389844898458984689847898488984989850898518985289853898548985589856898578985889859898608986189862898638986489865898668986789868898698987089871898728987389874898758987689877898788987989880898818988289883898848988589886898878988889889898908989189892898938989489895898968989789898898998990089901899028990389904899058990689907899088990989910899118991289913899148991589916899178991889919899208992189922899238992489925899268992789928899298993089931899328993389934899358993689937899388993989940899418994289943899448994589946899478994889949899508995189952899538995489955899568995789958899598996089961899628996389964899658996689967899688996989970899718997289973899748997589976899778997889979899808998189982899838998489985899868998789988899898999089991899928999389994899958999689997899988999990000900019000290003900049000590006900079000890009900109001190012900139001490015900169001790018900199002090021900229002390024900259002690027900289002990030900319003290033900349003590036900379003890039900409004190042900439004490045900469004790048900499005090051900529005390054900559005690057900589005990060900619006290063900649006590066900679006890069900709007190072900739007490075900769007790078900799008090081900829008390084900859008690087900889008990090900919009290093900949009590096900979009890099901009010190102901039010490105901069010790108901099011090111901129011390114901159011690117901189011990120901219012290123901249012590126901279012890129901309013190132901339013490135901369013790138901399014090141901429014390144901459014690147901489014990150901519015290153901549015590156901579015890159901609016190162901639016490165901669016790168901699017090171901729017390174901759017690177901789017990180901819018290183901849018590186901879018890189901909019190192901939019490195901969019790198901999020090201902029020390204902059020690207902089020990210902119021290213902149021590216902179021890219902209022190222902239022490225902269022790228902299023090231902329023390234902359023690237902389023990240902419024290243902449024590246902479024890249902509025190252902539025490255902569025790258902599026090261902629026390264902659026690267902689026990270902719027290273902749027590276902779027890279902809028190282902839028490285902869028790288902899029090291902929029390294902959029690297902989029990300903019030290303903049030590306903079030890309903109031190312903139031490315903169031790318903199032090321903229032390324903259032690327903289032990330903319033290333903349033590336903379033890339903409034190342903439034490345903469034790348903499035090351903529035390354903559035690357903589035990360903619036290363903649036590366903679036890369903709037190372903739037490375903769037790378903799038090381903829038390384903859038690387903889038990390903919039290393903949039590396903979039890399904009040190402904039040490405904069040790408904099041090411904129041390414904159041690417904189041990420904219042290423904249042590426904279042890429904309043190432904339043490435904369043790438904399044090441904429044390444904459044690447904489044990450904519045290453904549045590456904579045890459904609046190462904639046490465904669046790468904699047090471904729047390474904759047690477904789047990480904819048290483904849048590486904879048890489904909049190492904939049490495904969049790498904999050090501905029050390504905059050690507905089050990510905119051290513905149051590516905179051890519905209052190522905239052490525905269052790528905299053090531905329053390534905359053690537905389053990540905419054290543905449054590546905479054890549905509055190552905539055490555905569055790558905599056090561905629056390564905659056690567905689056990570905719057290573905749057590576905779057890579905809058190582905839058490585905869058790588905899059090591905929059390594905959059690597905989059990600906019060290603906049060590606906079060890609906109061190612906139061490615906169061790618906199062090621906229062390624906259062690627906289062990630906319063290633906349063590636906379063890639906409064190642906439064490645906469064790648906499065090651906529065390654906559065690657906589065990660906619066290663906649066590666906679066890669906709067190672906739067490675906769067790678906799068090681906829068390684906859068690687906889068990690906919069290693906949069590696906979069890699907009070190702907039070490705907069070790708907099071090711907129071390714907159071690717907189071990720907219072290723907249072590726907279072890729907309073190732907339073490735907369073790738907399074090741907429074390744907459074690747907489074990750907519075290753907549075590756907579075890759907609076190762907639076490765907669076790768907699077090771907729077390774907759077690777907789077990780907819078290783907849078590786907879078890789907909079190792907939079490795907969079790798907999080090801908029080390804908059080690807908089080990810908119081290813908149081590816908179081890819908209082190822908239082490825908269082790828908299083090831908329083390834908359083690837908389083990840908419084290843908449084590846908479084890849908509085190852908539085490855908569085790858908599086090861908629086390864908659086690867908689086990870908719087290873908749087590876908779087890879908809088190882908839088490885908869088790888908899089090891908929089390894908959089690897908989089990900909019090290903909049090590906909079090890909909109091190912909139091490915909169091790918909199092090921909229092390924909259092690927909289092990930909319093290933909349093590936909379093890939909409094190942909439094490945909469094790948909499095090951909529095390954909559095690957909589095990960909619096290963909649096590966909679096890969909709097190972909739097490975909769097790978909799098090981909829098390984909859098690987909889098990990909919099290993909949099590996909979099890999910009100191002910039100491005910069100791008910099101091011910129101391014910159101691017910189101991020910219102291023910249102591026910279102891029910309103191032910339103491035910369103791038910399104091041910429104391044910459104691047910489104991050910519105291053910549105591056910579105891059910609106191062910639106491065910669106791068910699107091071910729107391074910759107691077910789107991080910819108291083910849108591086910879108891089910909109191092910939109491095910969109791098910999110091101911029110391104911059110691107911089110991110911119111291113911149111591116911179111891119911209112191122911239112491125911269112791128911299113091131911329113391134911359113691137911389113991140911419114291143911449114591146911479114891149911509115191152911539115491155911569115791158911599116091161911629116391164911659116691167911689116991170911719117291173911749117591176911779117891179911809118191182911839118491185911869118791188911899119091191911929119391194911959119691197911989119991200912019120291203912049120591206912079120891209912109121191212912139121491215912169121791218912199122091221912229122391224912259122691227912289122991230912319123291233912349123591236912379123891239912409124191242912439124491245912469124791248912499125091251912529125391254912559125691257912589125991260912619126291263912649126591266912679126891269912709127191272912739127491275912769127791278912799128091281912829128391284912859128691287912889128991290912919129291293912949129591296912979129891299913009130191302913039130491305913069130791308913099131091311913129131391314913159131691317913189131991320913219132291323913249132591326913279132891329913309133191332913339133491335913369133791338913399134091341913429134391344913459134691347913489134991350913519135291353913549135591356913579135891359913609136191362913639136491365913669136791368913699137091371913729137391374913759137691377913789137991380913819138291383913849138591386913879138891389913909139191392913939139491395913969139791398913999140091401914029140391404914059140691407914089140991410914119141291413914149141591416914179141891419914209142191422914239142491425914269142791428914299143091431914329143391434914359143691437914389143991440914419144291443914449144591446914479144891449914509145191452914539145491455914569145791458914599146091461914629146391464914659146691467914689146991470914719147291473914749147591476914779147891479914809148191482914839148491485914869148791488914899149091491914929149391494914959149691497914989149991500915019150291503915049150591506915079150891509915109151191512915139151491515915169151791518915199152091521915229152391524915259152691527915289152991530915319153291533915349153591536915379153891539915409154191542915439154491545915469154791548915499155091551915529155391554915559155691557915589155991560915619156291563915649156591566915679156891569915709157191572915739157491575915769157791578915799158091581915829158391584915859158691587915889158991590915919159291593915949159591596915979159891599916009160191602916039160491605916069160791608916099161091611916129161391614916159161691617916189161991620916219162291623916249162591626916279162891629916309163191632916339163491635916369163791638916399164091641916429164391644916459164691647916489164991650916519165291653916549165591656916579165891659916609166191662916639166491665916669166791668916699167091671916729167391674916759167691677916789167991680916819168291683916849168591686916879168891689916909169191692916939169491695916969169791698916999170091701917029170391704917059170691707917089170991710917119171291713917149171591716917179171891719917209172191722917239172491725917269172791728917299173091731917329173391734917359173691737917389173991740917419174291743917449174591746917479174891749917509175191752917539175491755917569175791758917599176091761917629176391764917659176691767917689176991770917719177291773917749177591776917779177891779917809178191782917839178491785917869178791788917899179091791917929179391794917959179691797917989179991800918019180291803918049180591806918079180891809918109181191812918139181491815918169181791818918199182091821918229182391824918259182691827918289182991830918319183291833918349183591836918379183891839918409184191842918439184491845918469184791848918499185091851918529185391854918559185691857918589185991860918619186291863918649186591866918679186891869918709187191872918739187491875918769187791878918799188091881918829188391884918859188691887918889188991890918919189291893918949189591896918979189891899919009190191902919039190491905919069190791908919099191091911919129191391914919159191691917919189191991920919219192291923919249192591926919279192891929919309193191932919339193491935919369193791938919399194091941919429194391944919459194691947919489194991950919519195291953919549195591956919579195891959919609196191962919639196491965919669196791968919699197091971919729197391974919759197691977919789197991980919819198291983919849198591986919879198891989919909199191992919939199491995919969199791998919999200092001920029200392004920059200692007920089200992010920119201292013920149201592016920179201892019920209202192022920239202492025920269202792028920299203092031920329203392034920359203692037920389203992040920419204292043920449204592046920479204892049920509205192052920539205492055920569205792058920599206092061920629206392064920659206692067920689206992070920719207292073920749207592076920779207892079920809208192082920839208492085920869208792088920899209092091920929209392094920959209692097920989209992100921019210292103921049210592106921079210892109921109211192112921139211492115921169211792118921199212092121921229212392124921259212692127921289212992130921319213292133921349213592136921379213892139921409214192142921439214492145921469214792148921499215092151921529215392154921559215692157921589215992160921619216292163921649216592166921679216892169921709217192172921739217492175921769217792178921799218092181921829218392184921859218692187921889218992190921919219292193921949219592196921979219892199922009220192202922039220492205922069220792208922099221092211922129221392214922159221692217922189221992220922219222292223922249222592226922279222892229922309223192232922339223492235922369223792238922399224092241922429224392244922459224692247922489224992250922519225292253922549225592256922579225892259922609226192262922639226492265922669226792268922699227092271922729227392274922759227692277922789227992280922819228292283922849228592286922879228892289922909229192292922939229492295922969229792298922999230092301923029230392304923059230692307923089230992310923119231292313923149231592316923179231892319923209232192322923239232492325923269232792328923299233092331923329233392334923359233692337923389233992340923419234292343923449234592346923479234892349923509235192352923539235492355923569235792358923599236092361923629236392364923659236692367923689236992370923719237292373923749237592376923779237892379923809238192382923839238492385923869238792388923899239092391923929239392394923959239692397923989239992400924019240292403924049240592406924079240892409924109241192412924139241492415924169241792418924199242092421924229242392424924259242692427924289242992430924319243292433924349243592436924379243892439924409244192442924439244492445924469244792448924499245092451924529245392454924559245692457924589245992460924619246292463924649246592466924679246892469924709247192472924739247492475924769247792478924799248092481924829248392484924859248692487924889248992490924919249292493924949249592496924979249892499925009250192502925039250492505925069250792508925099251092511925129251392514925159251692517925189251992520925219252292523925249252592526925279252892529925309253192532925339253492535925369253792538925399254092541925429254392544925459254692547925489254992550925519255292553925549255592556925579255892559925609256192562925639256492565925669256792568925699257092571925729257392574925759257692577925789257992580925819258292583925849258592586925879258892589925909259192592925939259492595925969259792598925999260092601926029260392604926059260692607926089260992610926119261292613926149261592616926179261892619926209262192622926239262492625926269262792628926299263092631926329263392634926359263692637926389263992640926419264292643926449264592646926479264892649926509265192652926539265492655926569265792658926599266092661926629266392664926659266692667926689266992670926719267292673926749267592676926779267892679926809268192682926839268492685926869268792688926899269092691926929269392694926959269692697926989269992700927019270292703927049270592706927079270892709927109271192712927139271492715927169271792718927199272092721927229272392724927259272692727927289272992730927319273292733927349273592736927379273892739927409274192742927439274492745927469274792748927499275092751927529275392754927559275692757927589275992760927619276292763927649276592766927679276892769927709277192772927739277492775927769277792778927799278092781927829278392784927859278692787927889278992790927919279292793927949279592796927979279892799928009280192802928039280492805928069280792808928099281092811928129281392814928159281692817928189281992820928219282292823928249282592826928279282892829928309283192832928339283492835928369283792838928399284092841928429284392844928459284692847928489284992850928519285292853928549285592856928579285892859928609286192862928639286492865928669286792868928699287092871928729287392874928759287692877928789287992880928819288292883928849288592886928879288892889928909289192892928939289492895928969289792898928999290092901929029290392904929059290692907929089290992910929119291292913929149291592916929179291892919929209292192922929239292492925929269292792928929299293092931929329293392934929359293692937929389293992940929419294292943929449294592946929479294892949929509295192952929539295492955929569295792958929599296092961929629296392964929659296692967929689296992970929719297292973929749297592976929779297892979929809298192982929839298492985929869298792988929899299092991929929299392994929959299692997929989299993000930019300293003930049300593006930079300893009930109301193012930139301493015930169301793018930199302093021930229302393024930259302693027930289302993030930319303293033930349303593036930379303893039930409304193042930439304493045930469304793048930499305093051930529305393054930559305693057930589305993060930619306293063930649306593066930679306893069930709307193072930739307493075930769307793078930799308093081930829308393084930859308693087930889308993090930919309293093930949309593096930979309893099931009310193102931039310493105931069310793108931099311093111931129311393114931159311693117931189311993120931219312293123931249312593126931279312893129931309313193132931339313493135931369313793138931399314093141931429314393144931459314693147931489314993150931519315293153931549315593156931579315893159931609316193162931639316493165931669316793168931699317093171931729317393174931759317693177931789317993180931819318293183931849318593186931879318893189931909319193192931939319493195931969319793198931999320093201932029320393204932059320693207932089320993210932119321293213932149321593216932179321893219932209322193222932239322493225932269322793228932299323093231932329323393234932359323693237932389323993240932419324293243932449324593246932479324893249932509325193252932539325493255932569325793258932599326093261932629326393264932659326693267932689326993270932719327293273932749327593276932779327893279932809328193282932839328493285932869328793288932899329093291932929329393294932959329693297932989329993300933019330293303933049330593306933079330893309933109331193312933139331493315933169331793318933199332093321933229332393324933259332693327933289332993330933319333293333933349333593336933379333893339933409334193342933439334493345933469334793348933499335093351933529335393354933559335693357933589335993360933619336293363933649336593366933679336893369933709337193372933739337493375933769337793378933799338093381933829338393384933859338693387933889338993390933919339293393933949339593396933979339893399934009340193402934039340493405934069340793408934099341093411934129341393414934159341693417934189341993420934219342293423934249342593426934279342893429934309343193432934339343493435934369343793438934399344093441934429344393444934459344693447934489344993450934519345293453934549345593456934579345893459934609346193462934639346493465934669346793468934699347093471934729347393474934759347693477934789347993480934819348293483934849348593486934879348893489934909349193492934939349493495934969349793498934999350093501935029350393504935059350693507935089350993510935119351293513935149351593516935179351893519935209352193522935239352493525935269352793528935299353093531935329353393534935359353693537935389353993540935419354293543935449354593546935479354893549935509355193552935539355493555935569355793558935599356093561935629356393564935659356693567935689356993570935719357293573935749357593576935779357893579935809358193582935839358493585935869358793588935899359093591935929359393594935959359693597935989359993600936019360293603936049360593606936079360893609936109361193612936139361493615936169361793618936199362093621936229362393624936259362693627936289362993630936319363293633936349363593636936379363893639936409364193642936439364493645936469364793648936499365093651936529365393654936559365693657936589365993660936619366293663936649366593666936679366893669936709367193672936739367493675936769367793678936799368093681936829368393684936859368693687936889368993690936919369293693936949369593696936979369893699937009370193702937039370493705937069370793708937099371093711937129371393714937159371693717937189371993720937219372293723937249372593726937279372893729937309373193732937339373493735937369373793738937399374093741937429374393744937459374693747937489374993750937519375293753937549375593756937579375893759937609376193762937639376493765937669376793768937699377093771937729377393774937759377693777937789377993780937819378293783937849378593786937879378893789937909379193792937939379493795937969379793798937999380093801938029380393804938059380693807938089380993810938119381293813938149381593816938179381893819938209382193822938239382493825938269382793828938299383093831938329383393834938359383693837938389383993840938419384293843938449384593846938479384893849938509385193852938539385493855938569385793858938599386093861938629386393864938659386693867938689386993870938719387293873938749387593876938779387893879938809388193882938839388493885938869388793888938899389093891938929389393894938959389693897938989389993900939019390293903939049390593906939079390893909939109391193912939139391493915939169391793918939199392093921939229392393924939259392693927939289392993930939319393293933939349393593936939379393893939939409394193942939439394493945939469394793948939499395093951939529395393954939559395693957939589395993960939619396293963939649396593966939679396893969939709397193972939739397493975939769397793978939799398093981939829398393984939859398693987939889398993990939919399293993939949399593996939979399893999940009400194002940039400494005940069400794008940099401094011940129401394014940159401694017940189401994020940219402294023940249402594026940279402894029940309403194032940339403494035940369403794038940399404094041940429404394044940459404694047940489404994050940519405294053940549405594056940579405894059940609406194062940639406494065940669406794068940699407094071940729407394074940759407694077940789407994080940819408294083940849408594086940879408894089940909409194092940939409494095940969409794098940999410094101941029410394104941059410694107941089410994110941119411294113941149411594116941179411894119941209412194122941239412494125941269412794128941299413094131941329413394134941359413694137941389413994140941419414294143941449414594146941479414894149941509415194152941539415494155941569415794158941599416094161941629416394164941659416694167941689416994170941719417294173941749417594176941779417894179941809418194182941839418494185941869418794188941899419094191941929419394194941959419694197941989419994200942019420294203942049420594206942079420894209942109421194212942139421494215942169421794218942199422094221942229422394224942259422694227942289422994230942319423294233942349423594236942379423894239942409424194242942439424494245942469424794248942499425094251942529425394254942559425694257942589425994260942619426294263942649426594266942679426894269942709427194272942739427494275942769427794278942799428094281942829428394284942859428694287942889428994290942919429294293942949429594296942979429894299943009430194302943039430494305943069430794308943099431094311943129431394314943159431694317943189431994320943219432294323943249432594326943279432894329943309433194332943339433494335943369433794338943399434094341943429434394344943459434694347943489434994350943519435294353943549435594356943579435894359943609436194362943639436494365943669436794368943699437094371943729437394374943759437694377943789437994380943819438294383943849438594386943879438894389943909439194392943939439494395943969439794398943999440094401944029440394404944059440694407944089440994410944119441294413944149441594416944179441894419944209442194422944239442494425944269442794428944299443094431944329443394434944359443694437944389443994440944419444294443944449444594446944479444894449944509445194452944539445494455944569445794458944599446094461944629446394464944659446694467944689446994470944719447294473944749447594476944779447894479944809448194482944839448494485944869448794488944899449094491944929449394494944959449694497944989449994500945019450294503945049450594506945079450894509945109451194512945139451494515945169451794518945199452094521945229452394524945259452694527945289452994530945319453294533945349453594536945379453894539945409454194542945439454494545945469454794548945499455094551945529455394554945559455694557945589455994560945619456294563945649456594566945679456894569945709457194572945739457494575945769457794578945799458094581945829458394584945859458694587945889458994590945919459294593945949459594596945979459894599946009460194602946039460494605946069460794608946099461094611946129461394614946159461694617946189461994620946219462294623946249462594626946279462894629946309463194632946339463494635946369463794638946399464094641946429464394644946459464694647946489464994650946519465294653946549465594656946579465894659946609466194662946639466494665946669466794668946699467094671946729467394674946759467694677946789467994680946819468294683946849468594686946879468894689946909469194692946939469494695946969469794698946999470094701947029470394704947059470694707947089470994710947119471294713947149471594716947179471894719947209472194722947239472494725947269472794728947299473094731947329473394734947359473694737947389473994740947419474294743947449474594746947479474894749947509475194752947539475494755947569475794758947599476094761947629476394764947659476694767947689476994770947719477294773947749477594776947779477894779947809478194782947839478494785947869478794788947899479094791947929479394794947959479694797947989479994800948019480294803948049480594806948079480894809948109481194812948139481494815948169481794818948199482094821948229482394824948259482694827948289482994830948319483294833948349483594836948379483894839948409484194842948439484494845948469484794848948499485094851948529485394854948559485694857948589485994860948619486294863948649486594866948679486894869948709487194872948739487494875948769487794878948799488094881948829488394884948859488694887948889488994890948919489294893948949489594896948979489894899949009490194902949039490494905949069490794908949099491094911949129491394914949159491694917949189491994920949219492294923949249492594926949279492894929949309493194932949339493494935949369493794938949399494094941949429494394944949459494694947949489494994950949519495294953949549495594956949579495894959949609496194962949639496494965949669496794968949699497094971949729497394974949759497694977949789497994980949819498294983949849498594986949879498894989949909499194992949939499494995949969499794998949999500095001950029500395004950059500695007950089500995010950119501295013950149501595016950179501895019950209502195022950239502495025950269502795028950299503095031950329503395034950359503695037950389503995040950419504295043950449504595046950479504895049950509505195052950539505495055950569505795058950599506095061950629506395064950659506695067950689506995070950719507295073950749507595076950779507895079950809508195082950839508495085950869508795088950899509095091950929509395094950959509695097950989509995100951019510295103951049510595106951079510895109951109511195112951139511495115951169511795118951199512095121951229512395124951259512695127951289512995130951319513295133951349513595136951379513895139951409514195142951439514495145951469514795148951499515095151951529515395154951559515695157951589515995160951619516295163951649516595166951679516895169951709517195172951739517495175951769517795178951799518095181951829518395184951859518695187951889518995190951919519295193951949519595196951979519895199952009520195202952039520495205952069520795208952099521095211952129521395214952159521695217952189521995220952219522295223952249522595226952279522895229952309523195232952339523495235952369523795238952399524095241952429524395244952459524695247952489524995250952519525295253952549525595256952579525895259952609526195262952639526495265952669526795268952699527095271952729527395274952759527695277952789527995280952819528295283952849528595286952879528895289952909529195292952939529495295952969529795298952999530095301953029530395304953059530695307953089530995310953119531295313953149531595316953179531895319953209532195322953239532495325953269532795328953299533095331953329533395334953359533695337953389533995340953419534295343953449534595346953479534895349953509535195352953539535495355953569535795358953599536095361953629536395364953659536695367953689536995370953719537295373953749537595376953779537895379953809538195382953839538495385953869538795388953899539095391953929539395394953959539695397953989539995400954019540295403954049540595406954079540895409954109541195412954139541495415954169541795418954199542095421954229542395424954259542695427954289542995430954319543295433954349543595436954379543895439954409544195442954439544495445954469544795448954499545095451954529545395454954559545695457954589545995460954619546295463954649546595466954679546895469954709547195472954739547495475954769547795478954799548095481954829548395484954859548695487954889548995490954919549295493954949549595496954979549895499955009550195502955039550495505955069550795508955099551095511955129551395514955159551695517955189551995520955219552295523955249552595526955279552895529955309553195532955339553495535955369553795538955399554095541955429554395544955459554695547955489554995550955519555295553955549555595556955579555895559955609556195562955639556495565955669556795568955699557095571955729557395574955759557695577955789557995580955819558295583955849558595586955879558895589955909559195592955939559495595955969559795598955999560095601956029560395604956059560695607956089560995610956119561295613956149561595616956179561895619956209562195622956239562495625956269562795628956299563095631956329563395634956359563695637956389563995640956419564295643956449564595646956479564895649956509565195652956539565495655956569565795658956599566095661956629566395664956659566695667956689566995670956719567295673956749567595676956779567895679956809568195682956839568495685956869568795688956899569095691956929569395694956959569695697956989569995700957019570295703957049570595706957079570895709957109571195712957139571495715957169571795718957199572095721957229572395724957259572695727957289572995730957319573295733957349573595736957379573895739957409574195742957439574495745957469574795748957499575095751957529575395754957559575695757957589575995760957619576295763957649576595766957679576895769957709577195772957739577495775957769577795778957799578095781957829578395784957859578695787957889578995790957919579295793957949579595796957979579895799958009580195802958039580495805958069580795808958099581095811958129581395814958159581695817958189581995820958219582295823958249582595826958279582895829958309583195832958339583495835958369583795838958399584095841958429584395844958459584695847958489584995850958519585295853958549585595856958579585895859958609586195862958639586495865958669586795868958699587095871958729587395874958759587695877958789587995880958819588295883958849588595886958879588895889958909589195892958939589495895958969589795898958999590095901959029590395904959059590695907959089590995910959119591295913959149591595916959179591895919959209592195922959239592495925959269592795928959299593095931959329593395934959359593695937959389593995940959419594295943959449594595946959479594895949959509595195952959539595495955959569595795958959599596095961959629596395964959659596695967959689596995970959719597295973959749597595976959779597895979959809598195982959839598495985959869598795988959899599095991959929599395994959959599695997959989599996000960019600296003960049600596006960079600896009960109601196012960139601496015960169601796018960199602096021960229602396024960259602696027960289602996030960319603296033960349603596036960379603896039960409604196042960439604496045960469604796048960499605096051960529605396054960559605696057960589605996060960619606296063960649606596066960679606896069960709607196072960739607496075960769607796078960799608096081960829608396084960859608696087960889608996090960919609296093960949609596096960979609896099961009610196102961039610496105961069610796108961099611096111961129611396114961159611696117961189611996120961219612296123961249612596126961279612896129961309613196132961339613496135961369613796138961399614096141961429614396144961459614696147961489614996150961519615296153961549615596156961579615896159961609616196162961639616496165961669616796168961699617096171961729617396174961759617696177961789617996180961819618296183961849618596186961879618896189961909619196192961939619496195961969619796198961999620096201962029620396204962059620696207962089620996210962119621296213962149621596216962179621896219962209622196222962239622496225962269622796228962299623096231962329623396234962359623696237962389623996240962419624296243962449624596246962479624896249962509625196252962539625496255962569625796258962599626096261962629626396264962659626696267962689626996270962719627296273962749627596276962779627896279962809628196282962839628496285962869628796288962899629096291962929629396294962959629696297962989629996300963019630296303963049630596306963079630896309963109631196312963139631496315963169631796318963199632096321963229632396324963259632696327963289632996330963319633296333963349633596336963379633896339963409634196342963439634496345963469634796348963499635096351963529635396354963559635696357963589635996360963619636296363963649636596366963679636896369963709637196372963739637496375963769637796378963799638096381963829638396384963859638696387963889638996390963919639296393963949639596396963979639896399964009640196402964039640496405964069640796408964099641096411964129641396414964159641696417964189641996420964219642296423964249642596426964279642896429964309643196432964339643496435964369643796438964399644096441964429644396444964459644696447964489644996450964519645296453964549645596456964579645896459964609646196462964639646496465964669646796468964699647096471964729647396474964759647696477964789647996480964819648296483964849648596486964879648896489964909649196492964939649496495964969649796498964999650096501965029650396504965059650696507965089650996510965119651296513965149651596516965179651896519965209652196522965239652496525965269652796528965299653096531965329653396534965359653696537965389653996540965419654296543965449654596546965479654896549965509655196552965539655496555965569655796558965599656096561965629656396564965659656696567965689656996570965719657296573965749657596576965779657896579965809658196582965839658496585965869658796588965899659096591965929659396594965959659696597965989659996600966019660296603966049660596606966079660896609966109661196612966139661496615966169661796618966199662096621966229662396624966259662696627966289662996630966319663296633966349663596636966379663896639966409664196642966439664496645966469664796648966499665096651966529665396654966559665696657966589665996660966619666296663966649666596666966679666896669966709667196672966739667496675966769667796678966799668096681966829668396684966859668696687966889668996690966919669296693966949669596696966979669896699967009670196702967039670496705967069670796708967099671096711967129671396714967159671696717967189671996720967219672296723967249672596726967279672896729967309673196732967339673496735967369673796738967399674096741967429674396744967459674696747967489674996750967519675296753967549675596756967579675896759967609676196762967639676496765967669676796768967699677096771967729677396774967759677696777967789677996780967819678296783967849678596786967879678896789967909679196792967939679496795967969679796798967999680096801968029680396804968059680696807968089680996810968119681296813968149681596816968179681896819968209682196822968239682496825968269682796828968299683096831968329683396834968359683696837968389683996840968419684296843968449684596846968479684896849968509685196852968539685496855968569685796858968599686096861968629686396864968659686696867968689686996870968719687296873968749687596876968779687896879968809688196882968839688496885968869688796888968899689096891968929689396894968959689696897968989689996900969019690296903969049690596906969079690896909969109691196912969139691496915969169691796918969199692096921969229692396924969259692696927969289692996930969319693296933969349693596936969379693896939969409694196942969439694496945969469694796948969499695096951969529695396954969559695696957969589695996960969619696296963969649696596966969679696896969969709697196972969739697496975969769697796978969799698096981969829698396984969859698696987969889698996990969919699296993969949699596996969979699896999970009700197002970039700497005970069700797008970099701097011970129701397014970159701697017970189701997020970219702297023970249702597026970279702897029970309703197032970339703497035970369703797038970399704097041970429704397044970459704697047970489704997050970519705297053970549705597056970579705897059970609706197062970639706497065970669706797068970699707097071970729707397074970759707697077970789707997080970819708297083970849708597086970879708897089970909709197092970939709497095970969709797098970999710097101971029710397104971059710697107971089710997110971119711297113971149711597116971179711897119971209712197122971239712497125971269712797128971299713097131971329713397134971359713697137971389713997140971419714297143971449714597146971479714897149971509715197152971539715497155971569715797158971599716097161971629716397164971659716697167971689716997170971719717297173971749717597176971779717897179971809718197182971839718497185971869718797188971899719097191971929719397194971959719697197971989719997200972019720297203972049720597206972079720897209972109721197212972139721497215972169721797218972199722097221972229722397224972259722697227972289722997230972319723297233972349723597236972379723897239972409724197242972439724497245972469724797248972499725097251972529725397254972559725697257972589725997260972619726297263972649726597266972679726897269972709727197272972739727497275972769727797278972799728097281972829728397284972859728697287972889728997290972919729297293972949729597296972979729897299973009730197302973039730497305973069730797308973099731097311973129731397314973159731697317973189731997320973219732297323973249732597326973279732897329973309733197332973339733497335973369733797338973399734097341973429734397344973459734697347973489734997350973519735297353973549735597356973579735897359973609736197362973639736497365973669736797368973699737097371973729737397374973759737697377973789737997380973819738297383973849738597386973879738897389973909739197392973939739497395973969739797398973999740097401974029740397404974059740697407974089740997410974119741297413974149741597416974179741897419974209742197422974239742497425974269742797428974299743097431974329743397434974359743697437974389743997440974419744297443974449744597446974479744897449974509745197452974539745497455974569745797458974599746097461974629746397464974659746697467974689746997470974719747297473974749747597476974779747897479974809748197482974839748497485974869748797488974899749097491974929749397494974959749697497974989749997500975019750297503975049750597506975079750897509975109751197512975139751497515975169751797518975199752097521975229752397524975259752697527975289752997530975319753297533975349753597536975379753897539975409754197542975439754497545975469754797548975499755097551975529755397554975559755697557975589755997560975619756297563975649756597566975679756897569975709757197572975739757497575975769757797578975799758097581975829758397584975859758697587975889758997590975919759297593975949759597596975979759897599976009760197602976039760497605976069760797608976099761097611976129761397614976159761697617976189761997620976219762297623976249762597626976279762897629976309763197632976339763497635976369763797638976399764097641976429764397644976459764697647976489764997650976519765297653976549765597656976579765897659976609766197662976639766497665976669766797668976699767097671976729767397674976759767697677976789767997680976819768297683976849768597686976879768897689976909769197692976939769497695976969769797698976999770097701977029770397704977059770697707977089770997710977119771297713977149771597716977179771897719977209772197722977239772497725977269772797728977299773097731977329773397734977359773697737977389773997740977419774297743977449774597746977479774897749977509775197752977539775497755977569775797758977599776097761977629776397764977659776697767977689776997770977719777297773977749777597776977779777897779977809778197782977839778497785977869778797788977899779097791977929779397794977959779697797977989779997800978019780297803978049780597806978079780897809978109781197812978139781497815978169781797818978199782097821978229782397824978259782697827978289782997830978319783297833978349783597836978379783897839978409784197842978439784497845978469784797848978499785097851978529785397854978559785697857978589785997860978619786297863978649786597866978679786897869978709787197872978739787497875978769787797878978799788097881978829788397884978859788697887978889788997890978919789297893978949789597896978979789897899979009790197902979039790497905979069790797908979099791097911979129791397914979159791697917979189791997920979219792297923979249792597926979279792897929979309793197932979339793497935979369793797938979399794097941979429794397944979459794697947979489794997950979519795297953979549795597956979579795897959979609796197962979639796497965979669796797968979699797097971979729797397974979759797697977979789797997980979819798297983979849798597986979879798897989979909799197992979939799497995979969799797998979999800098001980029800398004980059800698007980089800998010980119801298013980149801598016980179801898019980209802198022980239802498025980269802798028980299803098031980329803398034980359803698037980389803998040980419804298043980449804598046980479804898049980509805198052980539805498055980569805798058980599806098061980629806398064980659806698067980689806998070980719807298073980749807598076980779807898079980809808198082980839808498085980869808798088980899809098091980929809398094980959809698097980989809998100981019810298103981049810598106981079810898109981109811198112981139811498115981169811798118981199812098121981229812398124981259812698127981289812998130981319813298133981349813598136981379813898139981409814198142981439814498145981469814798148981499815098151981529815398154981559815698157981589815998160981619816298163981649816598166981679816898169981709817198172981739817498175981769817798178981799818098181981829818398184981859818698187981889818998190981919819298193981949819598196981979819898199982009820198202982039820498205982069820798208982099821098211982129821398214982159821698217982189821998220982219822298223982249822598226982279822898229982309823198232982339823498235982369823798238982399824098241982429824398244982459824698247982489824998250982519825298253982549825598256982579825898259982609826198262982639826498265982669826798268982699827098271982729827398274982759827698277982789827998280982819828298283982849828598286982879828898289982909829198292982939829498295982969829798298982999830098301983029830398304983059830698307983089830998310983119831298313983149831598316983179831898319983209832198322983239832498325983269832798328983299833098331983329833398334983359833698337983389833998340983419834298343983449834598346983479834898349983509835198352983539835498355983569835798358983599836098361983629836398364983659836698367983689836998370983719837298373983749837598376983779837898379983809838198382983839838498385983869838798388983899839098391983929839398394983959839698397983989839998400984019840298403984049840598406984079840898409984109841198412984139841498415984169841798418984199842098421984229842398424984259842698427984289842998430984319843298433984349843598436984379843898439984409844198442984439844498445984469844798448984499845098451984529845398454984559845698457984589845998460984619846298463984649846598466984679846898469984709847198472984739847498475984769847798478984799848098481984829848398484984859848698487984889848998490984919849298493984949849598496984979849898499985009850198502985039850498505985069850798508985099851098511985129851398514985159851698517985189851998520985219852298523985249852598526985279852898529985309853198532985339853498535985369853798538985399854098541985429854398544985459854698547985489854998550985519855298553985549855598556985579855898559985609856198562985639856498565985669856798568985699857098571985729857398574985759857698577985789857998580985819858298583985849858598586985879858898589985909859198592985939859498595985969859798598985999860098601986029860398604986059860698607986089860998610986119861298613986149861598616986179861898619986209862198622986239862498625986269862798628986299863098631986329863398634986359863698637986389863998640986419864298643986449864598646986479864898649986509865198652986539865498655986569865798658986599866098661986629866398664986659866698667986689866998670986719867298673986749867598676986779867898679986809868198682986839868498685986869868798688986899869098691986929869398694986959869698697986989869998700987019870298703987049870598706987079870898709987109871198712987139871498715987169871798718987199872098721987229872398724987259872698727987289872998730987319873298733987349873598736987379873898739987409874198742987439874498745987469874798748987499875098751987529875398754987559875698757987589875998760987619876298763987649876598766987679876898769987709877198772987739877498775987769877798778987799878098781987829878398784987859878698787987889878998790987919879298793987949879598796987979879898799988009880198802988039880498805988069880798808988099881098811988129881398814988159881698817988189881998820988219882298823988249882598826988279882898829988309883198832988339883498835988369883798838988399884098841988429884398844988459884698847988489884998850988519885298853988549885598856988579885898859988609886198862988639886498865988669886798868988699887098871988729887398874988759887698877988789887998880988819888298883988849888598886988879888898889988909889198892988939889498895988969889798898988999890098901989029890398904989059890698907989089890998910989119891298913989149891598916989179891898919989209892198922989239892498925989269892798928989299893098931989329893398934989359893698937989389893998940989419894298943989449894598946989479894898949989509895198952989539895498955989569895798958989599896098961989629896398964989659896698967989689896998970989719897298973989749897598976989779897898979989809898198982989839898498985989869898798988989899899098991989929899398994989959899698997989989899999000990019900299003990049900599006990079900899009990109901199012990139901499015990169901799018990199902099021990229902399024990259902699027990289902999030990319903299033990349903599036990379903899039990409904199042990439904499045990469904799048990499905099051990529905399054990559905699057990589905999060990619906299063990649906599066990679906899069990709907199072990739907499075990769907799078990799908099081990829908399084990859908699087990889908999090990919909299093990949909599096990979909899099991009910199102991039910499105991069910799108991099911099111991129911399114991159911699117991189911999120991219912299123991249912599126991279912899129991309913199132991339913499135991369913799138991399914099141991429914399144991459914699147991489914999150991519915299153991549915599156991579915899159991609916199162991639916499165991669916799168991699917099171991729917399174991759917699177991789917999180991819918299183991849918599186991879918899189991909919199192991939919499195991969919799198991999920099201992029920399204992059920699207992089920999210992119921299213992149921599216992179921899219992209922199222992239922499225992269922799228992299923099231992329923399234992359923699237992389923999240992419924299243992449924599246992479924899249992509925199252992539925499255992569925799258992599926099261992629926399264992659926699267992689926999270992719927299273992749927599276992779927899279992809928199282992839928499285992869928799288992899929099291992929929399294992959929699297992989929999300993019930299303993049930599306993079930899309993109931199312993139931499315993169931799318993199932099321993229932399324993259932699327993289932999330993319933299333993349933599336993379933899339993409934199342993439934499345993469934799348993499935099351993529935399354993559935699357993589935999360993619936299363993649936599366993679936899369993709937199372993739937499375993769937799378993799938099381993829938399384993859938699387993889938999390993919939299393993949939599396993979939899399994009940199402994039940499405994069940799408994099941099411994129941399414994159941699417994189941999420994219942299423994249942599426994279942899429994309943199432994339943499435994369943799438994399944099441994429944399444994459944699447994489944999450994519945299453994549945599456994579945899459994609946199462994639946499465994669946799468994699947099471994729947399474994759947699477994789947999480994819948299483994849948599486994879948899489994909949199492994939949499495994969949799498994999950099501995029950399504995059950699507995089950999510995119951299513995149951599516995179951899519995209952199522995239952499525995269952799528995299953099531995329953399534995359953699537995389953999540995419954299543995449954599546995479954899549995509955199552995539955499555995569955799558995599956099561995629956399564995659956699567995689956999570995719957299573995749957599576995779957899579995809958199582995839958499585995869958799588995899959099591995929959399594995959959699597995989959999600996019960299603996049960599606996079960899609996109961199612996139961499615996169961799618996199962099621996229962399624996259962699627996289962999630996319963299633996349963599636996379963899639996409964199642996439964499645996469964799648996499965099651996529965399654996559965699657996589965999660996619966299663996649966599666996679966899669996709967199672996739967499675996769967799678996799968099681996829968399684996859968699687996889968999690996919969299693996949969599696996979969899699997009970199702997039970499705997069970799708997099971099711997129971399714997159971699717997189971999720997219972299723997249972599726997279972899729997309973199732997339973499735997369973799738997399974099741997429974399744997459974699747997489974999750997519975299753997549975599756997579975899759997609976199762997639976499765997669976799768997699977099771997729977399774997759977699777997789977999780997819978299783997849978599786997879978899789997909979199792997939979499795997969979799798997999980099801998029980399804998059980699807998089980999810998119981299813998149981599816998179981899819998209982199822998239982499825998269982799828998299983099831998329983399834998359983699837998389983999840998419984299843998449984599846998479984899849998509985199852998539985499855998569985799858998599986099861998629986399864998659986699867998689986999870998719987299873998749987599876998779987899879998809988199882998839988499885998869988799888998899989099891998929989399894998959989699897998989989999900999019990299903999049990599906999079990899909999109991199912999139991499915999169991799918999199992099921999229992399924999259992699927999289992999930999319993299933999349993599936999379993899939999409994199942999439994499945999469994799948999499995099951999529995399954999559995699957999589995999960999619996299963999649996599966999679996899969999709997199972999739997499975999769997799978999799998099981999829998399984999859998699987999889998999990999919999299993999949999599996999979999899999100000100001100002100003100004100005100006100007100008100009100010100011100012100013100014100015100016100017100018100019100020100021100022100023100024100025100026100027100028100029100030100031100032100033100034100035100036100037100038100039100040100041100042100043100044100045100046100047100048100049100050100051100052100053100054100055100056100057100058100059100060100061100062100063100064100065100066100067100068100069100070100071100072100073100074100075100076100077100078100079100080100081100082100083100084100085100086100087100088100089100090100091100092100093100094100095100096100097100098100099100100100101100102100103100104100105100106100107100108100109100110100111100112100113100114100115100116100117100118100119100120100121100122100123100124100125100126100127100128100129100130100131100132100133100134100135100136100137100138100139100140100141100142100143100144100145100146100147100148100149100150100151100152100153100154100155100156100157100158100159100160100161100162100163100164100165100166100167100168100169100170100171100172100173100174100175100176100177100178100179100180100181100182100183100184100185100186100187100188100189100190100191100192100193100194100195100196100197100198100199100200100201100202100203100204100205100206100207100208100209100210100211100212100213100214100215100216100217100218100219100220100221100222100223100224100225100226100227100228100229100230100231100232100233100234100235100236100237100238100239100240100241100242100243100244100245100246100247100248100249100250100251100252100253100254100255100256100257100258100259100260100261100262100263100264100265100266100267100268100269100270100271100272100273100274100275100276100277100278100279100280100281100282100283100284100285100286100287100288100289100290100291100292100293100294100295100296100297100298100299100300100301100302100303100304100305100306100307100308100309100310100311100312100313100314100315100316100317100318100319100320100321100322100323100324100325100326100327100328100329100330100331100332100333100334100335100336100337100338100339100340100341100342100343100344100345100346100347100348100349100350100351100352100353100354100355100356100357100358100359100360100361100362100363100364100365100366100367100368100369100370100371100372100373100374100375100376100377100378100379100380100381100382100383100384100385100386100387100388100389100390100391100392100393100394100395100396100397100398100399100400100401100402100403100404100405100406100407100408100409100410100411100412100413100414100415100416100417100418100419100420100421100422100423100424100425100426100427100428100429100430100431100432100433100434100435100436100437100438100439100440100441100442100443100444100445100446100447100448100449100450100451100452100453100454100455100456100457100458100459100460100461100462100463100464100465100466100467100468100469100470100471100472100473100474100475100476100477100478100479100480100481100482100483100484100485100486100487100488100489100490100491100492100493100494100495100496100497100498100499100500100501100502100503100504100505100506100507100508100509100510100511100512100513100514100515100516100517100518100519100520100521100522100523100524100525100526100527100528100529100530100531100532100533100534100535100536100537100538100539100540100541100542100543100544100545100546100547100548100549100550100551100552100553100554100555100556100557100558100559100560100561100562100563100564100565100566100567100568100569100570100571100572100573100574100575100576100577100578100579100580100581100582100583100584100585100586100587100588100589100590100591100592100593100594100595100596100597100598100599100600100601100602100603100604100605100606100607100608100609100610100611100612100613100614100615100616100617100618100619100620100621100622100623100624100625100626100627100628100629100630100631100632100633100634100635100636100637100638100639100640100641100642100643100644100645100646100647100648100649100650100651100652100653100654100655100656100657100658100659100660100661100662100663100664100665100666100667100668100669100670100671100672100673100674100675100676100677100678100679100680100681100682100683100684100685100686100687100688100689100690100691100692100693100694100695100696100697100698100699100700100701100702100703100704100705100706100707100708100709100710100711100712100713100714100715100716100717100718100719100720100721100722100723100724100725100726100727100728100729100730100731100732100733100734100735100736100737100738100739100740100741100742100743100744100745100746100747100748100749100750100751100752100753100754100755100756100757100758100759100760100761100762100763100764100765100766100767100768100769100770100771100772100773100774100775100776100777100778100779100780100781100782100783100784100785100786100787100788100789100790100791100792100793100794100795100796100797100798100799100800100801100802100803100804100805100806100807100808100809100810100811100812100813100814100815100816100817100818100819100820100821100822100823100824100825100826100827100828100829100830100831100832100833100834100835100836100837100838100839100840100841100842100843100844100845100846100847100848100849100850100851100852100853100854100855100856100857100858100859100860100861100862100863100864100865100866100867100868100869100870100871100872100873100874100875100876100877100878100879100880100881100882100883100884100885100886100887100888100889100890100891100892100893100894100895100896100897100898100899100900100901100902100903100904100905100906100907100908100909100910100911100912100913100914100915100916100917100918100919100920100921100922100923100924100925100926100927100928100929100930100931100932100933100934100935100936100937100938100939100940100941100942100943100944100945100946100947100948100949100950100951100952100953100954100955100956100957100958100959100960100961100962100963100964100965100966100967100968100969100970100971100972100973100974100975100976100977100978100979100980100981100982100983100984100985100986100987100988100989100990100991100992100993100994100995100996100997100998100999101000101001101002101003101004101005101006101007101008101009101010101011101012101013101014101015101016101017101018101019101020101021101022101023101024101025101026101027101028101029101030101031101032101033101034101035101036101037101038101039101040101041101042101043101044101045101046101047101048101049101050101051101052101053101054101055101056101057101058101059101060101061101062101063101064101065101066101067101068101069101070101071101072101073101074101075101076101077101078101079101080101081101082101083101084101085101086101087101088101089101090101091101092101093101094101095101096101097101098101099101100101101101102101103101104101105101106101107101108101109101110101111101112101113101114101115101116101117101118101119101120101121101122101123101124101125101126101127101128101129101130101131101132101133101134101135101136101137101138101139101140101141101142101143101144101145101146101147101148101149101150101151101152101153101154101155101156101157101158101159101160101161101162101163101164101165101166101167101168101169101170101171101172101173101174101175101176101177101178101179101180101181101182101183101184101185101186101187101188101189101190101191101192101193101194101195101196101197101198101199101200101201101202101203101204101205101206101207101208101209101210101211101212101213101214101215101216101217101218101219101220101221101222101223101224101225101226101227101228101229101230101231101232101233101234101235101236101237101238101239101240101241101242101243101244101245101246101247101248101249101250101251101252101253101254101255101256101257101258101259101260101261101262101263101264101265101266101267101268101269101270101271101272101273101274101275101276101277101278101279101280101281101282101283101284101285101286101287101288101289101290101291101292101293101294101295101296101297101298101299101300101301101302101303101304101305101306101307101308101309101310101311101312101313101314101315101316101317101318101319101320101321101322101323101324101325101326101327101328101329101330101331101332101333101334101335101336101337101338101339101340101341101342101343101344101345101346101347101348101349101350101351101352101353101354101355101356101357101358101359101360101361101362101363101364101365101366101367101368101369101370101371101372101373101374101375101376101377101378101379101380101381101382101383101384101385101386101387101388101389101390101391101392101393101394101395101396101397101398101399101400101401101402101403101404101405101406101407101408101409101410101411101412101413101414101415101416101417101418101419101420101421101422101423101424101425101426101427101428101429101430101431101432101433101434101435101436101437101438101439101440101441101442101443101444101445101446101447101448101449101450101451101452101453101454101455101456101457101458101459101460101461101462101463101464101465101466101467101468101469101470101471101472101473101474101475101476101477101478101479101480101481101482101483101484101485101486101487101488101489101490101491101492101493101494101495101496101497101498101499101500101501101502101503101504101505101506101507101508101509101510101511101512101513101514101515101516101517101518101519101520101521101522101523101524101525101526101527101528101529101530101531101532101533101534101535101536101537101538101539101540101541101542101543101544101545101546101547101548101549101550101551101552101553101554101555101556101557101558101559101560101561101562101563101564101565101566101567101568101569101570101571101572101573101574101575101576101577101578101579101580101581101582101583101584101585101586101587101588101589101590101591101592101593101594101595101596101597101598101599101600101601101602101603101604101605101606101607101608101609101610101611101612101613101614101615101616101617101618101619101620101621101622101623101624101625101626101627101628101629101630101631101632101633101634101635101636101637101638101639101640101641101642101643101644101645101646101647101648101649101650101651101652101653101654101655101656101657101658101659101660101661101662101663101664101665101666101667101668101669101670101671101672101673101674101675101676101677101678101679101680101681101682101683101684101685101686101687101688101689101690101691101692101693101694101695101696101697101698101699101700101701101702101703101704101705101706101707101708101709101710101711101712101713101714101715101716101717101718101719101720101721101722101723101724101725101726101727101728101729101730101731101732101733101734101735101736101737101738101739101740101741101742101743101744101745101746101747101748101749101750101751101752101753101754101755101756101757101758101759101760101761101762101763101764101765101766101767101768101769101770101771101772101773101774101775101776101777101778101779101780101781101782101783101784101785101786101787101788101789101790101791101792101793101794101795101796101797101798101799101800101801101802101803101804101805101806101807101808101809101810101811101812101813101814101815101816101817101818101819101820101821101822101823101824101825101826101827101828101829101830101831101832101833101834101835101836101837101838101839101840101841101842101843101844101845101846101847101848101849101850101851101852101853101854101855101856101857101858101859101860101861101862101863101864101865101866101867101868101869101870101871101872101873101874101875101876101877101878101879101880101881101882101883101884101885101886101887101888101889101890101891101892101893101894101895101896101897101898101899101900101901101902101903101904101905101906101907101908101909101910101911101912101913101914101915101916101917101918101919101920101921101922101923101924101925101926101927101928101929101930101931101932101933101934101935101936101937101938101939101940101941101942101943101944101945101946101947101948101949101950101951101952101953101954101955101956101957101958101959101960101961101962101963101964101965101966101967101968101969101970101971101972101973101974101975101976101977101978101979101980101981101982101983101984101985101986101987101988101989101990101991101992101993101994101995101996101997101998101999102000102001102002102003102004102005102006102007102008102009102010102011102012102013102014102015102016102017102018102019102020102021102022102023102024102025102026102027102028102029102030102031102032102033102034102035102036102037102038102039102040102041102042102043102044102045102046102047102048102049102050102051102052102053102054102055102056102057102058102059102060102061102062102063102064102065102066102067102068102069102070102071102072102073102074102075102076102077102078102079102080102081102082102083102084102085102086102087102088102089102090102091102092102093102094102095102096102097102098102099102100102101102102102103102104102105102106102107102108102109102110102111102112102113102114102115102116102117102118102119102120102121102122102123102124102125102126102127102128102129102130102131102132102133102134102135102136102137102138102139102140102141102142102143102144102145102146102147102148102149102150102151102152102153102154102155102156102157102158102159102160102161102162102163102164102165102166102167102168102169102170102171102172102173102174102175102176102177102178102179102180102181102182102183102184102185102186102187102188102189102190102191102192102193102194102195102196102197102198102199102200102201102202102203102204102205102206102207102208102209102210102211102212102213102214102215102216102217102218102219102220102221102222102223102224102225102226102227102228102229102230102231102232102233102234102235102236102237102238102239102240102241102242102243102244102245102246102247102248102249102250102251102252102253102254102255102256102257102258102259102260102261102262102263102264102265102266102267102268102269102270102271102272102273102274102275102276102277102278102279102280102281102282102283102284102285102286102287102288102289102290102291102292102293102294102295102296102297102298102299102300102301102302102303102304102305102306102307102308102309102310102311102312102313102314102315102316102317102318102319102320102321102322102323102324102325102326102327102328102329102330102331102332102333102334102335102336102337102338102339102340102341102342102343102344102345102346102347102348102349102350102351102352102353102354102355102356102357102358102359102360102361102362102363102364102365102366102367102368102369102370102371102372102373102374102375102376102377102378102379102380102381102382102383102384102385102386102387102388102389102390102391102392102393102394102395102396102397102398102399102400102401102402102403102404102405102406102407102408102409102410102411102412102413102414102415102416102417102418102419102420102421102422102423102424102425102426102427102428102429102430102431102432102433102434102435102436102437102438102439102440102441102442102443102444102445102446102447102448102449102450102451102452102453102454102455102456102457102458102459102460102461102462102463102464102465102466102467102468102469102470102471102472102473102474102475102476102477102478102479102480102481102482102483102484102485102486102487102488102489102490102491102492102493102494102495102496102497102498102499102500102501102502102503102504102505102506102507102508102509102510102511102512102513102514102515102516102517102518102519102520102521102522102523102524102525102526102527102528102529102530102531102532102533102534102535102536102537102538102539102540102541102542102543102544102545102546102547102548102549102550102551102552102553102554102555102556102557102558102559102560102561102562102563102564102565102566102567102568102569102570102571102572102573102574102575102576102577102578102579102580102581102582102583102584102585102586102587102588102589102590102591102592102593102594102595102596102597102598102599102600102601102602102603102604102605102606102607102608102609102610102611102612102613102614102615102616102617102618102619102620102621102622102623102624102625102626102627102628102629102630102631102632102633102634102635102636102637102638102639102640102641102642102643102644102645102646102647102648102649102650102651102652102653102654102655102656102657102658102659102660102661102662102663102664102665102666102667102668102669102670102671102672102673102674102675102676102677102678102679102680102681102682102683102684102685102686102687102688102689102690102691102692102693102694102695102696102697102698102699102700102701102702102703102704102705102706102707102708102709102710102711102712102713102714102715102716102717102718102719102720102721102722102723102724102725102726102727102728102729102730102731102732102733102734102735102736102737102738102739102740102741102742102743102744102745102746102747102748102749102750102751102752102753102754102755102756102757102758102759102760102761102762102763102764102765102766102767102768102769102770102771102772102773102774102775102776102777102778102779102780102781102782102783102784102785102786102787102788102789102790102791102792102793102794102795102796102797102798102799102800102801102802102803102804102805102806102807102808102809102810102811102812102813102814102815102816102817102818102819102820102821102822102823102824102825102826102827102828102829102830102831102832102833102834102835102836102837102838102839102840102841102842102843102844102845102846102847102848102849102850102851102852102853102854102855102856102857102858102859102860102861102862102863102864102865102866102867102868102869102870102871102872102873102874102875102876102877102878102879102880102881102882102883102884102885102886102887102888102889102890102891102892102893102894102895102896102897102898102899102900102901102902102903102904102905102906102907102908102909102910102911102912102913102914102915102916102917102918102919102920102921102922102923102924102925102926102927102928102929102930102931102932102933102934102935102936102937102938102939102940102941102942102943102944102945102946102947102948102949102950102951102952102953102954102955102956102957102958102959102960102961102962102963102964102965102966102967102968102969102970102971102972102973102974102975102976102977102978102979102980102981102982102983102984102985102986102987102988102989102990102991102992102993102994102995102996102997102998102999103000103001103002103003103004103005103006103007103008103009103010103011103012103013103014103015103016103017103018103019103020103021103022103023103024103025103026103027103028103029103030103031103032103033103034103035103036103037103038103039103040103041103042103043103044103045103046103047103048103049103050103051103052103053103054103055103056103057103058103059103060103061103062103063103064103065103066103067103068103069103070103071103072103073103074103075103076103077103078103079103080103081103082103083103084103085103086103087103088103089103090103091103092103093103094103095103096103097103098103099103100103101103102103103103104103105103106103107103108103109103110103111103112103113103114103115103116103117103118103119103120103121103122103123103124103125103126103127103128103129103130103131103132103133103134103135103136103137103138103139103140103141103142103143103144103145103146103147103148103149103150103151103152103153103154103155103156103157103158103159103160103161103162103163103164103165103166103167103168103169103170103171103172103173103174103175103176103177103178103179103180103181103182103183103184103185103186103187103188103189103190103191103192103193103194103195103196103197103198103199103200103201103202103203103204103205103206103207103208103209103210103211103212103213103214103215103216103217103218103219103220103221103222103223103224103225103226103227103228103229103230103231103232103233103234103235103236103237103238103239103240103241103242103243103244103245103246103247103248103249103250103251103252103253103254103255103256103257103258103259103260103261103262103263103264103265103266103267103268103269103270103271103272103273103274103275103276103277103278103279103280103281103282103283103284103285103286103287103288103289103290103291103292103293103294103295103296103297103298103299103300103301103302103303103304103305103306103307103308103309103310103311103312103313103314103315103316103317103318103319103320103321103322103323103324103325103326103327103328103329103330103331103332103333103334103335103336103337103338103339103340103341103342103343103344103345103346103347103348103349103350103351103352103353103354103355103356103357103358103359103360103361103362103363103364103365103366103367103368103369103370103371103372103373103374103375103376103377103378103379103380103381103382103383103384103385103386103387103388103389103390103391103392103393103394103395103396103397103398103399103400103401103402103403103404103405103406103407103408103409103410103411103412103413103414103415103416103417103418103419103420103421103422103423103424103425103426103427103428103429103430103431103432103433103434103435103436103437103438103439103440103441103442103443103444103445103446103447103448103449103450103451103452103453103454103455103456103457103458103459103460103461103462103463103464103465103466103467103468103469103470103471103472103473103474103475103476103477103478103479103480103481103482103483103484103485103486103487103488103489103490103491103492103493103494103495103496103497103498103499103500103501103502103503103504103505103506103507103508103509103510103511103512103513103514103515103516103517103518103519103520103521103522103523103524103525103526103527103528103529103530103531103532103533103534103535103536103537103538103539103540103541103542103543103544103545103546103547103548103549103550103551103552103553103554103555103556103557103558103559103560103561103562103563103564103565103566103567103568103569103570103571103572103573103574103575103576103577103578103579103580103581103582103583103584103585103586103587103588103589103590103591103592103593103594103595103596103597103598103599103600103601103602103603103604103605103606103607103608103609103610103611103612103613103614103615103616103617103618103619103620103621103622103623103624103625103626103627103628103629103630103631103632103633103634103635103636103637103638103639103640103641103642103643103644103645103646103647103648103649103650103651103652103653103654103655103656103657103658103659103660103661103662103663103664103665103666103667103668103669103670103671103672103673103674103675103676103677103678103679103680103681103682103683103684103685103686103687103688103689103690103691103692103693103694103695103696103697103698103699103700103701103702103703103704103705103706103707103708103709103710103711103712103713103714103715103716103717103718103719103720103721103722103723103724103725103726103727103728103729103730103731103732103733103734103735103736103737103738103739103740103741103742103743103744103745103746103747103748103749103750103751103752103753103754103755103756103757103758103759103760103761103762103763103764103765103766103767103768103769103770103771103772103773103774103775103776103777103778103779103780103781103782103783103784103785103786103787103788103789103790103791103792103793103794103795103796103797103798103799103800103801103802103803103804103805103806103807103808103809103810103811103812103813103814103815103816103817103818103819103820103821103822103823103824103825103826103827103828103829103830103831103832103833103834103835103836103837103838103839103840103841103842103843103844103845103846103847103848103849103850103851103852103853103854103855103856103857103858103859103860103861103862103863103864103865103866103867103868103869103870103871103872103873103874103875103876103877103878103879103880103881103882103883103884103885103886103887103888103889103890103891103892103893103894103895103896103897103898103899103900103901103902103903103904103905103906103907103908103909103910103911103912103913103914103915103916103917103918103919103920103921103922103923103924103925103926103927103928103929103930103931103932103933103934103935103936103937103938103939103940103941103942103943103944103945103946103947103948103949103950103951103952103953103954103955103956103957103958103959103960103961103962103963103964103965103966103967103968103969103970103971103972103973103974103975103976103977103978103979103980103981103982103983103984103985103986103987103988103989103990103991103992103993103994103995103996103997103998103999104000104001104002104003104004104005104006104007104008104009104010104011104012104013104014104015104016104017104018104019104020104021104022104023104024104025104026104027104028104029104030104031104032104033104034104035104036104037104038104039104040104041104042104043104044104045104046104047104048104049104050104051104052104053104054104055104056104057104058104059104060104061104062104063104064104065104066104067104068104069104070104071104072104073104074104075104076104077104078104079104080104081104082104083104084104085104086104087104088104089104090104091104092104093104094104095104096104097104098104099104100104101104102104103104104104105104106104107104108104109104110104111104112104113104114104115104116104117104118104119104120104121104122104123104124104125104126104127104128104129104130104131104132104133104134104135104136104137104138104139104140104141104142104143104144104145104146104147104148104149104150104151104152104153104154104155104156104157104158104159104160104161104162104163104164104165104166104167104168104169104170104171104172104173104174104175104176104177104178104179104180104181104182104183104184104185104186104187104188104189104190104191104192104193104194104195104196104197104198104199104200104201104202104203104204104205104206104207104208104209104210104211104212104213104214104215104216104217104218104219104220104221104222104223104224104225104226104227104228104229104230104231104232104233104234104235104236104237104238104239104240104241104242104243104244104245104246104247104248104249104250104251104252104253104254104255104256104257104258104259104260104261104262104263104264104265104266104267104268104269104270104271104272104273104274104275104276104277104278104279104280104281104282104283104284104285104286104287104288104289104290104291104292104293104294104295104296104297104298104299104300104301104302104303104304104305104306104307104308104309104310104311104312104313104314104315104316104317104318104319104320104321104322104323104324104325104326104327104328104329104330104331104332104333104334104335104336104337104338104339104340104341104342104343104344104345104346104347104348104349104350104351104352104353104354104355104356104357104358104359104360104361104362104363104364104365104366104367104368104369104370104371104372104373104374104375104376104377104378104379104380104381104382104383104384104385104386104387104388104389104390104391104392104393104394104395104396104397104398104399104400104401104402104403104404104405104406104407104408104409104410104411104412104413104414104415104416104417104418104419104420104421104422104423104424104425104426104427104428104429104430104431104432104433104434104435104436104437104438104439104440104441104442104443104444104445104446104447104448104449104450104451104452104453104454104455104456104457104458104459104460104461104462104463104464104465104466104467104468104469104470104471104472104473104474104475104476104477104478104479104480104481104482104483104484104485104486104487104488104489104490104491104492104493104494104495104496104497104498104499104500104501104502104503104504104505104506104507104508104509104510104511104512104513104514104515104516104517104518104519104520104521104522104523104524104525104526104527104528104529104530104531104532104533104534104535104536104537104538104539104540104541104542104543104544104545104546104547104548104549104550104551104552104553104554104555104556104557104558104559104560104561104562104563104564104565104566104567104568104569104570104571104572104573104574104575104576104577104578104579104580104581104582104583104584104585104586104587104588104589104590104591104592104593104594104595104596104597104598104599104600104601104602104603104604104605104606104607104608104609104610104611104612104613104614104615104616104617104618104619104620104621104622104623104624104625104626104627104628104629104630104631104632104633104634104635104636104637104638104639104640104641104642104643104644104645104646104647104648104649104650104651104652104653104654104655104656104657104658104659104660104661104662104663104664104665104666104667104668104669104670104671104672104673104674104675104676104677104678104679104680104681104682104683104684104685104686104687104688104689104690104691104692104693104694104695104696104697104698104699104700104701104702104703104704104705104706104707104708104709104710104711104712104713104714104715104716104717104718104719104720104721104722104723104724104725104726104727104728104729104730104731104732104733104734104735104736104737104738104739104740104741104742104743104744104745104746104747104748104749104750104751104752104753104754104755104756104757104758104759104760104761104762104763104764104765104766104767104768104769104770104771104772104773104774104775104776104777104778104779104780104781104782104783104784104785104786104787104788104789104790104791104792104793104794104795104796104797104798104799104800104801104802104803104804104805104806104807104808104809104810104811104812104813104814104815104816104817104818104819104820104821104822104823104824104825104826104827104828104829104830104831104832104833104834104835104836104837104838104839104840104841104842104843104844104845104846104847104848104849104850104851104852104853104854104855104856104857104858104859104860104861104862104863104864104865104866104867104868104869104870104871104872104873104874104875104876104877104878104879104880104881104882104883104884104885104886104887104888104889104890104891104892104893104894104895104896104897104898104899104900104901104902104903104904104905104906104907104908104909104910104911104912104913104914104915104916104917104918104919104920104921104922104923104924104925104926104927104928104929104930104931104932104933104934104935104936104937104938104939104940104941104942104943104944104945104946104947104948104949104950104951104952104953104954104955104956104957104958104959104960104961104962104963104964104965104966104967104968104969104970104971104972104973104974104975104976104977104978104979104980104981104982104983104984104985104986104987104988104989104990104991104992104993104994104995104996104997104998104999105000105001105002105003105004105005105006105007105008105009105010105011105012105013105014105015105016105017105018105019105020105021105022105023105024105025105026105027105028105029105030105031105032105033105034105035105036105037105038105039105040105041105042105043105044105045105046105047105048105049105050105051105052105053105054105055105056105057105058105059105060105061105062105063105064105065105066105067105068105069105070105071105072105073105074105075105076105077105078105079105080105081105082105083105084105085105086105087105088105089105090105091105092105093105094105095105096105097105098105099105100105101105102105103105104105105105106105107105108105109105110105111105112105113105114105115105116105117105118105119105120105121105122105123105124105125105126105127105128105129105130105131105132105133105134105135105136105137105138105139105140105141105142105143105144105145105146105147105148105149105150105151105152105153105154105155105156105157105158105159105160105161105162105163105164105165105166105167105168105169105170105171105172105173105174105175105176105177105178105179105180105181105182105183105184105185105186105187105188105189105190105191105192105193105194105195105196105197105198105199105200105201105202105203105204105205105206105207105208105209105210105211105212105213105214105215105216105217105218105219105220105221105222105223105224105225105226105227105228105229105230105231105232105233105234105235105236105237105238105239105240105241105242105243105244105245105246105247105248105249105250105251105252105253105254105255105256105257105258105259105260105261105262105263105264105265105266105267105268105269105270105271105272105273105274105275105276105277105278105279105280105281105282105283105284105285105286105287105288105289105290105291105292105293105294105295105296105297105298105299105300105301105302105303105304105305105306105307105308105309105310105311105312105313105314105315105316105317105318105319105320105321105322105323105324105325105326105327105328105329105330105331105332105333105334105335105336105337105338105339105340105341105342105343105344105345105346105347105348105349105350105351105352105353105354105355105356105357105358105359105360105361105362105363105364105365105366105367105368105369105370105371105372105373105374105375105376105377105378105379105380105381105382105383105384105385105386105387105388105389105390105391105392105393105394105395105396105397105398105399105400105401105402105403105404105405105406105407105408105409105410105411105412105413105414105415105416105417105418105419105420105421105422105423105424105425105426105427105428105429105430105431105432105433105434105435105436105437105438105439105440105441105442105443105444105445105446105447105448105449105450105451105452105453105454105455105456105457105458105459105460105461105462105463105464105465105466105467105468105469105470105471105472105473105474105475105476105477105478105479105480105481105482105483105484105485105486105487105488105489105490105491105492105493105494105495105496105497105498105499105500105501105502105503105504105505105506105507105508105509105510105511105512105513105514105515105516105517105518105519105520105521105522105523105524105525105526105527105528105529105530105531105532105533105534105535105536105537105538105539105540105541105542105543105544105545105546105547105548105549105550105551105552105553105554105555105556105557105558105559105560105561105562105563105564105565105566105567105568105569105570105571105572105573105574105575105576105577105578105579105580105581105582105583105584105585105586105587105588105589105590105591105592105593105594105595105596105597105598105599105600105601105602105603105604105605105606105607105608105609105610105611105612105613105614105615105616105617105618105619105620105621105622105623105624105625105626105627105628105629105630105631105632105633105634105635105636105637105638105639105640105641105642105643105644105645105646105647105648105649105650105651105652105653105654105655105656105657105658105659105660105661105662105663105664105665105666105667105668105669105670105671105672105673105674105675105676105677105678105679105680105681105682105683105684105685105686105687105688105689105690105691105692105693105694105695105696105697105698105699105700105701105702105703105704105705105706105707105708105709105710105711105712105713105714105715105716105717105718105719105720105721105722105723105724105725105726105727105728105729105730105731105732105733105734105735105736105737105738105739105740105741105742105743105744105745105746105747105748105749105750105751105752105753105754105755105756105757105758105759105760105761105762105763105764105765105766105767105768105769105770105771105772105773105774105775105776105777105778105779105780105781105782105783105784105785105786105787105788105789105790105791105792105793105794105795105796105797105798105799105800105801105802105803105804105805105806105807105808105809105810105811105812105813105814105815105816105817105818105819105820105821105822105823105824105825105826105827105828105829105830105831105832105833105834105835105836105837105838105839105840105841105842105843105844105845105846105847105848105849105850105851105852105853105854105855105856105857105858105859105860105861105862105863105864105865105866105867105868105869105870105871105872105873105874105875105876105877105878105879105880105881105882105883105884105885105886105887105888105889105890105891105892105893105894105895105896105897105898105899105900105901105902105903105904105905105906105907105908105909105910105911105912105913105914105915105916105917105918105919105920105921105922105923105924105925105926105927105928105929105930105931105932105933105934105935105936105937105938105939105940105941105942105943105944105945105946105947105948105949105950105951105952105953105954105955105956105957105958105959105960105961105962105963105964105965105966105967105968105969105970105971105972105973105974105975105976105977105978105979105980105981105982105983105984105985105986105987105988105989105990105991105992105993105994105995105996105997105998105999106000106001106002106003106004106005106006106007106008106009106010106011106012106013106014106015106016106017106018106019106020106021106022106023106024106025106026106027106028106029106030106031106032106033106034106035106036106037106038106039106040106041106042106043106044106045106046106047106048106049106050106051106052106053106054106055106056106057106058106059106060106061106062106063106064106065106066106067106068106069106070106071106072106073106074106075106076106077106078106079106080106081106082106083106084106085106086106087106088106089106090106091106092106093106094106095106096106097106098106099106100106101106102106103106104106105106106106107106108106109106110106111106112106113106114106115106116106117106118106119106120106121106122106123106124106125106126106127106128106129106130106131106132106133106134106135106136106137106138106139106140106141106142106143106144106145106146106147106148106149106150106151106152106153106154106155106156106157106158106159106160106161106162106163106164106165106166106167106168106169106170106171106172106173106174106175106176106177106178106179106180106181106182106183106184106185106186106187106188106189106190106191106192106193106194106195106196106197106198106199106200106201106202106203106204106205106206106207106208106209106210106211106212106213106214106215106216106217106218106219106220106221106222106223106224106225106226106227106228106229106230106231106232106233106234106235106236106237106238106239106240106241106242106243106244106245106246106247106248106249106250106251106252106253106254106255106256106257106258106259106260106261106262106263106264106265106266106267106268106269106270106271106272106273106274106275106276106277106278106279106280106281106282106283106284106285106286106287106288106289106290106291106292106293106294106295106296106297106298106299106300106301106302106303106304106305106306106307106308106309106310106311106312106313106314106315106316106317106318106319106320106321106322106323106324106325106326106327106328106329106330106331106332106333106334106335106336106337106338106339106340106341106342106343106344106345106346106347106348106349106350106351106352106353106354106355106356106357106358106359106360106361106362106363106364106365106366106367106368106369106370106371106372106373106374106375106376106377106378106379106380106381106382106383106384106385106386106387106388106389106390106391106392106393106394106395106396106397106398106399106400106401106402106403106404106405106406106407106408106409106410106411106412106413106414106415106416106417106418106419106420106421106422106423106424106425106426106427106428106429106430106431106432106433106434106435106436106437106438106439106440106441106442106443106444106445106446106447106448106449106450106451106452106453106454106455106456106457106458106459106460106461106462106463106464106465106466106467106468106469106470106471106472106473106474106475106476106477106478106479106480106481106482106483106484106485106486106487106488106489106490106491106492106493106494106495106496106497106498106499106500106501106502106503106504106505106506106507106508106509106510106511106512106513106514106515106516106517106518106519106520106521106522106523106524106525106526106527106528106529106530106531106532106533106534106535106536106537106538106539106540106541106542106543106544106545106546106547106548106549106550106551106552106553106554106555106556106557106558106559106560106561106562106563106564106565106566106567106568106569106570106571106572106573106574106575106576106577106578106579106580106581106582106583106584106585106586106587106588106589106590106591106592106593106594106595106596106597106598106599106600106601106602106603106604106605106606106607106608106609106610106611106612106613106614106615106616106617106618106619106620106621106622106623106624106625106626106627106628106629106630106631106632106633106634106635106636106637106638106639106640106641106642106643106644106645106646106647106648106649106650106651106652106653106654106655106656106657106658106659106660106661106662106663106664106665106666106667106668106669106670106671106672106673106674106675106676106677106678106679106680106681106682106683106684106685106686106687106688106689106690106691106692106693106694106695106696106697106698106699106700106701106702106703106704106705106706106707106708106709106710106711106712106713106714106715106716106717106718106719106720106721106722106723106724106725106726106727106728106729106730106731106732106733106734106735106736106737106738106739106740106741106742106743106744106745106746106747106748106749106750106751106752106753106754106755106756106757106758106759106760106761106762106763106764106765106766106767106768106769106770106771106772106773106774106775106776106777106778106779106780106781106782106783106784106785106786106787106788106789106790106791106792106793106794106795106796106797106798106799106800106801106802106803106804106805106806106807106808106809106810106811106812106813106814106815106816106817106818106819106820106821106822106823106824106825106826106827106828106829106830106831106832106833106834106835106836106837106838106839106840106841106842106843106844106845106846106847106848106849106850106851106852106853106854106855106856106857106858106859106860106861106862106863106864106865106866106867106868106869106870106871106872106873106874106875106876106877106878106879106880106881106882106883106884106885106886106887106888106889106890106891106892106893106894106895106896106897106898106899106900106901106902106903106904106905106906106907106908106909106910106911106912106913106914106915106916106917106918106919106920106921106922106923106924106925106926106927106928106929106930106931106932106933106934106935106936106937106938106939106940106941106942106943106944106945106946106947106948106949106950106951106952106953106954106955106956106957106958106959106960106961106962106963106964106965106966106967106968106969106970106971106972106973106974106975106976106977106978106979106980106981106982106983106984106985106986106987106988106989106990106991106992106993106994106995106996106997106998106999107000107001107002107003107004107005107006107007107008107009107010107011107012107013107014107015107016107017107018107019107020107021107022107023107024107025107026107027107028107029107030107031107032107033107034107035107036107037107038107039107040107041107042107043107044107045107046107047107048107049107050107051107052107053107054107055107056107057107058107059107060107061107062107063107064107065107066107067107068107069107070107071107072107073107074107075107076107077107078107079107080107081107082107083107084107085107086107087107088107089107090107091107092107093107094107095107096107097107098107099107100107101107102107103107104107105107106107107107108107109107110107111107112107113107114107115107116107117107118107119107120107121107122107123107124107125107126107127107128107129107130107131107132107133107134107135107136107137107138107139107140107141107142107143107144107145107146107147107148107149107150107151107152107153107154107155107156107157107158107159107160107161107162107163107164107165107166107167107168107169107170107171107172107173107174107175107176107177107178107179107180107181107182107183107184107185107186107187107188107189107190107191107192107193107194107195107196107197107198107199107200107201107202107203107204107205107206107207107208107209107210107211107212107213107214107215107216107217107218107219107220107221107222107223107224107225107226107227107228107229107230107231107232107233107234107235107236107237107238107239107240107241107242107243107244107245107246107247107248107249107250107251107252107253107254107255107256107257107258107259107260107261107262107263107264107265107266107267107268107269107270107271107272107273107274107275107276107277107278107279107280107281107282107283107284107285107286107287107288107289107290107291107292107293107294107295107296107297107298107299107300107301107302107303107304107305107306107307107308107309107310107311107312107313107314107315107316107317107318107319107320107321107322107323107324107325107326107327107328107329107330107331107332107333107334107335107336107337107338107339107340107341107342107343107344107345107346107347107348107349107350107351107352107353107354107355107356107357107358107359107360107361107362107363107364107365107366107367107368107369107370107371107372107373107374107375107376107377107378107379107380107381107382107383107384107385107386107387107388107389107390107391107392107393107394107395107396107397107398107399107400107401107402107403107404107405107406107407107408107409107410107411107412107413107414107415107416107417107418107419107420107421107422107423107424107425107426107427107428107429107430107431107432107433107434107435107436107437107438107439107440107441107442107443107444107445107446107447107448107449107450107451107452107453107454107455107456107457107458107459107460107461107462107463107464107465107466107467107468107469107470107471107472107473107474107475107476107477107478107479107480107481107482107483107484107485107486107487107488107489107490107491107492107493107494107495107496107497107498107499107500107501107502107503107504107505107506107507107508107509107510107511107512107513107514107515107516107517107518107519107520107521107522107523107524107525107526107527107528107529107530107531107532107533107534107535107536107537107538107539107540107541107542107543107544107545107546107547107548107549107550107551107552107553107554107555107556107557107558107559107560107561107562107563107564107565107566107567107568107569107570107571107572107573107574107575107576107577107578107579107580107581107582107583107584107585107586107587107588107589107590107591107592107593107594107595107596107597107598107599107600107601107602107603107604107605107606107607107608107609107610107611107612107613107614107615107616107617107618107619107620107621107622107623107624107625107626107627107628107629107630107631107632107633107634107635107636107637107638107639107640107641107642107643107644107645107646107647107648107649107650107651107652107653107654107655107656107657107658107659107660107661107662107663107664107665107666107667107668107669107670107671107672107673107674107675107676107677107678107679107680107681107682107683107684107685107686107687107688107689107690107691107692107693107694107695107696107697107698107699107700107701107702107703107704107705107706107707107708107709107710107711107712107713107714107715107716107717107718107719107720107721107722107723107724107725107726107727107728107729107730107731107732107733107734107735107736107737107738107739107740107741107742107743107744107745107746107747107748107749107750107751107752107753107754107755107756107757107758107759107760107761107762107763107764107765107766107767107768107769107770107771107772107773107774107775107776107777107778107779107780107781107782107783107784107785107786107787107788107789107790107791107792107793107794107795107796107797107798107799107800107801107802107803107804107805107806107807107808107809107810107811107812107813107814107815107816107817107818107819107820107821107822107823107824107825107826107827107828107829107830107831107832107833107834107835107836107837107838107839107840107841107842107843107844107845107846107847107848107849107850107851107852107853107854107855107856107857107858107859107860107861107862107863107864107865107866107867107868107869107870107871107872107873107874107875107876107877107878107879107880107881107882107883107884107885107886107887107888107889107890107891107892107893107894107895107896107897107898107899107900107901107902107903107904107905107906107907107908107909107910107911107912107913107914107915107916107917107918107919107920107921107922107923107924107925107926107927107928107929107930107931107932107933107934107935107936107937107938107939107940107941107942107943107944107945107946107947107948107949107950107951107952107953107954107955107956107957107958107959107960107961107962107963107964107965107966107967107968107969107970107971107972107973107974107975107976107977107978107979107980107981107982107983107984107985107986107987107988107989107990107991107992107993107994107995107996107997107998107999108000108001108002108003108004108005108006108007108008108009108010108011108012108013108014108015108016108017108018108019108020108021108022108023108024108025108026108027108028108029108030108031108032108033108034108035108036108037108038108039108040108041108042108043108044108045108046108047108048108049108050108051108052108053108054108055108056108057108058108059108060108061108062108063108064108065108066108067108068108069108070108071108072108073108074108075108076108077108078108079108080108081108082108083108084108085108086108087108088108089108090108091108092108093108094108095108096108097108098108099108100108101108102108103108104108105108106108107108108108109108110108111108112108113108114108115108116108117108118108119108120108121108122108123108124108125108126108127108128108129108130108131108132108133108134108135108136108137108138108139108140108141108142108143108144108145108146108147108148108149108150108151108152108153108154108155108156108157108158108159108160108161108162108163108164108165108166108167108168108169108170108171108172108173108174108175108176108177108178108179108180108181108182108183108184108185108186108187108188108189108190108191108192108193108194108195108196108197108198108199108200108201108202108203108204108205108206108207108208108209108210108211108212108213108214108215108216108217108218108219108220108221108222108223108224108225108226108227108228108229108230108231108232108233108234108235108236108237108238108239108240108241108242108243108244108245108246108247108248108249108250108251108252108253108254108255108256108257108258108259108260108261108262108263108264108265108266108267108268108269108270108271108272108273108274108275108276108277108278108279108280108281108282108283108284108285108286108287108288108289108290108291108292108293108294108295108296108297108298108299108300108301108302108303108304108305108306108307108308108309108310108311108312108313108314108315108316108317108318108319108320108321108322108323108324108325108326108327108328108329108330108331108332108333108334108335108336108337108338108339108340108341108342108343108344108345108346108347108348108349108350108351108352108353108354108355108356108357108358108359108360108361108362108363108364108365108366108367108368108369108370108371108372108373108374108375108376108377108378108379108380108381108382108383108384108385108386108387108388108389108390108391108392108393108394108395108396108397108398108399108400108401108402108403108404108405108406108407108408108409108410108411108412108413108414108415108416108417108418108419108420108421108422108423108424108425108426108427108428108429108430108431108432108433108434108435108436108437108438108439108440108441108442108443108444108445108446108447108448108449108450108451108452108453108454108455108456108457108458108459108460108461108462108463108464108465108466108467108468108469108470108471108472108473108474108475108476108477108478108479108480108481108482108483108484108485108486108487108488108489108490108491108492108493108494108495108496108497108498108499108500108501108502108503108504108505108506108507108508108509108510108511108512108513108514108515108516108517108518108519108520108521108522108523108524108525108526108527108528108529108530108531108532108533108534108535108536108537108538108539108540108541108542108543108544108545108546108547108548108549108550108551108552108553108554108555108556108557108558108559108560108561108562108563108564108565108566108567108568108569108570108571108572108573108574108575108576108577108578108579108580108581108582108583108584108585108586108587108588108589108590108591108592108593108594108595108596108597108598108599108600108601108602108603108604108605108606108607108608108609108610108611108612108613108614108615108616108617108618108619108620108621108622108623108624108625108626108627108628108629108630108631108632108633108634108635108636108637108638108639108640108641108642108643108644108645108646108647108648108649108650108651108652108653108654108655108656108657108658108659108660108661108662108663108664108665108666108667108668108669108670108671108672108673108674108675108676108677108678108679108680108681108682108683108684108685108686108687108688108689108690108691108692108693108694108695108696108697108698108699108700108701108702108703108704108705108706108707108708108709108710108711108712108713108714108715108716108717108718108719108720108721108722108723108724108725108726108727108728108729108730108731108732108733108734108735108736108737108738108739108740108741108742108743108744108745108746108747108748108749108750108751108752108753108754108755108756108757108758108759108760108761108762108763108764108765108766108767108768108769108770108771108772108773108774108775108776108777108778108779108780108781108782108783108784108785108786108787108788108789108790108791108792108793108794108795108796108797108798108799108800108801108802108803108804108805108806108807108808108809108810108811108812108813108814108815108816108817108818108819108820108821108822108823108824108825108826108827108828108829108830108831108832108833108834108835108836108837108838108839108840108841108842108843108844108845108846108847108848108849108850108851108852108853108854108855108856108857108858108859108860108861108862108863108864108865108866108867108868108869108870108871108872108873108874108875108876108877108878108879108880108881108882108883108884108885108886108887108888108889108890108891108892108893108894108895108896108897108898108899108900108901108902108903108904108905108906108907108908108909108910108911108912108913108914108915108916108917108918108919108920108921108922108923108924108925108926108927108928108929108930108931108932108933108934108935108936108937108938108939108940108941108942108943108944108945108946108947108948108949108950108951108952108953108954108955108956108957108958108959108960108961108962108963108964108965108966108967108968108969108970108971108972108973108974108975108976108977108978108979108980108981108982108983108984108985108986108987108988108989108990108991108992108993108994108995108996108997108998108999109000109001109002109003109004109005109006109007109008109009109010109011109012109013109014109015109016109017109018109019109020109021109022109023109024109025109026109027109028109029109030109031109032109033109034109035109036109037109038109039109040109041109042109043109044109045109046109047109048109049109050109051109052109053109054109055109056109057109058109059109060109061109062109063109064109065109066109067109068109069109070109071109072109073109074109075109076109077109078109079109080109081109082109083109084109085109086109087109088109089109090109091109092109093109094109095109096109097109098109099109100109101109102109103109104109105109106109107109108109109109110109111109112109113109114109115109116109117109118109119109120109121109122109123109124109125109126109127109128109129109130109131109132109133109134109135109136109137109138109139109140109141109142109143109144109145109146109147109148109149109150109151109152109153109154109155109156109157109158109159109160109161109162109163109164109165109166109167109168109169109170109171109172109173109174109175109176109177109178109179109180109181109182109183109184109185109186109187109188109189109190109191109192109193109194109195109196109197109198109199109200109201109202109203109204109205109206109207109208109209109210109211109212109213109214109215109216109217109218109219109220109221109222109223109224109225109226109227109228109229109230109231109232109233109234109235109236109237109238109239109240109241109242109243109244109245109246109247109248109249109250109251109252109253109254109255109256109257109258109259109260109261109262109263109264109265109266109267109268109269109270109271109272109273109274109275109276109277109278109279109280109281109282109283109284109285109286109287109288109289109290109291109292109293109294109295109296109297109298109299109300109301109302109303109304109305109306109307109308109309109310109311109312109313109314109315109316109317109318109319109320109321109322109323109324109325109326109327109328109329109330109331109332109333109334109335109336109337109338109339109340109341109342109343109344109345109346109347109348109349109350109351109352109353109354109355109356109357109358109359109360109361109362109363109364109365109366109367109368109369109370109371109372109373109374109375109376109377109378109379109380109381109382109383109384109385109386109387109388109389109390109391109392109393109394109395109396109397109398109399109400109401109402109403109404109405109406109407109408109409109410109411109412109413109414109415109416109417109418109419109420109421109422109423109424109425109426109427109428109429109430109431109432109433109434109435109436109437109438109439109440109441109442109443109444109445109446109447109448109449109450109451109452109453109454109455109456109457109458109459109460109461109462109463109464109465109466109467109468109469109470109471109472109473109474109475109476109477109478109479109480109481109482109483109484109485109486109487109488109489109490109491109492109493109494109495109496109497109498109499109500109501109502109503109504109505109506109507109508109509109510109511109512109513109514109515109516109517109518109519109520109521109522109523109524109525109526109527109528109529109530109531109532109533109534109535109536109537109538109539109540109541109542109543109544109545109546109547109548109549109550109551109552109553109554109555109556109557109558109559109560109561109562109563109564109565109566109567109568109569109570109571109572109573109574109575109576109577109578109579109580109581109582109583109584109585109586109587109588109589109590109591109592109593109594109595109596109597109598109599109600109601109602109603109604109605109606109607109608109609109610109611109612109613109614109615109616109617109618109619109620109621109622109623109624109625109626109627109628109629109630109631109632109633109634109635109636109637109638109639109640109641109642109643109644109645109646109647109648109649109650109651109652109653109654109655109656109657109658109659109660109661109662109663109664109665109666109667109668109669109670109671109672109673109674109675109676109677109678109679109680109681109682109683109684109685109686109687109688109689109690109691109692109693109694109695109696109697109698109699109700109701109702109703109704109705109706109707109708109709109710109711109712109713109714109715109716109717109718109719109720109721109722109723109724109725109726109727109728109729109730109731109732109733109734109735109736109737109738109739109740109741109742109743109744109745109746109747109748109749109750109751109752109753109754109755109756109757109758109759109760109761109762109763109764109765109766109767109768109769109770109771109772109773109774109775109776109777109778109779109780109781109782109783109784109785109786109787109788109789109790109791109792109793109794109795109796109797109798109799109800109801109802109803109804109805109806109807109808109809109810109811109812109813109814109815109816109817109818109819109820109821109822109823109824109825109826109827109828109829109830109831109832109833109834109835109836109837109838109839109840109841109842109843109844109845109846109847109848109849109850109851109852109853109854109855109856109857109858109859109860109861109862109863109864109865109866109867109868109869109870109871109872109873109874109875109876109877109878109879109880109881109882109883109884109885109886109887109888109889109890109891109892109893109894109895109896109897109898109899109900109901109902109903109904109905109906109907109908109909109910109911109912109913109914109915109916109917109918109919109920109921109922109923109924109925109926109927109928109929109930109931109932109933109934109935109936109937109938109939109940109941109942109943109944109945109946109947109948109949109950109951109952109953109954109955109956109957109958109959109960109961109962109963109964109965109966109967109968109969109970109971109972109973109974109975109976109977109978109979109980109981109982109983109984109985109986109987109988109989109990109991109992109993109994109995109996109997109998109999110000110001110002110003110004110005110006110007110008110009110010110011110012110013110014110015110016110017110018110019110020110021110022110023110024110025110026110027110028110029110030110031110032110033110034110035110036110037110038110039110040110041110042110043110044110045110046110047110048110049110050110051110052110053110054110055110056110057110058110059110060110061110062110063110064110065110066110067110068110069110070110071110072110073110074110075110076110077110078110079110080110081110082110083110084110085110086110087110088110089110090110091110092110093110094110095110096110097110098110099110100110101110102110103110104110105110106110107110108110109110110110111110112110113110114110115110116110117110118110119110120110121110122110123110124110125110126110127110128110129110130110131110132110133110134110135110136110137110138110139110140110141110142110143110144110145110146110147110148110149110150110151110152110153110154110155110156110157110158110159110160110161110162110163110164110165110166110167110168110169110170110171110172110173110174110175110176110177110178110179110180110181110182110183110184110185110186110187110188110189110190110191110192110193110194110195110196110197110198110199110200110201110202110203110204110205110206110207110208110209110210110211110212110213110214110215110216110217110218110219110220110221110222110223110224110225110226110227110228110229110230110231110232110233110234110235110236110237110238110239110240110241110242110243110244110245110246110247110248110249110250110251110252110253110254110255110256110257110258110259110260110261110262110263110264110265110266110267110268110269110270110271110272110273110274110275110276110277110278110279110280110281110282110283110284110285110286110287110288110289110290110291110292110293110294110295110296110297110298110299110300110301110302110303110304110305110306110307110308110309110310110311110312110313110314110315110316110317110318110319110320110321110322110323110324110325110326110327110328110329110330110331110332110333110334110335110336110337110338110339110340110341110342110343110344110345110346110347110348110349110350110351110352110353110354110355110356110357110358110359110360110361110362110363110364110365110366110367110368110369110370110371110372110373110374110375110376110377110378110379110380110381110382110383110384110385110386110387110388110389110390110391110392110393110394110395110396110397110398110399110400110401110402110403110404110405110406110407110408110409110410110411110412110413110414110415110416110417110418110419110420110421110422110423110424110425110426110427110428110429110430110431110432110433110434110435110436110437110438110439110440110441110442110443110444110445110446110447110448110449110450110451110452110453110454110455110456110457110458110459110460110461110462110463110464110465110466110467110468110469110470110471110472110473110474110475110476110477110478110479110480110481110482110483110484110485110486110487110488110489110490110491110492110493110494110495110496110497110498110499110500110501110502110503110504110505110506110507110508110509110510110511110512110513110514110515110516110517110518110519110520110521110522110523110524110525110526110527110528110529110530110531110532110533110534110535110536110537110538110539110540110541110542110543110544110545110546110547110548110549110550110551110552110553110554110555110556110557110558110559110560110561110562110563110564110565110566110567110568110569110570110571110572110573110574110575110576110577110578110579110580110581110582110583110584110585110586110587110588110589110590110591110592110593110594110595110596110597110598110599110600110601110602110603110604110605110606110607110608110609110610110611110612110613110614110615110616110617110618110619110620110621110622110623110624110625110626110627110628110629110630110631110632110633110634110635110636110637110638110639110640110641110642110643110644110645110646110647110648110649110650110651110652110653110654110655110656110657110658110659110660110661110662110663110664110665110666110667110668110669110670110671110672110673110674110675110676110677110678110679110680110681110682110683110684110685110686110687110688110689110690110691110692110693110694110695110696110697110698110699110700110701110702110703110704110705110706110707110708110709110710110711110712110713110714110715110716110717110718110719110720110721110722110723110724110725110726110727110728110729110730110731110732110733110734110735110736110737110738110739110740110741110742110743110744110745110746110747110748110749110750110751110752110753110754110755110756110757110758110759110760110761110762110763110764110765110766110767110768110769110770110771110772110773110774110775110776110777110778110779110780110781110782110783110784110785110786110787110788110789110790110791110792110793110794110795110796110797110798110799110800110801110802110803110804110805110806110807110808110809110810110811110812110813110814110815110816110817110818110819110820110821110822110823110824110825110826110827110828110829110830110831110832110833110834110835110836110837110838110839110840110841110842110843110844110845110846110847110848110849110850110851110852110853110854110855110856110857110858110859110860110861110862110863110864110865110866110867110868110869110870110871110872110873110874110875110876110877110878110879110880110881110882110883110884110885110886110887110888110889110890110891110892110893110894110895110896110897110898110899110900110901110902110903110904110905110906110907110908110909110910110911110912110913110914110915110916110917110918110919110920110921110922110923110924110925110926110927110928110929110930110931110932110933110934110935110936110937110938110939110940110941110942110943110944110945110946110947110948110949110950110951110952110953110954110955110956110957110958110959110960110961110962110963110964110965110966110967110968110969110970110971110972110973110974110975110976110977110978110979110980110981110982110983110984110985110986110987110988110989110990110991110992110993110994110995110996110997110998110999111000111001111002111003111004111005111006111007111008111009111010111011111012111013111014111015111016111017111018111019111020111021111022111023111024111025111026111027111028111029111030111031111032111033111034111035111036111037111038111039111040111041111042111043111044111045111046111047111048111049111050111051111052111053111054111055111056111057111058111059111060111061111062111063111064111065111066111067111068111069111070111071111072111073111074111075111076111077111078111079111080111081111082111083111084111085111086111087111088111089111090111091111092111093111094111095111096111097111098111099111100111101111102111103111104111105111106111107111108111109111110111111111112111113111114111115111116111117111118111119111120111121111122111123111124111125111126111127111128111129111130111131111132111133111134111135111136111137111138111139111140111141111142111143111144111145111146111147111148111149111150111151111152111153111154111155111156111157111158111159111160111161111162111163111164111165111166111167111168111169111170111171111172111173111174111175111176111177111178111179111180111181111182111183111184111185111186111187111188111189111190111191111192111193111194111195111196111197111198111199111200111201111202111203111204111205111206111207111208111209111210111211111212111213111214111215111216111217111218111219111220111221111222111223111224111225111226111227111228111229111230111231111232111233111234111235111236111237111238111239111240111241111242111243111244111245111246111247111248111249111250111251111252111253111254111255111256111257111258111259111260111261111262111263111264111265111266111267111268111269111270111271111272111273111274111275111276111277111278111279111280111281111282111283111284111285111286111287111288111289111290111291111292111293111294111295111296111297111298111299111300111301111302111303111304111305111306111307111308111309111310111311111312111313111314111315111316111317111318111319111320111321111322111323111324111325111326111327111328111329111330111331111332111333111334111335111336111337111338111339111340111341111342111343111344111345111346111347111348111349111350111351111352111353111354111355111356111357111358111359111360111361111362111363111364111365111366111367111368111369111370111371111372111373111374111375111376111377111378111379111380111381111382111383111384111385111386111387111388111389111390111391111392111393111394111395111396111397111398111399111400111401111402111403111404111405111406111407111408111409111410111411111412111413111414111415111416111417111418111419111420111421111422111423111424111425111426111427111428111429111430111431111432111433111434111435111436111437111438111439111440111441111442111443111444111445111446111447111448111449111450111451111452111453111454111455111456111457111458111459111460111461111462111463111464111465111466111467111468111469111470111471111472111473111474111475111476111477111478111479111480111481111482111483111484111485111486111487111488111489111490111491111492111493111494111495111496111497111498111499111500111501111502111503111504111505111506111507111508111509111510111511111512111513111514111515111516111517111518111519111520111521111522111523111524111525111526111527111528111529111530111531111532111533111534111535111536111537111538111539111540111541111542111543111544111545111546111547111548111549111550111551111552111553111554111555111556111557111558111559111560111561111562111563111564111565111566111567111568111569111570111571111572111573111574111575111576111577111578111579111580111581111582111583111584111585111586111587111588111589111590111591111592111593111594111595111596111597111598111599111600111601111602111603111604111605111606111607111608111609111610111611111612111613111614111615111616111617111618111619111620111621111622111623111624111625111626111627111628111629111630111631111632111633111634111635111636111637111638111639111640111641111642111643111644111645111646111647111648111649111650111651111652111653111654111655111656111657111658111659111660111661111662111663111664111665111666111667111668111669111670111671111672111673111674111675111676111677111678111679111680111681111682111683111684111685111686111687111688111689111690111691111692111693111694111695111696111697111698111699111700111701111702111703111704111705111706111707111708111709111710111711111712111713111714111715111716111717111718111719111720111721111722111723111724111725111726111727111728111729111730111731111732111733111734111735111736111737111738111739111740111741111742111743111744111745111746111747111748111749111750111751111752111753111754111755111756111757111758111759111760111761111762111763111764111765111766111767111768111769111770111771111772111773111774111775111776111777111778111779111780111781111782111783111784111785111786111787111788111789111790111791111792111793111794111795111796111797111798111799111800111801111802111803111804111805111806111807111808111809111810111811111812111813111814111815111816111817111818111819111820111821111822111823111824111825111826111827111828111829111830111831111832111833111834111835111836111837111838111839111840111841111842111843111844111845111846111847111848111849111850111851111852111853111854111855111856111857111858111859111860111861111862111863111864111865111866111867111868111869111870111871111872111873111874111875111876111877111878111879111880111881111882111883111884111885111886111887111888111889111890111891111892111893111894111895111896111897111898111899111900111901111902111903111904111905111906111907111908111909111910111911111912111913111914111915111916111917111918111919111920111921111922111923111924111925111926111927111928111929111930111931111932111933111934111935111936111937111938111939111940111941111942111943111944111945111946111947111948111949111950111951111952111953111954111955111956111957111958111959111960111961111962111963111964111965111966111967111968111969111970111971111972111973111974111975111976111977111978111979111980111981111982111983111984111985111986111987111988111989111990111991111992111993111994111995111996111997111998111999112000112001112002112003112004112005112006112007112008112009112010112011112012112013112014112015112016112017112018112019112020112021112022112023112024112025112026112027112028112029112030112031112032112033112034112035112036112037112038112039112040112041112042112043112044112045112046112047112048112049112050112051112052112053112054112055112056112057112058112059112060112061112062112063112064112065112066112067112068112069112070112071112072112073112074112075112076112077112078112079112080112081112082112083112084112085112086112087112088112089112090112091112092112093112094112095112096112097112098112099112100112101112102112103112104112105112106112107112108112109112110112111112112112113112114112115112116112117112118112119112120112121112122112123112124112125112126112127112128112129112130112131112132112133112134112135112136112137112138112139112140112141112142112143112144112145112146112147112148112149112150112151112152112153112154112155112156112157112158112159112160112161112162112163112164112165112166112167112168112169112170112171112172112173112174112175112176112177112178112179112180112181112182112183112184112185112186112187112188112189112190112191112192112193112194112195112196112197112198112199112200112201112202112203112204112205112206112207112208112209112210112211112212112213112214112215112216112217112218112219112220112221112222112223112224112225112226112227112228112229112230112231112232112233112234112235112236112237112238112239112240112241112242112243112244112245112246112247112248112249112250112251112252112253112254112255112256112257112258112259112260112261112262112263112264112265112266112267112268112269112270112271112272112273112274112275112276112277112278112279112280112281112282112283112284112285112286112287112288112289112290112291112292112293112294112295112296112297112298112299112300112301112302112303112304112305112306112307112308112309112310112311112312112313112314112315112316112317112318112319112320112321112322112323112324112325112326112327112328112329112330112331112332112333112334112335112336112337112338112339112340112341112342112343112344112345112346112347112348112349112350112351112352112353112354112355112356112357112358112359112360112361112362112363112364112365112366112367112368112369112370112371112372112373112374112375112376112377112378112379112380112381112382112383112384112385112386112387112388112389112390112391112392112393112394112395112396112397112398112399112400112401112402112403112404112405112406112407112408112409112410112411112412112413112414112415112416112417112418112419112420112421112422112423112424112425112426112427112428112429112430112431112432112433112434112435112436112437112438112439112440112441112442112443112444112445112446112447112448112449112450112451112452112453112454112455112456112457112458112459112460112461112462112463112464112465112466112467112468112469112470112471112472112473112474112475112476112477112478112479112480112481112482112483112484112485112486112487112488112489112490112491112492112493112494112495112496112497112498112499112500112501112502112503112504112505112506112507112508112509112510112511112512112513112514112515112516112517112518112519112520112521112522112523112524112525112526112527112528112529112530112531112532112533112534112535112536112537112538112539112540112541112542112543112544112545112546112547112548112549112550112551112552112553112554112555112556112557112558112559112560112561112562112563112564112565112566112567112568112569112570112571112572112573112574112575112576112577112578112579112580112581112582112583112584112585112586112587112588112589112590112591112592112593112594112595112596112597112598112599112600112601112602112603112604112605112606112607112608112609112610112611112612112613112614112615112616112617112618112619112620112621112622112623112624112625112626112627112628112629112630112631112632112633112634112635112636112637112638112639112640112641112642112643112644112645112646112647112648112649112650112651112652112653112654112655112656112657112658112659112660112661112662112663112664112665112666112667112668112669112670112671112672112673112674112675112676112677112678112679112680112681112682112683112684112685112686112687112688112689112690112691112692112693112694112695112696112697112698112699112700112701112702112703112704112705112706112707112708112709112710112711112712112713112714112715112716112717112718112719112720112721112722112723112724112725112726112727112728112729112730112731112732112733112734112735112736112737112738112739112740112741112742112743112744112745112746112747112748112749112750112751112752112753112754112755112756112757112758112759112760112761112762112763112764112765112766112767112768112769112770112771112772112773112774112775112776112777112778112779112780112781112782112783112784112785112786112787112788112789112790112791112792112793112794112795112796112797112798112799112800112801112802112803112804112805112806112807112808112809112810112811112812112813112814112815112816112817112818112819112820112821112822112823112824112825112826112827112828112829112830112831112832112833112834112835112836112837112838112839112840112841112842112843112844112845112846112847112848112849112850112851112852112853112854112855112856112857112858112859112860112861112862112863112864112865112866112867112868112869112870112871112872112873112874112875112876112877112878112879112880112881112882112883112884112885112886112887112888112889112890112891112892112893112894112895112896112897112898112899112900112901112902112903112904112905112906112907112908112909112910112911112912112913112914112915112916112917112918112919112920112921112922112923112924112925112926112927112928112929112930112931112932112933112934112935112936112937112938112939112940112941112942112943112944112945112946112947112948112949112950112951112952112953112954112955112956112957112958112959112960112961112962112963112964112965112966112967112968112969112970112971112972112973112974112975112976112977112978112979112980112981112982112983112984112985112986112987112988112989112990112991112992112993112994112995112996112997112998112999113000113001113002113003113004113005113006113007113008113009113010113011113012113013113014113015113016113017113018113019113020113021113022113023113024113025113026113027113028113029113030113031113032113033113034113035113036113037113038113039113040113041113042113043113044113045113046113047113048113049113050113051113052113053113054113055113056113057113058113059113060113061113062113063113064113065113066113067113068113069113070113071113072113073113074113075113076113077113078113079113080113081113082113083113084113085113086113087113088113089113090113091113092113093113094113095113096113097113098113099113100113101113102113103113104113105113106113107113108113109113110113111113112113113113114113115113116113117113118113119113120113121113122113123113124113125113126113127113128113129113130113131113132113133113134113135113136113137113138113139113140113141113142113143113144113145113146113147113148113149113150113151113152113153113154113155113156113157113158113159113160113161113162113163113164113165113166113167113168113169113170113171113172113173113174113175113176113177113178113179113180113181113182113183113184113185113186113187113188113189113190113191113192113193113194113195113196113197113198113199113200113201113202113203113204113205113206113207113208113209113210113211113212113213113214113215113216113217113218113219113220113221113222113223113224113225113226113227113228113229113230113231113232113233113234113235113236113237113238113239113240113241113242113243113244113245113246113247113248113249113250113251113252113253113254113255113256113257113258113259113260113261113262113263113264113265113266113267113268113269113270113271113272113273113274113275113276113277113278113279113280113281113282113283113284113285113286113287113288113289113290113291113292113293113294113295113296113297113298113299113300113301113302113303113304113305113306113307113308113309113310113311113312113313113314113315113316113317113318113319113320113321113322113323113324113325113326113327113328113329113330113331113332113333113334113335113336113337113338113339113340113341113342113343113344113345113346113347113348113349113350113351113352113353113354113355113356113357113358113359113360113361113362113363113364113365113366113367113368113369113370113371113372113373113374113375113376113377113378113379113380113381113382113383113384113385113386113387113388113389113390113391113392113393113394113395113396113397113398113399113400113401113402113403113404113405113406113407113408113409113410113411113412113413113414113415113416113417113418113419113420113421113422113423113424113425113426113427113428113429113430113431113432113433113434113435113436113437113438113439113440113441113442113443113444113445113446113447113448113449113450113451113452113453113454113455113456113457113458113459113460113461113462113463113464113465113466113467113468113469113470113471113472113473113474113475113476113477113478113479113480113481113482113483113484113485113486113487113488113489113490113491113492113493113494113495113496113497113498113499113500113501113502113503113504113505113506113507113508113509113510113511113512113513113514113515113516113517113518113519113520113521113522113523113524113525113526113527113528113529113530113531113532113533113534113535113536113537113538113539113540113541113542113543113544113545113546113547113548113549113550113551113552113553113554113555113556113557113558113559113560113561113562113563113564113565113566113567113568113569113570113571113572113573113574113575113576113577113578113579113580113581113582113583113584113585113586113587113588113589113590113591113592113593113594113595113596113597113598113599113600113601113602113603113604113605113606113607113608113609113610113611113612113613113614113615113616113617113618113619113620113621113622113623113624113625113626113627113628113629113630113631113632113633113634113635113636113637113638113639113640113641113642113643113644113645113646113647113648113649113650113651113652113653113654113655113656113657113658113659113660113661113662113663113664113665113666113667113668113669113670113671113672113673113674113675113676113677113678113679113680113681113682113683113684113685113686113687113688113689113690113691113692113693113694113695113696113697113698113699113700113701113702113703113704113705113706113707113708113709113710113711113712113713113714113715113716113717113718113719113720113721113722113723113724113725113726113727113728113729113730113731113732113733113734113735113736113737113738113739113740113741113742113743113744113745113746113747113748113749113750113751113752113753113754113755113756113757113758113759113760113761113762113763113764113765113766113767113768113769113770113771113772113773113774113775113776113777113778113779113780113781113782113783113784113785113786113787113788113789113790113791113792113793113794113795113796113797113798113799113800113801113802113803113804113805113806113807113808113809113810113811113812113813113814113815113816113817113818113819113820113821113822113823113824113825113826113827113828113829113830113831113832113833113834113835113836113837113838113839113840113841113842113843113844113845113846113847113848113849113850113851113852113853113854113855113856113857113858113859113860113861113862113863113864113865113866113867113868113869113870113871113872113873113874113875113876113877113878113879113880113881113882113883113884113885113886113887113888113889113890113891113892113893113894113895113896113897113898113899113900113901113902113903113904113905113906113907113908113909113910113911113912113913113914113915113916113917113918113919113920113921113922113923113924113925113926113927113928113929113930113931113932113933113934113935113936113937113938113939113940113941113942113943113944113945113946113947113948113949113950113951113952113953113954113955113956113957113958113959113960113961113962113963113964113965113966113967113968113969113970113971113972113973113974113975113976113977113978113979113980113981113982113983113984113985113986113987113988113989113990113991113992113993113994113995113996113997113998113999114000114001114002114003114004114005114006114007114008114009114010114011114012114013114014114015114016114017114018114019114020114021114022114023114024114025114026114027114028114029114030114031114032114033114034114035114036114037114038114039114040114041114042114043114044114045114046114047114048114049114050114051114052114053114054114055114056114057114058114059114060114061114062114063114064114065114066114067114068114069114070114071114072114073114074114075114076114077114078114079114080114081114082114083114084114085114086114087114088114089114090114091114092114093114094114095114096114097114098114099114100114101114102114103114104114105114106114107114108114109114110114111114112114113114114114115114116114117114118114119114120114121114122114123114124114125114126114127114128114129114130114131114132114133114134114135114136114137114138114139114140114141114142114143114144114145114146114147114148114149114150114151114152114153114154114155114156114157114158114159114160114161114162114163114164114165114166114167114168114169114170114171114172114173114174114175114176114177114178114179114180114181114182114183114184114185114186114187114188114189114190114191114192114193114194114195114196114197114198114199114200114201114202114203114204114205114206114207114208114209114210114211114212114213114214114215114216114217114218114219114220114221114222114223114224114225114226114227114228114229114230114231114232114233114234114235114236114237114238114239114240114241114242114243114244114245114246114247114248114249114250114251114252114253114254114255114256114257114258114259114260114261114262114263114264114265114266114267114268114269114270114271114272114273114274114275114276114277114278114279114280114281114282114283114284114285114286114287114288114289114290114291114292114293114294114295114296114297114298114299114300114301114302114303114304114305114306114307114308114309114310114311114312114313114314114315114316114317114318114319114320114321114322114323114324114325114326114327114328114329114330114331114332114333114334114335114336114337114338114339114340114341114342114343114344114345114346114347114348114349114350114351114352114353114354114355114356114357114358114359114360114361114362114363114364114365114366114367114368114369114370114371114372114373114374114375114376114377114378114379114380114381114382114383114384114385114386114387114388114389114390114391114392114393114394114395114396114397114398114399114400114401114402114403114404114405114406114407114408114409114410114411114412114413114414114415114416114417114418114419114420114421114422114423114424114425114426114427114428114429114430114431114432114433114434114435114436114437114438114439114440114441114442114443114444114445114446114447114448114449114450114451114452114453114454114455114456114457114458114459114460114461114462114463114464114465114466114467114468114469114470114471114472114473114474114475114476114477114478114479114480114481114482114483114484114485114486114487114488114489114490114491114492114493114494114495114496114497114498114499114500114501114502114503114504114505114506114507114508114509114510114511114512114513114514114515114516114517114518114519114520114521114522114523114524114525114526114527114528114529114530114531114532114533114534114535114536114537114538114539114540114541114542114543114544114545114546114547114548114549114550114551114552114553114554114555114556114557114558114559114560114561114562114563114564114565114566114567114568114569114570114571114572114573114574114575114576114577114578114579114580114581114582114583114584114585114586114587114588114589114590114591114592114593114594114595114596114597114598114599114600114601114602114603114604114605114606114607114608114609114610114611114612114613114614114615114616114617114618114619114620114621114622114623114624114625114626114627114628114629114630114631114632114633114634114635114636114637114638114639114640114641114642114643114644114645114646114647114648114649114650114651114652114653114654114655114656114657114658114659114660114661114662114663114664114665114666114667114668114669114670114671114672114673114674114675114676114677114678114679114680114681114682114683114684114685114686114687114688114689114690114691114692114693114694114695114696114697114698114699114700114701114702114703114704114705114706114707114708114709114710114711114712114713114714114715114716114717114718114719114720114721114722114723114724114725114726114727114728114729114730114731114732114733114734114735114736114737114738114739114740114741114742114743114744114745114746114747114748114749114750114751114752114753114754114755114756114757114758114759114760114761114762114763114764114765114766114767114768114769114770114771114772114773114774114775114776114777114778114779114780114781114782114783114784114785114786114787114788114789114790114791114792114793114794114795114796114797114798114799114800114801114802114803114804114805114806114807114808114809114810114811114812114813114814114815114816114817114818114819114820114821114822114823114824114825114826114827114828114829114830114831114832114833114834114835114836114837114838114839114840114841114842114843114844114845114846114847114848114849114850114851114852114853114854114855114856114857114858114859114860114861114862114863114864114865114866114867114868114869114870114871114872114873114874114875114876114877114878114879114880114881114882114883114884114885114886114887114888114889114890114891114892114893114894114895114896114897114898114899114900114901114902114903114904114905114906114907114908114909114910114911114912114913114914114915114916114917114918114919114920114921114922114923114924114925114926114927114928114929114930114931114932114933114934114935114936114937114938114939114940114941114942114943114944114945114946114947114948114949114950114951114952114953114954114955114956114957114958114959114960114961114962114963114964114965114966114967114968114969114970114971114972114973114974114975114976114977114978114979114980114981114982114983114984114985114986114987114988114989114990114991114992114993114994114995114996114997114998114999115000115001115002115003115004115005115006115007115008115009115010115011115012115013115014115015115016115017115018115019115020115021115022115023115024115025115026115027115028115029115030115031115032115033115034115035115036115037115038115039115040115041115042115043115044115045115046115047115048115049115050115051115052115053115054115055115056115057115058115059115060115061115062115063115064115065115066115067115068115069115070115071115072115073115074115075115076115077115078115079115080115081115082115083115084115085115086115087115088115089115090115091115092115093115094115095115096115097115098115099115100115101115102115103115104115105115106115107115108115109115110115111115112115113115114115115115116115117115118115119115120115121115122115123115124115125115126115127115128115129115130115131115132115133115134115135115136115137115138115139115140115141115142115143115144115145115146115147115148115149115150115151115152115153115154115155115156115157115158115159115160115161115162115163115164115165115166115167115168115169115170115171115172115173115174115175115176115177115178115179115180115181115182115183115184115185115186115187115188115189115190115191115192115193115194115195115196115197115198115199115200115201115202115203115204115205115206115207115208115209115210115211115212115213115214115215115216115217115218115219115220115221115222115223115224115225115226115227115228115229115230115231115232115233115234115235115236115237115238115239115240115241115242115243115244115245115246115247115248115249115250115251115252115253115254115255115256115257115258115259115260115261115262115263115264115265115266115267115268115269115270115271115272115273115274115275115276115277115278115279115280115281115282115283115284115285115286115287115288115289115290115291115292115293115294115295115296115297115298115299115300115301115302115303115304115305115306115307115308115309115310115311115312115313115314115315115316115317115318115319115320115321115322115323115324115325115326115327115328115329115330115331115332115333115334115335115336115337115338115339115340115341115342115343115344115345115346115347115348115349115350115351115352115353115354115355115356115357115358115359115360115361115362115363115364115365115366115367115368115369115370115371115372115373115374115375115376115377115378115379115380115381115382115383115384115385115386115387115388115389115390115391115392115393115394115395115396115397115398115399115400115401115402115403115404115405115406115407115408115409115410115411115412115413115414115415115416115417115418115419115420115421115422115423115424115425115426115427115428115429115430115431115432115433115434115435115436115437115438115439115440115441115442115443115444115445115446115447115448115449115450115451115452115453115454115455115456115457115458115459115460115461115462115463115464115465115466115467115468115469115470115471115472115473115474115475115476115477115478115479115480115481115482115483115484115485115486115487115488115489115490115491115492115493115494115495115496115497115498115499115500115501115502115503115504115505115506115507115508115509115510115511115512115513115514115515115516115517115518115519115520115521115522115523115524115525115526115527115528115529115530115531115532115533115534115535115536115537115538115539115540115541115542115543115544115545115546115547115548115549115550115551115552115553115554115555115556115557115558115559115560115561115562115563115564115565115566115567115568115569115570115571115572115573115574115575115576115577115578115579115580115581115582115583115584115585115586115587115588115589115590115591115592115593115594115595115596115597115598115599115600115601115602115603115604115605115606115607115608115609115610115611115612115613115614115615115616115617115618115619115620115621115622115623115624115625115626115627115628115629115630115631115632115633115634115635115636115637115638115639115640115641115642115643115644115645115646115647115648115649115650115651115652115653115654115655115656115657115658115659115660115661115662115663115664115665115666115667115668115669115670115671115672115673115674115675115676115677115678115679115680115681115682115683115684115685115686115687115688115689115690115691115692115693115694115695115696115697115698115699115700115701115702115703115704115705115706115707115708115709115710115711115712115713115714115715115716115717115718115719115720115721115722115723115724115725115726115727115728115729115730115731115732115733115734115735115736115737115738115739115740115741115742115743115744115745115746115747115748115749115750115751115752115753115754115755115756115757115758115759115760115761115762115763115764115765115766115767115768115769115770115771115772115773115774115775115776115777115778115779115780115781115782115783115784115785115786115787115788115789115790115791115792115793115794115795115796115797115798115799115800115801115802115803115804115805115806115807115808115809115810115811115812115813115814115815115816115817115818115819115820115821115822115823115824115825115826115827115828115829115830115831115832115833115834115835115836115837115838115839115840115841115842115843115844115845115846115847115848115849115850115851115852115853115854115855115856115857115858115859115860115861115862115863115864115865115866115867115868115869115870115871115872115873115874115875115876115877115878115879115880115881115882115883115884115885115886115887115888115889115890115891115892115893115894115895115896115897115898115899115900115901115902115903115904115905115906115907115908115909115910115911115912115913115914115915115916115917115918115919115920115921115922115923115924115925115926115927115928115929115930115931115932115933115934115935115936115937115938115939115940115941115942115943115944115945115946115947115948115949115950115951115952115953115954115955115956115957115958115959115960115961115962115963115964115965115966115967115968115969115970115971115972115973115974115975115976115977115978115979115980115981115982115983115984115985115986115987115988115989115990115991115992115993115994115995115996115997115998115999116000116001116002116003116004116005116006116007116008116009116010116011116012116013116014116015116016116017116018116019116020116021116022116023116024116025116026116027116028116029116030116031116032116033116034116035116036116037116038116039116040116041116042116043116044116045116046116047116048116049116050116051116052116053116054116055116056116057116058116059116060116061116062116063116064116065116066116067116068116069116070116071116072116073116074116075116076116077116078116079116080116081116082116083116084116085116086116087116088116089116090116091116092116093116094116095116096116097116098116099116100116101116102116103116104116105116106116107116108116109116110116111116112116113116114116115116116116117116118116119116120116121116122116123116124116125116126116127116128116129116130116131116132116133116134116135116136116137116138116139116140116141116142116143116144116145116146116147116148116149116150116151116152116153116154116155116156116157116158116159116160116161116162116163116164116165116166116167116168116169116170116171116172116173116174116175116176116177116178116179116180116181116182116183116184116185116186116187116188116189116190116191116192116193116194116195116196116197116198116199116200116201116202116203116204116205116206116207116208116209116210116211116212116213116214116215116216116217116218116219116220116221116222116223116224116225116226116227116228116229116230116231116232116233116234116235116236116237116238116239116240116241116242116243116244116245116246116247116248116249116250116251116252116253116254116255116256116257116258116259116260116261116262116263116264116265116266116267116268116269116270116271116272116273116274116275116276116277116278116279116280116281116282116283116284116285116286116287116288116289116290116291116292116293116294116295116296116297116298116299116300116301116302116303116304116305116306116307116308116309116310116311116312116313116314116315116316116317116318116319116320116321116322116323116324116325116326116327116328116329116330116331116332116333116334116335116336116337116338116339116340116341116342116343116344116345116346116347116348116349116350116351116352116353116354116355116356116357116358116359116360116361116362116363116364116365116366116367116368116369116370116371116372116373116374116375116376116377116378116379116380116381116382116383116384116385116386116387116388116389116390116391116392116393116394116395116396116397116398116399116400116401116402116403116404116405116406116407116408116409116410116411116412116413116414116415116416116417116418116419116420116421116422116423116424116425116426116427116428116429116430116431116432116433116434116435116436116437116438116439116440116441116442116443116444116445116446116447116448116449116450116451116452116453116454116455116456116457116458116459116460116461116462116463116464116465116466116467116468116469116470116471116472116473116474116475116476116477116478116479116480116481116482116483116484116485116486116487116488116489116490116491116492116493116494116495116496116497116498116499116500116501116502116503116504116505116506116507116508116509116510116511116512116513116514116515116516116517116518116519116520116521116522116523116524116525116526116527116528116529116530116531116532116533116534116535116536116537116538116539116540116541116542116543116544116545116546116547116548116549116550116551116552116553116554116555116556116557116558116559116560116561116562116563116564116565116566116567116568116569116570116571116572116573116574116575116576116577116578116579116580116581116582116583116584116585116586116587116588116589116590116591116592116593116594116595116596116597116598116599116600116601116602116603116604116605116606116607116608116609116610116611116612116613116614116615116616116617116618116619116620116621116622116623116624116625116626116627116628116629116630116631116632116633116634116635116636116637116638116639116640116641116642116643116644116645116646116647116648116649116650116651116652116653116654116655116656116657116658116659116660116661116662116663116664116665116666116667116668116669116670116671116672116673116674116675116676116677116678116679116680116681116682116683116684116685116686116687116688116689116690116691116692116693116694116695116696116697116698116699116700116701116702116703116704116705116706116707116708116709116710116711116712116713116714116715116716116717116718116719116720116721116722116723116724116725116726116727116728116729116730116731116732116733116734116735116736116737116738116739116740116741116742116743116744116745116746116747116748116749116750116751116752116753116754116755116756116757116758116759116760116761116762116763116764116765116766116767116768116769116770116771116772116773116774116775116776116777116778116779116780116781116782116783116784116785116786116787116788116789116790116791116792116793116794116795116796116797116798116799116800116801116802116803116804116805116806116807116808116809116810116811116812116813116814116815116816116817116818116819116820116821116822116823116824116825116826116827116828116829116830116831116832116833116834116835116836116837116838116839116840116841116842116843116844116845116846116847116848116849116850116851116852116853116854116855116856116857116858116859116860116861116862116863116864116865116866116867116868116869116870116871116872116873116874116875116876116877116878116879116880116881116882116883116884116885116886116887116888116889116890116891116892116893116894116895116896116897116898116899116900116901116902116903116904116905116906116907116908116909116910116911116912116913116914116915116916116917116918116919116920116921116922116923116924116925116926116927116928116929116930116931116932116933116934116935116936116937116938116939116940116941116942116943116944116945116946116947116948116949116950116951116952116953116954116955116956116957116958116959116960116961116962116963116964116965116966116967116968116969116970116971116972116973116974116975116976116977116978116979116980116981116982116983116984116985116986116987116988116989116990116991116992116993116994116995116996116997116998116999117000117001117002117003117004117005117006117007117008117009117010117011117012117013117014117015117016117017117018117019117020117021117022117023117024117025117026117027117028117029117030117031117032117033117034117035117036117037117038117039117040117041117042117043117044117045117046117047117048117049117050117051117052117053117054117055117056117057117058117059117060117061117062117063117064117065117066117067117068117069117070117071117072117073117074117075117076117077117078117079117080117081117082117083117084117085117086117087117088117089117090117091117092117093117094117095117096117097117098117099117100117101117102117103117104117105117106117107117108117109117110117111117112117113117114117115117116117117117118117119117120117121117122117123117124117125117126117127117128117129117130117131117132117133117134117135117136117137117138117139117140117141117142117143117144117145117146117147117148117149117150117151117152117153117154117155117156117157117158117159117160117161117162117163117164117165117166117167117168117169117170117171117172117173117174117175117176117177117178117179117180117181117182117183117184117185117186117187117188117189117190117191117192117193117194117195117196117197117198117199117200117201117202117203117204117205117206117207117208117209117210117211117212117213117214117215117216117217117218117219117220117221117222117223117224117225117226117227117228117229117230117231117232117233117234117235117236117237117238117239117240117241117242117243117244117245117246117247117248117249117250117251117252117253117254117255117256117257117258117259117260117261117262117263117264117265117266117267117268117269117270117271117272117273117274117275117276117277117278117279117280117281117282117283117284117285117286117287117288117289117290117291117292117293117294117295117296117297117298117299117300117301117302117303117304117305117306117307117308117309117310117311117312117313117314117315117316117317117318117319117320117321117322117323117324117325117326117327117328117329117330117331117332117333117334117335117336117337117338117339117340117341117342117343117344117345117346117347117348117349117350117351117352117353117354117355117356117357117358117359117360117361117362117363117364117365117366117367117368117369117370117371117372117373117374117375117376117377117378117379117380117381117382117383117384117385117386117387117388117389117390117391117392117393117394117395117396117397117398117399117400117401117402117403117404117405117406117407117408117409117410117411117412117413117414117415117416117417117418117419117420117421117422117423117424117425117426117427117428117429117430117431117432117433117434117435117436117437117438117439117440117441117442117443117444117445117446117447117448117449117450117451117452117453117454117455117456117457117458117459117460117461117462117463117464117465117466117467117468117469117470117471117472117473117474117475117476117477117478117479117480117481117482117483117484117485117486117487117488117489117490117491117492117493117494117495117496117497117498117499117500117501117502117503117504117505117506117507117508117509117510117511117512117513117514117515117516117517117518117519117520117521117522117523117524117525117526117527117528117529117530117531117532117533117534117535117536117537117538117539117540117541117542117543117544117545117546117547117548117549117550117551117552117553117554117555117556117557117558117559117560117561117562117563117564117565117566117567117568117569117570117571117572117573117574117575117576117577117578117579117580117581117582117583117584117585117586117587117588117589117590117591117592117593117594117595117596117597117598117599117600117601117602117603117604117605117606117607117608117609117610117611117612117613117614117615117616117617117618117619117620117621117622117623117624117625117626117627117628117629117630117631117632117633117634117635117636117637117638117639117640117641117642117643117644117645117646117647117648117649117650117651117652117653117654117655117656117657117658117659117660117661117662117663117664117665117666117667117668117669117670117671117672117673117674117675117676117677117678117679117680117681117682117683117684117685117686117687117688117689117690117691117692117693117694117695117696117697117698117699117700117701117702117703117704117705117706117707117708117709117710117711117712117713117714117715117716117717117718117719117720117721117722117723117724117725117726117727117728117729117730117731117732117733117734117735117736117737117738117739117740117741117742117743117744117745117746117747117748117749117750117751117752117753117754117755117756117757117758117759117760117761117762117763117764117765117766117767117768117769117770117771117772117773117774117775117776117777117778117779117780117781117782117783117784117785117786117787117788117789117790117791117792117793117794117795117796117797117798117799117800117801117802117803117804117805117806117807117808117809117810117811117812117813117814117815117816117817117818117819117820117821117822117823117824117825117826117827117828117829117830117831117832117833117834117835117836117837117838117839117840117841117842117843117844117845117846117847117848117849117850117851117852117853117854117855117856117857117858117859117860117861117862117863117864117865117866117867117868117869117870117871117872117873117874117875117876117877117878117879117880117881117882117883117884117885117886117887117888117889117890117891117892117893117894117895117896117897117898117899117900117901117902117903117904117905117906117907117908117909117910117911117912117913117914117915117916117917117918117919117920117921117922117923117924117925117926117927117928117929117930117931117932117933117934117935117936117937117938117939117940117941117942117943117944117945117946117947117948117949117950117951117952117953117954117955117956117957117958117959117960117961117962117963117964117965117966117967117968117969117970117971117972117973117974117975117976117977117978117979117980117981117982117983117984117985117986117987117988117989117990117991117992117993117994117995117996117997117998117999118000118001118002118003118004118005118006118007118008118009118010118011118012118013118014118015118016118017118018118019118020118021118022118023118024118025118026118027118028118029118030118031118032118033118034118035118036118037118038118039118040118041118042118043118044118045118046118047118048118049118050118051118052118053118054118055118056118057118058118059118060118061118062118063118064118065118066118067118068118069118070118071118072118073118074118075118076118077118078118079118080118081118082118083118084118085118086118087118088118089118090118091118092118093118094118095118096118097118098118099118100118101118102118103118104118105118106118107118108118109118110118111118112118113118114118115118116118117118118118119118120118121118122118123118124118125118126118127118128118129118130118131118132118133118134118135118136118137118138118139118140118141118142118143118144118145118146118147118148118149118150118151118152118153118154118155118156118157118158118159118160118161118162118163118164118165118166118167118168118169118170118171118172118173118174118175118176118177118178118179118180118181118182118183118184118185118186118187118188118189118190118191118192118193118194118195118196118197118198118199118200118201118202118203118204118205118206118207118208118209118210118211118212118213118214118215118216118217118218118219118220118221118222118223118224118225118226118227118228118229118230118231118232118233118234118235118236118237118238118239118240118241118242118243118244118245118246118247118248118249118250118251118252118253118254118255118256118257118258118259118260118261118262118263118264118265118266118267118268118269118270118271118272118273118274118275118276118277118278118279118280118281118282118283118284118285118286118287118288118289118290118291118292118293118294118295118296118297118298118299118300118301118302118303118304118305118306118307118308118309118310118311118312118313118314118315118316118317118318118319118320118321118322118323118324118325118326118327118328118329118330118331118332118333118334118335118336118337118338118339118340118341118342118343118344118345118346118347118348118349118350118351118352118353118354118355118356118357118358118359118360118361118362118363118364118365118366118367118368118369118370118371118372118373118374118375118376118377118378118379118380118381118382118383118384118385118386118387118388118389118390118391118392118393118394118395118396118397118398118399118400118401118402118403118404118405118406118407118408118409118410118411118412118413118414118415118416118417118418118419118420118421118422118423118424118425118426118427118428118429118430118431118432118433118434118435118436118437118438118439118440118441118442118443118444118445118446118447118448118449118450118451118452118453118454118455118456118457118458118459118460118461118462118463118464118465118466118467118468118469118470118471118472118473118474118475118476118477118478118479118480118481118482118483118484118485118486118487118488118489118490118491118492118493118494118495118496118497118498118499118500118501118502118503118504118505118506118507118508118509118510118511118512118513118514118515118516118517118518118519118520118521118522118523118524118525118526118527118528118529118530118531118532118533118534118535118536118537118538118539118540118541118542118543118544118545118546118547118548118549118550118551118552118553118554118555118556118557118558118559118560118561118562118563118564118565118566118567118568118569118570118571118572118573118574118575118576118577118578118579118580118581118582118583118584118585118586118587118588118589118590118591118592118593118594118595118596118597118598118599118600118601118602118603118604118605118606118607118608118609118610118611118612118613118614118615118616118617118618118619118620118621118622118623118624118625118626118627118628118629118630118631118632118633118634118635118636118637118638118639118640118641118642118643118644118645118646118647118648118649118650118651118652118653118654118655118656118657118658118659118660118661118662118663118664118665118666118667118668118669118670118671118672118673118674118675118676118677118678118679118680118681118682118683118684118685118686118687118688118689118690118691118692118693118694118695118696118697118698118699118700118701118702118703118704118705118706118707118708118709118710118711118712118713118714118715118716118717118718118719118720118721118722118723118724118725118726118727118728118729118730118731118732118733118734118735118736118737118738118739118740118741118742118743118744118745118746118747118748118749118750118751118752118753118754118755118756118757118758118759118760118761118762118763118764118765118766118767118768118769118770118771118772118773118774118775118776118777118778118779118780118781118782118783118784118785118786118787118788118789118790118791118792118793118794118795118796118797118798118799118800118801118802118803118804118805118806118807118808118809118810118811118812118813118814118815118816118817118818118819118820118821118822118823118824118825118826118827118828118829118830118831118832118833118834118835118836118837118838118839118840118841118842118843118844118845118846118847118848118849118850118851118852118853118854118855118856118857118858118859118860118861118862118863118864118865118866118867118868118869118870118871118872118873118874118875118876118877118878118879118880118881118882118883118884118885118886118887118888118889118890118891118892118893118894118895118896118897118898118899118900118901118902118903118904118905118906118907118908118909118910118911118912118913118914118915118916118917118918118919118920118921118922118923118924118925118926118927118928118929118930118931118932118933118934118935118936118937118938118939118940118941118942118943118944118945118946118947118948118949118950118951118952118953118954118955118956118957118958118959118960118961118962118963118964118965118966118967118968118969118970118971118972118973118974118975118976118977118978118979118980118981118982118983118984118985118986118987118988118989118990118991118992118993118994118995118996118997118998118999119000119001119002119003119004119005119006119007119008119009119010119011119012119013119014119015119016119017119018119019119020119021119022119023119024119025119026119027119028119029119030119031119032119033119034119035119036119037119038119039119040119041119042119043119044119045119046119047119048119049119050119051119052119053119054119055119056119057119058119059119060119061119062119063119064119065119066119067119068119069119070119071119072119073119074119075119076119077119078119079119080119081119082119083119084119085119086119087119088119089119090119091119092119093119094119095119096119097119098119099119100119101119102119103119104119105119106119107119108119109119110119111119112119113119114119115119116119117119118119119119120119121119122119123119124119125119126119127119128119129119130119131119132119133119134119135119136119137119138119139119140119141119142119143119144119145119146119147119148119149119150119151119152119153119154119155119156119157119158119159119160119161119162119163119164119165119166119167119168119169119170119171119172119173119174119175119176119177119178119179119180119181119182119183119184119185119186119187119188119189119190119191119192119193119194119195119196119197119198119199119200119201119202119203119204119205119206119207119208119209119210119211119212119213119214119215119216119217119218119219119220119221119222119223119224119225119226119227119228119229119230119231119232119233119234119235119236119237119238119239119240119241119242119243119244119245119246119247119248119249119250119251119252119253119254119255119256119257119258119259119260119261119262119263119264119265119266119267119268119269119270119271119272119273119274119275119276119277119278119279119280119281119282119283119284119285119286119287119288119289119290119291119292119293119294119295119296119297119298119299119300119301119302119303119304119305119306119307119308119309119310119311119312119313119314119315119316119317119318119319119320119321119322119323119324119325119326119327119328119329119330119331119332119333119334119335119336119337119338119339119340119341119342119343119344119345119346119347119348119349119350119351119352119353119354119355119356119357119358119359119360119361119362119363119364119365119366119367119368119369119370119371119372119373119374119375119376119377119378119379119380119381119382119383119384119385119386119387119388119389119390119391119392119393119394119395119396119397119398119399119400119401119402119403119404119405119406119407119408119409119410119411119412119413119414119415119416119417119418119419119420119421119422119423119424119425119426119427119428119429119430119431119432119433119434119435119436119437119438119439119440119441119442119443119444119445119446119447119448119449119450119451119452119453119454119455119456119457119458119459119460119461119462119463119464119465119466119467119468119469119470119471119472119473119474119475119476119477119478119479119480119481119482119483119484119485119486119487119488119489119490119491119492119493119494119495119496119497119498119499119500119501119502119503119504119505119506119507119508119509119510119511119512119513119514119515119516119517119518119519119520119521119522119523119524119525119526119527119528119529119530119531119532119533119534119535119536119537119538119539119540119541119542119543119544119545119546119547119548119549119550119551119552119553119554119555119556119557119558119559119560119561119562119563119564119565119566119567119568119569119570119571119572119573119574119575119576119577119578119579119580119581119582119583119584119585119586119587119588119589119590119591119592119593119594119595119596119597119598119599119600119601119602119603119604119605119606119607119608119609119610119611119612119613119614119615119616119617119618119619119620119621119622119623119624119625119626119627119628119629119630119631119632119633119634119635119636119637119638119639119640119641119642119643119644119645119646119647119648119649119650119651119652119653119654119655119656119657119658119659119660119661119662119663119664119665119666119667119668119669119670119671119672119673119674119675119676119677119678119679119680119681119682119683119684119685119686119687119688119689119690119691119692119693119694119695119696119697119698119699119700119701119702119703119704119705119706119707119708119709119710119711119712119713119714119715119716119717119718119719119720119721119722119723119724119725119726119727119728119729119730119731119732119733119734119735119736119737119738119739119740119741119742119743119744119745119746119747119748119749119750119751119752119753119754119755119756119757119758119759119760119761119762119763119764119765119766119767119768119769119770119771119772119773119774119775119776119777119778119779119780119781119782119783119784119785119786119787119788119789119790119791119792119793119794119795119796119797119798119799119800119801119802119803119804119805119806119807119808119809119810119811119812119813119814119815119816119817119818119819119820119821119822119823119824119825119826119827119828119829119830119831119832119833119834119835119836119837119838119839119840119841119842119843119844119845119846119847119848119849119850119851119852119853119854119855119856119857119858119859119860119861119862119863119864119865119866119867119868119869119870119871119872119873119874119875119876119877119878119879119880119881119882119883119884119885119886119887119888119889119890119891119892119893119894119895119896119897119898119899119900119901119902119903119904119905119906119907119908119909119910119911119912119913119914119915119916119917119918119919119920119921119922119923119924119925119926119927119928119929119930119931119932119933119934119935119936119937119938119939119940119941119942119943119944119945119946119947119948119949119950119951119952119953119954119955119956119957119958119959119960119961119962119963119964119965119966119967119968119969119970119971119972119973119974119975119976119977119978119979119980119981119982119983119984119985119986119987119988119989119990119991119992119993119994119995119996119997119998119999120000120001120002120003120004120005120006120007120008120009120010120011120012120013120014120015120016120017120018120019120020120021120022120023120024120025120026120027120028120029120030120031120032120033120034120035120036120037120038120039120040120041120042120043120044120045120046120047120048120049120050120051120052120053120054120055120056120057120058120059120060120061120062120063120064120065120066120067120068120069120070120071120072120073120074120075120076120077120078120079120080120081120082120083120084120085120086120087120088120089120090120091120092120093120094120095120096120097120098120099120100120101120102120103120104120105120106120107120108120109120110120111120112120113120114120115120116120117120118120119120120120121120122120123120124120125120126120127120128120129120130120131120132120133120134120135120136120137120138120139120140120141120142120143120144120145120146120147120148120149120150120151120152120153120154120155120156120157120158120159120160120161120162120163120164120165120166120167120168120169120170120171120172120173120174120175120176120177120178120179120180120181120182120183120184120185120186120187120188120189120190120191120192120193120194120195120196120197120198120199120200120201120202120203120204120205120206120207120208120209120210120211120212120213120214120215120216120217120218120219120220120221120222120223120224120225120226120227120228120229120230120231120232120233120234120235120236120237120238120239120240120241120242120243120244120245120246120247120248120249120250120251120252120253120254120255120256120257120258120259120260120261120262120263120264120265120266120267120268120269120270120271120272120273120274120275120276120277120278120279120280120281120282120283120284120285120286120287120288120289120290120291120292120293120294120295120296120297120298120299120300120301120302120303120304120305120306120307120308120309120310120311120312120313120314120315120316120317120318120319120320120321120322120323120324120325120326120327120328120329120330120331120332120333120334120335120336120337120338120339120340120341120342120343120344120345120346120347120348120349120350120351120352120353120354120355120356120357120358120359120360120361120362120363120364120365120366120367120368120369120370120371120372120373120374120375120376120377120378120379120380120381120382120383120384120385120386120387120388120389120390120391120392120393120394120395120396120397120398120399120400120401120402120403120404120405120406120407120408120409120410120411120412120413120414120415120416120417120418120419120420120421120422120423120424120425120426120427120428120429120430120431120432120433120434120435120436120437120438120439120440120441120442120443120444120445120446120447120448120449120450120451120452120453120454120455120456120457120458120459120460120461120462120463120464120465120466120467120468120469120470120471120472120473120474120475120476120477120478120479120480120481120482120483120484120485120486120487120488120489120490120491120492120493120494120495120496120497120498120499120500120501120502120503120504120505120506120507120508120509120510120511120512120513120514120515120516120517120518120519120520120521120522120523120524120525120526120527120528120529120530120531120532120533120534120535120536120537120538120539120540120541120542120543120544120545120546120547120548120549120550120551120552120553120554120555120556120557120558120559120560120561120562120563120564120565120566120567120568120569120570120571120572120573120574120575120576120577120578120579120580120581120582120583120584120585120586120587120588120589120590120591120592120593120594120595120596120597120598120599120600120601120602120603120604120605120606120607120608120609120610120611120612120613120614120615120616120617120618120619120620120621120622120623120624120625120626120627120628120629120630120631120632120633120634120635120636120637120638120639120640120641120642120643120644120645120646120647120648120649120650120651120652120653120654120655120656120657120658120659120660120661120662120663120664120665120666120667120668120669120670120671120672120673120674120675120676120677120678120679120680120681120682120683120684120685120686120687120688120689120690120691120692120693120694120695120696120697120698120699120700120701120702120703120704120705120706120707120708120709120710120711120712120713120714120715120716120717120718120719120720120721120722120723120724120725120726120727120728120729120730120731120732120733120734120735120736120737120738120739120740120741120742120743120744120745120746120747120748120749120750120751120752120753120754120755120756120757120758120759120760120761120762120763120764120765120766120767120768120769120770120771120772120773120774120775120776120777120778120779120780120781120782120783120784120785120786120787120788120789120790120791120792120793120794120795120796120797120798120799120800120801120802120803120804120805120806120807120808120809120810120811120812120813120814120815120816120817120818120819120820120821120822120823120824120825120826120827120828120829120830120831120832120833120834120835120836120837120838120839120840120841120842120843120844120845120846120847120848120849120850120851120852120853120854120855120856120857120858120859120860120861120862120863120864120865120866120867120868120869120870120871120872120873120874120875120876120877120878120879120880120881120882120883120884120885120886120887120888120889120890120891120892120893120894120895120896120897120898120899120900120901120902120903120904120905120906120907120908120909120910120911120912120913120914120915120916120917120918120919120920120921120922120923120924120925120926120927120928120929120930120931120932120933120934120935120936120937120938120939120940120941120942120943120944120945120946120947120948120949120950120951120952120953120954120955120956120957120958120959120960120961120962120963120964120965120966120967120968120969120970120971120972120973120974120975120976120977120978120979120980120981120982120983120984120985120986120987120988120989120990120991120992120993120994120995120996120997120998120999121000121001121002121003121004121005121006121007121008121009121010121011121012121013121014121015121016121017121018121019121020121021121022121023121024121025121026121027121028121029121030121031121032121033121034121035121036121037121038121039121040121041121042121043121044121045121046121047121048121049121050121051121052121053121054121055121056121057121058121059121060121061121062121063121064121065121066121067121068121069121070121071121072121073121074121075121076121077121078121079121080121081121082121083121084121085121086121087121088121089121090121091121092121093121094121095121096121097121098121099121100121101121102121103121104121105121106121107121108121109121110121111121112121113121114121115121116121117121118121119121120121121121122121123121124121125121126121127121128121129121130121131121132121133121134121135121136121137121138121139121140121141121142121143121144121145121146121147121148121149121150121151121152121153121154121155121156121157121158121159121160121161121162121163121164121165121166121167121168121169121170121171121172121173121174121175121176121177121178121179121180121181121182121183121184121185121186121187121188121189121190121191121192121193121194121195121196121197121198121199121200121201121202121203121204121205121206121207121208121209121210121211121212121213121214121215121216121217121218121219121220121221121222121223121224121225121226121227121228121229121230121231121232121233121234121235121236121237121238121239121240121241121242121243121244121245121246121247121248121249121250121251121252121253121254121255121256121257121258121259121260121261121262121263121264121265121266121267121268121269121270121271121272121273121274121275121276121277121278121279121280121281121282121283121284121285121286121287121288121289121290121291121292121293121294121295121296121297121298121299121300121301121302121303121304121305121306121307121308121309121310121311121312121313121314121315121316121317121318121319121320121321121322121323121324121325121326121327121328121329121330121331121332121333121334121335121336121337121338121339121340121341121342121343121344121345121346121347121348121349121350121351121352121353121354121355121356121357121358121359121360121361121362121363121364121365121366121367121368121369121370121371121372121373121374121375121376121377121378121379121380121381121382121383121384121385121386121387121388121389121390121391121392121393121394121395121396121397121398121399121400121401121402121403121404121405121406121407121408121409121410121411121412121413121414121415121416121417121418121419121420121421121422121423121424121425121426121427121428121429121430121431121432121433121434121435121436121437121438121439121440121441121442121443121444121445121446121447121448121449121450121451121452121453121454121455121456121457121458121459121460121461121462121463121464121465121466121467121468121469121470121471121472121473121474121475121476121477121478121479121480121481121482121483121484121485121486121487121488121489121490121491121492121493121494121495121496121497121498121499121500121501121502121503121504121505121506121507121508121509121510121511121512121513121514121515121516121517121518121519121520121521121522121523121524121525121526121527121528121529121530121531121532121533121534121535121536121537121538121539121540121541121542121543121544121545121546121547121548121549121550121551121552121553121554121555121556121557121558121559121560121561121562121563121564121565121566121567121568121569121570121571121572121573121574121575121576121577121578121579121580121581121582121583121584121585121586121587121588121589121590121591121592121593121594121595121596121597121598121599121600121601121602121603121604121605121606121607121608121609121610121611121612121613121614121615121616121617121618121619121620121621121622121623121624121625121626121627121628121629121630121631121632121633121634121635121636121637121638121639121640121641121642121643121644121645121646121647121648121649121650121651121652121653121654121655121656121657121658121659121660121661121662121663121664121665121666121667121668121669121670121671121672121673121674121675121676121677121678121679121680121681121682121683121684121685121686121687121688121689121690121691121692121693121694121695121696121697121698121699121700121701121702121703121704121705121706121707121708121709121710121711121712121713121714121715121716121717121718121719121720121721121722121723121724121725121726121727121728121729121730121731121732121733121734121735121736121737121738121739121740121741121742121743121744121745121746121747121748121749121750121751121752121753121754121755121756121757121758121759121760121761121762121763121764121765121766121767121768121769121770121771121772121773121774121775121776121777121778121779121780121781121782121783121784121785121786121787121788121789121790121791121792121793121794121795121796121797121798121799121800121801121802121803121804121805121806121807121808121809121810121811121812121813121814121815121816121817121818121819121820121821121822121823121824121825121826121827121828121829121830121831121832121833121834121835121836121837121838121839121840121841121842121843121844121845121846121847121848121849121850121851121852121853121854121855121856121857121858121859121860121861121862121863121864121865121866121867121868121869121870121871121872121873121874121875121876121877121878121879121880121881121882121883121884121885121886121887121888121889121890121891121892121893121894121895121896121897121898121899121900121901121902121903121904121905121906121907121908121909121910121911121912121913121914121915121916121917121918121919121920121921121922121923121924121925121926121927121928121929121930121931121932121933121934121935121936121937121938121939121940121941121942121943121944121945121946121947121948121949121950121951121952121953121954121955121956121957121958121959121960121961121962121963121964121965121966121967121968121969121970121971121972121973121974121975121976121977121978121979121980121981121982121983121984121985121986121987121988121989121990121991121992121993121994121995121996121997121998121999122000122001122002122003122004122005122006122007122008122009122010122011122012122013122014122015122016122017122018122019122020122021122022122023122024122025122026122027122028122029122030122031122032122033122034122035122036122037122038122039122040122041122042122043122044122045122046122047122048122049122050122051122052122053122054122055122056122057122058122059122060122061122062122063122064122065122066122067122068122069122070122071122072122073122074122075122076122077122078122079122080122081122082122083122084122085122086122087122088122089122090122091122092122093122094122095122096122097122098122099122100122101122102122103122104122105122106122107122108122109122110122111122112122113122114122115122116122117122118122119122120122121122122122123122124122125122126122127122128122129122130122131122132122133122134122135122136122137122138122139122140122141122142122143122144122145122146122147122148122149122150122151122152122153122154122155122156122157122158122159122160122161122162122163122164122165122166122167122168122169122170122171122172122173122174122175122176122177122178122179122180122181122182122183122184122185122186122187122188122189122190122191122192122193122194122195122196122197122198122199122200122201122202122203122204122205122206122207122208122209122210122211122212122213122214122215122216122217122218122219122220122221122222122223122224122225122226122227122228122229122230122231122232122233122234122235122236122237122238122239122240122241122242122243122244122245122246122247122248122249122250122251122252122253122254122255122256122257122258122259122260122261122262122263122264122265122266122267122268122269122270122271122272122273122274122275122276122277122278122279122280122281122282122283122284122285122286122287122288122289122290122291122292122293122294122295122296122297122298122299122300122301122302122303122304122305122306122307122308122309122310122311122312122313122314122315122316122317122318122319122320122321122322122323122324122325122326122327122328122329122330122331122332122333122334122335122336122337122338122339122340122341122342122343122344122345122346122347122348122349122350122351122352122353122354122355122356122357122358122359122360122361122362122363122364122365122366122367122368122369122370122371122372122373122374122375122376122377122378122379122380122381122382122383122384122385122386122387122388122389122390122391122392122393122394122395122396122397122398122399122400122401122402122403122404122405122406122407122408122409122410122411122412122413122414122415122416122417122418122419122420122421122422122423122424122425122426122427122428122429122430122431122432122433122434122435122436122437122438122439122440122441122442122443122444122445122446122447122448122449122450122451122452122453122454122455122456122457122458122459122460122461122462122463122464122465122466122467122468122469122470122471122472122473122474122475122476122477122478122479122480122481122482122483122484122485122486122487122488122489122490122491122492122493122494122495122496122497122498122499122500122501122502122503122504122505122506122507122508122509122510122511122512122513122514122515122516122517122518122519122520122521122522122523122524122525122526122527122528122529122530122531122532122533122534122535122536122537122538122539122540122541122542122543122544122545122546122547122548122549122550122551122552122553122554122555122556122557122558122559122560122561122562122563122564122565122566122567122568122569122570122571122572122573122574122575122576122577122578122579122580122581122582122583122584122585122586122587122588122589122590122591122592122593122594122595122596122597122598122599122600122601122602122603122604122605122606122607122608122609122610122611122612122613122614122615122616122617122618122619122620122621122622122623122624122625122626122627122628122629122630122631122632122633122634122635122636122637122638122639122640122641122642122643122644122645122646122647122648122649122650122651122652122653122654122655122656122657122658122659122660122661122662122663122664122665122666122667122668122669122670122671122672122673122674122675122676122677122678122679122680122681122682122683122684122685122686122687122688122689122690122691122692122693122694122695122696122697122698122699122700122701122702122703122704122705122706122707122708122709122710122711122712122713122714122715122716122717122718122719122720122721122722122723122724122725122726122727122728122729122730122731122732122733122734122735122736122737122738122739122740122741122742122743122744122745122746122747122748122749122750122751122752122753122754122755122756122757122758122759122760122761122762122763122764122765122766122767122768122769122770122771122772122773122774122775122776122777122778122779122780122781122782122783122784122785122786122787122788122789122790122791122792122793122794122795122796122797122798122799122800122801122802122803122804122805122806122807122808122809122810122811122812122813122814122815122816122817122818122819122820122821122822122823122824122825122826122827122828122829122830122831122832122833122834122835122836122837122838122839122840122841122842122843122844122845122846122847122848122849122850122851122852122853122854122855122856122857122858122859122860122861122862122863122864122865122866122867122868122869122870122871122872122873122874122875122876122877122878122879122880122881122882122883122884122885122886122887122888122889122890122891122892122893122894122895122896122897122898122899122900122901122902122903122904122905122906122907122908122909122910122911122912122913122914122915122916122917122918122919122920122921122922122923122924122925122926122927122928122929122930122931122932122933122934122935122936122937122938122939122940122941122942122943122944122945122946122947122948122949122950122951122952122953122954122955122956122957122958122959122960122961122962122963122964122965122966122967122968122969122970122971122972122973122974122975122976122977122978122979122980122981122982122983122984122985122986122987122988122989122990122991122992122993122994122995122996122997122998122999123000123001123002123003123004123005123006123007123008123009123010123011123012123013123014123015123016123017123018123019123020123021123022123023123024123025123026123027123028123029123030123031123032123033123034123035123036123037123038123039123040123041123042123043123044123045123046123047123048123049123050123051123052123053123054123055123056123057123058123059123060123061123062123063123064123065123066123067123068123069123070123071123072123073123074123075123076123077123078123079123080123081123082123083123084123085123086123087123088123089123090123091123092123093123094123095123096123097123098123099123100123101123102123103123104123105123106123107123108123109123110123111123112123113123114123115123116123117123118123119123120123121123122123123123124123125123126123127123128123129123130123131123132123133123134123135123136123137123138123139123140123141123142123143123144123145123146123147123148123149123150123151123152123153123154123155123156123157123158123159123160123161123162123163123164123165123166123167123168123169123170123171123172123173123174123175123176123177123178123179123180123181123182123183123184123185123186123187123188123189123190123191123192123193123194123195123196123197123198123199123200123201123202123203123204123205123206123207123208123209123210123211123212123213123214123215123216123217123218123219123220123221123222123223123224123225123226123227123228123229123230123231123232123233123234123235123236123237123238123239123240123241123242123243123244123245123246123247123248123249123250123251123252123253123254123255123256123257123258123259123260123261123262123263123264123265123266123267123268123269123270123271123272123273123274123275123276123277123278123279123280123281123282123283123284123285123286123287123288123289123290123291123292123293123294123295123296123297123298123299123300123301123302123303123304123305123306123307123308123309123310123311123312123313123314123315123316123317123318123319123320123321123322123323123324123325123326123327123328123329123330123331123332123333123334123335123336123337123338123339123340123341123342123343123344123345123346123347123348123349123350123351123352123353123354123355123356123357123358123359123360123361123362123363123364123365123366123367123368123369123370123371123372123373123374123375123376123377123378123379123380123381123382123383123384123385123386123387123388123389123390123391123392123393123394123395123396123397123398123399123400123401123402123403123404123405123406123407123408123409123410123411123412123413123414123415123416123417123418123419123420123421123422123423123424123425123426123427123428123429123430123431123432123433123434123435123436123437123438123439123440123441123442123443123444123445123446123447123448123449123450123451123452123453123454123455123456123457123458123459123460123461123462123463123464123465123466123467123468123469123470123471123472123473123474123475123476123477123478123479123480123481123482123483123484123485123486123487123488123489123490123491123492123493123494123495123496123497123498123499123500123501123502123503123504123505123506123507123508123509123510123511123512123513123514123515123516123517123518123519123520123521123522123523123524123525123526123527123528123529123530123531123532123533123534123535123536123537123538123539123540123541123542123543123544123545123546123547123548123549123550123551123552123553123554123555123556123557123558123559123560123561123562123563123564123565123566123567123568123569123570123571123572123573123574123575123576123577123578123579123580123581123582123583123584123585123586123587123588123589123590123591123592123593123594123595123596123597123598123599123600123601123602123603123604123605123606123607123608123609123610123611123612123613123614123615123616123617123618123619123620123621123622123623123624123625123626123627123628123629123630123631123632123633123634123635123636123637123638123639123640123641123642123643123644123645123646123647123648123649123650123651123652123653123654123655123656123657123658123659123660123661123662123663123664123665123666123667123668123669123670123671123672123673123674123675123676123677123678123679123680123681123682123683123684123685123686123687123688123689123690123691123692123693123694123695123696123697123698123699123700123701123702123703123704123705123706123707123708123709123710123711123712123713123714123715123716123717123718123719123720123721123722123723123724123725123726123727123728123729123730123731123732123733123734123735123736123737123738123739123740123741123742123743123744123745123746123747123748123749123750123751123752123753123754123755123756123757123758123759123760123761123762123763123764123765123766123767123768123769123770123771123772123773123774123775123776123777123778123779123780123781123782123783123784123785123786123787123788123789123790123791123792123793123794123795123796123797123798123799123800123801123802123803123804123805123806123807123808123809123810123811123812123813123814123815123816123817123818123819123820123821123822123823123824123825123826123827123828123829123830123831123832123833123834123835123836123837123838123839123840123841123842123843123844123845123846123847123848123849123850123851123852123853123854123855123856123857123858123859123860123861123862123863123864123865123866123867123868123869123870123871123872123873123874123875123876123877123878123879123880123881123882123883123884123885123886123887123888123889123890123891123892123893123894123895123896123897123898123899123900123901123902123903123904123905123906123907123908123909123910123911123912123913123914123915123916123917123918123919123920123921123922123923123924123925123926123927123928123929123930123931123932123933123934123935123936123937123938123939123940123941123942123943123944123945123946123947123948123949123950123951123952123953123954123955123956123957123958123959123960123961123962123963123964123965123966123967123968123969123970123971123972123973123974123975123976123977123978123979123980123981123982123983123984123985123986123987123988123989123990123991123992123993123994123995123996123997123998123999124000124001124002124003124004124005124006124007124008124009124010124011124012124013124014124015124016124017124018124019124020124021124022124023124024124025124026124027124028124029124030124031124032124033124034124035124036124037124038124039124040124041124042124043124044124045124046124047124048124049124050124051124052124053124054124055124056124057124058124059124060124061124062124063124064124065124066124067124068124069124070124071124072124073124074124075124076124077124078124079124080124081124082124083124084124085124086124087124088124089124090124091124092124093124094124095124096124097124098124099124100124101124102124103124104124105124106124107124108124109124110124111124112124113124114124115124116124117124118124119124120124121124122124123124124124125124126124127124128124129124130124131124132124133124134124135124136124137124138124139124140124141124142124143124144124145124146124147124148124149124150124151124152124153124154124155124156124157124158124159124160124161124162124163124164124165124166124167124168124169124170124171124172124173124174124175124176124177124178124179124180124181124182124183124184124185124186124187124188124189124190124191124192124193124194124195124196124197124198124199124200124201124202124203124204124205124206124207124208124209124210124211124212124213124214124215124216124217124218124219124220124221124222124223124224124225124226124227124228124229124230124231124232124233124234124235124236124237124238124239124240124241124242124243124244124245124246124247124248124249124250124251124252124253124254124255124256124257124258124259124260124261124262124263124264124265124266124267124268124269124270124271124272124273124274124275124276124277124278124279124280124281124282124283124284124285124286124287124288124289124290124291124292124293124294124295124296124297124298124299124300124301124302124303124304124305124306124307124308124309124310124311124312124313124314124315124316124317124318124319124320124321124322124323124324124325124326124327124328124329124330124331124332124333124334124335124336124337124338124339124340124341124342124343124344124345124346124347124348124349124350124351124352124353124354124355124356124357124358124359124360124361124362124363124364124365124366124367124368124369124370124371124372124373124374124375124376124377124378124379124380124381124382124383124384124385124386124387124388124389124390124391124392124393124394124395124396124397124398124399124400124401124402124403124404124405124406124407124408124409124410124411124412124413124414124415124416124417124418124419124420124421124422124423124424124425124426124427124428124429124430124431124432124433124434124435124436124437124438124439124440124441124442124443124444124445124446124447124448124449124450124451124452124453124454124455124456124457124458124459124460124461124462124463124464124465124466124467124468124469124470124471124472124473124474124475124476124477124478124479124480124481124482124483124484124485124486124487124488124489124490124491124492124493124494124495124496124497124498124499124500124501124502124503124504124505124506124507124508124509124510124511124512124513124514124515124516124517124518124519124520124521124522124523124524124525124526124527124528124529124530124531124532124533124534124535124536124537124538124539124540124541124542124543124544124545124546124547124548124549124550124551124552124553124554124555124556124557124558124559124560124561124562124563124564124565124566124567124568124569124570124571124572124573124574124575124576124577124578124579124580124581124582124583124584124585124586124587124588124589124590124591124592124593124594124595124596124597124598124599124600124601124602124603124604124605124606124607124608124609124610124611124612124613124614124615124616124617124618124619124620124621124622124623124624124625124626124627124628124629124630124631124632124633124634124635124636124637124638124639124640124641124642124643124644124645124646124647124648124649124650124651124652124653124654124655124656124657124658124659124660124661124662124663124664124665124666124667124668124669124670124671124672124673124674124675124676124677124678124679124680124681124682124683124684124685124686124687124688124689124690124691124692124693124694124695124696124697124698124699124700124701124702124703124704124705124706124707124708124709124710124711124712124713124714124715124716124717124718124719124720124721124722124723124724124725124726124727124728124729124730124731124732124733124734124735124736124737124738124739124740124741124742124743124744124745124746124747124748124749124750124751124752124753124754124755124756124757124758124759124760124761124762124763124764124765124766124767124768124769124770124771124772124773124774124775124776124777124778124779124780124781124782124783124784124785124786124787124788124789124790124791124792124793124794124795124796124797124798124799124800124801124802124803124804124805124806124807124808124809124810124811124812124813124814124815124816124817124818124819124820124821124822124823124824124825124826124827124828124829124830124831124832124833124834124835124836124837124838124839124840124841124842124843124844124845124846124847124848124849124850124851124852124853124854124855124856124857124858124859124860124861124862124863124864124865124866124867124868124869124870124871124872124873124874124875124876124877124878124879124880124881124882124883124884124885124886124887124888124889124890124891124892124893124894124895124896124897124898124899124900124901124902124903124904124905124906124907124908124909124910124911124912124913124914124915124916124917124918124919124920124921124922124923124924124925124926124927124928124929124930124931124932124933124934124935124936124937124938124939124940124941124942124943124944124945124946124947124948124949124950124951124952124953124954124955124956124957124958124959124960124961124962124963124964124965124966124967124968124969124970124971124972124973124974124975124976124977124978124979124980124981124982124983124984124985124986124987124988124989124990124991124992124993124994124995124996124997124998124999125000125001125002125003125004125005125006125007125008125009125010125011125012125013125014125015125016125017125018125019125020125021125022125023125024125025125026125027125028125029125030125031125032125033125034125035125036125037125038125039125040125041125042125043125044125045125046125047125048125049125050125051125052125053125054125055125056125057125058125059125060125061125062125063125064125065125066125067125068125069125070125071125072125073125074125075125076125077125078125079125080125081125082125083125084125085125086125087125088125089125090125091125092125093125094125095125096125097125098125099125100125101125102125103125104125105125106125107125108125109125110125111125112125113125114125115125116125117125118125119125120125121125122125123125124125125125126125127125128125129125130125131125132125133125134125135125136125137125138125139125140125141125142125143125144125145125146125147125148125149125150125151125152125153125154125155125156125157125158125159125160125161125162125163125164125165125166125167125168125169125170125171125172125173125174125175125176125177125178125179125180125181125182125183125184125185125186125187125188125189125190125191125192125193125194125195125196125197125198125199125200125201125202125203125204125205125206125207125208125209125210125211125212125213125214125215125216125217125218125219125220125221125222125223125224125225125226125227125228125229125230125231125232125233125234125235125236125237125238125239125240125241125242125243125244125245125246125247125248125249125250125251125252125253125254125255125256125257125258125259125260125261125262125263125264125265125266125267125268125269125270125271125272125273125274125275125276125277125278125279125280125281125282125283125284125285125286125287125288125289125290125291125292125293125294125295125296125297125298125299125300125301125302125303125304125305125306125307125308125309125310125311125312125313125314125315125316125317125318125319125320125321125322125323125324125325125326125327125328125329125330125331125332125333125334125335125336125337125338125339125340125341125342125343125344125345125346125347125348125349125350125351125352125353125354125355125356125357125358125359125360125361125362125363125364125365125366125367125368125369125370125371125372125373125374125375125376125377125378125379125380125381125382125383125384125385125386125387125388125389125390125391125392125393125394125395125396125397125398125399125400125401125402125403125404125405125406125407125408125409125410125411125412125413125414125415125416125417125418125419125420125421125422125423125424125425125426125427125428125429125430125431125432125433125434125435125436125437125438125439125440125441125442125443125444125445125446125447125448125449125450125451125452125453125454125455125456125457125458125459125460125461125462125463125464125465125466125467125468125469125470125471125472125473125474125475125476125477125478125479125480125481125482125483125484125485125486125487125488125489125490125491125492125493125494125495125496125497125498125499125500125501125502125503125504125505125506125507125508125509125510125511125512125513125514125515125516125517125518125519125520125521125522125523125524125525125526125527125528125529125530125531125532125533125534125535125536125537125538125539125540125541125542125543125544125545125546125547125548125549125550125551125552125553125554125555125556125557125558125559125560125561125562125563125564125565125566125567125568125569125570125571125572125573125574125575125576125577125578125579125580125581125582125583125584125585125586125587125588125589125590125591125592125593125594125595125596125597125598125599125600125601125602125603125604125605125606125607125608125609125610125611125612125613125614125615125616125617125618125619125620125621125622125623125624125625125626125627125628125629125630125631125632125633125634125635125636125637125638125639125640125641125642125643125644125645125646125647125648125649125650125651125652125653125654125655125656125657125658125659125660125661125662125663125664125665125666125667125668125669125670125671125672125673125674125675125676125677125678125679125680125681125682125683125684125685125686125687125688125689125690125691125692125693125694125695125696125697125698125699125700125701125702125703125704125705125706125707125708125709125710125711125712125713125714125715125716125717125718125719125720125721125722125723125724125725125726125727125728125729125730125731125732125733125734125735125736125737125738125739125740125741125742125743125744125745125746125747125748125749125750125751125752125753125754125755125756125757125758125759125760125761125762125763125764125765125766125767125768125769125770125771125772125773125774125775125776125777125778125779125780125781125782125783125784125785125786125787125788125789125790125791125792125793125794125795125796125797125798125799125800125801125802125803125804125805125806125807125808125809125810125811125812125813125814125815125816125817125818125819125820125821125822125823125824125825125826125827125828125829125830125831125832125833125834125835125836125837125838125839125840125841125842125843125844125845125846125847125848125849125850125851125852125853125854125855125856125857125858125859125860125861125862125863125864125865125866125867125868125869125870125871125872125873125874125875125876125877125878125879125880125881125882125883125884125885125886125887125888125889125890125891125892125893125894125895125896125897125898125899125900125901125902125903125904125905125906125907125908125909125910125911125912125913125914125915125916125917125918125919125920125921125922125923125924125925125926125927125928125929125930125931125932125933125934125935125936125937125938125939125940125941125942125943125944125945125946125947125948125949125950125951125952125953125954125955125956125957125958125959125960125961125962125963125964125965125966125967125968125969125970125971125972125973125974125975125976125977125978125979125980125981125982125983125984125985125986125987125988125989125990125991125992125993125994125995125996125997125998125999126000126001126002126003126004126005126006126007126008126009126010126011126012126013126014126015126016126017126018126019126020126021126022126023126024126025126026126027126028126029126030126031126032126033126034126035126036126037126038126039126040126041126042126043126044126045126046126047126048126049126050126051126052126053126054126055126056126057126058126059126060126061126062126063126064126065126066126067126068126069126070126071126072126073126074126075126076126077126078126079126080126081126082126083126084126085126086126087126088126089126090126091126092126093126094126095126096126097126098126099126100126101126102126103126104126105126106126107126108126109126110126111126112126113126114126115126116126117126118126119126120126121126122126123126124126125126126126127126128126129126130126131126132126133126134126135126136126137126138126139126140126141126142126143126144126145126146126147126148126149126150126151126152126153126154126155126156126157126158126159126160126161126162126163126164126165126166126167126168126169126170126171126172126173126174126175126176126177126178126179126180126181126182126183126184126185126186126187126188126189126190126191126192126193126194126195126196126197126198126199126200126201126202126203126204126205126206126207126208126209126210126211126212126213126214126215126216126217126218126219126220126221126222126223126224126225126226126227126228126229126230126231126232126233126234126235126236126237126238126239126240126241126242126243126244126245126246126247126248126249126250126251126252126253126254126255126256126257126258126259126260126261126262126263126264126265126266126267126268126269126270126271126272126273126274126275126276126277126278126279126280126281126282126283126284126285126286126287126288126289126290126291126292126293126294126295126296126297126298126299126300126301126302126303126304126305126306126307126308126309126310126311126312126313126314126315126316126317126318126319126320126321126322126323126324126325126326126327126328126329126330126331126332126333126334126335126336126337126338126339126340126341126342126343126344126345126346126347126348126349126350126351126352126353126354126355126356126357126358126359126360126361126362126363126364126365126366126367126368126369126370126371126372126373126374126375126376126377126378126379126380126381126382126383126384126385126386126387126388126389126390126391126392126393126394126395126396126397126398126399126400126401126402126403126404126405126406126407126408126409126410126411126412126413126414126415126416126417126418126419126420126421126422126423126424126425126426126427126428126429126430126431126432126433126434126435126436126437126438126439126440126441126442126443126444126445126446126447126448126449126450126451126452126453126454126455126456126457126458126459126460126461126462126463126464126465126466126467126468126469126470126471126472126473126474126475126476126477126478126479126480126481126482126483126484126485126486126487126488126489126490126491126492126493126494126495126496126497126498126499126500126501126502126503126504126505126506126507126508126509126510126511126512126513126514126515126516126517126518126519126520126521126522126523126524126525126526126527126528126529126530126531126532126533126534126535126536126537126538126539126540126541126542126543126544126545126546126547126548126549126550126551126552126553126554126555126556126557126558126559126560126561126562126563126564126565126566126567126568126569126570126571126572126573126574126575126576126577126578126579126580126581126582126583126584126585126586126587126588126589126590126591126592126593126594126595126596126597126598126599126600126601126602126603126604126605126606126607126608126609126610126611126612126613126614126615126616126617126618126619126620126621126622126623126624126625126626126627126628126629126630126631126632126633126634126635126636126637126638126639126640126641126642126643126644126645126646126647126648126649126650126651126652126653126654126655126656126657126658126659126660126661126662126663126664126665126666126667126668126669126670126671126672126673126674126675126676126677126678126679126680126681126682126683126684126685126686126687126688126689126690126691126692126693126694126695126696126697126698126699126700126701126702126703126704126705126706126707126708126709126710126711126712126713126714126715126716126717126718126719126720126721126722126723126724126725126726126727126728126729126730126731126732126733126734126735126736126737126738126739126740126741126742126743126744126745126746126747126748126749126750126751126752126753126754126755126756126757126758126759126760126761126762126763126764126765126766126767126768126769126770126771126772126773126774126775126776126777126778126779126780126781126782126783126784126785126786126787126788126789126790126791126792126793126794126795126796126797126798126799126800126801126802126803126804126805126806126807126808126809126810126811126812126813126814126815126816126817126818126819126820126821126822126823126824126825126826126827126828126829126830126831126832126833126834126835126836126837126838126839126840126841126842126843126844126845126846126847126848126849126850126851126852126853126854126855126856126857126858126859126860126861126862126863126864126865126866126867126868126869126870126871126872126873126874126875126876126877126878126879126880126881126882126883126884126885126886126887126888126889126890126891126892126893126894126895126896126897126898126899126900126901126902126903126904126905126906126907126908126909126910126911126912126913126914126915126916126917126918126919126920126921126922126923126924126925126926126927126928126929126930126931126932126933126934126935126936126937126938126939126940126941126942126943126944126945126946126947126948126949126950126951126952126953126954126955126956126957126958126959126960126961126962126963126964126965126966126967126968126969126970126971126972126973126974126975126976126977126978126979126980126981126982126983126984126985126986126987126988126989126990126991126992126993126994126995126996126997126998126999127000127001127002127003127004127005127006127007127008127009127010127011127012127013127014127015127016127017127018127019127020127021127022127023127024127025127026127027127028127029127030127031127032127033127034127035127036127037127038127039127040127041127042127043127044127045127046127047127048127049127050127051127052127053127054127055127056127057127058127059127060127061127062127063127064127065127066127067127068127069127070127071127072127073127074127075127076127077127078127079127080127081127082127083127084127085127086127087127088127089127090127091127092127093127094127095127096127097127098127099127100127101127102127103127104127105127106127107127108127109127110127111127112127113127114127115127116127117127118127119127120127121127122127123127124127125127126127127127128127129127130127131127132127133127134127135127136127137127138127139127140127141127142127143127144127145127146127147127148127149127150127151127152127153127154127155127156127157127158127159127160127161127162127163127164127165127166127167127168127169127170127171127172127173127174127175127176127177127178127179127180127181127182127183127184127185127186127187127188127189127190127191127192127193127194127195127196127197127198127199127200127201127202127203127204127205127206127207127208127209127210127211127212127213127214127215127216127217127218127219127220127221127222127223127224127225127226127227127228127229127230127231127232127233127234127235127236127237127238127239127240127241127242127243127244127245127246127247127248127249127250127251127252127253127254127255127256127257127258127259127260127261127262127263127264127265127266127267127268127269127270127271127272127273127274127275127276127277127278127279127280127281127282127283127284127285127286127287127288127289127290127291127292127293127294127295127296127297127298127299127300127301127302127303127304127305127306127307127308127309127310127311127312127313127314127315127316127317127318127319127320127321127322127323127324127325127326127327127328127329127330127331127332127333127334127335127336127337127338127339127340127341127342127343127344127345127346127347127348127349127350127351127352127353127354127355127356127357127358127359127360127361127362127363127364127365127366127367127368127369127370127371127372127373127374127375127376127377127378127379127380127381127382127383127384127385127386127387127388127389127390127391127392127393127394127395127396127397127398127399127400127401127402127403127404127405127406127407127408127409127410127411127412127413127414127415127416127417127418127419127420127421127422127423127424127425127426127427127428127429127430127431127432127433127434127435127436127437127438127439127440127441127442127443127444127445127446127447127448127449127450127451127452127453127454127455127456127457127458127459127460127461127462127463127464127465127466127467127468127469127470127471127472127473127474127475127476127477127478127479127480127481127482127483127484127485127486127487127488127489127490127491127492127493127494127495127496127497127498127499127500127501127502127503127504127505127506127507127508127509127510127511127512127513127514127515127516127517127518127519127520127521127522127523127524127525127526127527127528127529127530127531127532127533127534127535127536127537127538127539127540127541127542127543127544127545127546127547127548127549127550127551127552127553127554127555127556127557127558127559127560127561127562127563127564127565127566127567127568127569127570127571127572127573127574127575127576127577127578127579127580127581127582127583127584127585127586127587127588127589127590127591127592127593127594127595127596127597127598127599127600127601127602127603127604127605127606127607127608127609127610127611127612127613127614127615127616127617127618127619127620127621127622127623127624127625127626127627127628127629127630127631127632127633127634127635127636127637127638127639127640127641127642127643127644127645127646127647127648127649127650127651127652127653127654127655127656127657127658127659127660127661127662127663127664127665127666127667127668127669127670127671127672127673127674127675127676127677127678127679127680127681127682127683127684127685127686127687127688127689127690127691127692127693127694127695127696127697127698127699127700127701127702127703127704127705127706127707127708127709127710127711127712127713127714127715127716127717127718127719127720127721127722127723127724127725127726127727127728127729127730127731127732127733127734127735127736127737127738127739127740127741127742127743127744127745127746127747127748127749127750127751127752127753127754127755127756127757127758127759127760127761127762127763127764127765127766127767127768127769127770127771127772127773127774127775127776127777127778127779127780127781127782127783127784127785127786127787127788127789127790127791127792127793127794127795127796127797127798127799127800127801127802127803127804127805127806127807127808127809127810127811127812127813127814127815127816127817127818127819127820127821127822127823127824127825127826127827127828127829127830127831127832127833127834127835127836127837127838127839127840127841127842127843127844127845127846127847127848127849127850127851127852127853127854127855127856127857127858127859127860127861127862127863127864127865127866127867127868127869127870127871127872127873127874127875127876127877127878127879127880127881127882127883127884127885127886127887127888127889127890127891127892127893127894127895127896127897127898127899127900127901127902127903127904127905127906127907127908127909127910127911127912127913127914127915127916127917127918127919127920127921127922127923127924127925127926127927127928127929127930127931127932127933127934127935127936127937127938127939127940127941127942127943127944127945127946127947127948127949127950127951127952127953127954127955127956127957127958127959127960127961127962127963127964127965127966127967127968127969127970127971127972127973127974127975127976127977127978127979127980127981127982127983127984127985127986127987127988127989127990127991127992127993127994127995127996127997127998127999128000128001128002128003128004128005128006128007128008128009128010128011128012128013128014128015128016128017128018128019128020128021128022128023128024128025128026128027128028128029128030128031128032128033128034128035128036128037128038128039128040128041128042128043128044128045128046128047128048128049128050128051128052128053128054128055128056128057128058128059128060128061128062128063128064128065128066128067128068128069128070128071128072128073128074128075128076128077128078128079128080128081128082128083128084128085128086128087128088128089128090128091128092128093128094128095128096128097128098128099128100128101128102128103128104128105128106128107128108128109128110128111128112128113128114128115128116128117128118128119128120128121128122128123128124128125128126128127128128128129128130128131128132128133128134128135128136128137128138128139128140128141128142128143128144128145128146128147128148128149128150128151128152128153128154128155128156128157128158128159128160128161128162128163128164128165128166128167128168128169128170128171128172128173128174128175128176128177128178128179128180128181128182128183128184128185128186128187128188128189128190128191128192128193128194128195128196128197128198128199128200128201128202128203128204128205128206128207128208128209128210128211128212128213128214128215128216128217128218128219128220128221128222128223128224128225128226128227128228128229128230128231128232128233128234128235128236128237128238128239128240128241128242128243128244128245128246128247128248128249128250128251128252128253128254128255128256128257128258128259128260128261128262128263128264128265128266128267128268128269128270128271128272128273128274128275128276128277128278128279128280128281128282128283128284128285128286128287128288128289128290128291128292128293128294128295128296128297128298128299128300128301128302128303128304128305128306128307128308128309128310128311128312128313128314128315128316128317128318128319128320128321128322128323128324128325128326128327128328128329128330128331128332128333128334128335128336128337128338128339128340128341128342128343128344128345128346128347128348128349128350128351128352128353128354128355128356128357128358128359128360128361128362128363128364128365128366128367128368128369128370128371128372128373128374128375128376128377128378128379128380128381128382128383128384128385128386128387128388128389128390128391128392128393128394128395128396128397128398128399128400128401128402128403128404128405128406128407128408128409128410128411128412128413128414128415128416128417128418128419128420128421128422128423128424128425128426128427128428128429128430128431128432128433128434128435128436128437128438128439128440128441128442128443128444128445128446128447128448128449128450128451128452128453128454128455128456128457128458128459128460128461128462128463128464128465128466128467128468128469128470128471128472128473128474128475128476128477128478128479128480128481128482128483128484128485128486128487128488128489128490128491128492128493128494128495128496128497128498128499128500128501128502128503128504128505128506128507128508128509128510128511128512128513128514128515128516128517128518128519128520128521128522128523128524128525128526128527128528128529128530128531128532128533128534128535128536128537128538128539128540128541128542128543128544128545128546128547128548128549128550128551128552128553128554128555128556128557128558128559128560128561128562128563128564128565128566128567128568128569128570128571128572128573128574128575128576128577128578128579128580128581128582128583128584128585128586128587128588128589128590128591128592128593128594128595128596128597128598128599128600128601128602128603128604128605128606128607128608128609128610128611128612128613128614128615128616128617128618128619128620128621128622128623128624128625128626128627128628128629128630128631128632128633128634128635128636128637128638128639128640128641128642128643128644128645128646128647128648128649128650128651128652128653128654128655128656128657128658128659128660128661128662128663128664128665128666128667128668128669128670128671128672128673128674128675128676128677128678128679128680128681128682128683128684128685128686128687128688128689128690128691128692128693128694128695128696128697128698128699128700128701128702128703128704128705128706128707128708128709128710128711128712128713128714128715128716128717128718128719128720128721128722128723128724128725128726128727128728128729128730128731128732128733128734128735128736128737128738128739128740128741128742128743128744128745128746128747128748128749128750128751128752128753128754128755128756128757128758128759128760128761128762128763128764128765128766128767128768128769128770128771128772128773128774128775128776128777128778128779128780128781
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = global || self, factory(global.Potree = {}));
  5. }(this, (function (exports) { 'use strict';
  6. function mobileVersion(e, t) {
  7. //ios的版本
  8. var i = window.navigator.userAgent,
  9. n = i.match(e);
  10. return (
  11. (n = n ? n[1].split(t) : []),
  12. {
  13. major: parseInt(n[0]) || 0,
  14. minor: parseInt(n[1]) || 0,
  15. patch: parseInt(n[2]) || 0,
  16. }
  17. )
  18. }
  19. var browser = {
  20. isFullscreen: function() {
  21. return (
  22. document.fullscreenElement ||
  23. document.mozFullscreenElement ||
  24. document.mozFullScreenElement ||
  25. document.webkitFullscreenElement ||
  26. document.msFullscreenElement
  27. )
  28. },
  29. supportsFullscreen: function() {
  30. return (
  31. document.fullscreenEnabled ||
  32. document.mozFullscreenEnabled ||
  33. document.mozFullScreenEnabled ||
  34. document.webkitFullscreenEnabled ||
  35. document.msFullscreenEnabled
  36. )
  37. },
  38. isPointerLocked: function() {
  39. return (
  40. document.pointerLockElement ||
  41. document.mozPointerLockElement ||
  42. document.webkitPointerLockElement
  43. )
  44. },
  45. requestFullscreen: function(dom, t) {
  46. dom.requestFullscreen ?
  47. dom.requestFullscreen() :
  48. dom.mozRequestFullScreen ?
  49. dom.mozRequestFullScreen() :
  50. dom.webkitRequestFullscreen ?
  51. dom.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT) :
  52. dom.msRequestFullscreen && dom.msRequestFullscreen(),
  53. t &&
  54. $(document).on(
  55. "fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange",
  56. browser.requestPointerLock
  57. );
  58. },
  59. requestPointerLock: function() {
  60. var e;
  61. if (document.fullscreenElement) e = document.fullscreenElement();
  62. else if (document.mozFullscreenElement) e = document.mozFullscreenElement();
  63. else if (document.mozFullScreenElement) e = document.mozFullScreenElement();
  64. else {
  65. if (!document.webkitFullscreenElement) return
  66. e = document.webkitFullscreenElement();
  67. };
  68. (e.requestPointerLock =
  69. e.requestPointerLock || e.mozRequestPointerLock || e.webkitRequestPointerLock),
  70. e.requestPointerLock(),
  71. $(document).off(
  72. "fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange",
  73. this
  74. );
  75. },
  76. exitPointerLock: function() {
  77. ;
  78. (document.exitPointerLock =
  79. document.exitPointerLock ||
  80. document.mozExitPointerLock ||
  81. document.webkitExitPointerLock),
  82. document.exitPointerLock();
  83. },
  84. exitFullscreen: function() {
  85. document.exitFullscreen ?
  86. document.exitFullscreen() :
  87. document.msExitFullscreen ?
  88. document.msExitFullscreen() :
  89. document.mozCancelFullScreen ?
  90. document.mozCancelFullScreen() :
  91. document.webkitExitFullscreen && document.webkitExitFullscreen();
  92. },
  93. details: function() {
  94. var e = navigator.userAgent.match("(Firefox|Chrome|Safari)/([\\d]+)");
  95. return e ?
  96. {
  97. name: e[1],
  98. version: parseInt(e[2]),
  99. platform: navigator.platform,
  100. } : {}
  101. },
  102. is: function(e) {
  103. return this.details() && this.details().name === e
  104. },
  105. inIframe: function() {
  106. return window.parent !== window
  107. },
  108. aspectRatio: function($elem) {
  109. $elem = $elem || $("#player");
  110. var e = $elem.width() / $elem.height();
  111. return isFinite(e) ? e : 0
  112. },
  113. userAgent: function() {
  114. return window.navigator.userAgent
  115. },
  116. isMobile: function() {
  117. var e = navigator.userAgent || navigator.vendor || window.opera;
  118. return (
  119. /(android|bb\d+|meego).+mobile|android|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
  120. e
  121. ) ||
  122. /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
  123. e.substr(0, 4)
  124. )
  125. )
  126. },
  127. isLandscape: function() {
  128. return this.isMobile && this.aspectRatio() > 1
  129. },
  130. isSmallScreen: function() {
  131. var e = screen.width / window.devicePixelRatio;
  132. return e < 240
  133. },
  134. detectIE: function() {
  135. var e = window.navigator.userAgent,
  136. t = e.indexOf("MSIE ");
  137. return t !== -1 || !!navigator.userAgent.match(/Trident.*rv\:11\./)
  138. },
  139. detectSafari: function() {
  140. var e = window.navigator.userAgent,
  141. t = e.indexOf("Safari");
  142. return t !== -1 && !this.detectOpera() && !this.detectChrome() //xzw add detectOpera
  143. },
  144. detectFirefox: function() {
  145. var e = window.navigator.userAgent;
  146. return e.indexOf("Firefox") !== -1
  147. },
  148. detectChrome: function() {
  149. var e = window.navigator.userAgent;
  150. return e.indexOf("Chrome") !== -1 && !this.detectOpera()
  151. },
  152. detectOpera: function() {
  153. var e = window.navigator.userAgent;
  154. return e.indexOf("OPR") !== -1
  155. },
  156. detectIOS: function() {
  157. return this.detectIPhone() || this.detectIPad() || this.detectIPod()
  158. },
  159. detectIPad: function() {
  160. var e = window.navigator.userAgent,
  161. t = /iPad/;
  162. return t.test(e)
  163. },
  164. detectIPod: function() {
  165. var e = window.navigator.userAgent,
  166. t = /iPod/;
  167. return t.test(e)
  168. },
  169. detectIPhone: function() {
  170. var e = window.navigator.userAgent,
  171. t = /iPhone/;
  172. return t.test(e)
  173. },
  174. detectAndroid: function() {
  175. var e = window.navigator.userAgent;
  176. return e.indexOf("Android") !== -1
  177. },
  178. detectAndroidMobile: function() {
  179. var e = window.navigator.userAgent;
  180. return this.detectAndroid() && e.indexOf("Mobile") !== -1
  181. },
  182. detectSamsungNative: function() {
  183. var e = window.navigator.userAgent;
  184. return (
  185. e.indexOf("SM-G900H") !== -1 ||
  186. e.indexOf("GT-I9500") !== -1 ||
  187. e.indexOf("SM-N900") !== -1
  188. )
  189. },
  190. detectSamsungS6: function() {
  191. var e = window.navigator.userAgent;
  192. return e.indexOf("SM-G92") !== -1
  193. },
  194. /************************************************************徐世廷*************************************************************/
  195. detectHUAWEI5X: function() {
  196. return -1 !== window.navigator.userAgent.indexOf("KIW-TL00H")
  197. },
  198. /*******************************************************************************************************************************/
  199. detectWebVR: function() {
  200. return !(!window.navigator.getVRDisplays || !window.VRDisplay)
  201. },
  202. getVRDisplay: function() {
  203. var e = $.Deferred();
  204. return this.detectWebVR() ?
  205. (navigator.getVRDisplays().then(function(t) {
  206. t.length >= 1 && e.resolve(t[0]), e.reject(null);
  207. }),
  208. e) :
  209. e.reject(null)
  210. },
  211. iosVersion: function() {
  212. if (!this.detectIOS()) throw new DeviceMismatchException("Did not detect an iDevice")
  213. var e = /((?:\d+\_?){1,3}) like Mac OS/,
  214. t = "_";
  215. return mobileVersion(e, t)
  216. },
  217. androidVersion: function() {
  218. if (!this.detectAndroid())
  219. throw new DeviceMismatchException("Did not detect an Android based device")
  220. var e = /Android ((?:\d+\.?){1,3})/,
  221. t = ".";
  222. return mobileVersion(e, t)
  223. },
  224. valueFromCookie: function(e, t) {
  225. var i = new RegExp(e + "=([0-9a-f]+)(; ?|$)").exec(document.cookie);
  226. if (!i) return t
  227. var n = i[1];
  228. return "boolean" == typeof t ?
  229. "true" === n || "1" === n :
  230. "number" == typeof t ?
  231. parseFloat(n) :
  232. n
  233. },
  234. valueFromHash: function(e, t) {
  235. var i = new RegExp("[#&?]" + e + "=([^#&?]*)"),
  236. n = i.exec(window.location.href);
  237. if (!n) return t
  238. var r = n[1];
  239. return "boolean" == typeof t ?
  240. "true" === r || "1" === r :
  241. "number" == typeof t ?
  242. parseFloat(r) :
  243. window.decodeURIComponent(r)
  244. },
  245. //-------许钟文:-------------------------------------------------
  246. getProjectNum: function() {
  247. //获取场景projectNum
  248. if (window.__ProjectNum && window.__ProjectNum != "__ProjectNum__") {
  249. return window.__ProjectNum
  250. }
  251. var number = window.location.href.substring(window.location.href.indexOf("=") + 1);
  252. if (number.indexOf("&") != -1) {
  253. number = number.substring(0, number.indexOf("&"));
  254. }
  255. if (number.indexOf("#") != -1) {
  256. number = number.substring(0, number.indexOf("#"));
  257. }
  258. return number
  259. },
  260. urlHasValue: function(key, isGetValue) {
  261. // debugger
  262. // if (getValue) { //得到类似n=1 的 1
  263. // var b = window.location.href.substring(window.location.href.indexOf("?") + 1);
  264. // var a = b.indexOf('&' + t + "=");
  265. // if (a > -1) {
  266. // var s = b.substring(a + ('&' + t + "=").length);
  267. // s.indexOf("&") > -1 && (s = s.substring(0, s.indexOf("&")));
  268. // s.indexOf("#") > -1 && (s = s.substring(0, s.indexOf("#")));
  269. // return s;
  270. // } else return false;
  271. // } else return window.location.search.match("&" + t + "|\\?" + t) != null; //window.location.href.substring(window.location.href.indexOf("?") + 1).indexOf('&' + t) > -1;
  272. //const value = window.location.search.match("&" + t + "|\\?" + t)
  273. if (key === "m" && window.__ProjectNum && window.__ProjectNum != "__ProjectNum__") {
  274. return window.__ProjectNum
  275. }
  276. let querys = window.location.search.substr(1).split("&");
  277. if (isGetValue) {
  278. for (let i = 0; i < querys.length; i++) {
  279. let keypair = querys[i].split("=");
  280. if (keypair.length === 2 && keypair[0] === key) {
  281. return keypair[1]
  282. }
  283. }
  284. return ""
  285. } else {
  286. //return window.location.search.match("&" + key + "|\\?" + key) != null 有bug
  287. for (let i = 0; i < querys.length; i++) {
  288. let keypair = querys[i].split("=");
  289. if (keypair[0] == key) {
  290. return true
  291. }
  292. }
  293. return false
  294. }
  295. },
  296. /**
  297. * 获取查询参数的值
  298. * @param {String} key
  299. * @returns String
  300. */
  301. urlQueryValue(key) {
  302. return this.urlHasValue(key, true) || ""
  303. },
  304. /**
  305. * 获取hash参数的值
  306. * @param {String} key
  307. * @returns String
  308. */
  309. urlHashValue(key) {
  310. let querys = window.location.hash.substr(1).replace('/?', '').split("&");
  311. for (let i = 0; i < querys.length; i++) {
  312. let keypair = querys[i].split("=");
  313. if (keypair.length === 2 && keypair[0] === key) {
  314. return keypair[1]
  315. }
  316. }
  317. return ""
  318. },
  319. /**
  320. * 判断是否存在hash
  321. * @param {String} key
  322. * @returns Boolean
  323. */
  324. urlIsHasHash(key) {
  325. let querys = window.location.hash.substr(1).replace('/?', '').split("&");
  326. return querys.includes(key)
  327. },
  328. islongPhone: function() {
  329. //是否是刘海全面屏幕 仅仅根据比例判断 - -
  330. //screen.height == 812 && screen.width == 375)
  331. var r = screen.height / screen.width; //可能横屏
  332. return this.isMobile() && (r > 1.99 || r < 0.502512) //18/9=2.165 //???
  333. },
  334. detectWeixin: function() {
  335. //微信 包括PC的微信
  336. return window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == "micromessenger"
  337. },
  338. detectWeixinMiniProgram: function() {
  339. return window.navigator.userAgent.match("miniProgram")
  340. },
  341. detectEdge: function() {
  342. return window.navigator.userAgent.indexOf("Edge") > -1
  343. },
  344. detectApp: function() {
  345. return this.urlHasValue("app")
  346. },
  347. /**
  348. * 判断标签页是否切换状态
  349. */
  350. isTabHidden: function() {
  351. var prefixes = ["webkit", "moz", "ms", "o"];
  352. if ("hidden" in document) return document.hidden
  353. for (var i = 0; i < prefixes.length; i++) {
  354. if (prefixes[i] + "Hidden" in document) return document[prefixes[i] + "Hidden"]
  355. }
  356. return false
  357. },
  358. };
  359. //xzw add
  360. const config$1 = {//配置参数 不可修改
  361. displayMode:{
  362. showPointCloud:{
  363. atPano:{
  364. showPoint : true,
  365. showSkybox: false,
  366. pointUsePanoTex : false
  367. },
  368. transition:{
  369. showPoint: true,
  370. showSkybox: false,
  371. pointUsePanoTex: false
  372. },
  373. canLeavePano: true //是否能离开pano位置
  374. },
  375. showPanos:{
  376. atPano:{
  377. showPoint : false,
  378. showSkybox: true,
  379. pointUsePanoTex : false
  380. },
  381. transition:{
  382. //showPoint: true,
  383. showSkybox: true,
  384. //pointUsePanoTex: true //是否使用全景贴图
  385. },
  386. canLeavePano: false
  387. },
  388. showBoth:{
  389. atPano:{
  390. showPoint : true,
  391. showSkybox: true,
  392. pointUsePanoTex : false //?
  393. },
  394. transition:{
  395. showPoint: true,
  396. showSkybox: true,
  397. pointUsePanoTex: true
  398. },
  399. canLeavePano: true //是否能离开pano位置 离开后自动变为showPointCloud
  400. },
  401. //test:
  402. pointUsePanoTex:{ //---静止时调点云
  403. atPano:{
  404. showPoint : true,
  405. showSkybox: false,
  406. pointUsePanoTex : true
  407. },
  408. transition:{
  409. showPoint: true,
  410. showSkybox: true,
  411. pointUsePanoTex: true //是否使用全景贴图
  412. },
  413. canLeavePano: false
  414. },
  415. },
  416. urls:{
  417. //localTextures:'../resources/textures/',
  418. prefix: 'https://laser-oss.4dkankan.com',//oss
  419. prefix2: 'https://testlaser.4dkankan.com',
  420. prefix3: 'https://4dkk.4dage.com',
  421. prefix4: 'https://uat-laser.4dkankan.com/',//test.4dkankan
  422. },
  423. /* transitionsTime:{
  424. flyTime : 1000 // 毫秒/米
  425. panoToPano: 1000,
  426. flyIn:1000,
  427. flyOut:1000,
  428. } */
  429. transitionsTime:{
  430. flyMinTime : 500 /* * 3 */, // 毫秒/米
  431. flytimeDistanceMultiplier: 150/* * 3 */,
  432. panoToPanoMax: 2000/* * 3 */,
  433. flyIn:1000,
  434. flyOut:1000
  435. }
  436. ,
  437. moveSpeedAdujust : 0.5 //越小越慢
  438. ,
  439. view:{
  440. fov:70, //navvis:50
  441. near:0.1,
  442. far: 10000,
  443. },
  444. map:{//mapViewer
  445. mapHeight : -1000,//要比点云低。最低
  446. cameraHeight : 1000, //最高 ,注意(如sitemodel)其他的物体不能超过这个高度
  447. },
  448. pointDensity:{
  449. magnifier:{
  450. maxLevelPercent: 1,
  451. pointBudget : 8*1000*1000,
  452. },
  453. panorama:{//显示全景时的漫游。因为点只能显示1个像素的大小,所以必须很密集,但又要限制点的数量
  454. maxLevelPercent: 0.6,
  455. pointBudget : /* 4*1000*1000// */browser.isMobile() ? 0.1*1000*1000 : 0.4*1000*1000, //点云总最大数
  456. },
  457. fourViewports:{//分四屏时防止卡顿
  458. maxLevelPercent: 0.4,
  459. pointBudget :1*1000*1000, // 只要限制这个就足够 (为什么分屏focus区域不同会闪烁,navvis不会)(navvis:maxLevel:5,pointBudget:1*1000*1000)
  460. },
  461. fourViewportsMain:{//分四屏时防止卡顿
  462. maxLevelPercent: 0.8,
  463. pointBudget :1*1000*1000, // 只要限制这个就足够 (为什么分屏focus区域不同会闪烁,navvis不会)(navvis:maxLevel:5,pointBudget:1*1000*1000)
  464. }
  465. ,
  466. panoEdit:{
  467. maxLevelPercent: 1, //在远处时由于pointBudget限制而展示稀疏,凑近时就变为最高质量了
  468. pointBudget :1*1000*1000, //避免卡顿
  469. },
  470. low:{//highPerformance
  471. maxLevelPercent: 0.4, //最小为0
  472. percentByUser:true, //如果用户定义了percent,使用用户的
  473. pointBudget : 1*1000*1000,
  474. },
  475. middle:{//balanced //不同场景相同级别所产生的numVisibleNodes和numVisiblePoints不同,如果分层比较细,可能要到level8才能看清,那么level5看到的点就很大且很少,如隧道t-e2Kb2iU
  476. maxLevelPercent: 0.7,
  477. percentByUser:true,
  478. pointBudget:browser.isMobile() ? 4*1000*1000 : 2*1000*1000,
  479. },
  480. high:{//highQuality
  481. maxLevelPercent: 1,
  482. percentByUser:true,
  483. pointBudget:browser.isMobile() ? 8*1000*1000 : 4*1000*1000,
  484. }
  485. //browser.isMobile() 时要不要限制下pointBudget,还是让用户自己调低质量?
  486. //minNodeSize?
  487. //数值由testLevelSteps得来,其中nodeMaxLevel为2时,low和middle的都是1,如果真有这么低的点云就单独处理下。
  488. //多个viewport尽量保证pointBudget一样,或者pointBudget不能太低于所需,否则会反复加载了又清除
  489. },
  490. clip:{
  491. color: '#FFC266', //map
  492. },
  493. panoFieldRadius : 10, //当前位置多远范围内可以切全景模式
  494. measure:{
  495. color:'#00C8AF',
  496. default:{
  497. color:"#64C8BB",//"#00c7b2",
  498. opacity:0.7
  499. },
  500. highlight:{
  501. color:'#00C8AF',//"#00c7b2",
  502. opacity:1
  503. },
  504. guide:{
  505. color:'#FFFFFF',
  506. opacity:1
  507. }
  508. ,
  509. backColor:'#333333',
  510. lineWidth: 4,
  511. textColor: "#FFFFFF"
  512. },
  513. material:{//初始化
  514. pointSize: 0.1,
  515. realPointSize : 0.1,//实际上的ui滑动条默认大小(兼容旧的版本)
  516. minSize: 0.1,
  517. maxSize: 10000,
  518. pointSizeType: 'ATTENUATED', //'ADAPTIVE'//'ADAPTIVE' \ FIXED //ADAPTIVE的在小房间里大小会不太匹配,但在远景似乎更好
  519. /*
  520. ATTENUATED : 衰减 真实大小,靠近时感觉是点云一点点变多,缝隙变小
  521. ADAPTIVE: 自适应 大小根据level变化,越高越小。靠近时感觉点云由大慢慢细分成小份。这个感觉更佳但是navvis为何不用这个
  522. */
  523. absolutePanoramaSize: 1.3 ,//全景漫游时的size 是fixed的模式
  524. //sizeAtPanoRtEDL : 2000,
  525. pointColor:'#ffffff',
  526. //sizeAddAtPanoRtEDL : 0.5, //全景模式静止时的size
  527. //ADAPTIVE : 字会失真扭曲
  528. //'ATTENUATED' 往旁边看有缝隙、点在浮动
  529. //navvis的shader在哪里 为什么不会抖动
  530. }
  531. ,
  532. renderLayers:{//渲染层,方便分批渲染管理,替代scene的创建。数字不代表顺序。(数字不能太大)
  533. bg: 20,
  534. bg2: 21,
  535. skybox: 1,
  536. pointcloud: 11,
  537. sceneObjects:0,//default
  538. measure:4,
  539. magnifier:5,
  540. magnifierContent:16,
  541. volume:6,
  542. transformationTool:7,
  543. map:8,
  544. mapObjects:9,//default
  545. bothMapAndScene: 3,
  546. siteModeOnlyMapVisi:12,//只能mapViewer可见
  547. siteModelMapUnvisi:13,//只有mapViewer不可见
  548. siteModeSideVisi:14,//只有侧面可见
  549. },
  550. siteModel:{
  551. names:{
  552. 'building': '建筑',
  553. 'floor':'楼层',
  554. 'room':'房间'
  555. },
  556. floorHeightDefault: 5,//一层楼的高度
  557. },
  558. panosEdit:{
  559. },
  560. tiling: {
  561. panoPreRenderRepeatDelay: 2500,
  562. panoPreRenderDelay: 500,
  563. preRenderTourPanos: browser.valueFromHash("tileprerender", 0),
  564. tilingFlagNames: ["usetiles", "tiles"],
  565. maxNavPanoQuality: browser.valueFromHash("maxtileq", null),
  566. maxZoomPanoQuality: browser.valueFromHash("maxztileq", null),
  567. overlayStyle: browser.valueFromHash("tileoverlay", 0),
  568. uploadIntervalDelay: browser.valueFromHash("tileupdelay", 10),
  569. initialIntervalDelay: browser.valueFromHash("itiledelay", 0),
  570. maxNonBaseUploadsPerFrame: browser.valueFromHash("maxnbtpf", 2),
  571. maxBaseUploadsPerFrame: browser.valueFromHash("maxbtpf", 6),
  572. customCompression: browser.valueFromHash("tilecustcomp", 0),
  573. mobileHighQualityOverride: !1,
  574. allowUltraHighResolution: !0
  575. },
  576. navigation: {
  577. panoScores: !1,
  578. mouseDirection: !0,
  579. filterStrictness: .75,
  580. angleFactor: -30,
  581. directionFactor: 10,
  582. distanceFactor: -1,
  583. optionalityFactor: 3
  584. }
  585. ,
  586. axis : { 'x':{color:'#d0021b'/* 'red' */}, 'y':{ color:'#86c542' /* 'green' */}, 'z': {color:'#3399c8' /* 'blue' */}},
  587. highQualityMaxZoom: 2,
  588. ultraHighQualityMaxZoom: 3,
  589. clickMaxDragDis:5,
  590. clickMaxPressTime:500, //ms
  591. doubleClickTime:200,//双击间隔时间
  592. background: '#232323',
  593. mapBG:'#F5F5F5', //地图的clearColor
  594. colors: { //from navvis
  595. red: [213,0,0],
  596. pink: [197,17,98],
  597. purple: [170,0,255],
  598. "deep purple": [98,0,234],
  599. blue: [ 41,98,255],
  600. "light blue": [ 0,145,234],
  601. cyan: [ 0,184,212],
  602. teal: [ 0,191,165],
  603. green: [0,200,83],
  604. "light green": [ 100,221,23],
  605. lime: [ 174,234,0],
  606. yellow: [ 255,214,0],
  607. amber: [ 255,171,0],
  608. orange: [ 255,109,0],
  609. "deep orange": [ 255,61,0],
  610. },
  611. };
  612. config$1.OrthoCameraLimit = {
  613. standard:{
  614. zoom:{min:0.001, max:500}, //如果camera缩太小,地图会因为数字边界问题而扭曲
  615. posBound:{
  616. min: {x:-1e5, y:-1e5,z: config$1.map.cameraHeight},
  617. max: {x:1e5, y:1e5, z:1 / 0 }
  618. }
  619. },
  620. expand:{ //范围再大些,用于编辑空间模型等(但是万一中心点靠近地图边缘的话,就很容易扭曲了)
  621. zoom:{min:0.0004, max:100}, //如果camera缩太小,地图会因为数字边界问题而扭曲
  622. posBound:{
  623. min: {x:-5000000, y:-1000000,z:config$1.map.cameraHeight},
  624. max: {x:5000000, y:1000000, z:1 / 0 }
  625. }//40075017
  626. }
  627. };
  628. /* 显示模式:
  629. 1只显示点云: 滚轮为前进后退,方向键可以行走。进入漫游点时自动变为混合(这样全景可以弥补缝隙),过渡时只显示点云。
  630. 2只显示全景: 不能任意行走。 过渡时显示贴图材质非edl的点云(否则有折痕不贴合)。
  631. 3混合:都显示。 不能任意行走。过渡时显示贴图材质非edl的点云(因为只显示点云的话不太美,点云很碎,不细腻)
  632. */
  633. window.testLevelSteps = function(steps){//[0.4,0.7,1]
  634. if(!steps){
  635. let s = Potree.config.pointDensity;
  636. steps = [s.low.maxLevelPercent, s.middle.maxLevelPercent, s.high.maxLevelPercent, ];
  637. }
  638. let max = 1;
  639. while(++max<=12){
  640. let r1 = steps.map(e=>e * max);
  641. let r2 = steps.map(e=>Math.round(e * max));
  642. console.log(`当nodeMaxLevel为${max}时,每一级的level分别为${r2}, (小数:${r1})`);
  643. }
  644. console.log('请检查每一层的三个level是否有重复');
  645. };
  646. function getPrefix(){
  647. let u = window.location.href.split('//');
  648. let v = u[1].split('/');
  649. return v[0]
  650. }
  651. let settings = {//设置 可修改
  652. editType : '',
  653. number: '', //场景序号
  654. originDatasetId:'',//场景原本的数据集id,应该就是数据集第一个吧
  655. isOfficial:false,
  656. webSite:'testdata',//'data', //不同环境对应的静态文件的地址不同
  657. isLocal:false, //是否本地 局域网版本
  658. libsUrl:'../libs/',
  659. displayMode:'',
  660. isTest :browser.urlHasValue('test'),
  661. prefix: getPrefix(),
  662. pointDensity: '', UserPointDensity:'',//pointDensity会随着进入不同的模块而自动改变,UserPointDensity记录了用户的设置
  663. UserDensityPercent:null,//点云密度百分比
  664. ifShowMarker:true,//显示漫游点
  665. floorplanType:{},//平面图类型 'default' | 'diy' 不同数据集不同{datasetId:...}
  666. floorplanEnable:false,
  667. floorplanEnables:{},
  668. floorplanRequests:{},//开始加载了的
  669. mapEnable:true,//地图区域是否加载地图
  670. cameraFar : config$1.view.far, //相机最远范围 1-300
  671. //limitFar: true, //是否使用setting的cameraFar来限制(如在点云裁剪时为false)
  672. showPanoMesh:false, //显示小球,
  673. dblToFocusPoint:false,//调试时如果需要双击飞向某个点云的点,就打开。此时不在漫游点的话单击将无法漫游。//因和单击漫游冲突
  674. unableNavigate : false,//进入如裁剪界面时 禁止漫游
  675. sizeFitToLevel: false,//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
  676. zoom:{
  677. enabled : true,
  678. min:1,
  679. max: config$1.highQualityMaxZoom,
  680. activationThreshold: 1.1,
  681. },
  682. navConstantly:true,
  683. navTileClass: browser.isMobile() ? '1k' : '2k', //默认加载到
  684. tileClass:'4k', //最高可达
  685. /* loadTilesWhenUnfocus:false, //页面unfocus时也仍在加载tiles
  686. loadPointsWhenUnfocus:true, //页面unfocus时也仍在加载点云 */
  687. //initialShowPano:true
  688. drawEntityData: false,
  689. zoomFromPointert:{//定点缩放(包括点云模式、全景模式、地图)
  690. whenPanos:true,
  691. whenPointCloud:true,
  692. map:true,
  693. },
  694. rotAroundPoint:true,//点云模式是否能绕intersectPoint旋转
  695. tourTestCameraMove:false, //测试镜头时,不移动真实的镜头, 只移动frustum
  696. cameraAniSmoothRatio : 20, //镜头动画平滑系数,越高越平滑
  697. urls : $.extend({}, config$1.urls),
  698. useDepthTex: true,//使用深度贴图,但不代表一定有(得到的intersect更快速准确和稳定) SS-t-7DUfWAUZ3V
  699. matUseDepth:false,
  700. //panoEdit:
  701. datasetsPanos:{},
  702. //mergeModel:
  703. boundAddObjs:false,
  704. intersectOnObjs:false,
  705. };
  706. //JSON.parse(localStorage.getItem('setting'))
  707. settings.isLocalhost = settings.prefix.includes('localhost');
  708. // threejs.org/license
  709. const REVISION = '124';
  710. const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
  711. const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
  712. const CullFaceNone = 0;
  713. const CullFaceBack = 1;
  714. const CullFaceFront = 2;
  715. const CullFaceFrontBack = 3;
  716. const BasicShadowMap = 0;
  717. const PCFShadowMap = 1;
  718. const PCFSoftShadowMap = 2;
  719. const VSMShadowMap = 3;
  720. const FrontSide = 0;
  721. const BackSide = 1;
  722. const DoubleSide = 2;
  723. const FlatShading = 1;
  724. const SmoothShading = 2;
  725. const NoBlending = 0;
  726. const NormalBlending = 1;
  727. const AdditiveBlending = 2;
  728. const SubtractiveBlending = 3;
  729. const MultiplyBlending = 4;
  730. const CustomBlending = 5;
  731. const AddEquation = 100;
  732. const SubtractEquation = 101;
  733. const ReverseSubtractEquation = 102;
  734. const MinEquation = 103;
  735. const MaxEquation = 104;
  736. const ZeroFactor = 200;
  737. const OneFactor = 201;
  738. const SrcColorFactor = 202;
  739. const OneMinusSrcColorFactor = 203;
  740. const SrcAlphaFactor = 204;
  741. const OneMinusSrcAlphaFactor = 205;
  742. const DstAlphaFactor = 206;
  743. const OneMinusDstAlphaFactor = 207;
  744. const DstColorFactor = 208;
  745. const OneMinusDstColorFactor = 209;
  746. const SrcAlphaSaturateFactor = 210;
  747. const NeverDepth = 0;
  748. const AlwaysDepth = 1;
  749. const LessDepth = 2;
  750. const LessEqualDepth = 3;
  751. const EqualDepth = 4;
  752. const GreaterEqualDepth = 5;
  753. const GreaterDepth = 6;
  754. const NotEqualDepth = 7;
  755. const MultiplyOperation = 0;
  756. const MixOperation = 1;
  757. const AddOperation = 2;
  758. const NoToneMapping = 0;
  759. const LinearToneMapping = 1;
  760. const ReinhardToneMapping = 2;
  761. const CineonToneMapping = 3;
  762. const ACESFilmicToneMapping = 4;
  763. const CustomToneMapping = 5;
  764. const UVMapping = 300;
  765. const CubeReflectionMapping = 301;
  766. const CubeRefractionMapping = 302;
  767. const EquirectangularReflectionMapping = 303;
  768. const EquirectangularRefractionMapping = 304;
  769. const CubeUVReflectionMapping = 306;
  770. const CubeUVRefractionMapping = 307;
  771. const RepeatWrapping = 1000;
  772. const ClampToEdgeWrapping = 1001;
  773. const MirroredRepeatWrapping = 1002;
  774. const NearestFilter = 1003;
  775. const NearestMipmapNearestFilter = 1004;
  776. const NearestMipMapNearestFilter = 1004;
  777. const NearestMipmapLinearFilter = 1005;
  778. const NearestMipMapLinearFilter = 1005;
  779. const LinearFilter = 1006;
  780. const LinearMipmapNearestFilter = 1007;
  781. const LinearMipMapNearestFilter = 1007;
  782. const LinearMipmapLinearFilter = 1008;
  783. const LinearMipMapLinearFilter = 1008;
  784. const UnsignedByteType = 1009;
  785. const ByteType = 1010;
  786. const ShortType = 1011;
  787. const UnsignedShortType = 1012;
  788. const IntType = 1013;
  789. const UnsignedIntType = 1014;
  790. const FloatType = 1015;
  791. const HalfFloatType = 1016;
  792. const UnsignedShort4444Type = 1017;
  793. const UnsignedShort5551Type = 1018;
  794. const UnsignedShort565Type = 1019;
  795. const UnsignedInt248Type$1 = 1020;
  796. const AlphaFormat = 1021;
  797. const RGBFormat = 1022;
  798. const RGBAFormat = 1023;
  799. const LuminanceFormat = 1024;
  800. const LuminanceAlphaFormat = 1025;
  801. const RGBEFormat = RGBAFormat;
  802. const DepthFormat = 1026;
  803. const DepthStencilFormat = 1027;
  804. const RedFormat = 1028;
  805. const RedIntegerFormat = 1029;
  806. const RGFormat = 1030;
  807. const RGIntegerFormat = 1031;
  808. const RGBIntegerFormat = 1032;
  809. const RGBAIntegerFormat = 1033;
  810. const RGB_S3TC_DXT1_Format = 33776;
  811. const RGBA_S3TC_DXT1_Format$1 = 33777;
  812. const RGBA_S3TC_DXT3_Format = 33778;
  813. const RGBA_S3TC_DXT5_Format$1 = 33779;
  814. const RGB_PVRTC_4BPPV1_Format = 35840;
  815. const RGB_PVRTC_2BPPV1_Format = 35841;
  816. const RGBA_PVRTC_4BPPV1_Format = 35842;
  817. const RGBA_PVRTC_2BPPV1_Format = 35843;
  818. const RGB_ETC1_Format = 36196;
  819. const RGB_ETC2_Format = 37492;
  820. const RGBA_ETC2_EAC_Format = 37496;
  821. const RGBA_ASTC_4x4_Format = 37808;
  822. const RGBA_ASTC_5x4_Format = 37809;
  823. const RGBA_ASTC_5x5_Format = 37810;
  824. const RGBA_ASTC_6x5_Format = 37811;
  825. const RGBA_ASTC_6x6_Format = 37812;
  826. const RGBA_ASTC_8x5_Format = 37813;
  827. const RGBA_ASTC_8x6_Format = 37814;
  828. const RGBA_ASTC_8x8_Format = 37815;
  829. const RGBA_ASTC_10x5_Format = 37816;
  830. const RGBA_ASTC_10x6_Format = 37817;
  831. const RGBA_ASTC_10x8_Format = 37818;
  832. const RGBA_ASTC_10x10_Format = 37819;
  833. const RGBA_ASTC_12x10_Format = 37820;
  834. const RGBA_ASTC_12x12_Format = 37821;
  835. const RGBA_BPTC_Format = 36492;
  836. const SRGB8_ALPHA8_ASTC_4x4_Format = 37840;
  837. const SRGB8_ALPHA8_ASTC_5x4_Format = 37841;
  838. const SRGB8_ALPHA8_ASTC_5x5_Format = 37842;
  839. const SRGB8_ALPHA8_ASTC_6x5_Format = 37843;
  840. const SRGB8_ALPHA8_ASTC_6x6_Format = 37844;
  841. const SRGB8_ALPHA8_ASTC_8x5_Format = 37845;
  842. const SRGB8_ALPHA8_ASTC_8x6_Format = 37846;
  843. const SRGB8_ALPHA8_ASTC_8x8_Format = 37847;
  844. const SRGB8_ALPHA8_ASTC_10x5_Format = 37848;
  845. const SRGB8_ALPHA8_ASTC_10x6_Format = 37849;
  846. const SRGB8_ALPHA8_ASTC_10x8_Format = 37850;
  847. const SRGB8_ALPHA8_ASTC_10x10_Format = 37851;
  848. const SRGB8_ALPHA8_ASTC_12x10_Format = 37852;
  849. const SRGB8_ALPHA8_ASTC_12x12_Format = 37853;
  850. const LoopOnce = 2200;
  851. const LoopRepeat = 2201;
  852. const LoopPingPong = 2202;
  853. const InterpolateDiscrete = 2300;
  854. const InterpolateLinear = 2301;
  855. const InterpolateSmooth = 2302;
  856. const ZeroCurvatureEnding = 2400;
  857. const ZeroSlopeEnding = 2401;
  858. const WrapAroundEnding = 2402;
  859. const NormalAnimationBlendMode = 2500;
  860. const AdditiveAnimationBlendMode = 2501;
  861. const TrianglesDrawMode = 0;
  862. const TriangleStripDrawMode = 1;
  863. const TriangleFanDrawMode = 2;
  864. const LinearEncoding = 3000;
  865. const sRGBEncoding = 3001;
  866. const GammaEncoding = 3007;
  867. const RGBEEncoding = 3002;
  868. const LogLuvEncoding = 3003;
  869. const RGBM7Encoding = 3004;
  870. const RGBM16Encoding = 3005;
  871. const RGBDEncoding = 3006;
  872. const BasicDepthPacking = 3200;
  873. const RGBADepthPacking = 3201;
  874. const TangentSpaceNormalMap = 0;
  875. const ObjectSpaceNormalMap = 1;
  876. const ZeroStencilOp = 0;
  877. const KeepStencilOp = 7680;
  878. const ReplaceStencilOp = 7681;
  879. const IncrementStencilOp = 7682;
  880. const DecrementStencilOp = 7683;
  881. const IncrementWrapStencilOp = 34055;
  882. const DecrementWrapStencilOp = 34056;
  883. const InvertStencilOp = 5386;
  884. const NeverStencilFunc = 512;
  885. const LessStencilFunc = 513;
  886. const EqualStencilFunc = 514;
  887. const LessEqualStencilFunc = 515;
  888. const GreaterStencilFunc = 516;
  889. const NotEqualStencilFunc = 517;
  890. const GreaterEqualStencilFunc = 518;
  891. const AlwaysStencilFunc = 519;
  892. const StaticDrawUsage = 35044;
  893. const DynamicDrawUsage = 35048;
  894. const StreamDrawUsage = 35040;
  895. const StaticReadUsage = 35045;
  896. const DynamicReadUsage = 35049;
  897. const StreamReadUsage = 35041;
  898. const StaticCopyUsage = 35046;
  899. const DynamicCopyUsage = 35050;
  900. const StreamCopyUsage = 35042;
  901. const GLSL1 = '100';
  902. const GLSL3 = '300 es';
  903. /**
  904. * https://github.com/mrdoob/eventdispatcher.js/
  905. */
  906. function EventDispatcher() {}
  907. Object.assign( EventDispatcher.prototype, {
  908. addEventListener: function ( type, listener, importance=0 ) {//add importance
  909. if ( this._listeners === undefined ) this._listeners = {};
  910. const listeners = this._listeners;
  911. if ( listeners[ type ] === undefined ) {
  912. listeners[ type ] = [];
  913. }
  914. if ( !listeners[ type ].some(e=>e.listener == listener ) ) {
  915. //listeners[ type ].push( listener );
  916. listeners[type].push({ listener, importance});
  917. listeners[type] = listeners[type].sort((e,a)=> a.importance - e.importance);//add
  918. }
  919. },
  920. hasEventListener: function ( type, listener ) {
  921. if ( this._listeners === undefined ) return false;
  922. const listeners = this._listeners;
  923. return listeners[ type ] !== undefined && listeners[ type ].some(e=>e.listener == listener )
  924. },
  925. removeEventListener: function ( type, listener ) {
  926. if ( this._listeners === undefined ) return;
  927. const listeners = this._listeners;
  928. const listenerArray = listeners[ type ];
  929. if ( listenerArray !== undefined ) {
  930. /* const index = listenerArray.indexOf( listener );
  931. if ( index !== - 1 ) {
  932. listenerArray.splice( index, 1 );
  933. } */
  934. let item = listenerArray.find(e=>e.listener == listener);
  935. item && listenerArray.splice(listenerArray.indexOf(item), 1);
  936. }
  937. },
  938. removeEventListeners(type){//add
  939. if(this._listeners && this._listeners[type] !== undefined){
  940. delete this._listeners[type];
  941. }
  942. } ,
  943. removeAllListeners(){ //add
  944. this._listeners = {};
  945. },
  946. dispatchEvent: function ( event ) {
  947. if(typeof event == 'string'){//add
  948. event = {type:event};
  949. }
  950. if ( this._listeners === undefined ) return;
  951. const listeners = this._listeners;
  952. const listenerArray = listeners[ event.type ];
  953. if ( listenerArray !== undefined ) {
  954. event.target = this;
  955. // Make a copy, in case listeners are removed while iterating.
  956. for(let {listener} of listenerArray.slice(0)){
  957. let result = listener.call(this, event); //add stopContinue
  958. if(result && result.stopContinue){
  959. break
  960. }
  961. }
  962. }
  963. }
  964. } );
  965. const _lut = [];
  966. for ( let i = 0; i < 256; i ++ ) {
  967. _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
  968. }
  969. let _seed = 1234567;
  970. const MathUtils = {
  971. DEG2RAD: Math.PI / 180,
  972. RAD2DEG: 180 / Math.PI,
  973. generateUUID: function () {
  974. // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
  975. const d0 = Math.random() * 0xffffffff | 0;
  976. const d1 = Math.random() * 0xffffffff | 0;
  977. const d2 = Math.random() * 0xffffffff | 0;
  978. const d3 = Math.random() * 0xffffffff | 0;
  979. const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
  980. _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
  981. _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
  982. _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
  983. // .toUpperCase() here flattens concatenated strings to save heap memory space.
  984. return uuid.toUpperCase();
  985. },
  986. clamp: function ( value, min, max ) {
  987. return Math.max( min, Math.min( max, value ) );
  988. },
  989. // compute euclidian modulo of m % n
  990. // https://en.wikipedia.org/wiki/Modulo_operation
  991. euclideanModulo: function ( n, m ) {
  992. return ( ( n % m ) + m ) % m;
  993. },
  994. // Linear mapping from range <a1, a2> to range <b1, b2>
  995. mapLinear: function ( x, a1, a2, b1, b2 ) {
  996. return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
  997. },
  998. // https://en.wikipedia.org/wiki/Linear_interpolation
  999. lerp: function ( x, y, t ) {
  1000. return ( 1 - t ) * x + t * y;
  1001. },
  1002. // http://en.wikipedia.org/wiki/Smoothstep
  1003. smoothstep: function ( x, min, max ) {
  1004. if ( x <= min ) return 0;
  1005. if ( x >= max ) return 1;
  1006. x = ( x - min ) / ( max - min );
  1007. return x * x * ( 3 - 2 * x );
  1008. },
  1009. smootherstep: function ( x, min, max ) {
  1010. if ( x <= min ) return 0;
  1011. if ( x >= max ) return 1;
  1012. x = ( x - min ) / ( max - min );
  1013. return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
  1014. },
  1015. // Random integer from <low, high> interval
  1016. randInt: function ( low, high ) {
  1017. return low + Math.floor( Math.random() * ( high - low + 1 ) );
  1018. },
  1019. // Random float from <low, high> interval
  1020. randFloat: function ( low, high ) {
  1021. return low + Math.random() * ( high - low );
  1022. },
  1023. // Random float from <-range/2, range/2> interval
  1024. randFloatSpread: function ( range ) {
  1025. return range * ( 0.5 - Math.random() );
  1026. },
  1027. // Deterministic pseudo-random float in the interval [ 0, 1 ]
  1028. seededRandom: function ( s ) {
  1029. if ( s !== undefined ) _seed = s % 2147483647;
  1030. // Park-Miller algorithm
  1031. _seed = _seed * 16807 % 2147483647;
  1032. return ( _seed - 1 ) / 2147483646;
  1033. },
  1034. degToRad: function ( degrees ) {
  1035. return degrees * MathUtils.DEG2RAD;
  1036. },
  1037. radToDeg: function ( radians ) {
  1038. return radians * MathUtils.RAD2DEG;
  1039. },
  1040. isPowerOfTwo: function ( value ) {
  1041. return ( value & ( value - 1 ) ) === 0 && value !== 0;
  1042. },
  1043. ceilPowerOfTwo: function ( value ) {
  1044. return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
  1045. },
  1046. floorPowerOfTwo: function ( value ) {
  1047. return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
  1048. },
  1049. setQuaternionFromProperEuler: function ( q, a, b, c, order ) {
  1050. // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
  1051. // rotations are applied to the axes in the order specified by 'order'
  1052. // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
  1053. // angles are in radians
  1054. const cos = Math.cos;
  1055. const sin = Math.sin;
  1056. const c2 = cos( b / 2 );
  1057. const s2 = sin( b / 2 );
  1058. const c13 = cos( ( a + c ) / 2 );
  1059. const s13 = sin( ( a + c ) / 2 );
  1060. const c1_3 = cos( ( a - c ) / 2 );
  1061. const s1_3 = sin( ( a - c ) / 2 );
  1062. const c3_1 = cos( ( c - a ) / 2 );
  1063. const s3_1 = sin( ( c - a ) / 2 );
  1064. switch ( order ) {
  1065. case 'XYX':
  1066. q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
  1067. break;
  1068. case 'YZY':
  1069. q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
  1070. break;
  1071. case 'ZXZ':
  1072. q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
  1073. break;
  1074. case 'XZX':
  1075. q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
  1076. break;
  1077. case 'YXY':
  1078. q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
  1079. break;
  1080. case 'ZYZ':
  1081. q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
  1082. break;
  1083. default:
  1084. console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
  1085. }
  1086. }
  1087. };
  1088. class Vector2$1 {
  1089. constructor( x = 0, y = 0 ) {
  1090. Object.defineProperty( this, 'isVector2', { value: true } );
  1091. this.x = x;
  1092. this.y = y;
  1093. }
  1094. get width() {
  1095. return this.x;
  1096. }
  1097. set width( value ) {
  1098. this.x = value;
  1099. }
  1100. get height() {
  1101. return this.y;
  1102. }
  1103. set height( value ) {
  1104. this.y = value;
  1105. }
  1106. set( x, y ) {
  1107. this.x = x;
  1108. this.y = y;
  1109. return this;
  1110. }
  1111. setScalar( scalar ) {
  1112. this.x = scalar;
  1113. this.y = scalar;
  1114. return this;
  1115. }
  1116. setX( x ) {
  1117. this.x = x;
  1118. return this;
  1119. }
  1120. setY( y ) {
  1121. this.y = y;
  1122. return this;
  1123. }
  1124. setComponent( index, value ) {
  1125. switch ( index ) {
  1126. case 0: this.x = value; break;
  1127. case 1: this.y = value; break;
  1128. default: throw new Error( 'index is out of range: ' + index );
  1129. }
  1130. return this;
  1131. }
  1132. getComponent( index ) {
  1133. switch ( index ) {
  1134. case 0: return this.x;
  1135. case 1: return this.y;
  1136. default: throw new Error( 'index is out of range: ' + index );
  1137. }
  1138. }
  1139. clone() {
  1140. return new this.constructor( this.x, this.y );
  1141. }
  1142. copy( v ) {
  1143. this.x = v.x;
  1144. this.y = v.y;
  1145. return this;
  1146. }
  1147. add( v, w ) {
  1148. if ( w !== undefined ) {
  1149. console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
  1150. return this.addVectors( v, w );
  1151. }
  1152. this.x += v.x;
  1153. this.y += v.y;
  1154. return this;
  1155. }
  1156. addScalar( s ) {
  1157. this.x += s;
  1158. this.y += s;
  1159. return this;
  1160. }
  1161. addVectors( a, b ) {
  1162. this.x = a.x + b.x;
  1163. this.y = a.y + b.y;
  1164. return this;
  1165. }
  1166. addScaledVector( v, s ) {
  1167. this.x += v.x * s;
  1168. this.y += v.y * s;
  1169. return this;
  1170. }
  1171. sub( v, w ) {
  1172. if ( w !== undefined ) {
  1173. console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
  1174. return this.subVectors( v, w );
  1175. }
  1176. this.x -= v.x;
  1177. this.y -= v.y;
  1178. return this;
  1179. }
  1180. subScalar( s ) {
  1181. this.x -= s;
  1182. this.y -= s;
  1183. return this;
  1184. }
  1185. subVectors( a, b ) {
  1186. this.x = a.x - b.x;
  1187. this.y = a.y - b.y;
  1188. return this;
  1189. }
  1190. multiply( v ) {
  1191. this.x *= v.x;
  1192. this.y *= v.y;
  1193. return this;
  1194. }
  1195. multiplyScalar( scalar ) {
  1196. this.x *= scalar;
  1197. this.y *= scalar;
  1198. return this;
  1199. }
  1200. divide( v ) {
  1201. this.x /= v.x;
  1202. this.y /= v.y;
  1203. return this;
  1204. }
  1205. divideScalar( scalar ) {
  1206. return this.multiplyScalar( 1 / scalar );
  1207. }
  1208. applyMatrix3( m ) {
  1209. const x = this.x, y = this.y;
  1210. const e = m.elements;
  1211. this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
  1212. this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
  1213. return this;
  1214. }
  1215. min( v ) {
  1216. this.x = Math.min( this.x, v.x );
  1217. this.y = Math.min( this.y, v.y );
  1218. return this;
  1219. }
  1220. max( v ) {
  1221. this.x = Math.max( this.x, v.x );
  1222. this.y = Math.max( this.y, v.y );
  1223. return this;
  1224. }
  1225. clamp( min, max ) {
  1226. // assumes min < max, componentwise
  1227. this.x = Math.max( min.x, Math.min( max.x, this.x ) );
  1228. this.y = Math.max( min.y, Math.min( max.y, this.y ) );
  1229. return this;
  1230. }
  1231. clampScalar( minVal, maxVal ) {
  1232. this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
  1233. this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
  1234. return this;
  1235. }
  1236. clampLength( min, max ) {
  1237. const length = this.length();
  1238. return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
  1239. }
  1240. floor() {
  1241. this.x = Math.floor( this.x );
  1242. this.y = Math.floor( this.y );
  1243. return this;
  1244. }
  1245. ceil() {
  1246. this.x = Math.ceil( this.x );
  1247. this.y = Math.ceil( this.y );
  1248. return this;
  1249. }
  1250. round() {
  1251. this.x = Math.round( this.x );
  1252. this.y = Math.round( this.y );
  1253. return this;
  1254. }
  1255. roundToZero() {
  1256. this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
  1257. this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
  1258. return this;
  1259. }
  1260. negate() {
  1261. this.x = - this.x;
  1262. this.y = - this.y;
  1263. return this;
  1264. }
  1265. dot( v ) {
  1266. return this.x * v.x + this.y * v.y;
  1267. }
  1268. cross( v ) {
  1269. return this.x * v.y - this.y * v.x;
  1270. }
  1271. lengthSq() {
  1272. return this.x * this.x + this.y * this.y;
  1273. }
  1274. length() {
  1275. return Math.sqrt( this.x * this.x + this.y * this.y );
  1276. }
  1277. manhattanLength() {
  1278. return Math.abs( this.x ) + Math.abs( this.y );
  1279. }
  1280. normalize() {
  1281. return this.divideScalar( this.length() || 1 );
  1282. }
  1283. angle() {
  1284. // computes the angle in radians with respect to the positive x-axis
  1285. const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
  1286. return angle;
  1287. }
  1288. distanceTo( v ) {
  1289. return Math.sqrt( this.distanceToSquared( v ) );
  1290. }
  1291. distanceToSquared( v ) {
  1292. const dx = this.x - v.x, dy = this.y - v.y;
  1293. return dx * dx + dy * dy;
  1294. }
  1295. manhattanDistanceTo( v ) {
  1296. return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
  1297. }
  1298. setLength( length ) {
  1299. return this.normalize().multiplyScalar( length );
  1300. }
  1301. lerp( v, alpha ) {
  1302. this.x += ( v.x - this.x ) * alpha;
  1303. this.y += ( v.y - this.y ) * alpha;
  1304. return this;
  1305. }
  1306. lerpVectors( v1, v2, alpha ) {
  1307. this.x = v1.x + ( v2.x - v1.x ) * alpha;
  1308. this.y = v1.y + ( v2.y - v1.y ) * alpha;
  1309. return this;
  1310. }
  1311. equals( v ) {
  1312. return ( ( v.x === this.x ) && ( v.y === this.y ) );
  1313. }
  1314. fromArray( array, offset = 0 ) {
  1315. this.x = array[ offset ];
  1316. this.y = array[ offset + 1 ];
  1317. return this;
  1318. }
  1319. toArray( array = [], offset = 0 ) {
  1320. array[ offset ] = this.x;
  1321. array[ offset + 1 ] = this.y;
  1322. return array;
  1323. }
  1324. fromBufferAttribute( attribute, index, offset ) {
  1325. if ( offset !== undefined ) {
  1326. console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
  1327. }
  1328. this.x = attribute.getX( index );
  1329. this.y = attribute.getY( index );
  1330. return this;
  1331. }
  1332. rotateAround( center, angle ) {
  1333. const c = Math.cos( angle ), s = Math.sin( angle );
  1334. const x = this.x - center.x;
  1335. const y = this.y - center.y;
  1336. this.x = x * c - y * s + center.x;
  1337. this.y = x * s + y * c + center.y;
  1338. return this;
  1339. }
  1340. random() {
  1341. this.x = Math.random();
  1342. this.y = Math.random();
  1343. return this;
  1344. }
  1345. }
  1346. class Matrix3 {
  1347. constructor() {
  1348. Object.defineProperty( this, 'isMatrix3', { value: true } );
  1349. this.elements = [
  1350. 1, 0, 0,
  1351. 0, 1, 0,
  1352. 0, 0, 1
  1353. ];
  1354. if ( arguments.length > 0 ) {
  1355. console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
  1356. }
  1357. }
  1358. set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
  1359. const te = this.elements;
  1360. te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
  1361. te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
  1362. te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
  1363. return this;
  1364. }
  1365. identity() {
  1366. this.set(
  1367. 1, 0, 0,
  1368. 0, 1, 0,
  1369. 0, 0, 1
  1370. );
  1371. return this;
  1372. }
  1373. clone() {
  1374. return new this.constructor().fromArray( this.elements );
  1375. }
  1376. copy( m ) {
  1377. const te = this.elements;
  1378. const me = m.elements;
  1379. te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
  1380. te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
  1381. te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
  1382. return this;
  1383. }
  1384. extractBasis( xAxis, yAxis, zAxis ) {
  1385. xAxis.setFromMatrix3Column( this, 0 );
  1386. yAxis.setFromMatrix3Column( this, 1 );
  1387. zAxis.setFromMatrix3Column( this, 2 );
  1388. return this;
  1389. }
  1390. setFromMatrix4( m ) {
  1391. const me = m.elements;
  1392. this.set(
  1393. me[ 0 ], me[ 4 ], me[ 8 ],
  1394. me[ 1 ], me[ 5 ], me[ 9 ],
  1395. me[ 2 ], me[ 6 ], me[ 10 ]
  1396. );
  1397. return this;
  1398. }
  1399. multiply( m ) {
  1400. return this.multiplyMatrices( this, m );
  1401. }
  1402. premultiply( m ) {
  1403. return this.multiplyMatrices( m, this );
  1404. }
  1405. multiplyMatrices( a, b ) {
  1406. const ae = a.elements;
  1407. const be = b.elements;
  1408. const te = this.elements;
  1409. const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
  1410. const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
  1411. const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
  1412. const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
  1413. const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
  1414. const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
  1415. te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
  1416. te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
  1417. te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
  1418. te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
  1419. te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
  1420. te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
  1421. te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
  1422. te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
  1423. te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
  1424. return this;
  1425. }
  1426. multiplyScalar( s ) {
  1427. const te = this.elements;
  1428. te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
  1429. te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
  1430. te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
  1431. return this;
  1432. }
  1433. determinant() {
  1434. const te = this.elements;
  1435. const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
  1436. d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
  1437. g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
  1438. return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
  1439. }
  1440. invert() {
  1441. const te = this.elements,
  1442. n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
  1443. n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
  1444. n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
  1445. t11 = n33 * n22 - n32 * n23,
  1446. t12 = n32 * n13 - n33 * n12,
  1447. t13 = n23 * n12 - n22 * n13,
  1448. det = n11 * t11 + n21 * t12 + n31 * t13;
  1449. if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
  1450. const detInv = 1 / det;
  1451. te[ 0 ] = t11 * detInv;
  1452. te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
  1453. te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
  1454. te[ 3 ] = t12 * detInv;
  1455. te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
  1456. te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
  1457. te[ 6 ] = t13 * detInv;
  1458. te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
  1459. te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
  1460. return this;
  1461. }
  1462. transpose() {
  1463. let tmp;
  1464. const m = this.elements;
  1465. tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
  1466. tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
  1467. tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
  1468. return this;
  1469. }
  1470. getNormalMatrix( matrix4 ) {
  1471. return this.setFromMatrix4( matrix4 ).copy( this ).invert().transpose();
  1472. }
  1473. transposeIntoArray( r ) {
  1474. const m = this.elements;
  1475. r[ 0 ] = m[ 0 ];
  1476. r[ 1 ] = m[ 3 ];
  1477. r[ 2 ] = m[ 6 ];
  1478. r[ 3 ] = m[ 1 ];
  1479. r[ 4 ] = m[ 4 ];
  1480. r[ 5 ] = m[ 7 ];
  1481. r[ 6 ] = m[ 2 ];
  1482. r[ 7 ] = m[ 5 ];
  1483. r[ 8 ] = m[ 8 ];
  1484. return this;
  1485. }
  1486. setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
  1487. const c = Math.cos( rotation );
  1488. const s = Math.sin( rotation );
  1489. this.set(
  1490. sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
  1491. - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
  1492. 0, 0, 1
  1493. );
  1494. return this;
  1495. }
  1496. scale( sx, sy ) {
  1497. const te = this.elements;
  1498. te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
  1499. te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
  1500. return this;
  1501. }
  1502. rotate( theta ) {
  1503. const c = Math.cos( theta );
  1504. const s = Math.sin( theta );
  1505. const te = this.elements;
  1506. const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
  1507. const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
  1508. te[ 0 ] = c * a11 + s * a21;
  1509. te[ 3 ] = c * a12 + s * a22;
  1510. te[ 6 ] = c * a13 + s * a23;
  1511. te[ 1 ] = - s * a11 + c * a21;
  1512. te[ 4 ] = - s * a12 + c * a22;
  1513. te[ 7 ] = - s * a13 + c * a23;
  1514. return this;
  1515. }
  1516. translate( tx, ty ) {
  1517. const te = this.elements;
  1518. te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
  1519. te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
  1520. return this;
  1521. }
  1522. equals( matrix ) {
  1523. const te = this.elements;
  1524. const me = matrix.elements;
  1525. for ( let i = 0; i < 9; i ++ ) {
  1526. if ( te[ i ] !== me[ i ] ) return false;
  1527. }
  1528. return true;
  1529. }
  1530. fromArray( array, offset = 0 ) {
  1531. for ( let i = 0; i < 9; i ++ ) {
  1532. this.elements[ i ] = array[ i + offset ];
  1533. }
  1534. return this;
  1535. }
  1536. toArray( array = [], offset = 0 ) {
  1537. const te = this.elements;
  1538. array[ offset ] = te[ 0 ];
  1539. array[ offset + 1 ] = te[ 1 ];
  1540. array[ offset + 2 ] = te[ 2 ];
  1541. array[ offset + 3 ] = te[ 3 ];
  1542. array[ offset + 4 ] = te[ 4 ];
  1543. array[ offset + 5 ] = te[ 5 ];
  1544. array[ offset + 6 ] = te[ 6 ];
  1545. array[ offset + 7 ] = te[ 7 ];
  1546. array[ offset + 8 ] = te[ 8 ];
  1547. return array;
  1548. }
  1549. }
  1550. let _canvas;
  1551. const ImageUtils = {
  1552. getDataURL: function ( image ) {
  1553. if ( /^data:/i.test( image.src ) ) {
  1554. return image.src;
  1555. }
  1556. if ( typeof HTMLCanvasElement == 'undefined' ) {
  1557. return image.src;
  1558. }
  1559. let canvas;
  1560. if ( image instanceof HTMLCanvasElement ) {
  1561. canvas = image;
  1562. } else {
  1563. if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
  1564. _canvas.width = image.width;
  1565. _canvas.height = image.height;
  1566. const context = _canvas.getContext( '2d' );
  1567. if ( image instanceof ImageData ) {
  1568. context.putImageData( image, 0, 0 );
  1569. } else {
  1570. context.drawImage( image, 0, 0, image.width, image.height );
  1571. }
  1572. canvas = _canvas;
  1573. }
  1574. if ( canvas.width > 2048 || canvas.height > 2048 ) {
  1575. return canvas.toDataURL( 'image/jpeg', 0.6 );
  1576. } else {
  1577. return canvas.toDataURL( 'image/png' );
  1578. }
  1579. }
  1580. };
  1581. let textureId = 0;
  1582. function Texture( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) {
  1583. Object.defineProperty( this, 'id', { value: textureId ++ } );
  1584. this.uuid = MathUtils.generateUUID();
  1585. this.name = '';
  1586. this.image = image;
  1587. this.mipmaps = [];
  1588. this.mapping = mapping;
  1589. this.wrapS = wrapS;
  1590. this.wrapT = wrapT;
  1591. this.magFilter = magFilter;
  1592. this.minFilter = minFilter;
  1593. this.anisotropy = anisotropy;
  1594. this.format = format;
  1595. this.internalFormat = null;
  1596. this.type = type;
  1597. this.offset = new Vector2$1( 0, 0 );
  1598. this.repeat = new Vector2$1( 1, 1 );
  1599. this.center = new Vector2$1( 0, 0 );
  1600. this.rotation = 0;
  1601. this.matrixAutoUpdate = true;
  1602. this.matrix = new Matrix3();
  1603. this.generateMipmaps = true;
  1604. this.premultiplyAlpha = false;
  1605. this.flipY = true;
  1606. this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
  1607. // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
  1608. //
  1609. // Also changing the encoding after already used by a Material will not automatically make the Material
  1610. // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
  1611. this.encoding = encoding;
  1612. this.version = 0;
  1613. this.onUpdate = null;
  1614. }
  1615. Texture.DEFAULT_IMAGE = undefined;
  1616. Texture.DEFAULT_MAPPING = UVMapping;
  1617. Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  1618. constructor: Texture,
  1619. isTexture: true,
  1620. updateMatrix: function () {
  1621. this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
  1622. },
  1623. clone: function () {
  1624. return new this.constructor().copy( this );
  1625. },
  1626. copy: function ( source ) {
  1627. this.name = source.name;
  1628. this.image = source.image;
  1629. this.mipmaps = source.mipmaps.slice( 0 );
  1630. this.mapping = source.mapping;
  1631. this.wrapS = source.wrapS;
  1632. this.wrapT = source.wrapT;
  1633. this.magFilter = source.magFilter;
  1634. this.minFilter = source.minFilter;
  1635. this.anisotropy = source.anisotropy;
  1636. this.format = source.format;
  1637. this.internalFormat = source.internalFormat;
  1638. this.type = source.type;
  1639. this.offset.copy( source.offset );
  1640. this.repeat.copy( source.repeat );
  1641. this.center.copy( source.center );
  1642. this.rotation = source.rotation;
  1643. this.matrixAutoUpdate = source.matrixAutoUpdate;
  1644. this.matrix.copy( source.matrix );
  1645. this.generateMipmaps = source.generateMipmaps;
  1646. this.premultiplyAlpha = source.premultiplyAlpha;
  1647. this.flipY = source.flipY;
  1648. this.unpackAlignment = source.unpackAlignment;
  1649. this.encoding = source.encoding;
  1650. return this;
  1651. },
  1652. toJSON: function ( meta ) {
  1653. const isRootObject = ( meta === undefined || typeof meta === 'string' );
  1654. if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
  1655. return meta.textures[ this.uuid ];
  1656. }
  1657. const output = {
  1658. metadata: {
  1659. version: 4.5,
  1660. type: 'Texture',
  1661. generator: 'Texture.toJSON'
  1662. },
  1663. uuid: this.uuid,
  1664. name: this.name,
  1665. mapping: this.mapping,
  1666. repeat: [ this.repeat.x, this.repeat.y ],
  1667. offset: [ this.offset.x, this.offset.y ],
  1668. center: [ this.center.x, this.center.y ],
  1669. rotation: this.rotation,
  1670. wrap: [ this.wrapS, this.wrapT ],
  1671. format: this.format,
  1672. type: this.type,
  1673. encoding: this.encoding,
  1674. minFilter: this.minFilter,
  1675. magFilter: this.magFilter,
  1676. anisotropy: this.anisotropy,
  1677. flipY: this.flipY,
  1678. premultiplyAlpha: this.premultiplyAlpha,
  1679. unpackAlignment: this.unpackAlignment
  1680. };
  1681. if ( this.image !== undefined ) {
  1682. // TODO: Move to THREE.Image
  1683. const image = this.image;
  1684. if ( image.uuid === undefined ) {
  1685. image.uuid = MathUtils.generateUUID(); // UGH
  1686. }
  1687. if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
  1688. let url;
  1689. if ( Array.isArray( image ) ) {
  1690. // process array of images e.g. CubeTexture
  1691. url = [];
  1692. for ( let i = 0, l = image.length; i < l; i ++ ) {
  1693. // check cube texture with data textures
  1694. if ( image[ i ].isDataTexture ) {
  1695. url.push( serializeImage( image[ i ].image ) );
  1696. } else {
  1697. url.push( serializeImage( image[ i ] ) );
  1698. }
  1699. }
  1700. } else {
  1701. // process single image
  1702. url = serializeImage( image );
  1703. }
  1704. meta.images[ image.uuid ] = {
  1705. uuid: image.uuid,
  1706. url: url
  1707. };
  1708. }
  1709. output.image = image.uuid;
  1710. }
  1711. if ( ! isRootObject ) {
  1712. meta.textures[ this.uuid ] = output;
  1713. }
  1714. return output;
  1715. },
  1716. dispose: function () {
  1717. this.dispatchEvent( { type: 'dispose' } );
  1718. },
  1719. transformUv: function ( uv ) {
  1720. if ( this.mapping !== UVMapping ) return uv;
  1721. uv.applyMatrix3( this.matrix );
  1722. if ( uv.x < 0 || uv.x > 1 ) {
  1723. switch ( this.wrapS ) {
  1724. case RepeatWrapping:
  1725. uv.x = uv.x - Math.floor( uv.x );
  1726. break;
  1727. case ClampToEdgeWrapping:
  1728. uv.x = uv.x < 0 ? 0 : 1;
  1729. break;
  1730. case MirroredRepeatWrapping:
  1731. if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
  1732. uv.x = Math.ceil( uv.x ) - uv.x;
  1733. } else {
  1734. uv.x = uv.x - Math.floor( uv.x );
  1735. }
  1736. break;
  1737. }
  1738. }
  1739. if ( uv.y < 0 || uv.y > 1 ) {
  1740. switch ( this.wrapT ) {
  1741. case RepeatWrapping:
  1742. uv.y = uv.y - Math.floor( uv.y );
  1743. break;
  1744. case ClampToEdgeWrapping:
  1745. uv.y = uv.y < 0 ? 0 : 1;
  1746. break;
  1747. case MirroredRepeatWrapping:
  1748. if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
  1749. uv.y = Math.ceil( uv.y ) - uv.y;
  1750. } else {
  1751. uv.y = uv.y - Math.floor( uv.y );
  1752. }
  1753. break;
  1754. }
  1755. }
  1756. if ( this.flipY ) {
  1757. uv.y = 1 - uv.y;
  1758. }
  1759. return uv;
  1760. }
  1761. } );
  1762. Object.defineProperty( Texture.prototype, 'needsUpdate', {
  1763. set: function ( value ) {
  1764. if ( value === true ) this.version ++;
  1765. }
  1766. } );
  1767. function serializeImage( image ) {
  1768. if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
  1769. ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
  1770. ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
  1771. // default images
  1772. return ImageUtils.getDataURL( image );
  1773. } else {
  1774. if ( image.data ) {
  1775. // images of DataTexture
  1776. return {
  1777. data: Array.prototype.slice.call( image.data ),
  1778. width: image.width,
  1779. height: image.height,
  1780. type: image.data.constructor.name
  1781. };
  1782. } else {
  1783. console.warn( 'THREE.Texture: Unable to serialize Texture.' );
  1784. return {};
  1785. }
  1786. }
  1787. }
  1788. class Vector4 {
  1789. constructor( x = 0, y = 0, z = 0, w = 1 ) {
  1790. Object.defineProperty( this, 'isVector4', { value: true } );
  1791. this.x = x;
  1792. this.y = y;
  1793. this.z = z;
  1794. this.w = w;
  1795. }
  1796. get width() {
  1797. return this.z;
  1798. }
  1799. set width( value ) {
  1800. this.z = value;
  1801. }
  1802. get height() {
  1803. return this.w;
  1804. }
  1805. set height( value ) {
  1806. this.w = value;
  1807. }
  1808. set( x, y, z, w ) {
  1809. this.x = x;
  1810. this.y = y;
  1811. this.z = z;
  1812. this.w = w;
  1813. return this;
  1814. }
  1815. setScalar( scalar ) {
  1816. this.x = scalar;
  1817. this.y = scalar;
  1818. this.z = scalar;
  1819. this.w = scalar;
  1820. return this;
  1821. }
  1822. setX( x ) {
  1823. this.x = x;
  1824. return this;
  1825. }
  1826. setY( y ) {
  1827. this.y = y;
  1828. return this;
  1829. }
  1830. setZ( z ) {
  1831. this.z = z;
  1832. return this;
  1833. }
  1834. setW( w ) {
  1835. this.w = w;
  1836. return this;
  1837. }
  1838. setComponent( index, value ) {
  1839. switch ( index ) {
  1840. case 0: this.x = value; break;
  1841. case 1: this.y = value; break;
  1842. case 2: this.z = value; break;
  1843. case 3: this.w = value; break;
  1844. default: throw new Error( 'index is out of range: ' + index );
  1845. }
  1846. return this;
  1847. }
  1848. getComponent( index ) {
  1849. switch ( index ) {
  1850. case 0: return this.x;
  1851. case 1: return this.y;
  1852. case 2: return this.z;
  1853. case 3: return this.w;
  1854. default: throw new Error( 'index is out of range: ' + index );
  1855. }
  1856. }
  1857. clone() {
  1858. return new this.constructor( this.x, this.y, this.z, this.w );
  1859. }
  1860. copy( v ) {
  1861. this.x = v.x;
  1862. this.y = v.y;
  1863. this.z = v.z;
  1864. this.w = ( v.w !== undefined ) ? v.w : 1;
  1865. return this;
  1866. }
  1867. add( v, w ) {
  1868. if ( w !== undefined ) {
  1869. console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
  1870. return this.addVectors( v, w );
  1871. }
  1872. this.x += v.x;
  1873. this.y += v.y;
  1874. this.z += v.z;
  1875. this.w += v.w;
  1876. return this;
  1877. }
  1878. addScalar( s ) {
  1879. this.x += s;
  1880. this.y += s;
  1881. this.z += s;
  1882. this.w += s;
  1883. return this;
  1884. }
  1885. addVectors( a, b ) {
  1886. this.x = a.x + b.x;
  1887. this.y = a.y + b.y;
  1888. this.z = a.z + b.z;
  1889. this.w = a.w + b.w;
  1890. return this;
  1891. }
  1892. addScaledVector( v, s ) {
  1893. this.x += v.x * s;
  1894. this.y += v.y * s;
  1895. this.z += v.z * s;
  1896. this.w += v.w * s;
  1897. return this;
  1898. }
  1899. sub( v, w ) {
  1900. if ( w !== undefined ) {
  1901. console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
  1902. return this.subVectors( v, w );
  1903. }
  1904. this.x -= v.x;
  1905. this.y -= v.y;
  1906. this.z -= v.z;
  1907. this.w -= v.w;
  1908. return this;
  1909. }
  1910. subScalar( s ) {
  1911. this.x -= s;
  1912. this.y -= s;
  1913. this.z -= s;
  1914. this.w -= s;
  1915. return this;
  1916. }
  1917. subVectors( a, b ) {
  1918. this.x = a.x - b.x;
  1919. this.y = a.y - b.y;
  1920. this.z = a.z - b.z;
  1921. this.w = a.w - b.w;
  1922. return this;
  1923. }
  1924. multiplyScalar( scalar ) {
  1925. this.x *= scalar;
  1926. this.y *= scalar;
  1927. this.z *= scalar;
  1928. this.w *= scalar;
  1929. return this;
  1930. }
  1931. applyMatrix4( m ) {
  1932. const x = this.x, y = this.y, z = this.z, w = this.w;
  1933. const e = m.elements;
  1934. this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
  1935. this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
  1936. this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
  1937. this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
  1938. return this;
  1939. }
  1940. divideScalar( scalar ) {
  1941. return this.multiplyScalar( 1 / scalar );
  1942. }
  1943. setAxisAngleFromQuaternion( q ) {
  1944. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
  1945. // q is assumed to be normalized
  1946. this.w = 2 * Math.acos( q.w );
  1947. const s = Math.sqrt( 1 - q.w * q.w );
  1948. if ( s < 0.0001 ) {
  1949. this.x = 1;
  1950. this.y = 0;
  1951. this.z = 0;
  1952. } else {
  1953. this.x = q.x / s;
  1954. this.y = q.y / s;
  1955. this.z = q.z / s;
  1956. }
  1957. return this;
  1958. }
  1959. setAxisAngleFromRotationMatrix( m ) {
  1960. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
  1961. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  1962. let angle, x, y, z; // variables for result
  1963. const epsilon = 0.01, // margin to allow for rounding errors
  1964. epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
  1965. te = m.elements,
  1966. m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
  1967. m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
  1968. m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
  1969. if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
  1970. ( Math.abs( m13 - m31 ) < epsilon ) &&
  1971. ( Math.abs( m23 - m32 ) < epsilon ) ) {
  1972. // singularity found
  1973. // first check for identity matrix which must have +1 for all terms
  1974. // in leading diagonal and zero in other terms
  1975. if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
  1976. ( Math.abs( m13 + m31 ) < epsilon2 ) &&
  1977. ( Math.abs( m23 + m32 ) < epsilon2 ) &&
  1978. ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
  1979. // this singularity is identity matrix so angle = 0
  1980. this.set( 1, 0, 0, 0 );
  1981. return this; // zero angle, arbitrary axis
  1982. }
  1983. // otherwise this singularity is angle = 180
  1984. angle = Math.PI;
  1985. const xx = ( m11 + 1 ) / 2;
  1986. const yy = ( m22 + 1 ) / 2;
  1987. const zz = ( m33 + 1 ) / 2;
  1988. const xy = ( m12 + m21 ) / 4;
  1989. const xz = ( m13 + m31 ) / 4;
  1990. const yz = ( m23 + m32 ) / 4;
  1991. if ( ( xx > yy ) && ( xx > zz ) ) {
  1992. // m11 is the largest diagonal term
  1993. if ( xx < epsilon ) {
  1994. x = 0;
  1995. y = 0.707106781;
  1996. z = 0.707106781;
  1997. } else {
  1998. x = Math.sqrt( xx );
  1999. y = xy / x;
  2000. z = xz / x;
  2001. }
  2002. } else if ( yy > zz ) {
  2003. // m22 is the largest diagonal term
  2004. if ( yy < epsilon ) {
  2005. x = 0.707106781;
  2006. y = 0;
  2007. z = 0.707106781;
  2008. } else {
  2009. y = Math.sqrt( yy );
  2010. x = xy / y;
  2011. z = yz / y;
  2012. }
  2013. } else {
  2014. // m33 is the largest diagonal term so base result on this
  2015. if ( zz < epsilon ) {
  2016. x = 0.707106781;
  2017. y = 0.707106781;
  2018. z = 0;
  2019. } else {
  2020. z = Math.sqrt( zz );
  2021. x = xz / z;
  2022. y = yz / z;
  2023. }
  2024. }
  2025. this.set( x, y, z, angle );
  2026. return this; // return 180 deg rotation
  2027. }
  2028. // as we have reached here there are no singularities so we can handle normally
  2029. let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
  2030. ( m13 - m31 ) * ( m13 - m31 ) +
  2031. ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
  2032. if ( Math.abs( s ) < 0.001 ) s = 1;
  2033. // prevent divide by zero, should not happen if matrix is orthogonal and should be
  2034. // caught by singularity test above, but I've left it in just in case
  2035. this.x = ( m32 - m23 ) / s;
  2036. this.y = ( m13 - m31 ) / s;
  2037. this.z = ( m21 - m12 ) / s;
  2038. this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
  2039. return this;
  2040. }
  2041. min( v ) {
  2042. this.x = Math.min( this.x, v.x );
  2043. this.y = Math.min( this.y, v.y );
  2044. this.z = Math.min( this.z, v.z );
  2045. this.w = Math.min( this.w, v.w );
  2046. return this;
  2047. }
  2048. max( v ) {
  2049. this.x = Math.max( this.x, v.x );
  2050. this.y = Math.max( this.y, v.y );
  2051. this.z = Math.max( this.z, v.z );
  2052. this.w = Math.max( this.w, v.w );
  2053. return this;
  2054. }
  2055. clamp( min, max ) {
  2056. // assumes min < max, componentwise
  2057. this.x = Math.max( min.x, Math.min( max.x, this.x ) );
  2058. this.y = Math.max( min.y, Math.min( max.y, this.y ) );
  2059. this.z = Math.max( min.z, Math.min( max.z, this.z ) );
  2060. this.w = Math.max( min.w, Math.min( max.w, this.w ) );
  2061. return this;
  2062. }
  2063. clampScalar( minVal, maxVal ) {
  2064. this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
  2065. this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
  2066. this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
  2067. this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
  2068. return this;
  2069. }
  2070. clampLength( min, max ) {
  2071. const length = this.length();
  2072. return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
  2073. }
  2074. floor() {
  2075. this.x = Math.floor( this.x );
  2076. this.y = Math.floor( this.y );
  2077. this.z = Math.floor( this.z );
  2078. this.w = Math.floor( this.w );
  2079. return this;
  2080. }
  2081. ceil() {
  2082. this.x = Math.ceil( this.x );
  2083. this.y = Math.ceil( this.y );
  2084. this.z = Math.ceil( this.z );
  2085. this.w = Math.ceil( this.w );
  2086. return this;
  2087. }
  2088. round() {
  2089. this.x = Math.round( this.x );
  2090. this.y = Math.round( this.y );
  2091. this.z = Math.round( this.z );
  2092. this.w = Math.round( this.w );
  2093. return this;
  2094. }
  2095. roundToZero() {
  2096. this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
  2097. this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
  2098. this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
  2099. this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
  2100. return this;
  2101. }
  2102. negate() {
  2103. this.x = - this.x;
  2104. this.y = - this.y;
  2105. this.z = - this.z;
  2106. this.w = - this.w;
  2107. return this;
  2108. }
  2109. dot( v ) {
  2110. return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
  2111. }
  2112. lengthSq() {
  2113. return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
  2114. }
  2115. length() {
  2116. return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
  2117. }
  2118. manhattanLength() {
  2119. return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
  2120. }
  2121. normalize() {
  2122. return this.divideScalar( this.length() || 1 );
  2123. }
  2124. setLength( length ) {
  2125. return this.normalize().multiplyScalar( length );
  2126. }
  2127. lerp( v, alpha ) {
  2128. this.x += ( v.x - this.x ) * alpha;
  2129. this.y += ( v.y - this.y ) * alpha;
  2130. this.z += ( v.z - this.z ) * alpha;
  2131. this.w += ( v.w - this.w ) * alpha;
  2132. return this;
  2133. }
  2134. lerpVectors( v1, v2, alpha ) {
  2135. this.x = v1.x + ( v2.x - v1.x ) * alpha;
  2136. this.y = v1.y + ( v2.y - v1.y ) * alpha;
  2137. this.z = v1.z + ( v2.z - v1.z ) * alpha;
  2138. this.w = v1.w + ( v2.w - v1.w ) * alpha;
  2139. return this;
  2140. }
  2141. equals( v ) {
  2142. return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
  2143. }
  2144. fromArray( array, offset = 0 ) {
  2145. this.x = array[ offset ];
  2146. this.y = array[ offset + 1 ];
  2147. this.z = array[ offset + 2 ];
  2148. this.w = array[ offset + 3 ];
  2149. return this;
  2150. }
  2151. toArray( array = [], offset = 0 ) {
  2152. array[ offset ] = this.x;
  2153. array[ offset + 1 ] = this.y;
  2154. array[ offset + 2 ] = this.z;
  2155. array[ offset + 3 ] = this.w;
  2156. return array;
  2157. }
  2158. fromBufferAttribute( attribute, index, offset ) {
  2159. if ( offset !== undefined ) {
  2160. console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
  2161. }
  2162. this.x = attribute.getX( index );
  2163. this.y = attribute.getY( index );
  2164. this.z = attribute.getZ( index );
  2165. this.w = attribute.getW( index );
  2166. return this;
  2167. }
  2168. random() {
  2169. this.x = Math.random();
  2170. this.y = Math.random();
  2171. this.z = Math.random();
  2172. this.w = Math.random();
  2173. return this;
  2174. }
  2175. }
  2176. /*
  2177. In options, we can specify:
  2178. * Texture parameters for an auto-generated target texture
  2179. * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
  2180. */
  2181. function WebGLRenderTarget( width, height, options ) {
  2182. this.width = width;
  2183. this.height = height;
  2184. this.scissor = new Vector4( 0, 0, width, height );
  2185. this.scissorTest = false;
  2186. this.viewport = new Vector4( 0, 0, width, height );
  2187. options = options || {};
  2188. this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
  2189. this.texture.image = {};
  2190. this.texture.image.width = width;
  2191. this.texture.image.height = height;
  2192. this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
  2193. this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
  2194. this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
  2195. this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false;
  2196. this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
  2197. }
  2198. WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  2199. constructor: WebGLRenderTarget,
  2200. isWebGLRenderTarget: true,
  2201. setSize: function ( width, height ) {
  2202. if ( this.width !== width || this.height !== height ) {
  2203. this.width = width;
  2204. this.height = height;
  2205. this.texture.image.width = width;
  2206. this.texture.image.height = height;
  2207. this.dispose();
  2208. }
  2209. this.viewport.set( 0, 0, width, height );
  2210. this.scissor.set( 0, 0, width, height );
  2211. },
  2212. clone: function () {
  2213. return new this.constructor().copy( this );
  2214. },
  2215. copy: function ( source ) {
  2216. this.width = source.width;
  2217. this.height = source.height;
  2218. this.viewport.copy( source.viewport );
  2219. this.texture = source.texture.clone();
  2220. this.depthBuffer = source.depthBuffer;
  2221. this.stencilBuffer = source.stencilBuffer;
  2222. this.depthTexture = source.depthTexture;
  2223. return this;
  2224. },
  2225. dispose: function () {
  2226. this.dispatchEvent( { type: 'dispose' } );
  2227. }
  2228. } );
  2229. function WebGLMultisampleRenderTarget( width, height, options ) {
  2230. WebGLRenderTarget.call( this, width, height, options );
  2231. this.samples = 4;
  2232. }
  2233. WebGLMultisampleRenderTarget.prototype = Object.assign( Object.create( WebGLRenderTarget.prototype ), {
  2234. constructor: WebGLMultisampleRenderTarget,
  2235. isWebGLMultisampleRenderTarget: true,
  2236. copy: function ( source ) {
  2237. WebGLRenderTarget.prototype.copy.call( this, source );
  2238. this.samples = source.samples;
  2239. return this;
  2240. }
  2241. } );
  2242. class Quaternion {
  2243. constructor( x = 0, y = 0, z = 0, w = 1 ) {
  2244. Object.defineProperty( this, 'isQuaternion', { value: true } );
  2245. this._x = x;
  2246. this._y = y;
  2247. this._z = z;
  2248. this._w = w;
  2249. }
  2250. static slerp( qa, qb, qm, t ) {
  2251. return qm.copy( qa ).slerp( qb, t );
  2252. }
  2253. static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
  2254. // fuzz-free, array-based Quaternion SLERP operation
  2255. let x0 = src0[ srcOffset0 + 0 ],
  2256. y0 = src0[ srcOffset0 + 1 ],
  2257. z0 = src0[ srcOffset0 + 2 ],
  2258. w0 = src0[ srcOffset0 + 3 ];
  2259. const x1 = src1[ srcOffset1 + 0 ],
  2260. y1 = src1[ srcOffset1 + 1 ],
  2261. z1 = src1[ srcOffset1 + 2 ],
  2262. w1 = src1[ srcOffset1 + 3 ];
  2263. if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
  2264. let s = 1 - t;
  2265. const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
  2266. dir = ( cos >= 0 ? 1 : - 1 ),
  2267. sqrSin = 1 - cos * cos;
  2268. // Skip the Slerp for tiny steps to avoid numeric problems:
  2269. if ( sqrSin > Number.EPSILON ) {
  2270. const sin = Math.sqrt( sqrSin ),
  2271. len = Math.atan2( sin, cos * dir );
  2272. s = Math.sin( s * len ) / sin;
  2273. t = Math.sin( t * len ) / sin;
  2274. }
  2275. const tDir = t * dir;
  2276. x0 = x0 * s + x1 * tDir;
  2277. y0 = y0 * s + y1 * tDir;
  2278. z0 = z0 * s + z1 * tDir;
  2279. w0 = w0 * s + w1 * tDir;
  2280. // Normalize in case we just did a lerp:
  2281. if ( s === 1 - t ) {
  2282. const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
  2283. x0 *= f;
  2284. y0 *= f;
  2285. z0 *= f;
  2286. w0 *= f;
  2287. }
  2288. }
  2289. dst[ dstOffset ] = x0;
  2290. dst[ dstOffset + 1 ] = y0;
  2291. dst[ dstOffset + 2 ] = z0;
  2292. dst[ dstOffset + 3 ] = w0;
  2293. }
  2294. static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
  2295. const x0 = src0[ srcOffset0 ];
  2296. const y0 = src0[ srcOffset0 + 1 ];
  2297. const z0 = src0[ srcOffset0 + 2 ];
  2298. const w0 = src0[ srcOffset0 + 3 ];
  2299. const x1 = src1[ srcOffset1 ];
  2300. const y1 = src1[ srcOffset1 + 1 ];
  2301. const z1 = src1[ srcOffset1 + 2 ];
  2302. const w1 = src1[ srcOffset1 + 3 ];
  2303. dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
  2304. dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
  2305. dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
  2306. dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
  2307. return dst;
  2308. }
  2309. get x() {
  2310. return this._x;
  2311. }
  2312. set x( value ) {
  2313. this._x = value;
  2314. this._onChangeCallback();
  2315. }
  2316. get y() {
  2317. return this._y;
  2318. }
  2319. set y( value ) {
  2320. this._y = value;
  2321. this._onChangeCallback();
  2322. }
  2323. get z() {
  2324. return this._z;
  2325. }
  2326. set z( value ) {
  2327. this._z = value;
  2328. this._onChangeCallback();
  2329. }
  2330. get w() {
  2331. return this._w;
  2332. }
  2333. set w( value ) {
  2334. this._w = value;
  2335. this._onChangeCallback();
  2336. }
  2337. set( x, y, z, w ) {
  2338. this._x = x;
  2339. this._y = y;
  2340. this._z = z;
  2341. this._w = w;
  2342. this._onChangeCallback();
  2343. return this;
  2344. }
  2345. clone() {
  2346. return new this.constructor( this._x, this._y, this._z, this._w );
  2347. }
  2348. copy( quaternion ) {
  2349. this._x = quaternion.x;
  2350. this._y = quaternion.y;
  2351. this._z = quaternion.z;
  2352. this._w = quaternion.w;
  2353. this._onChangeCallback();
  2354. return this;
  2355. }
  2356. setFromEuler( euler, update ) {
  2357. if ( ! ( euler && euler.isEuler ) ) {
  2358. throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
  2359. }
  2360. const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
  2361. // http://www.mathworks.com/matlabcentral/fileexchange/
  2362. // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
  2363. // content/SpinCalc.m
  2364. const cos = Math.cos;
  2365. const sin = Math.sin;
  2366. const c1 = cos( x / 2 );
  2367. const c2 = cos( y / 2 );
  2368. const c3 = cos( z / 2 );
  2369. const s1 = sin( x / 2 );
  2370. const s2 = sin( y / 2 );
  2371. const s3 = sin( z / 2 );
  2372. switch ( order ) {
  2373. case 'XYZ':
  2374. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  2375. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  2376. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  2377. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  2378. break;
  2379. case 'YXZ':
  2380. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  2381. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  2382. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  2383. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  2384. break;
  2385. case 'ZXY':
  2386. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  2387. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  2388. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  2389. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  2390. break;
  2391. case 'ZYX':
  2392. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  2393. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  2394. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  2395. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  2396. break;
  2397. case 'YZX':
  2398. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  2399. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  2400. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  2401. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  2402. break;
  2403. case 'XZY':
  2404. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  2405. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  2406. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  2407. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  2408. break;
  2409. default:
  2410. console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
  2411. }
  2412. if ( update !== false ) this._onChangeCallback();
  2413. return this;
  2414. }
  2415. setFromAxisAngle( axis, angle ) {
  2416. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
  2417. // assumes axis is normalized
  2418. const halfAngle = angle / 2, s = Math.sin( halfAngle );
  2419. this._x = axis.x * s;
  2420. this._y = axis.y * s;
  2421. this._z = axis.z * s;
  2422. this._w = Math.cos( halfAngle );
  2423. this._onChangeCallback();
  2424. return this;
  2425. }
  2426. setFromRotationMatrix( m ) {
  2427. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  2428. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  2429. const te = m.elements,
  2430. m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
  2431. m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
  2432. m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
  2433. trace = m11 + m22 + m33;
  2434. if ( trace > 0 ) {
  2435. const s = 0.5 / Math.sqrt( trace + 1.0 );
  2436. this._w = 0.25 / s;
  2437. this._x = ( m32 - m23 ) * s;
  2438. this._y = ( m13 - m31 ) * s;
  2439. this._z = ( m21 - m12 ) * s;
  2440. } else if ( m11 > m22 && m11 > m33 ) {
  2441. const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
  2442. this._w = ( m32 - m23 ) / s;
  2443. this._x = 0.25 * s;
  2444. this._y = ( m12 + m21 ) / s;
  2445. this._z = ( m13 + m31 ) / s;
  2446. } else if ( m22 > m33 ) {
  2447. const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
  2448. this._w = ( m13 - m31 ) / s;
  2449. this._x = ( m12 + m21 ) / s;
  2450. this._y = 0.25 * s;
  2451. this._z = ( m23 + m32 ) / s;
  2452. } else {
  2453. const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
  2454. this._w = ( m21 - m12 ) / s;
  2455. this._x = ( m13 + m31 ) / s;
  2456. this._y = ( m23 + m32 ) / s;
  2457. this._z = 0.25 * s;
  2458. }
  2459. this._onChangeCallback();
  2460. return this;
  2461. }
  2462. setFromUnitVectors( vFrom, vTo ) {
  2463. // assumes direction vectors vFrom and vTo are normalized
  2464. const EPS = 0.000001;
  2465. let r = vFrom.dot( vTo ) + 1;
  2466. if ( r < EPS ) {
  2467. r = 0;
  2468. if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
  2469. this._x = - vFrom.y;
  2470. this._y = vFrom.x;
  2471. this._z = 0;
  2472. this._w = r;
  2473. } else {
  2474. this._x = 0;
  2475. this._y = - vFrom.z;
  2476. this._z = vFrom.y;
  2477. this._w = r;
  2478. }
  2479. } else {
  2480. // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
  2481. this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
  2482. this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
  2483. this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
  2484. this._w = r;
  2485. }
  2486. return this.normalize();
  2487. }
  2488. angleTo( q ) {
  2489. return 2 * Math.acos( Math.abs( MathUtils.clamp( this.dot( q ), - 1, 1 ) ) );
  2490. }
  2491. rotateTowards( q, step ) {
  2492. const angle = this.angleTo( q );
  2493. if ( angle === 0 ) return this;
  2494. const t = Math.min( 1, step / angle );
  2495. this.slerp( q, t );
  2496. return this;
  2497. }
  2498. identity() {
  2499. return this.set( 0, 0, 0, 1 );
  2500. }
  2501. invert() {
  2502. // quaternion is assumed to have unit length
  2503. return this.conjugate();
  2504. }
  2505. conjugate() {
  2506. this._x *= - 1;
  2507. this._y *= - 1;
  2508. this._z *= - 1;
  2509. this._onChangeCallback();
  2510. return this;
  2511. }
  2512. dot( v ) {
  2513. return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
  2514. }
  2515. lengthSq() {
  2516. return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
  2517. }
  2518. length() {
  2519. return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
  2520. }
  2521. normalize() {
  2522. let l = this.length();
  2523. if ( l === 0 ) {
  2524. this._x = 0;
  2525. this._y = 0;
  2526. this._z = 0;
  2527. this._w = 1;
  2528. } else {
  2529. l = 1 / l;
  2530. this._x = this._x * l;
  2531. this._y = this._y * l;
  2532. this._z = this._z * l;
  2533. this._w = this._w * l;
  2534. }
  2535. this._onChangeCallback();
  2536. return this;
  2537. }
  2538. multiply( q, p ) {
  2539. if ( p !== undefined ) {
  2540. console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
  2541. return this.multiplyQuaternions( q, p );
  2542. }
  2543. return this.multiplyQuaternions( this, q );
  2544. }
  2545. premultiply( q ) {
  2546. return this.multiplyQuaternions( q, this );
  2547. }
  2548. multiplyQuaternions( a, b ) {
  2549. // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
  2550. const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
  2551. const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
  2552. this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
  2553. this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
  2554. this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
  2555. this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
  2556. this._onChangeCallback();
  2557. return this;
  2558. }
  2559. slerp( qb, t ) {
  2560. if ( t === 0 ) return this;
  2561. if ( t === 1 ) return this.copy( qb );
  2562. const x = this._x, y = this._y, z = this._z, w = this._w;
  2563. // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
  2564. let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
  2565. if ( cosHalfTheta < 0 ) {
  2566. this._w = - qb._w;
  2567. this._x = - qb._x;
  2568. this._y = - qb._y;
  2569. this._z = - qb._z;
  2570. cosHalfTheta = - cosHalfTheta;
  2571. } else {
  2572. this.copy( qb );
  2573. }
  2574. if ( cosHalfTheta >= 1.0 ) {
  2575. this._w = w;
  2576. this._x = x;
  2577. this._y = y;
  2578. this._z = z;
  2579. return this;
  2580. }
  2581. const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
  2582. if ( sqrSinHalfTheta <= Number.EPSILON ) {
  2583. const s = 1 - t;
  2584. this._w = s * w + t * this._w;
  2585. this._x = s * x + t * this._x;
  2586. this._y = s * y + t * this._y;
  2587. this._z = s * z + t * this._z;
  2588. this.normalize();
  2589. this._onChangeCallback();
  2590. return this;
  2591. }
  2592. const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
  2593. const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
  2594. const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
  2595. ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
  2596. this._w = ( w * ratioA + this._w * ratioB );
  2597. this._x = ( x * ratioA + this._x * ratioB );
  2598. this._y = ( y * ratioA + this._y * ratioB );
  2599. this._z = ( z * ratioA + this._z * ratioB );
  2600. this._onChangeCallback();
  2601. return this;
  2602. }
  2603. equals( quaternion ) {
  2604. return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
  2605. }
  2606. fromArray( array, offset = 0 ) {
  2607. this._x = array[ offset ];
  2608. this._y = array[ offset + 1 ];
  2609. this._z = array[ offset + 2 ];
  2610. this._w = array[ offset + 3 ];
  2611. this._onChangeCallback();
  2612. return this;
  2613. }
  2614. toArray( array = [], offset = 0 ) {
  2615. array[ offset ] = this._x;
  2616. array[ offset + 1 ] = this._y;
  2617. array[ offset + 2 ] = this._z;
  2618. array[ offset + 3 ] = this._w;
  2619. return array;
  2620. }
  2621. fromBufferAttribute( attribute, index ) {
  2622. this._x = attribute.getX( index );
  2623. this._y = attribute.getY( index );
  2624. this._z = attribute.getZ( index );
  2625. this._w = attribute.getW( index );
  2626. return this;
  2627. }
  2628. _onChange( callback ) {
  2629. this._onChangeCallback = callback;
  2630. return this;
  2631. }
  2632. _onChangeCallback() {}
  2633. }
  2634. class Vector3 {
  2635. constructor( x = 0, y = 0, z = 0 ) {
  2636. Object.defineProperty( this, 'isVector3', { value: true } );
  2637. this.x = x;
  2638. this.y = y;
  2639. this.z = z;
  2640. }
  2641. set( x, y, z ) {
  2642. if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
  2643. this.x = x;
  2644. this.y = y;
  2645. this.z = z;
  2646. return this;
  2647. }
  2648. setScalar( scalar ) {
  2649. this.x = scalar;
  2650. this.y = scalar;
  2651. this.z = scalar;
  2652. return this;
  2653. }
  2654. setX( x ) {
  2655. this.x = x;
  2656. return this;
  2657. }
  2658. setY( y ) {
  2659. this.y = y;
  2660. return this;
  2661. }
  2662. setZ( z ) {
  2663. this.z = z;
  2664. return this;
  2665. }
  2666. setComponent( index, value ) {
  2667. switch ( index ) {
  2668. case 0: this.x = value; break;
  2669. case 1: this.y = value; break;
  2670. case 2: this.z = value; break;
  2671. default: throw new Error( 'index is out of range: ' + index );
  2672. }
  2673. return this;
  2674. }
  2675. getComponent( index ) {
  2676. switch ( index ) {
  2677. case 0: return this.x;
  2678. case 1: return this.y;
  2679. case 2: return this.z;
  2680. default: throw new Error( 'index is out of range: ' + index );
  2681. }
  2682. }
  2683. clone() {
  2684. return new this.constructor( this.x, this.y, this.z );
  2685. }
  2686. copy( v ) {
  2687. this.x = v.x;
  2688. this.y = v.y;
  2689. this.z = v.z;
  2690. return this;
  2691. }
  2692. add( v, w ) {
  2693. if ( w !== undefined ) {
  2694. console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
  2695. return this.addVectors( v, w );
  2696. }
  2697. this.x += v.x;
  2698. this.y += v.y;
  2699. this.z += v.z;
  2700. return this;
  2701. }
  2702. addScalar( s ) {
  2703. this.x += s;
  2704. this.y += s;
  2705. this.z += s;
  2706. return this;
  2707. }
  2708. addVectors( a, b ) {
  2709. this.x = a.x + b.x;
  2710. this.y = a.y + b.y;
  2711. this.z = a.z + b.z;
  2712. return this;
  2713. }
  2714. addScaledVector( v, s ) {
  2715. this.x += v.x * s;
  2716. this.y += v.y * s;
  2717. this.z += v.z * s;
  2718. return this;
  2719. }
  2720. sub( v, w ) {
  2721. if ( w !== undefined ) {
  2722. console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
  2723. return this.subVectors( v, w );
  2724. }
  2725. this.x -= v.x;
  2726. this.y -= v.y;
  2727. this.z -= v.z;
  2728. return this;
  2729. }
  2730. subScalar( s ) {
  2731. this.x -= s;
  2732. this.y -= s;
  2733. this.z -= s;
  2734. return this;
  2735. }
  2736. subVectors( a, b ) {
  2737. this.x = a.x - b.x;
  2738. this.y = a.y - b.y;
  2739. this.z = a.z - b.z;
  2740. return this;
  2741. }
  2742. multiply( v, w ) {
  2743. if ( w !== undefined ) {
  2744. console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
  2745. return this.multiplyVectors( v, w );
  2746. }
  2747. this.x *= v.x;
  2748. this.y *= v.y;
  2749. this.z *= v.z;
  2750. return this;
  2751. }
  2752. multiplyScalar( scalar ) {
  2753. this.x *= scalar;
  2754. this.y *= scalar;
  2755. this.z *= scalar;
  2756. return this;
  2757. }
  2758. multiplyVectors( a, b ) {
  2759. this.x = a.x * b.x;
  2760. this.y = a.y * b.y;
  2761. this.z = a.z * b.z;
  2762. return this;
  2763. }
  2764. applyEuler( euler ) {
  2765. if ( ! ( euler && euler.isEuler ) ) {
  2766. console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
  2767. }
  2768. return this.applyQuaternion( _quaternion.setFromEuler( euler ) );
  2769. }
  2770. applyAxisAngle( axis, angle ) {
  2771. return this.applyQuaternion( _quaternion.setFromAxisAngle( axis, angle ) );
  2772. }
  2773. applyMatrix3( m ) {
  2774. const x = this.x, y = this.y, z = this.z;
  2775. const e = m.elements;
  2776. this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
  2777. this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
  2778. this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
  2779. return this;
  2780. }
  2781. applyNormalMatrix( m ) {
  2782. return this.applyMatrix3( m ).normalize();
  2783. }
  2784. applyMatrix4( m ) {
  2785. const x = this.x, y = this.y, z = this.z;
  2786. const e = m.elements;
  2787. const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
  2788. this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
  2789. this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
  2790. this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
  2791. return this;
  2792. }
  2793. applyQuaternion( q ) {
  2794. const x = this.x, y = this.y, z = this.z;
  2795. const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
  2796. // calculate quat * vector
  2797. const ix = qw * x + qy * z - qz * y;
  2798. const iy = qw * y + qz * x - qx * z;
  2799. const iz = qw * z + qx * y - qy * x;
  2800. const iw = - qx * x - qy * y - qz * z;
  2801. // calculate result * inverse quat
  2802. this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
  2803. this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
  2804. this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
  2805. return this;
  2806. }
  2807. project( camera ) {
  2808. return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
  2809. }
  2810. unproject( camera ) {
  2811. return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
  2812. }
  2813. transformDirection( m ) {
  2814. // input: THREE.Matrix4 affine matrix
  2815. // vector interpreted as a direction
  2816. const x = this.x, y = this.y, z = this.z;
  2817. const e = m.elements;
  2818. this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
  2819. this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
  2820. this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
  2821. return this.normalize();
  2822. }
  2823. divide( v ) {
  2824. this.x /= v.x;
  2825. this.y /= v.y;
  2826. this.z /= v.z;
  2827. return this;
  2828. }
  2829. divideScalar( scalar ) {
  2830. return this.multiplyScalar( 1 / scalar );
  2831. }
  2832. min( v ) {
  2833. this.x = Math.min( this.x, v.x );
  2834. this.y = Math.min( this.y, v.y );
  2835. this.z = Math.min( this.z, v.z );
  2836. return this;
  2837. }
  2838. max( v ) {
  2839. this.x = Math.max( this.x, v.x );
  2840. this.y = Math.max( this.y, v.y );
  2841. this.z = Math.max( this.z, v.z );
  2842. return this;
  2843. }
  2844. clamp( min, max ) {
  2845. // assumes min < max, componentwise
  2846. this.x = Math.max( min.x, Math.min( max.x, this.x ) );
  2847. this.y = Math.max( min.y, Math.min( max.y, this.y ) );
  2848. this.z = Math.max( min.z, Math.min( max.z, this.z ) );
  2849. return this;
  2850. }
  2851. clampScalar( minVal, maxVal ) {
  2852. this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
  2853. this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
  2854. this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
  2855. return this;
  2856. }
  2857. clampLength( min, max ) {
  2858. const length = this.length();
  2859. return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
  2860. }
  2861. floor() {
  2862. this.x = Math.floor( this.x );
  2863. this.y = Math.floor( this.y );
  2864. this.z = Math.floor( this.z );
  2865. return this;
  2866. }
  2867. ceil() {
  2868. this.x = Math.ceil( this.x );
  2869. this.y = Math.ceil( this.y );
  2870. this.z = Math.ceil( this.z );
  2871. return this;
  2872. }
  2873. round() {
  2874. this.x = Math.round( this.x );
  2875. this.y = Math.round( this.y );
  2876. this.z = Math.round( this.z );
  2877. return this;
  2878. }
  2879. roundToZero() {
  2880. this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
  2881. this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
  2882. this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
  2883. return this;
  2884. }
  2885. negate() {
  2886. this.x = - this.x;
  2887. this.y = - this.y;
  2888. this.z = - this.z;
  2889. return this;
  2890. }
  2891. dot( v ) {
  2892. return this.x * v.x + this.y * v.y + this.z * v.z;
  2893. }
  2894. // TODO lengthSquared?
  2895. lengthSq() {
  2896. return this.x * this.x + this.y * this.y + this.z * this.z;
  2897. }
  2898. length() {
  2899. return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
  2900. }
  2901. manhattanLength() {
  2902. return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
  2903. }
  2904. normalize() {
  2905. return this.divideScalar( this.length() || 1 );
  2906. }
  2907. setLength( length ) {
  2908. return this.normalize().multiplyScalar( length );
  2909. }
  2910. lerp( v, alpha ) {
  2911. this.x += ( v.x - this.x ) * alpha;
  2912. this.y += ( v.y - this.y ) * alpha;
  2913. this.z += ( v.z - this.z ) * alpha;
  2914. return this;
  2915. }
  2916. lerpVectors( v1, v2, alpha ) {
  2917. this.x = v1.x + ( v2.x - v1.x ) * alpha;
  2918. this.y = v1.y + ( v2.y - v1.y ) * alpha;
  2919. this.z = v1.z + ( v2.z - v1.z ) * alpha;
  2920. return this;
  2921. }
  2922. cross( v, w ) {
  2923. if ( w !== undefined ) {
  2924. console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
  2925. return this.crossVectors( v, w );
  2926. }
  2927. return this.crossVectors( this, v );
  2928. }
  2929. crossVectors( a, b ) {
  2930. const ax = a.x, ay = a.y, az = a.z;
  2931. const bx = b.x, by = b.y, bz = b.z;
  2932. this.x = ay * bz - az * by;
  2933. this.y = az * bx - ax * bz;
  2934. this.z = ax * by - ay * bx;
  2935. return this;
  2936. }
  2937. projectOnVector( v ) {
  2938. const denominator = v.lengthSq();
  2939. if ( denominator === 0 ) return this.set( 0, 0, 0 );
  2940. const scalar = v.dot( this ) / denominator;
  2941. return this.copy( v ).multiplyScalar( scalar );
  2942. }
  2943. projectOnPlane( planeNormal ) {
  2944. _vector.copy( this ).projectOnVector( planeNormal );
  2945. return this.sub( _vector );
  2946. }
  2947. reflect( normal ) {
  2948. // reflect incident vector off plane orthogonal to normal
  2949. // normal is assumed to have unit length
  2950. return this.sub( _vector.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
  2951. }
  2952. angleTo( v ) {
  2953. const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
  2954. if ( denominator === 0 ) return Math.PI / 2;
  2955. const theta = this.dot( v ) / denominator;
  2956. // clamp, to handle numerical problems
  2957. return Math.acos( MathUtils.clamp( theta, - 1, 1 ) );
  2958. }
  2959. distanceTo( v ) {
  2960. return Math.sqrt( this.distanceToSquared( v ) );
  2961. }
  2962. distanceToSquared( v ) {
  2963. const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
  2964. return dx * dx + dy * dy + dz * dz;
  2965. }
  2966. manhattanDistanceTo( v ) {
  2967. return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
  2968. }
  2969. setFromSpherical( s ) {
  2970. return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
  2971. }
  2972. setFromSphericalCoords( radius, phi, theta ) {
  2973. const sinPhiRadius = Math.sin( phi ) * radius;
  2974. this.x = sinPhiRadius * Math.sin( theta );
  2975. this.y = Math.cos( phi ) * radius;
  2976. this.z = sinPhiRadius * Math.cos( theta );
  2977. return this;
  2978. }
  2979. setFromCylindrical( c ) {
  2980. return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
  2981. }
  2982. setFromCylindricalCoords( radius, theta, y ) {
  2983. this.x = radius * Math.sin( theta );
  2984. this.y = y;
  2985. this.z = radius * Math.cos( theta );
  2986. return this;
  2987. }
  2988. setFromMatrixPosition( m ) {
  2989. const e = m.elements;
  2990. this.x = e[ 12 ];
  2991. this.y = e[ 13 ];
  2992. this.z = e[ 14 ];
  2993. return this;
  2994. }
  2995. setFromMatrixScale( m ) {
  2996. const sx = this.setFromMatrixColumn( m, 0 ).length();
  2997. const sy = this.setFromMatrixColumn( m, 1 ).length();
  2998. const sz = this.setFromMatrixColumn( m, 2 ).length();
  2999. this.x = sx;
  3000. this.y = sy;
  3001. this.z = sz;
  3002. return this;
  3003. }
  3004. setFromMatrixColumn( m, index ) {
  3005. return this.fromArray( m.elements, index * 4 );
  3006. }
  3007. setFromMatrix3Column( m, index ) {
  3008. return this.fromArray( m.elements, index * 3 );
  3009. }
  3010. equals( v ) {
  3011. return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
  3012. }
  3013. fromArray( array, offset = 0 ) {
  3014. this.x = array[ offset ];
  3015. this.y = array[ offset + 1 ];
  3016. this.z = array[ offset + 2 ];
  3017. return this;
  3018. }
  3019. toArray( array = [], offset = 0 ) {
  3020. array[ offset ] = this.x;
  3021. array[ offset + 1 ] = this.y;
  3022. array[ offset + 2 ] = this.z;
  3023. return array;
  3024. }
  3025. fromBufferAttribute( attribute, index, offset ) {
  3026. if ( offset !== undefined ) {
  3027. console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
  3028. }
  3029. this.x = attribute.getX( index );
  3030. this.y = attribute.getY( index );
  3031. this.z = attribute.getZ( index );
  3032. return this;
  3033. }
  3034. random() {
  3035. this.x = Math.random();
  3036. this.y = Math.random();
  3037. this.z = Math.random();
  3038. return this;
  3039. }
  3040. }
  3041. const _vector = /*@__PURE__*/ new Vector3();
  3042. const _quaternion = /*@__PURE__*/ new Quaternion();
  3043. class Box3 {
  3044. constructor( min, max ) {
  3045. Object.defineProperty( this, 'isBox3', { value: true } );
  3046. this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
  3047. this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
  3048. }
  3049. set( min, max ) {
  3050. this.min.copy( min );
  3051. this.max.copy( max );
  3052. return this;
  3053. }
  3054. setFromArray( array ) {
  3055. let minX = + Infinity;
  3056. let minY = + Infinity;
  3057. let minZ = + Infinity;
  3058. let maxX = - Infinity;
  3059. let maxY = - Infinity;
  3060. let maxZ = - Infinity;
  3061. for ( let i = 0, l = array.length; i < l; i += 3 ) {
  3062. const x = array[ i ];
  3063. const y = array[ i + 1 ];
  3064. const z = array[ i + 2 ];
  3065. if ( x < minX ) minX = x;
  3066. if ( y < minY ) minY = y;
  3067. if ( z < minZ ) minZ = z;
  3068. if ( x > maxX ) maxX = x;
  3069. if ( y > maxY ) maxY = y;
  3070. if ( z > maxZ ) maxZ = z;
  3071. }
  3072. this.min.set( minX, minY, minZ );
  3073. this.max.set( maxX, maxY, maxZ );
  3074. return this;
  3075. }
  3076. setFromBufferAttribute( attribute ) {
  3077. let minX = + Infinity;
  3078. let minY = + Infinity;
  3079. let minZ = + Infinity;
  3080. let maxX = - Infinity;
  3081. let maxY = - Infinity;
  3082. let maxZ = - Infinity;
  3083. for ( let i = 0, l = attribute.count; i < l; i ++ ) {
  3084. const x = attribute.getX( i );
  3085. const y = attribute.getY( i );
  3086. const z = attribute.getZ( i );
  3087. if ( x < minX ) minX = x;
  3088. if ( y < minY ) minY = y;
  3089. if ( z < minZ ) minZ = z;
  3090. if ( x > maxX ) maxX = x;
  3091. if ( y > maxY ) maxY = y;
  3092. if ( z > maxZ ) maxZ = z;
  3093. }
  3094. this.min.set( minX, minY, minZ );
  3095. this.max.set( maxX, maxY, maxZ );
  3096. return this;
  3097. }
  3098. setFromPoints( points ) {
  3099. this.makeEmpty();
  3100. for ( let i = 0, il = points.length; i < il; i ++ ) {
  3101. this.expandByPoint( points[ i ] );
  3102. }
  3103. return this;
  3104. }
  3105. setFromCenterAndSize( center, size ) {
  3106. const halfSize = _vector$1.copy( size ).multiplyScalar( 0.5 );
  3107. this.min.copy( center ).sub( halfSize );
  3108. this.max.copy( center ).add( halfSize );
  3109. return this;
  3110. }
  3111. setFromObject( object ) {
  3112. this.makeEmpty();
  3113. return this.expandByObject( object );
  3114. }
  3115. clone() {
  3116. return new this.constructor().copy( this );
  3117. }
  3118. copy( box ) {
  3119. this.min.copy( box.min );
  3120. this.max.copy( box.max );
  3121. return this;
  3122. }
  3123. makeEmpty() {
  3124. this.min.x = this.min.y = this.min.z = + Infinity;
  3125. this.max.x = this.max.y = this.max.z = - Infinity;
  3126. return this;
  3127. }
  3128. isEmpty() {
  3129. // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
  3130. return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
  3131. }
  3132. getCenter( target ) {
  3133. if ( target === undefined ) {
  3134. console.warn( 'THREE.Box3: .getCenter() target is now required' );
  3135. target = new Vector3();
  3136. }
  3137. return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
  3138. }
  3139. getSize( target ) {
  3140. if ( target === undefined ) {
  3141. console.warn( 'THREE.Box3: .getSize() target is now required' );
  3142. target = new Vector3();
  3143. }
  3144. return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
  3145. }
  3146. expandByPoint( point ) {
  3147. this.min.min( point );
  3148. this.max.max( point );
  3149. return this;
  3150. }
  3151. expandByVector( vector ) {
  3152. this.min.sub( vector );
  3153. this.max.add( vector );
  3154. return this;
  3155. }
  3156. expandByScalar( scalar ) {
  3157. this.min.addScalar( - scalar );
  3158. this.max.addScalar( scalar );
  3159. return this;
  3160. }
  3161. expandByObject( object ) {
  3162. // Computes the world-axis-aligned bounding box of an object (including its children),
  3163. // accounting for both the object's, and children's, world transforms
  3164. object.updateWorldMatrix( false, false );
  3165. const geometry = object.geometry;
  3166. if ( geometry !== undefined ) {
  3167. if ( geometry.boundingBox === null ) {
  3168. geometry.computeBoundingBox();
  3169. }
  3170. _box.copy( geometry.boundingBox );
  3171. _box.applyMatrix4( object.matrixWorld );
  3172. this.union( _box );
  3173. }
  3174. const children = object.children;
  3175. for ( let i = 0, l = children.length; i < l; i ++ ) {
  3176. this.expandByObject( children[ i ] );
  3177. }
  3178. return this;
  3179. }
  3180. containsPoint( point ) {
  3181. return point.x < this.min.x || point.x > this.max.x ||
  3182. point.y < this.min.y || point.y > this.max.y ||
  3183. point.z < this.min.z || point.z > this.max.z ? false : true;
  3184. }
  3185. containsBox( box ) {
  3186. return this.min.x <= box.min.x && box.max.x <= this.max.x &&
  3187. this.min.y <= box.min.y && box.max.y <= this.max.y &&
  3188. this.min.z <= box.min.z && box.max.z <= this.max.z;
  3189. }
  3190. getParameter( point, target ) {
  3191. // This can potentially have a divide by zero if the box
  3192. // has a size dimension of 0.
  3193. if ( target === undefined ) {
  3194. console.warn( 'THREE.Box3: .getParameter() target is now required' );
  3195. target = new Vector3();
  3196. }
  3197. return target.set(
  3198. ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
  3199. ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
  3200. ( point.z - this.min.z ) / ( this.max.z - this.min.z )
  3201. );
  3202. }
  3203. intersectsBox( box ) {
  3204. // using 6 splitting planes to rule out intersections.
  3205. return box.max.x < this.min.x || box.min.x > this.max.x ||
  3206. box.max.y < this.min.y || box.min.y > this.max.y ||
  3207. box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
  3208. }
  3209. intersectsSphere( sphere ) {
  3210. // Find the point on the AABB closest to the sphere center.
  3211. this.clampPoint( sphere.center, _vector$1 );
  3212. // If that point is inside the sphere, the AABB and sphere intersect.
  3213. return _vector$1.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
  3214. }
  3215. intersectsPlane( plane ) {
  3216. // We compute the minimum and maximum dot product values. If those values
  3217. // are on the same side (back or front) of the plane, then there is no intersection.
  3218. let min, max;
  3219. if ( plane.normal.x > 0 ) {
  3220. min = plane.normal.x * this.min.x;
  3221. max = plane.normal.x * this.max.x;
  3222. } else {
  3223. min = plane.normal.x * this.max.x;
  3224. max = plane.normal.x * this.min.x;
  3225. }
  3226. if ( plane.normal.y > 0 ) {
  3227. min += plane.normal.y * this.min.y;
  3228. max += plane.normal.y * this.max.y;
  3229. } else {
  3230. min += plane.normal.y * this.max.y;
  3231. max += plane.normal.y * this.min.y;
  3232. }
  3233. if ( plane.normal.z > 0 ) {
  3234. min += plane.normal.z * this.min.z;
  3235. max += plane.normal.z * this.max.z;
  3236. } else {
  3237. min += plane.normal.z * this.max.z;
  3238. max += plane.normal.z * this.min.z;
  3239. }
  3240. return ( min <= - plane.constant && max >= - plane.constant );
  3241. }
  3242. intersectsTriangle( triangle ) {
  3243. if ( this.isEmpty() ) {
  3244. return false;
  3245. }
  3246. // compute box center and extents
  3247. this.getCenter( _center );
  3248. _extents.subVectors( this.max, _center );
  3249. // translate triangle to aabb origin
  3250. _v0.subVectors( triangle.a, _center );
  3251. _v1.subVectors( triangle.b, _center );
  3252. _v2.subVectors( triangle.c, _center );
  3253. // compute edge vectors for triangle
  3254. _f0.subVectors( _v1, _v0 );
  3255. _f1.subVectors( _v2, _v1 );
  3256. _f2.subVectors( _v0, _v2 );
  3257. // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
  3258. // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
  3259. // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
  3260. let axes = [
  3261. 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
  3262. _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
  3263. - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
  3264. ];
  3265. if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
  3266. return false;
  3267. }
  3268. // test 3 face normals from the aabb
  3269. axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
  3270. if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
  3271. return false;
  3272. }
  3273. // finally testing the face normal of the triangle
  3274. // use already existing triangle edge vectors here
  3275. _triangleNormal.crossVectors( _f0, _f1 );
  3276. axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
  3277. return satForAxes( axes, _v0, _v1, _v2, _extents );
  3278. }
  3279. clampPoint( point, target ) {
  3280. if ( target === undefined ) {
  3281. console.warn( 'THREE.Box3: .clampPoint() target is now required' );
  3282. target = new Vector3();
  3283. }
  3284. return target.copy( point ).clamp( this.min, this.max );
  3285. }
  3286. distanceToPoint( point ) {
  3287. const clampedPoint = _vector$1.copy( point ).clamp( this.min, this.max );
  3288. return clampedPoint.sub( point ).length();
  3289. }
  3290. getBoundingSphere( target ) {
  3291. if ( target === undefined ) {
  3292. console.error( 'THREE.Box3: .getBoundingSphere() target is now required' );
  3293. //target = new Sphere(); // removed to avoid cyclic dependency
  3294. }
  3295. this.getCenter( target.center );
  3296. target.radius = this.getSize( _vector$1 ).length() * 0.5;
  3297. return target;
  3298. }
  3299. intersect( box ) {
  3300. this.min.max( box.min );
  3301. this.max.min( box.max );
  3302. // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
  3303. if ( this.isEmpty() ) this.makeEmpty();
  3304. return this;
  3305. }
  3306. union( box ) {
  3307. this.min.min( box.min );
  3308. this.max.max( box.max );
  3309. return this;
  3310. }
  3311. applyMatrix4( matrix ) {
  3312. // transform of empty box is an empty box.
  3313. if ( this.isEmpty() ) return this;
  3314. // NOTE: I am using a binary pattern to specify all 2^3 combinations below
  3315. _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
  3316. _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
  3317. _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
  3318. _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
  3319. _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
  3320. _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
  3321. _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
  3322. _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
  3323. this.setFromPoints( _points );
  3324. return this;
  3325. }
  3326. translate( offset ) {
  3327. this.min.add( offset );
  3328. this.max.add( offset );
  3329. return this;
  3330. }
  3331. equals( box ) {
  3332. return box.min.equals( this.min ) && box.max.equals( this.max );
  3333. }
  3334. }
  3335. function satForAxes( axes, v0, v1, v2, extents ) {
  3336. for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
  3337. _testAxis.fromArray( axes, i );
  3338. // project the aabb onto the seperating axis
  3339. const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
  3340. // project all 3 vertices of the triangle onto the seperating axis
  3341. const p0 = v0.dot( _testAxis );
  3342. const p1 = v1.dot( _testAxis );
  3343. const p2 = v2.dot( _testAxis );
  3344. // actual test, basically see if either of the most extreme of the triangle points intersects r
  3345. if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
  3346. // points of the projected triangle are outside the projected half-length of the aabb
  3347. // the axis is seperating and we can exit
  3348. return false;
  3349. }
  3350. }
  3351. return true;
  3352. }
  3353. const _points = [
  3354. /*@__PURE__*/ new Vector3(),
  3355. /*@__PURE__*/ new Vector3(),
  3356. /*@__PURE__*/ new Vector3(),
  3357. /*@__PURE__*/ new Vector3(),
  3358. /*@__PURE__*/ new Vector3(),
  3359. /*@__PURE__*/ new Vector3(),
  3360. /*@__PURE__*/ new Vector3(),
  3361. /*@__PURE__*/ new Vector3()
  3362. ];
  3363. const _vector$1 = /*@__PURE__*/ new Vector3();
  3364. const _box = /*@__PURE__*/ new Box3();
  3365. // triangle centered vertices
  3366. const _v0 = /*@__PURE__*/ new Vector3();
  3367. const _v1 = /*@__PURE__*/ new Vector3();
  3368. const _v2 = /*@__PURE__*/ new Vector3();
  3369. // triangle edge vectors
  3370. const _f0 = /*@__PURE__*/ new Vector3();
  3371. const _f1 = /*@__PURE__*/ new Vector3();
  3372. const _f2 = /*@__PURE__*/ new Vector3();
  3373. const _center = /*@__PURE__*/ new Vector3();
  3374. const _extents = /*@__PURE__*/ new Vector3();
  3375. const _triangleNormal = /*@__PURE__*/ new Vector3();
  3376. const _testAxis = /*@__PURE__*/ new Vector3();
  3377. const _box$1 = /*@__PURE__*/ new Box3();
  3378. class Sphere {
  3379. constructor( center, radius ) {
  3380. this.center = ( center !== undefined ) ? center : new Vector3();
  3381. this.radius = ( radius !== undefined ) ? radius : - 1;
  3382. }
  3383. set( center, radius ) {
  3384. this.center.copy( center );
  3385. this.radius = radius;
  3386. return this;
  3387. }
  3388. setFromPoints( points, optionalCenter ) {
  3389. const center = this.center;
  3390. if ( optionalCenter !== undefined ) {
  3391. center.copy( optionalCenter );
  3392. } else {
  3393. _box$1.setFromPoints( points ).getCenter( center );
  3394. }
  3395. let maxRadiusSq = 0;
  3396. for ( let i = 0, il = points.length; i < il; i ++ ) {
  3397. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
  3398. }
  3399. this.radius = Math.sqrt( maxRadiusSq );
  3400. return this;
  3401. }
  3402. clone() {
  3403. return new this.constructor().copy( this );
  3404. }
  3405. copy( sphere ) {
  3406. this.center.copy( sphere.center );
  3407. this.radius = sphere.radius;
  3408. return this;
  3409. }
  3410. isEmpty() {
  3411. return ( this.radius < 0 );
  3412. }
  3413. makeEmpty() {
  3414. this.center.set( 0, 0, 0 );
  3415. this.radius = - 1;
  3416. return this;
  3417. }
  3418. containsPoint( point ) {
  3419. return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
  3420. }
  3421. distanceToPoint( point ) {
  3422. return ( point.distanceTo( this.center ) - this.radius );
  3423. }
  3424. intersectsSphere( sphere ) {
  3425. const radiusSum = this.radius + sphere.radius;
  3426. return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
  3427. }
  3428. intersectsBox( box ) {
  3429. return box.intersectsSphere( this );
  3430. }
  3431. intersectsPlane( plane ) {
  3432. return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
  3433. }
  3434. clampPoint( point, target ) {
  3435. const deltaLengthSq = this.center.distanceToSquared( point );
  3436. if ( target === undefined ) {
  3437. console.warn( 'THREE.Sphere: .clampPoint() target is now required' );
  3438. target = new Vector3();
  3439. }
  3440. target.copy( point );
  3441. if ( deltaLengthSq > ( this.radius * this.radius ) ) {
  3442. target.sub( this.center ).normalize();
  3443. target.multiplyScalar( this.radius ).add( this.center );
  3444. }
  3445. return target;
  3446. }
  3447. getBoundingBox( target ) {
  3448. if ( target === undefined ) {
  3449. console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' );
  3450. target = new Box3();
  3451. }
  3452. if ( this.isEmpty() ) {
  3453. // Empty sphere produces empty bounding box
  3454. target.makeEmpty();
  3455. return target;
  3456. }
  3457. target.set( this.center, this.center );
  3458. target.expandByScalar( this.radius );
  3459. return target;
  3460. }
  3461. applyMatrix4( matrix ) {
  3462. this.center.applyMatrix4( matrix );
  3463. this.radius = this.radius * matrix.getMaxScaleOnAxis();
  3464. return this;
  3465. }
  3466. translate( offset ) {
  3467. this.center.add( offset );
  3468. return this;
  3469. }
  3470. equals( sphere ) {
  3471. return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
  3472. }
  3473. }
  3474. const _vector$2 = /*@__PURE__*/ new Vector3();
  3475. const _segCenter = /*@__PURE__*/ new Vector3();
  3476. const _segDir = /*@__PURE__*/ new Vector3();
  3477. const _diff = /*@__PURE__*/ new Vector3();
  3478. const _edge1 = /*@__PURE__*/ new Vector3();
  3479. const _edge2 = /*@__PURE__*/ new Vector3();
  3480. const _normal = /*@__PURE__*/ new Vector3();
  3481. class Ray {
  3482. constructor( origin, direction ) {
  3483. this.origin = ( origin !== undefined ) ? origin : new Vector3();
  3484. this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 );
  3485. }
  3486. set( origin, direction ) {
  3487. this.origin.copy( origin );
  3488. this.direction.copy( direction );
  3489. return this;
  3490. }
  3491. clone() {
  3492. return new this.constructor().copy( this );
  3493. }
  3494. copy( ray ) {
  3495. this.origin.copy( ray.origin );
  3496. this.direction.copy( ray.direction );
  3497. return this;
  3498. }
  3499. at( t, target ) {
  3500. if ( target === undefined ) {
  3501. console.warn( 'THREE.Ray: .at() target is now required' );
  3502. target = new Vector3();
  3503. }
  3504. return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
  3505. }
  3506. lookAt( v ) {
  3507. this.direction.copy( v ).sub( this.origin ).normalize();
  3508. return this;
  3509. }
  3510. recast( t ) {
  3511. this.origin.copy( this.at( t, _vector$2 ) );
  3512. return this;
  3513. }
  3514. closestPointToPoint( point, target ) {
  3515. if ( target === undefined ) {
  3516. console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' );
  3517. target = new Vector3();
  3518. }
  3519. target.subVectors( point, this.origin );
  3520. const directionDistance = target.dot( this.direction );
  3521. if ( directionDistance < 0 ) {
  3522. return target.copy( this.origin );
  3523. }
  3524. return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
  3525. }
  3526. distanceToPoint( point ) {
  3527. return Math.sqrt( this.distanceSqToPoint( point ) );
  3528. }
  3529. distanceSqToPoint( point ) {
  3530. const directionDistance = _vector$2.subVectors( point, this.origin ).dot( this.direction );
  3531. // point behind the ray
  3532. if ( directionDistance < 0 ) {
  3533. return this.origin.distanceToSquared( point );
  3534. }
  3535. _vector$2.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
  3536. return _vector$2.distanceToSquared( point );
  3537. }
  3538. distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
  3539. // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
  3540. // It returns the min distance between the ray and the segment
  3541. // defined by v0 and v1
  3542. // It can also set two optional targets :
  3543. // - The closest point on the ray
  3544. // - The closest point on the segment
  3545. _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
  3546. _segDir.copy( v1 ).sub( v0 ).normalize();
  3547. _diff.copy( this.origin ).sub( _segCenter );
  3548. const segExtent = v0.distanceTo( v1 ) * 0.5;
  3549. const a01 = - this.direction.dot( _segDir );
  3550. const b0 = _diff.dot( this.direction );
  3551. const b1 = - _diff.dot( _segDir );
  3552. const c = _diff.lengthSq();
  3553. const det = Math.abs( 1 - a01 * a01 );
  3554. let s0, s1, sqrDist, extDet;
  3555. if ( det > 0 ) {
  3556. // The ray and segment are not parallel.
  3557. s0 = a01 * b1 - b0;
  3558. s1 = a01 * b0 - b1;
  3559. extDet = segExtent * det;
  3560. if ( s0 >= 0 ) {
  3561. if ( s1 >= - extDet ) {
  3562. if ( s1 <= extDet ) {
  3563. // region 0
  3564. // Minimum at interior points of ray and segment.
  3565. const invDet = 1 / det;
  3566. s0 *= invDet;
  3567. s1 *= invDet;
  3568. sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
  3569. } else {
  3570. // region 1
  3571. s1 = segExtent;
  3572. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  3573. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  3574. }
  3575. } else {
  3576. // region 5
  3577. s1 = - segExtent;
  3578. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  3579. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  3580. }
  3581. } else {
  3582. if ( s1 <= - extDet ) {
  3583. // region 4
  3584. s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
  3585. s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  3586. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  3587. } else if ( s1 <= extDet ) {
  3588. // region 3
  3589. s0 = 0;
  3590. s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
  3591. sqrDist = s1 * ( s1 + 2 * b1 ) + c;
  3592. } else {
  3593. // region 2
  3594. s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
  3595. s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  3596. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  3597. }
  3598. }
  3599. } else {
  3600. // Ray and segment are parallel.
  3601. s1 = ( a01 > 0 ) ? - segExtent : segExtent;
  3602. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  3603. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  3604. }
  3605. if ( optionalPointOnRay ) {
  3606. optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
  3607. }
  3608. if ( optionalPointOnSegment ) {
  3609. optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter );
  3610. }
  3611. return sqrDist;
  3612. }
  3613. intersectSphere( sphere, target ) {
  3614. _vector$2.subVectors( sphere.center, this.origin );
  3615. const tca = _vector$2.dot( this.direction );
  3616. const d2 = _vector$2.dot( _vector$2 ) - tca * tca;
  3617. const radius2 = sphere.radius * sphere.radius;
  3618. if ( d2 > radius2 ) return null;
  3619. const thc = Math.sqrt( radius2 - d2 );
  3620. // t0 = first intersect point - entrance on front of sphere
  3621. const t0 = tca - thc;
  3622. // t1 = second intersect point - exit point on back of sphere
  3623. const t1 = tca + thc;
  3624. // test to see if both t0 and t1 are behind the ray - if so, return null
  3625. if ( t0 < 0 && t1 < 0 ) return null;
  3626. // test to see if t0 is behind the ray:
  3627. // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
  3628. // in order to always return an intersect point that is in front of the ray.
  3629. if ( t0 < 0 ) return this.at( t1, target );
  3630. // else t0 is in front of the ray, so return the first collision point scaled by t0
  3631. return this.at( t0, target );
  3632. }
  3633. intersectsSphere( sphere ) {
  3634. return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
  3635. }
  3636. distanceToPlane( plane ) {
  3637. const denominator = plane.normal.dot( this.direction );
  3638. if ( denominator === 0 ) {
  3639. // line is coplanar, return origin
  3640. if ( plane.distanceToPoint( this.origin ) === 0 ) {
  3641. return 0;
  3642. }
  3643. // Null is preferable to undefined since undefined means.... it is undefined
  3644. return null;
  3645. }
  3646. const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
  3647. // Return if the ray never intersects the plane
  3648. return t >= 0 ? t : null;
  3649. }
  3650. intersectPlane( plane, target ) {
  3651. const t = this.distanceToPlane( plane );
  3652. if ( t === null ) {
  3653. return null;
  3654. }
  3655. return this.at( t, target );
  3656. }
  3657. intersectsPlane( plane ) {
  3658. // check if the ray lies on the plane first
  3659. const distToPoint = plane.distanceToPoint( this.origin );
  3660. if ( distToPoint === 0 ) {
  3661. return true;
  3662. }
  3663. const denominator = plane.normal.dot( this.direction );
  3664. if ( denominator * distToPoint < 0 ) {
  3665. return true;
  3666. }
  3667. // ray origin is behind the plane (and is pointing behind it)
  3668. return false;
  3669. }
  3670. intersectBox( box, target ) {
  3671. let tmin, tmax, tymin, tymax, tzmin, tzmax;
  3672. const invdirx = 1 / this.direction.x,
  3673. invdiry = 1 / this.direction.y,
  3674. invdirz = 1 / this.direction.z;
  3675. const origin = this.origin;
  3676. if ( invdirx >= 0 ) {
  3677. tmin = ( box.min.x - origin.x ) * invdirx;
  3678. tmax = ( box.max.x - origin.x ) * invdirx;
  3679. } else {
  3680. tmin = ( box.max.x - origin.x ) * invdirx;
  3681. tmax = ( box.min.x - origin.x ) * invdirx;
  3682. }
  3683. if ( invdiry >= 0 ) {
  3684. tymin = ( box.min.y - origin.y ) * invdiry;
  3685. tymax = ( box.max.y - origin.y ) * invdiry;
  3686. } else {
  3687. tymin = ( box.max.y - origin.y ) * invdiry;
  3688. tymax = ( box.min.y - origin.y ) * invdiry;
  3689. }
  3690. if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
  3691. // These lines also handle the case where tmin or tmax is NaN
  3692. // (result of 0 * Infinity). x !== x returns true if x is NaN
  3693. if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
  3694. if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
  3695. if ( invdirz >= 0 ) {
  3696. tzmin = ( box.min.z - origin.z ) * invdirz;
  3697. tzmax = ( box.max.z - origin.z ) * invdirz;
  3698. } else {
  3699. tzmin = ( box.max.z - origin.z ) * invdirz;
  3700. tzmax = ( box.min.z - origin.z ) * invdirz;
  3701. }
  3702. if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
  3703. if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
  3704. if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
  3705. //return point closest to the ray (positive side)
  3706. if ( tmax < 0 ) return null;
  3707. return this.at( tmin >= 0 ? tmin : tmax, target );
  3708. }
  3709. intersectsBox( box ) {
  3710. return this.intersectBox( box, _vector$2 ) !== null;
  3711. }
  3712. intersectTriangle( a, b, c, backfaceCulling, target ) {
  3713. // Compute the offset origin, edges, and normal.
  3714. // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
  3715. _edge1.subVectors( b, a );
  3716. _edge2.subVectors( c, a );
  3717. _normal.crossVectors( _edge1, _edge2 );
  3718. // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
  3719. // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
  3720. // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
  3721. // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
  3722. // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
  3723. let DdN = this.direction.dot( _normal );
  3724. let sign;
  3725. if ( DdN > 0 ) {
  3726. if ( backfaceCulling ) return null;
  3727. sign = 1;
  3728. } else if ( DdN < 0 ) {
  3729. sign = - 1;
  3730. DdN = - DdN;
  3731. } else {
  3732. return null;
  3733. }
  3734. _diff.subVectors( this.origin, a );
  3735. const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
  3736. // b1 < 0, no intersection
  3737. if ( DdQxE2 < 0 ) {
  3738. return null;
  3739. }
  3740. const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
  3741. // b2 < 0, no intersection
  3742. if ( DdE1xQ < 0 ) {
  3743. return null;
  3744. }
  3745. // b1+b2 > 1, no intersection
  3746. if ( DdQxE2 + DdE1xQ > DdN ) {
  3747. return null;
  3748. }
  3749. // Line intersects triangle, check if ray does.
  3750. const QdN = - sign * _diff.dot( _normal );
  3751. // t < 0, no intersection
  3752. if ( QdN < 0 ) {
  3753. return null;
  3754. }
  3755. // Ray intersects triangle.
  3756. return this.at( QdN / DdN, target );
  3757. }
  3758. applyMatrix4( matrix4 ) {
  3759. this.origin.applyMatrix4( matrix4 );
  3760. this.direction.transformDirection( matrix4 );
  3761. return this;
  3762. }
  3763. equals( ray ) {
  3764. return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
  3765. }
  3766. }
  3767. class Matrix4 {
  3768. constructor() {
  3769. Object.defineProperty( this, 'isMatrix4', { value: true } );
  3770. this.elements = [
  3771. 1, 0, 0, 0,
  3772. 0, 1, 0, 0,
  3773. 0, 0, 1, 0,
  3774. 0, 0, 0, 1
  3775. ];
  3776. if ( arguments.length > 0 ) {
  3777. console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
  3778. }
  3779. }
  3780. set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
  3781. const te = this.elements;
  3782. te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
  3783. te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
  3784. te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
  3785. te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
  3786. return this;
  3787. }
  3788. identity() {
  3789. this.set(
  3790. 1, 0, 0, 0,
  3791. 0, 1, 0, 0,
  3792. 0, 0, 1, 0,
  3793. 0, 0, 0, 1
  3794. );
  3795. return this;
  3796. }
  3797. clone() {
  3798. return new Matrix4().fromArray( this.elements );
  3799. }
  3800. copy( m ) {
  3801. const te = this.elements;
  3802. const me = m.elements;
  3803. te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
  3804. te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
  3805. te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
  3806. te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
  3807. return this;
  3808. }
  3809. copyPosition( m ) {
  3810. const te = this.elements, me = m.elements;
  3811. te[ 12 ] = me[ 12 ];
  3812. te[ 13 ] = me[ 13 ];
  3813. te[ 14 ] = me[ 14 ];
  3814. return this;
  3815. }
  3816. extractBasis( xAxis, yAxis, zAxis ) {
  3817. xAxis.setFromMatrixColumn( this, 0 );
  3818. yAxis.setFromMatrixColumn( this, 1 );
  3819. zAxis.setFromMatrixColumn( this, 2 );
  3820. return this;
  3821. }
  3822. makeBasis( xAxis, yAxis, zAxis ) {
  3823. this.set(
  3824. xAxis.x, yAxis.x, zAxis.x, 0,
  3825. xAxis.y, yAxis.y, zAxis.y, 0,
  3826. xAxis.z, yAxis.z, zAxis.z, 0,
  3827. 0, 0, 0, 1
  3828. );
  3829. return this;
  3830. }
  3831. extractRotation( m ) {
  3832. // this method does not support reflection matrices
  3833. const te = this.elements;
  3834. const me = m.elements;
  3835. const scaleX = 1 / _v1$1.setFromMatrixColumn( m, 0 ).length();
  3836. const scaleY = 1 / _v1$1.setFromMatrixColumn( m, 1 ).length();
  3837. const scaleZ = 1 / _v1$1.setFromMatrixColumn( m, 2 ).length();
  3838. te[ 0 ] = me[ 0 ] * scaleX;
  3839. te[ 1 ] = me[ 1 ] * scaleX;
  3840. te[ 2 ] = me[ 2 ] * scaleX;
  3841. te[ 3 ] = 0;
  3842. te[ 4 ] = me[ 4 ] * scaleY;
  3843. te[ 5 ] = me[ 5 ] * scaleY;
  3844. te[ 6 ] = me[ 6 ] * scaleY;
  3845. te[ 7 ] = 0;
  3846. te[ 8 ] = me[ 8 ] * scaleZ;
  3847. te[ 9 ] = me[ 9 ] * scaleZ;
  3848. te[ 10 ] = me[ 10 ] * scaleZ;
  3849. te[ 11 ] = 0;
  3850. te[ 12 ] = 0;
  3851. te[ 13 ] = 0;
  3852. te[ 14 ] = 0;
  3853. te[ 15 ] = 1;
  3854. return this;
  3855. }
  3856. makeRotationFromEuler( euler ) {
  3857. if ( ! ( euler && euler.isEuler ) ) {
  3858. console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
  3859. }
  3860. const te = this.elements;
  3861. const x = euler.x, y = euler.y, z = euler.z;
  3862. const a = Math.cos( x ), b = Math.sin( x );
  3863. const c = Math.cos( y ), d = Math.sin( y );
  3864. const e = Math.cos( z ), f = Math.sin( z );
  3865. if ( euler.order === 'XYZ' ) {
  3866. const ae = a * e, af = a * f, be = b * e, bf = b * f;
  3867. te[ 0 ] = c * e;
  3868. te[ 4 ] = - c * f;
  3869. te[ 8 ] = d;
  3870. te[ 1 ] = af + be * d;
  3871. te[ 5 ] = ae - bf * d;
  3872. te[ 9 ] = - b * c;
  3873. te[ 2 ] = bf - ae * d;
  3874. te[ 6 ] = be + af * d;
  3875. te[ 10 ] = a * c;
  3876. } else if ( euler.order === 'YXZ' ) {
  3877. const ce = c * e, cf = c * f, de = d * e, df = d * f;
  3878. te[ 0 ] = ce + df * b;
  3879. te[ 4 ] = de * b - cf;
  3880. te[ 8 ] = a * d;
  3881. te[ 1 ] = a * f;
  3882. te[ 5 ] = a * e;
  3883. te[ 9 ] = - b;
  3884. te[ 2 ] = cf * b - de;
  3885. te[ 6 ] = df + ce * b;
  3886. te[ 10 ] = a * c;
  3887. } else if ( euler.order === 'ZXY' ) {
  3888. const ce = c * e, cf = c * f, de = d * e, df = d * f;
  3889. te[ 0 ] = ce - df * b;
  3890. te[ 4 ] = - a * f;
  3891. te[ 8 ] = de + cf * b;
  3892. te[ 1 ] = cf + de * b;
  3893. te[ 5 ] = a * e;
  3894. te[ 9 ] = df - ce * b;
  3895. te[ 2 ] = - a * d;
  3896. te[ 6 ] = b;
  3897. te[ 10 ] = a * c;
  3898. } else if ( euler.order === 'ZYX' ) {
  3899. const ae = a * e, af = a * f, be = b * e, bf = b * f;
  3900. te[ 0 ] = c * e;
  3901. te[ 4 ] = be * d - af;
  3902. te[ 8 ] = ae * d + bf;
  3903. te[ 1 ] = c * f;
  3904. te[ 5 ] = bf * d + ae;
  3905. te[ 9 ] = af * d - be;
  3906. te[ 2 ] = - d;
  3907. te[ 6 ] = b * c;
  3908. te[ 10 ] = a * c;
  3909. } else if ( euler.order === 'YZX' ) {
  3910. const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
  3911. te[ 0 ] = c * e;
  3912. te[ 4 ] = bd - ac * f;
  3913. te[ 8 ] = bc * f + ad;
  3914. te[ 1 ] = f;
  3915. te[ 5 ] = a * e;
  3916. te[ 9 ] = - b * e;
  3917. te[ 2 ] = - d * e;
  3918. te[ 6 ] = ad * f + bc;
  3919. te[ 10 ] = ac - bd * f;
  3920. } else if ( euler.order === 'XZY' ) {
  3921. const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
  3922. te[ 0 ] = c * e;
  3923. te[ 4 ] = - f;
  3924. te[ 8 ] = d * e;
  3925. te[ 1 ] = ac * f + bd;
  3926. te[ 5 ] = a * e;
  3927. te[ 9 ] = ad * f - bc;
  3928. te[ 2 ] = bc * f - ad;
  3929. te[ 6 ] = b * e;
  3930. te[ 10 ] = bd * f + ac;
  3931. }
  3932. // bottom row
  3933. te[ 3 ] = 0;
  3934. te[ 7 ] = 0;
  3935. te[ 11 ] = 0;
  3936. // last column
  3937. te[ 12 ] = 0;
  3938. te[ 13 ] = 0;
  3939. te[ 14 ] = 0;
  3940. te[ 15 ] = 1;
  3941. return this;
  3942. }
  3943. makeRotationFromQuaternion( q ) {
  3944. return this.compose( _zero, q, _one );
  3945. }
  3946. lookAt( eye, target, up ) {
  3947. const te = this.elements;
  3948. _z.subVectors( eye, target );
  3949. if ( _z.lengthSq() === 0 ) {
  3950. // eye and target are in the same position
  3951. _z.z = 1;
  3952. }
  3953. _z.normalize();
  3954. _x.crossVectors( up, _z );
  3955. if ( _x.lengthSq() === 0 ) {
  3956. // up and z are parallel
  3957. if ( Math.abs( up.z ) === 1 ) {
  3958. _z.x += 0.0001;
  3959. } else {
  3960. _z.z += 0.0001;
  3961. }
  3962. _z.normalize();
  3963. _x.crossVectors( up, _z );
  3964. }
  3965. _x.normalize();
  3966. _y.crossVectors( _z, _x );
  3967. te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
  3968. te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
  3969. te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
  3970. return this;
  3971. }
  3972. multiply( m, n ) {
  3973. if ( n !== undefined ) {
  3974. console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
  3975. return this.multiplyMatrices( m, n );
  3976. }
  3977. return this.multiplyMatrices( this, m );
  3978. }
  3979. premultiply( m ) {
  3980. return this.multiplyMatrices( m, this );
  3981. }
  3982. multiplyMatrices( a, b ) {
  3983. const ae = a.elements;
  3984. const be = b.elements;
  3985. const te = this.elements;
  3986. const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
  3987. const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
  3988. const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
  3989. const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
  3990. const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
  3991. const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
  3992. const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
  3993. const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
  3994. te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
  3995. te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
  3996. te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
  3997. te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
  3998. te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
  3999. te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
  4000. te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
  4001. te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
  4002. te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
  4003. te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
  4004. te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
  4005. te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
  4006. te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
  4007. te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
  4008. te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
  4009. te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
  4010. return this;
  4011. }
  4012. multiplyScalar( s ) {
  4013. const te = this.elements;
  4014. te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
  4015. te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
  4016. te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
  4017. te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
  4018. return this;
  4019. }
  4020. determinant() {
  4021. const te = this.elements;
  4022. const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
  4023. const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
  4024. const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
  4025. const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
  4026. //TODO: make this more efficient
  4027. //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
  4028. return (
  4029. n41 * (
  4030. + n14 * n23 * n32
  4031. - n13 * n24 * n32
  4032. - n14 * n22 * n33
  4033. + n12 * n24 * n33
  4034. + n13 * n22 * n34
  4035. - n12 * n23 * n34
  4036. ) +
  4037. n42 * (
  4038. + n11 * n23 * n34
  4039. - n11 * n24 * n33
  4040. + n14 * n21 * n33
  4041. - n13 * n21 * n34
  4042. + n13 * n24 * n31
  4043. - n14 * n23 * n31
  4044. ) +
  4045. n43 * (
  4046. + n11 * n24 * n32
  4047. - n11 * n22 * n34
  4048. - n14 * n21 * n32
  4049. + n12 * n21 * n34
  4050. + n14 * n22 * n31
  4051. - n12 * n24 * n31
  4052. ) +
  4053. n44 * (
  4054. - n13 * n22 * n31
  4055. - n11 * n23 * n32
  4056. + n11 * n22 * n33
  4057. + n13 * n21 * n32
  4058. - n12 * n21 * n33
  4059. + n12 * n23 * n31
  4060. )
  4061. );
  4062. }
  4063. transpose() {
  4064. const te = this.elements;
  4065. let tmp;
  4066. tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
  4067. tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
  4068. tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
  4069. tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
  4070. tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
  4071. tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
  4072. return this;
  4073. }
  4074. setPosition( x, y, z ) {
  4075. const te = this.elements;
  4076. if ( x.isVector3 ) {
  4077. te[ 12 ] = x.x;
  4078. te[ 13 ] = x.y;
  4079. te[ 14 ] = x.z;
  4080. } else {
  4081. te[ 12 ] = x;
  4082. te[ 13 ] = y;
  4083. te[ 14 ] = z;
  4084. }
  4085. return this;
  4086. }
  4087. invert() {
  4088. // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
  4089. const te = this.elements,
  4090. n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
  4091. n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
  4092. n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
  4093. n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
  4094. t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
  4095. t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
  4096. t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
  4097. t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
  4098. const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
  4099. if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
  4100. const detInv = 1 / det;
  4101. te[ 0 ] = t11 * detInv;
  4102. te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
  4103. te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
  4104. te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
  4105. te[ 4 ] = t12 * detInv;
  4106. te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
  4107. te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
  4108. te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
  4109. te[ 8 ] = t13 * detInv;
  4110. te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
  4111. te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
  4112. te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
  4113. te[ 12 ] = t14 * detInv;
  4114. te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
  4115. te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
  4116. te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
  4117. return this;
  4118. }
  4119. scale( v ) {
  4120. const te = this.elements;
  4121. const x = v.x, y = v.y, z = v.z;
  4122. te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
  4123. te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
  4124. te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
  4125. te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
  4126. return this;
  4127. }
  4128. getMaxScaleOnAxis() {
  4129. const te = this.elements;
  4130. const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
  4131. const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
  4132. const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
  4133. return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
  4134. }
  4135. makeTranslation( x, y, z ) {
  4136. this.set(
  4137. 1, 0, 0, x,
  4138. 0, 1, 0, y,
  4139. 0, 0, 1, z,
  4140. 0, 0, 0, 1
  4141. );
  4142. return this;
  4143. }
  4144. makeRotationX( theta ) {
  4145. const c = Math.cos( theta ), s = Math.sin( theta );
  4146. this.set(
  4147. 1, 0, 0, 0,
  4148. 0, c, - s, 0,
  4149. 0, s, c, 0,
  4150. 0, 0, 0, 1
  4151. );
  4152. return this;
  4153. }
  4154. makeRotationY( theta ) {
  4155. const c = Math.cos( theta ), s = Math.sin( theta );
  4156. this.set(
  4157. c, 0, s, 0,
  4158. 0, 1, 0, 0,
  4159. - s, 0, c, 0,
  4160. 0, 0, 0, 1
  4161. );
  4162. return this;
  4163. }
  4164. makeRotationZ( theta ) {
  4165. const c = Math.cos( theta ), s = Math.sin( theta );
  4166. this.set(
  4167. c, - s, 0, 0,
  4168. s, c, 0, 0,
  4169. 0, 0, 1, 0,
  4170. 0, 0, 0, 1
  4171. );
  4172. return this;
  4173. }
  4174. makeRotationAxis( axis, angle ) {
  4175. // Based on http://www.gamedev.net/reference/articles/article1199.asp
  4176. const c = Math.cos( angle );
  4177. const s = Math.sin( angle );
  4178. const t = 1 - c;
  4179. const x = axis.x, y = axis.y, z = axis.z;
  4180. const tx = t * x, ty = t * y;
  4181. this.set(
  4182. tx * x + c, tx * y - s * z, tx * z + s * y, 0,
  4183. tx * y + s * z, ty * y + c, ty * z - s * x, 0,
  4184. tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
  4185. 0, 0, 0, 1
  4186. );
  4187. return this;
  4188. }
  4189. makeScale( x, y, z ) {
  4190. this.set(
  4191. x, 0, 0, 0,
  4192. 0, y, 0, 0,
  4193. 0, 0, z, 0,
  4194. 0, 0, 0, 1
  4195. );
  4196. return this;
  4197. }
  4198. makeShear( x, y, z ) {
  4199. this.set(
  4200. 1, y, z, 0,
  4201. x, 1, z, 0,
  4202. x, y, 1, 0,
  4203. 0, 0, 0, 1
  4204. );
  4205. return this;
  4206. }
  4207. compose( position, quaternion, scale ) {
  4208. const te = this.elements;
  4209. const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
  4210. const x2 = x + x, y2 = y + y, z2 = z + z;
  4211. const xx = x * x2, xy = x * y2, xz = x * z2;
  4212. const yy = y * y2, yz = y * z2, zz = z * z2;
  4213. const wx = w * x2, wy = w * y2, wz = w * z2;
  4214. const sx = scale.x, sy = scale.y, sz = scale.z;
  4215. te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
  4216. te[ 1 ] = ( xy + wz ) * sx;
  4217. te[ 2 ] = ( xz - wy ) * sx;
  4218. te[ 3 ] = 0;
  4219. te[ 4 ] = ( xy - wz ) * sy;
  4220. te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
  4221. te[ 6 ] = ( yz + wx ) * sy;
  4222. te[ 7 ] = 0;
  4223. te[ 8 ] = ( xz + wy ) * sz;
  4224. te[ 9 ] = ( yz - wx ) * sz;
  4225. te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
  4226. te[ 11 ] = 0;
  4227. te[ 12 ] = position.x;
  4228. te[ 13 ] = position.y;
  4229. te[ 14 ] = position.z;
  4230. te[ 15 ] = 1;
  4231. return this;
  4232. }
  4233. decompose( position, quaternion, scale ) {
  4234. const te = this.elements;
  4235. let sx = _v1$1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
  4236. const sy = _v1$1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
  4237. const sz = _v1$1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
  4238. // if determine is negative, we need to invert one scale
  4239. const det = this.determinant();
  4240. if ( det < 0 ) sx = - sx;
  4241. position.x = te[ 12 ];
  4242. position.y = te[ 13 ];
  4243. position.z = te[ 14 ];
  4244. // scale the rotation part
  4245. _m1.copy( this );
  4246. const invSX = 1 / sx;
  4247. const invSY = 1 / sy;
  4248. const invSZ = 1 / sz;
  4249. _m1.elements[ 0 ] *= invSX;
  4250. _m1.elements[ 1 ] *= invSX;
  4251. _m1.elements[ 2 ] *= invSX;
  4252. _m1.elements[ 4 ] *= invSY;
  4253. _m1.elements[ 5 ] *= invSY;
  4254. _m1.elements[ 6 ] *= invSY;
  4255. _m1.elements[ 8 ] *= invSZ;
  4256. _m1.elements[ 9 ] *= invSZ;
  4257. _m1.elements[ 10 ] *= invSZ;
  4258. quaternion.setFromRotationMatrix( _m1 );
  4259. scale.x = sx;
  4260. scale.y = sy;
  4261. scale.z = sz;
  4262. return this;
  4263. }
  4264. makePerspective( left, right, top, bottom, near, far ) {
  4265. if ( far === undefined ) {
  4266. console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
  4267. }
  4268. const te = this.elements;
  4269. const x = 2 * near / ( right - left );
  4270. const y = 2 * near / ( top - bottom );
  4271. const a = ( right + left ) / ( right - left );
  4272. const b = ( top + bottom ) / ( top - bottom );
  4273. const c = - ( far + near ) / ( far - near );
  4274. const d = - 2 * far * near / ( far - near );
  4275. te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
  4276. te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
  4277. te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
  4278. te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
  4279. return this;
  4280. }
  4281. makeOrthographic( left, right, top, bottom, near, far ) {
  4282. const te = this.elements;
  4283. const w = 1.0 / ( right - left );
  4284. const h = 1.0 / ( top - bottom );
  4285. const p = 1.0 / ( far - near );
  4286. const x = ( right + left ) * w;
  4287. const y = ( top + bottom ) * h;
  4288. const z = ( far + near ) * p;
  4289. te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
  4290. te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
  4291. te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
  4292. te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
  4293. return this;
  4294. }
  4295. equals( matrix ) {
  4296. const te = this.elements;
  4297. const me = matrix.elements;
  4298. for ( let i = 0; i < 16; i ++ ) {
  4299. if ( te[ i ] !== me[ i ] ) return false;
  4300. }
  4301. return true;
  4302. }
  4303. fromArray( array, offset = 0 ) {
  4304. for ( let i = 0; i < 16; i ++ ) {
  4305. this.elements[ i ] = array[ i + offset ];
  4306. }
  4307. return this;
  4308. }
  4309. toArray( array = [], offset = 0 ) {
  4310. const te = this.elements;
  4311. array[ offset ] = te[ 0 ];
  4312. array[ offset + 1 ] = te[ 1 ];
  4313. array[ offset + 2 ] = te[ 2 ];
  4314. array[ offset + 3 ] = te[ 3 ];
  4315. array[ offset + 4 ] = te[ 4 ];
  4316. array[ offset + 5 ] = te[ 5 ];
  4317. array[ offset + 6 ] = te[ 6 ];
  4318. array[ offset + 7 ] = te[ 7 ];
  4319. array[ offset + 8 ] = te[ 8 ];
  4320. array[ offset + 9 ] = te[ 9 ];
  4321. array[ offset + 10 ] = te[ 10 ];
  4322. array[ offset + 11 ] = te[ 11 ];
  4323. array[ offset + 12 ] = te[ 12 ];
  4324. array[ offset + 13 ] = te[ 13 ];
  4325. array[ offset + 14 ] = te[ 14 ];
  4326. array[ offset + 15 ] = te[ 15 ];
  4327. return array;
  4328. }
  4329. }
  4330. const _v1$1 = /*@__PURE__*/ new Vector3();
  4331. const _m1 = /*@__PURE__*/ new Matrix4();
  4332. const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
  4333. const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
  4334. const _x = /*@__PURE__*/ new Vector3();
  4335. const _y = /*@__PURE__*/ new Vector3();
  4336. const _z = /*@__PURE__*/ new Vector3();
  4337. class Euler {
  4338. constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) {
  4339. Object.defineProperty( this, 'isEuler', { value: true } );
  4340. this._x = x;
  4341. this._y = y;
  4342. this._z = z;
  4343. this._order = order;
  4344. }
  4345. get x() {
  4346. return this._x;
  4347. }
  4348. set x( value ) {
  4349. this._x = value;
  4350. this._onChangeCallback();
  4351. }
  4352. get y() {
  4353. return this._y;
  4354. }
  4355. set y( value ) {
  4356. this._y = value;
  4357. this._onChangeCallback();
  4358. }
  4359. get z() {
  4360. return this._z;
  4361. }
  4362. set z( value ) {
  4363. this._z = value;
  4364. this._onChangeCallback();
  4365. }
  4366. get order() {
  4367. return this._order;
  4368. }
  4369. set order( value ) {
  4370. this._order = value;
  4371. this._onChangeCallback();
  4372. }
  4373. set( x, y, z, order ) {
  4374. this._x = x;
  4375. this._y = y;
  4376. this._z = z;
  4377. this._order = order || this._order;
  4378. this._onChangeCallback();
  4379. return this;
  4380. }
  4381. clone() {
  4382. return new this.constructor( this._x, this._y, this._z, this._order );
  4383. }
  4384. copy( euler ) {
  4385. this._x = euler._x;
  4386. this._y = euler._y;
  4387. this._z = euler._z;
  4388. this._order = euler._order;
  4389. this._onChangeCallback();
  4390. return this;
  4391. }
  4392. setFromRotationMatrix( m, order, update ) {
  4393. const clamp = MathUtils.clamp;
  4394. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  4395. const te = m.elements;
  4396. const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
  4397. const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
  4398. const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
  4399. order = order || this._order;
  4400. switch ( order ) {
  4401. case 'XYZ':
  4402. this._y = Math.asin( clamp( m13, - 1, 1 ) );
  4403. if ( Math.abs( m13 ) < 0.9999999 ) {
  4404. this._x = Math.atan2( - m23, m33 );
  4405. this._z = Math.atan2( - m12, m11 );
  4406. } else {
  4407. this._x = Math.atan2( m32, m22 );
  4408. this._z = 0;
  4409. }
  4410. break;
  4411. case 'YXZ':
  4412. this._x = Math.asin( - clamp( m23, - 1, 1 ) );
  4413. if ( Math.abs( m23 ) < 0.9999999 ) {
  4414. this._y = Math.atan2( m13, m33 );
  4415. this._z = Math.atan2( m21, m22 );
  4416. } else {
  4417. this._y = Math.atan2( - m31, m11 );
  4418. this._z = 0;
  4419. }
  4420. break;
  4421. case 'ZXY':
  4422. this._x = Math.asin( clamp( m32, - 1, 1 ) );
  4423. if ( Math.abs( m32 ) < 0.9999999 ) {
  4424. this._y = Math.atan2( - m31, m33 );
  4425. this._z = Math.atan2( - m12, m22 );
  4426. } else {
  4427. this._y = 0;
  4428. this._z = Math.atan2( m21, m11 );
  4429. }
  4430. break;
  4431. case 'ZYX':
  4432. this._y = Math.asin( - clamp( m31, - 1, 1 ) );
  4433. if ( Math.abs( m31 ) < 0.9999999 ) {
  4434. this._x = Math.atan2( m32, m33 );
  4435. this._z = Math.atan2( m21, m11 );
  4436. } else {
  4437. this._x = 0;
  4438. this._z = Math.atan2( - m12, m22 );
  4439. }
  4440. break;
  4441. case 'YZX':
  4442. this._z = Math.asin( clamp( m21, - 1, 1 ) );
  4443. if ( Math.abs( m21 ) < 0.9999999 ) {
  4444. this._x = Math.atan2( - m23, m22 );
  4445. this._y = Math.atan2( - m31, m11 );
  4446. } else {
  4447. this._x = 0;
  4448. this._y = Math.atan2( m13, m33 );
  4449. }
  4450. break;
  4451. case 'XZY':
  4452. this._z = Math.asin( - clamp( m12, - 1, 1 ) );
  4453. if ( Math.abs( m12 ) < 0.9999999 ) {
  4454. this._x = Math.atan2( m32, m22 );
  4455. this._y = Math.atan2( m13, m11 );
  4456. } else {
  4457. this._x = Math.atan2( - m23, m33 );
  4458. this._y = 0;
  4459. }
  4460. break;
  4461. default:
  4462. console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
  4463. }
  4464. this._order = order;
  4465. if ( update !== false ) this._onChangeCallback();
  4466. return this;
  4467. }
  4468. setFromQuaternion( q, order, update ) {
  4469. _matrix.makeRotationFromQuaternion( q );
  4470. return this.setFromRotationMatrix( _matrix, order, update );
  4471. }
  4472. setFromVector3( v, order ) {
  4473. return this.set( v.x, v.y, v.z, order || this._order );
  4474. }
  4475. reorder( newOrder ) {
  4476. // WARNING: this discards revolution information -bhouston
  4477. _quaternion$1.setFromEuler( this );
  4478. return this.setFromQuaternion( _quaternion$1, newOrder );
  4479. }
  4480. equals( euler ) {
  4481. return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
  4482. }
  4483. fromArray( array ) {
  4484. this._x = array[ 0 ];
  4485. this._y = array[ 1 ];
  4486. this._z = array[ 2 ];
  4487. if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
  4488. this._onChangeCallback();
  4489. return this;
  4490. }
  4491. toArray( array = [], offset = 0 ) {
  4492. array[ offset ] = this._x;
  4493. array[ offset + 1 ] = this._y;
  4494. array[ offset + 2 ] = this._z;
  4495. array[ offset + 3 ] = this._order;
  4496. return array;
  4497. }
  4498. toVector3( optionalResult ) {
  4499. if ( optionalResult ) {
  4500. return optionalResult.set( this._x, this._y, this._z );
  4501. } else {
  4502. return new Vector3( this._x, this._y, this._z );
  4503. }
  4504. }
  4505. _onChange( callback ) {
  4506. this._onChangeCallback = callback;
  4507. return this;
  4508. }
  4509. _onChangeCallback() {}
  4510. }
  4511. Euler.DefaultOrder = 'XYZ';
  4512. Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
  4513. const _matrix = /*@__PURE__*/ new Matrix4();
  4514. const _quaternion$1 = /*@__PURE__*/ new Quaternion();
  4515. class Layers {
  4516. constructor() {
  4517. this.mask = 1 | 0;
  4518. }
  4519. set( channel ) {
  4520. this.mask = 1 << channel | 0;
  4521. }
  4522. enable( channel ) {
  4523. this.mask |= 1 << channel | 0;
  4524. }
  4525. enableAll() {
  4526. this.mask = 0xffffffff | 0;
  4527. }
  4528. toggle( channel ) {
  4529. this.mask ^= 1 << channel | 0;
  4530. }
  4531. disable( channel ) {
  4532. this.mask &= ~ ( 1 << channel | 0 );
  4533. }
  4534. disableAll() {
  4535. this.mask = 0;
  4536. }
  4537. test( layers ) {
  4538. return ( this.mask & layers.mask ) !== 0;
  4539. }
  4540. }
  4541. let _object3DId = 0;
  4542. const _v1$2 = new Vector3();
  4543. const _q1 = new Quaternion();
  4544. const _m1$1 = new Matrix4();
  4545. const _target = new Vector3();
  4546. const _position = new Vector3();
  4547. const _scale = new Vector3();
  4548. const _quaternion$2 = new Quaternion();
  4549. const _xAxis = new Vector3( 1, 0, 0 );
  4550. const _yAxis = new Vector3( 0, 1, 0 );
  4551. const _zAxis = new Vector3( 0, 0, 1 );
  4552. const _addedEvent = { type: 'added' };
  4553. const _removedEvent = { type: 'removed' };
  4554. function Object3D() {
  4555. Object.defineProperty( this, 'id', { value: _object3DId ++ } );
  4556. this.uuid = MathUtils.generateUUID();
  4557. this.name = '';
  4558. this.type = 'Object3D';
  4559. this.parent = null;
  4560. this.children = [];
  4561. this.up = Object3D.DefaultUp.clone();
  4562. const position = new Vector3();
  4563. const rotation = new Euler();
  4564. const quaternion = new Quaternion();
  4565. const scale = new Vector3( 1, 1, 1 );
  4566. function onRotationChange() {
  4567. quaternion.setFromEuler( rotation, false );
  4568. }
  4569. function onQuaternionChange() {
  4570. rotation.setFromQuaternion( quaternion, undefined, false );
  4571. }
  4572. rotation._onChange( onRotationChange );
  4573. quaternion._onChange( onQuaternionChange );
  4574. Object.defineProperties( this, {
  4575. position: {
  4576. configurable: true,
  4577. enumerable: true,
  4578. value: position
  4579. },
  4580. rotation: {
  4581. configurable: true,
  4582. enumerable: true,
  4583. value: rotation
  4584. },
  4585. quaternion: {
  4586. configurable: true,
  4587. enumerable: true,
  4588. value: quaternion
  4589. },
  4590. scale: {
  4591. configurable: true,
  4592. enumerable: true,
  4593. value: scale
  4594. },
  4595. modelViewMatrix: {
  4596. value: new Matrix4()
  4597. },
  4598. normalMatrix: {
  4599. value: new Matrix3()
  4600. }
  4601. } );
  4602. this.matrix = new Matrix4();
  4603. this.matrixWorld = new Matrix4();
  4604. this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
  4605. this.matrixWorldNeedsUpdate = false;
  4606. this.layers = new Layers();
  4607. this.visible = true;
  4608. this.castShadow = false;
  4609. this.receiveShadow = false;
  4610. this.frustumCulled = true;
  4611. this.renderOrder = 0;
  4612. this.animations = [];
  4613. this.userData = {};
  4614. }
  4615. Object3D.DefaultUp = new Vector3( 0, 1, 0 );
  4616. Object3D.DefaultMatrixAutoUpdate = true;
  4617. Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  4618. constructor: Object3D,
  4619. isObject3D: true,
  4620. onBeforeRender: function () {},
  4621. onAfterRender: function () {},
  4622. applyMatrix4: function ( matrix ) {
  4623. if ( this.matrixAutoUpdate ) this.updateMatrix();
  4624. this.matrix.premultiply( matrix );
  4625. this.matrix.decompose( this.position, this.quaternion, this.scale );
  4626. },
  4627. applyQuaternion: function ( q ) {
  4628. this.quaternion.premultiply( q );
  4629. return this;
  4630. },
  4631. setRotationFromAxisAngle: function ( axis, angle ) {
  4632. // assumes axis is normalized
  4633. this.quaternion.setFromAxisAngle( axis, angle );
  4634. },
  4635. setRotationFromEuler: function ( euler ) {
  4636. this.quaternion.setFromEuler( euler, true );
  4637. },
  4638. setRotationFromMatrix: function ( m ) {
  4639. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  4640. this.quaternion.setFromRotationMatrix( m );
  4641. },
  4642. setRotationFromQuaternion: function ( q ) {
  4643. // assumes q is normalized
  4644. this.quaternion.copy( q );
  4645. },
  4646. rotateOnAxis: function ( axis, angle ) {
  4647. // rotate object on axis in object space
  4648. // axis is assumed to be normalized
  4649. _q1.setFromAxisAngle( axis, angle );
  4650. this.quaternion.multiply( _q1 );
  4651. return this;
  4652. },
  4653. rotateOnWorldAxis: function ( axis, angle ) {
  4654. // rotate object on axis in world space
  4655. // axis is assumed to be normalized
  4656. // method assumes no rotated parent
  4657. _q1.setFromAxisAngle( axis, angle );
  4658. this.quaternion.premultiply( _q1 );
  4659. return this;
  4660. },
  4661. rotateX: function ( angle ) {
  4662. return this.rotateOnAxis( _xAxis, angle );
  4663. },
  4664. rotateY: function ( angle ) {
  4665. return this.rotateOnAxis( _yAxis, angle );
  4666. },
  4667. rotateZ: function ( angle ) {
  4668. return this.rotateOnAxis( _zAxis, angle );
  4669. },
  4670. translateOnAxis: function ( axis, distance ) {
  4671. // translate object by distance along axis in object space
  4672. // axis is assumed to be normalized
  4673. _v1$2.copy( axis ).applyQuaternion( this.quaternion );
  4674. this.position.add( _v1$2.multiplyScalar( distance ) );
  4675. return this;
  4676. },
  4677. translateX: function ( distance ) {
  4678. return this.translateOnAxis( _xAxis, distance );
  4679. },
  4680. translateY: function ( distance ) {
  4681. return this.translateOnAxis( _yAxis, distance );
  4682. },
  4683. translateZ: function ( distance ) {
  4684. return this.translateOnAxis( _zAxis, distance );
  4685. },
  4686. localToWorld: function ( vector ) {
  4687. return vector.applyMatrix4( this.matrixWorld );
  4688. },
  4689. worldToLocal: function ( vector ) {
  4690. return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
  4691. },
  4692. lookAt: function ( x, y, z ) {
  4693. // This method does not support objects having non-uniformly-scaled parent(s)
  4694. if ( x.isVector3 ) {
  4695. _target.copy( x );
  4696. } else {
  4697. _target.set( x, y, z );
  4698. }
  4699. const parent = this.parent;
  4700. this.updateWorldMatrix( true, false );
  4701. _position.setFromMatrixPosition( this.matrixWorld );
  4702. if ( this.isCamera || this.isLight ) {
  4703. _m1$1.lookAt( _position, _target, this.up );
  4704. } else {
  4705. _m1$1.lookAt( _target, _position, this.up );
  4706. }
  4707. this.quaternion.setFromRotationMatrix( _m1$1 );
  4708. if ( parent ) {
  4709. _m1$1.extractRotation( parent.matrixWorld );
  4710. _q1.setFromRotationMatrix( _m1$1 );
  4711. this.quaternion.premultiply( _q1.invert() );
  4712. }
  4713. },
  4714. add: function ( object ) {
  4715. if ( arguments.length > 1 ) {
  4716. for ( let i = 0; i < arguments.length; i ++ ) {
  4717. this.add( arguments[ i ] );
  4718. }
  4719. return this;
  4720. }
  4721. if ( object === this ) {
  4722. console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
  4723. return this;
  4724. }
  4725. if ( object && object.isObject3D ) {
  4726. if ( object.parent !== null ) {
  4727. object.parent.remove( object );
  4728. }
  4729. object.parent = this;
  4730. this.children.push( object );
  4731. object.dispatchEvent( _addedEvent );
  4732. } else {
  4733. console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
  4734. }
  4735. return this;
  4736. },
  4737. remove: function ( object ) {
  4738. if ( arguments.length > 1 ) {
  4739. for ( let i = 0; i < arguments.length; i ++ ) {
  4740. this.remove( arguments[ i ] );
  4741. }
  4742. return this;
  4743. }
  4744. const index = this.children.indexOf( object );
  4745. if ( index !== - 1 ) {
  4746. object.parent = null;
  4747. this.children.splice( index, 1 );
  4748. object.dispatchEvent( _removedEvent );
  4749. }
  4750. return this;
  4751. },
  4752. clear: function () {
  4753. for ( let i = 0; i < this.children.length; i ++ ) {
  4754. const object = this.children[ i ];
  4755. object.parent = null;
  4756. object.dispatchEvent( _removedEvent );
  4757. }
  4758. this.children.length = 0;
  4759. return this;
  4760. },
  4761. attach: function ( object ) {
  4762. // adds object as a child of this, while maintaining the object's world transform
  4763. this.updateWorldMatrix( true, false );
  4764. _m1$1.copy( this.matrixWorld ).invert();
  4765. if ( object.parent !== null ) {
  4766. object.parent.updateWorldMatrix( true, false );
  4767. _m1$1.multiply( object.parent.matrixWorld );
  4768. }
  4769. object.applyMatrix4( _m1$1 );
  4770. object.updateWorldMatrix( false, false );
  4771. this.add( object );
  4772. return this;
  4773. },
  4774. getObjectById: function ( id ) {
  4775. return this.getObjectByProperty( 'id', id );
  4776. },
  4777. getObjectByName: function ( name ) {
  4778. return this.getObjectByProperty( 'name', name );
  4779. },
  4780. getObjectByProperty: function ( name, value ) {
  4781. if ( this[ name ] === value ) return this;
  4782. for ( let i = 0, l = this.children.length; i < l; i ++ ) {
  4783. const child = this.children[ i ];
  4784. const object = child.getObjectByProperty( name, value );
  4785. if ( object !== undefined ) {
  4786. return object;
  4787. }
  4788. }
  4789. return undefined;
  4790. },
  4791. getWorldPosition: function ( target ) {
  4792. if ( target === undefined ) {
  4793. console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' );
  4794. target = new Vector3();
  4795. }
  4796. this.updateWorldMatrix( true, false );
  4797. return target.setFromMatrixPosition( this.matrixWorld );
  4798. },
  4799. getWorldQuaternion: function ( target ) {
  4800. if ( target === undefined ) {
  4801. console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
  4802. target = new Quaternion();
  4803. }
  4804. this.updateWorldMatrix( true, false );
  4805. this.matrixWorld.decompose( _position, target, _scale );
  4806. return target;
  4807. },
  4808. getWorldScale: function ( target ) {
  4809. if ( target === undefined ) {
  4810. console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
  4811. target = new Vector3();
  4812. }
  4813. this.updateWorldMatrix( true, false );
  4814. this.matrixWorld.decompose( _position, _quaternion$2, target );
  4815. return target;
  4816. },
  4817. getWorldDirection: function ( target ) {
  4818. if ( target === undefined ) {
  4819. console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' );
  4820. target = new Vector3();
  4821. }
  4822. this.updateWorldMatrix( true, false );
  4823. const e = this.matrixWorld.elements;
  4824. return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
  4825. },
  4826. raycast: function () {},
  4827. traverse: function ( callback ) {
  4828. callback( this );
  4829. const children = this.children;
  4830. for ( let i = 0, l = children.length; i < l; i ++ ) {
  4831. children[ i ].traverse( callback );
  4832. }
  4833. },
  4834. traverseVisible: function ( callback ) {
  4835. if ( this.visible === false ) return;
  4836. callback( this );
  4837. const children = this.children;
  4838. for ( let i = 0, l = children.length; i < l; i ++ ) {
  4839. children[ i ].traverseVisible( callback );
  4840. }
  4841. },
  4842. traverseAncestors: function ( callback ) {
  4843. const parent = this.parent;
  4844. if ( parent !== null ) {
  4845. callback( parent );
  4846. parent.traverseAncestors( callback );
  4847. }
  4848. },
  4849. updateMatrix: function () {
  4850. this.matrix.compose( this.position, this.quaternion, this.scale );
  4851. this.matrixWorldNeedsUpdate = true;
  4852. },
  4853. updateMatrixWorld: function ( force ) {
  4854. if ( this.matrixAutoUpdate ) this.updateMatrix();
  4855. if ( this.matrixWorldNeedsUpdate || force ) {
  4856. if ( this.parent === null ) {
  4857. this.matrixWorld.copy( this.matrix );
  4858. } else {
  4859. this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
  4860. }
  4861. this.matrixWorldNeedsUpdate = false;
  4862. force = true;
  4863. }
  4864. // update children
  4865. const children = this.children;
  4866. for ( let i = 0, l = children.length; i < l; i ++ ) {
  4867. children[ i ].updateMatrixWorld( force );
  4868. }
  4869. },
  4870. updateWorldMatrix: function ( updateParents, updateChildren ) {
  4871. const parent = this.parent;
  4872. if ( updateParents === true && parent !== null ) {
  4873. parent.updateWorldMatrix( true, false );
  4874. }
  4875. if ( this.matrixAutoUpdate ) this.updateMatrix();
  4876. if ( this.parent === null ) {
  4877. this.matrixWorld.copy( this.matrix );
  4878. } else {
  4879. this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
  4880. }
  4881. // update children
  4882. if ( updateChildren === true ) {
  4883. const children = this.children;
  4884. for ( let i = 0, l = children.length; i < l; i ++ ) {
  4885. children[ i ].updateWorldMatrix( false, true );
  4886. }
  4887. }
  4888. },
  4889. toJSON: function ( meta ) {
  4890. // meta is a string when called from JSON.stringify
  4891. const isRootObject = ( meta === undefined || typeof meta === 'string' );
  4892. const output = {};
  4893. // meta is a hash used to collect geometries, materials.
  4894. // not providing it implies that this is the root object
  4895. // being serialized.
  4896. if ( isRootObject ) {
  4897. // initialize meta obj
  4898. meta = {
  4899. geometries: {},
  4900. materials: {},
  4901. textures: {},
  4902. images: {},
  4903. shapes: {},
  4904. skeletons: {},
  4905. animations: {}
  4906. };
  4907. output.metadata = {
  4908. version: 4.5,
  4909. type: 'Object',
  4910. generator: 'Object3D.toJSON'
  4911. };
  4912. }
  4913. // standard Object3D serialization
  4914. const object = {};
  4915. object.uuid = this.uuid;
  4916. object.type = this.type;
  4917. if ( this.name !== '' ) object.name = this.name;
  4918. if ( this.castShadow === true ) object.castShadow = true;
  4919. if ( this.receiveShadow === true ) object.receiveShadow = true;
  4920. if ( this.visible === false ) object.visible = false;
  4921. if ( this.frustumCulled === false ) object.frustumCulled = false;
  4922. if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
  4923. if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
  4924. object.layers = this.layers.mask;
  4925. object.matrix = this.matrix.toArray();
  4926. if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
  4927. // object specific properties
  4928. if ( this.isInstancedMesh ) {
  4929. object.type = 'InstancedMesh';
  4930. object.count = this.count;
  4931. object.instanceMatrix = this.instanceMatrix.toJSON();
  4932. }
  4933. //
  4934. function serialize( library, element ) {
  4935. if ( library[ element.uuid ] === undefined ) {
  4936. library[ element.uuid ] = element.toJSON( meta );
  4937. }
  4938. return element.uuid;
  4939. }
  4940. if ( this.isMesh || this.isLine || this.isPoints ) {
  4941. object.geometry = serialize( meta.geometries, this.geometry );
  4942. const parameters = this.geometry.parameters;
  4943. if ( parameters !== undefined && parameters.shapes !== undefined ) {
  4944. const shapes = parameters.shapes;
  4945. if ( Array.isArray( shapes ) ) {
  4946. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  4947. const shape = shapes[ i ];
  4948. serialize( meta.shapes, shape );
  4949. }
  4950. } else {
  4951. serialize( meta.shapes, shapes );
  4952. }
  4953. }
  4954. }
  4955. if ( this.isSkinnedMesh ) {
  4956. object.bindMode = this.bindMode;
  4957. object.bindMatrix = this.bindMatrix.toArray();
  4958. if ( this.skeleton !== undefined ) {
  4959. serialize( meta.skeletons, this.skeleton );
  4960. object.skeleton = this.skeleton.uuid;
  4961. }
  4962. }
  4963. if ( this.material !== undefined ) {
  4964. if ( Array.isArray( this.material ) ) {
  4965. const uuids = [];
  4966. for ( let i = 0, l = this.material.length; i < l; i ++ ) {
  4967. uuids.push( serialize( meta.materials, this.material[ i ] ) );
  4968. }
  4969. object.material = uuids;
  4970. } else {
  4971. object.material = serialize( meta.materials, this.material );
  4972. }
  4973. }
  4974. //
  4975. if ( this.children.length > 0 ) {
  4976. object.children = [];
  4977. for ( let i = 0; i < this.children.length; i ++ ) {
  4978. object.children.push( this.children[ i ].toJSON( meta ).object );
  4979. }
  4980. }
  4981. //
  4982. if ( this.animations.length > 0 ) {
  4983. object.animations = [];
  4984. for ( let i = 0; i < this.animations.length; i ++ ) {
  4985. const animation = this.animations[ i ];
  4986. object.animations.push( serialize( meta.animations, animation ) );
  4987. }
  4988. }
  4989. if ( isRootObject ) {
  4990. const geometries = extractFromCache( meta.geometries );
  4991. const materials = extractFromCache( meta.materials );
  4992. const textures = extractFromCache( meta.textures );
  4993. const images = extractFromCache( meta.images );
  4994. const shapes = extractFromCache( meta.shapes );
  4995. const skeletons = extractFromCache( meta.skeletons );
  4996. const animations = extractFromCache( meta.animations );
  4997. if ( geometries.length > 0 ) output.geometries = geometries;
  4998. if ( materials.length > 0 ) output.materials = materials;
  4999. if ( textures.length > 0 ) output.textures = textures;
  5000. if ( images.length > 0 ) output.images = images;
  5001. if ( shapes.length > 0 ) output.shapes = shapes;
  5002. if ( skeletons.length > 0 ) output.skeletons = skeletons;
  5003. if ( animations.length > 0 ) output.animations = animations;
  5004. }
  5005. output.object = object;
  5006. return output;
  5007. // extract data from the cache hash
  5008. // remove metadata on each item
  5009. // and return as array
  5010. function extractFromCache( cache ) {
  5011. const values = [];
  5012. for ( const key in cache ) {
  5013. const data = cache[ key ];
  5014. delete data.metadata;
  5015. values.push( data );
  5016. }
  5017. return values;
  5018. }
  5019. },
  5020. clone: function ( recursive ) {
  5021. return new this.constructor().copy( this, recursive );
  5022. },
  5023. copy: function ( source, recursive = true ) {
  5024. this.name = source.name;
  5025. this.up.copy( source.up );
  5026. this.position.copy( source.position );
  5027. this.rotation.order = source.rotation.order;
  5028. this.quaternion.copy( source.quaternion );
  5029. this.scale.copy( source.scale );
  5030. this.matrix.copy( source.matrix );
  5031. this.matrixWorld.copy( source.matrixWorld );
  5032. this.matrixAutoUpdate = source.matrixAutoUpdate;
  5033. this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
  5034. this.layers.mask = source.layers.mask;
  5035. this.visible = source.visible;
  5036. this.castShadow = source.castShadow;
  5037. this.receiveShadow = source.receiveShadow;
  5038. this.frustumCulled = source.frustumCulled;
  5039. this.renderOrder = source.renderOrder;
  5040. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  5041. if ( recursive === true ) {
  5042. for ( let i = 0; i < source.children.length; i ++ ) {
  5043. const child = source.children[ i ];
  5044. this.add( child.clone() );
  5045. }
  5046. }
  5047. return this;
  5048. }
  5049. } );
  5050. const _vector1 = /*@__PURE__*/ new Vector3();
  5051. const _vector2 = /*@__PURE__*/ new Vector3();
  5052. const _normalMatrix = /*@__PURE__*/ new Matrix3();
  5053. class Plane {
  5054. constructor( normal, constant ) {
  5055. Object.defineProperty( this, 'isPlane', { value: true } );
  5056. // normal is assumed to be normalized
  5057. this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
  5058. this.constant = ( constant !== undefined ) ? constant : 0;
  5059. }
  5060. set( normal, constant ) {
  5061. this.normal.copy( normal );
  5062. this.constant = constant;
  5063. return this;
  5064. }
  5065. setComponents( x, y, z, w ) {
  5066. this.normal.set( x, y, z );
  5067. this.constant = w;
  5068. return this;
  5069. }
  5070. setFromNormalAndCoplanarPoint( normal, point ) {
  5071. this.normal.copy( normal );
  5072. this.constant = - point.dot( this.normal );
  5073. return this;
  5074. }
  5075. setFromCoplanarPoints( a, b, c ) {
  5076. const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
  5077. // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
  5078. this.setFromNormalAndCoplanarPoint( normal, a );
  5079. return this;
  5080. }
  5081. clone() {
  5082. return new this.constructor().copy( this );
  5083. }
  5084. copy( plane ) {
  5085. this.normal.copy( plane.normal );
  5086. this.constant = plane.constant;
  5087. return this;
  5088. }
  5089. normalize() {
  5090. // Note: will lead to a divide by zero if the plane is invalid.
  5091. const inverseNormalLength = 1.0 / this.normal.length();
  5092. this.normal.multiplyScalar( inverseNormalLength );
  5093. this.constant *= inverseNormalLength;
  5094. return this;
  5095. }
  5096. negate() {
  5097. this.constant *= - 1;
  5098. this.normal.negate();
  5099. return this;
  5100. }
  5101. distanceToPoint( point ) {
  5102. return this.normal.dot( point ) + this.constant;
  5103. }
  5104. distanceToSphere( sphere ) {
  5105. return this.distanceToPoint( sphere.center ) - sphere.radius;
  5106. }
  5107. projectPoint( point, target ) {
  5108. if ( target === undefined ) {
  5109. console.warn( 'THREE.Plane: .projectPoint() target is now required' );
  5110. target = new Vector3();
  5111. }
  5112. return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
  5113. }
  5114. intersectLine( line, target ) {
  5115. if ( target === undefined ) {
  5116. console.warn( 'THREE.Plane: .intersectLine() target is now required' );
  5117. target = new Vector3();
  5118. }
  5119. const direction = line.delta( _vector1 );
  5120. const denominator = this.normal.dot( direction );
  5121. if ( denominator === 0 ) {
  5122. // line is coplanar, return origin
  5123. if ( this.distanceToPoint( line.start ) === 0 ) {
  5124. return target.copy( line.start );
  5125. }
  5126. // Unsure if this is the correct method to handle this case.
  5127. return undefined;
  5128. }
  5129. const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
  5130. if ( t < 0 || t > 1 ) {
  5131. return undefined;
  5132. }
  5133. return target.copy( direction ).multiplyScalar( t ).add( line.start );
  5134. }
  5135. intersectsLine( line ) {
  5136. // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
  5137. const startSign = this.distanceToPoint( line.start );
  5138. const endSign = this.distanceToPoint( line.end );
  5139. return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
  5140. }
  5141. intersectsBox( box ) {
  5142. return box.intersectsPlane( this );
  5143. }
  5144. intersectsSphere( sphere ) {
  5145. return sphere.intersectsPlane( this );
  5146. }
  5147. coplanarPoint( target ) {
  5148. if ( target === undefined ) {
  5149. console.warn( 'THREE.Plane: .coplanarPoint() target is now required' );
  5150. target = new Vector3();
  5151. }
  5152. return target.copy( this.normal ).multiplyScalar( - this.constant );
  5153. }
  5154. applyMatrix4( matrix, optionalNormalMatrix ) {
  5155. const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
  5156. const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
  5157. const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
  5158. this.constant = - referencePoint.dot( normal );
  5159. return this;
  5160. }
  5161. translate( offset ) {
  5162. this.constant -= offset.dot( this.normal );
  5163. return this;
  5164. }
  5165. equals( plane ) {
  5166. return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
  5167. }
  5168. }
  5169. const _v0$1 = /*@__PURE__*/ new Vector3();
  5170. const _v1$3 = /*@__PURE__*/ new Vector3();
  5171. const _v2$1 = /*@__PURE__*/ new Vector3();
  5172. const _v3 = /*@__PURE__*/ new Vector3();
  5173. const _vab = /*@__PURE__*/ new Vector3();
  5174. const _vac = /*@__PURE__*/ new Vector3();
  5175. const _vbc = /*@__PURE__*/ new Vector3();
  5176. const _vap = /*@__PURE__*/ new Vector3();
  5177. const _vbp = /*@__PURE__*/ new Vector3();
  5178. const _vcp = /*@__PURE__*/ new Vector3();
  5179. class Triangle {
  5180. constructor( a, b, c ) {
  5181. this.a = ( a !== undefined ) ? a : new Vector3();
  5182. this.b = ( b !== undefined ) ? b : new Vector3();
  5183. this.c = ( c !== undefined ) ? c : new Vector3();
  5184. }
  5185. static getNormal( a, b, c, target ) {
  5186. if ( target === undefined ) {
  5187. console.warn( 'THREE.Triangle: .getNormal() target is now required' );
  5188. target = new Vector3();
  5189. }
  5190. target.subVectors( c, b );
  5191. _v0$1.subVectors( a, b );
  5192. target.cross( _v0$1 );
  5193. const targetLengthSq = target.lengthSq();
  5194. if ( targetLengthSq > 0 ) {
  5195. return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
  5196. }
  5197. return target.set( 0, 0, 0 );
  5198. }
  5199. // static/instance method to calculate barycentric coordinates
  5200. // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
  5201. static getBarycoord( point, a, b, c, target ) {
  5202. _v0$1.subVectors( c, a );
  5203. _v1$3.subVectors( b, a );
  5204. _v2$1.subVectors( point, a );
  5205. const dot00 = _v0$1.dot( _v0$1 );
  5206. const dot01 = _v0$1.dot( _v1$3 );
  5207. const dot02 = _v0$1.dot( _v2$1 );
  5208. const dot11 = _v1$3.dot( _v1$3 );
  5209. const dot12 = _v1$3.dot( _v2$1 );
  5210. const denom = ( dot00 * dot11 - dot01 * dot01 );
  5211. if ( target === undefined ) {
  5212. console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
  5213. target = new Vector3();
  5214. }
  5215. // collinear or singular triangle
  5216. if ( denom === 0 ) {
  5217. // arbitrary location outside of triangle?
  5218. // not sure if this is the best idea, maybe should be returning undefined
  5219. return target.set( - 2, - 1, - 1 );
  5220. }
  5221. const invDenom = 1 / denom;
  5222. const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  5223. const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  5224. // barycentric coordinates must always sum to 1
  5225. return target.set( 1 - u - v, v, u );
  5226. }
  5227. static containsPoint( point, a, b, c ) {
  5228. this.getBarycoord( point, a, b, c, _v3 );
  5229. return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 );
  5230. }
  5231. static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
  5232. this.getBarycoord( point, p1, p2, p3, _v3 );
  5233. target.set( 0, 0 );
  5234. target.addScaledVector( uv1, _v3.x );
  5235. target.addScaledVector( uv2, _v3.y );
  5236. target.addScaledVector( uv3, _v3.z );
  5237. return target;
  5238. }
  5239. static isFrontFacing( a, b, c, direction ) {
  5240. _v0$1.subVectors( c, b );
  5241. _v1$3.subVectors( a, b );
  5242. // strictly front facing
  5243. return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
  5244. }
  5245. set( a, b, c ) {
  5246. this.a.copy( a );
  5247. this.b.copy( b );
  5248. this.c.copy( c );
  5249. return this;
  5250. }
  5251. setFromPointsAndIndices( points, i0, i1, i2 ) {
  5252. this.a.copy( points[ i0 ] );
  5253. this.b.copy( points[ i1 ] );
  5254. this.c.copy( points[ i2 ] );
  5255. return this;
  5256. }
  5257. clone() {
  5258. return new this.constructor().copy( this );
  5259. }
  5260. copy( triangle ) {
  5261. this.a.copy( triangle.a );
  5262. this.b.copy( triangle.b );
  5263. this.c.copy( triangle.c );
  5264. return this;
  5265. }
  5266. getArea() {
  5267. _v0$1.subVectors( this.c, this.b );
  5268. _v1$3.subVectors( this.a, this.b );
  5269. return _v0$1.cross( _v1$3 ).length() * 0.5;
  5270. }
  5271. getMidpoint( target ) {
  5272. if ( target === undefined ) {
  5273. console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
  5274. target = new Vector3();
  5275. }
  5276. return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
  5277. }
  5278. getNormal( target ) {
  5279. return Triangle.getNormal( this.a, this.b, this.c, target );
  5280. }
  5281. getPlane( target ) {
  5282. if ( target === undefined ) {
  5283. console.warn( 'THREE.Triangle: .getPlane() target is now required' );
  5284. target = new Plane();
  5285. }
  5286. return target.setFromCoplanarPoints( this.a, this.b, this.c );
  5287. }
  5288. getBarycoord( point, target ) {
  5289. return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
  5290. }
  5291. getUV( point, uv1, uv2, uv3, target ) {
  5292. return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
  5293. }
  5294. containsPoint( point ) {
  5295. return Triangle.containsPoint( point, this.a, this.b, this.c );
  5296. }
  5297. isFrontFacing( direction ) {
  5298. return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
  5299. }
  5300. intersectsBox( box ) {
  5301. return box.intersectsTriangle( this );
  5302. }
  5303. closestPointToPoint( p, target ) {
  5304. if ( target === undefined ) {
  5305. console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
  5306. target = new Vector3();
  5307. }
  5308. const a = this.a, b = this.b, c = this.c;
  5309. let v, w;
  5310. // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
  5311. // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
  5312. // under the accompanying license; see chapter 5.1.5 for detailed explanation.
  5313. // basically, we're distinguishing which of the voronoi regions of the triangle
  5314. // the point lies in with the minimum amount of redundant computation.
  5315. _vab.subVectors( b, a );
  5316. _vac.subVectors( c, a );
  5317. _vap.subVectors( p, a );
  5318. const d1 = _vab.dot( _vap );
  5319. const d2 = _vac.dot( _vap );
  5320. if ( d1 <= 0 && d2 <= 0 ) {
  5321. // vertex region of A; barycentric coords (1, 0, 0)
  5322. return target.copy( a );
  5323. }
  5324. _vbp.subVectors( p, b );
  5325. const d3 = _vab.dot( _vbp );
  5326. const d4 = _vac.dot( _vbp );
  5327. if ( d3 >= 0 && d4 <= d3 ) {
  5328. // vertex region of B; barycentric coords (0, 1, 0)
  5329. return target.copy( b );
  5330. }
  5331. const vc = d1 * d4 - d3 * d2;
  5332. if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
  5333. v = d1 / ( d1 - d3 );
  5334. // edge region of AB; barycentric coords (1-v, v, 0)
  5335. return target.copy( a ).addScaledVector( _vab, v );
  5336. }
  5337. _vcp.subVectors( p, c );
  5338. const d5 = _vab.dot( _vcp );
  5339. const d6 = _vac.dot( _vcp );
  5340. if ( d6 >= 0 && d5 <= d6 ) {
  5341. // vertex region of C; barycentric coords (0, 0, 1)
  5342. return target.copy( c );
  5343. }
  5344. const vb = d5 * d2 - d1 * d6;
  5345. if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
  5346. w = d2 / ( d2 - d6 );
  5347. // edge region of AC; barycentric coords (1-w, 0, w)
  5348. return target.copy( a ).addScaledVector( _vac, w );
  5349. }
  5350. const va = d3 * d6 - d5 * d4;
  5351. if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
  5352. _vbc.subVectors( c, b );
  5353. w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
  5354. // edge region of BC; barycentric coords (0, 1-w, w)
  5355. return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
  5356. }
  5357. // face region
  5358. const denom = 1 / ( va + vb + vc );
  5359. // u = va * denom
  5360. v = vb * denom;
  5361. w = vc * denom;
  5362. return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
  5363. }
  5364. equals( triangle ) {
  5365. return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
  5366. }
  5367. }
  5368. const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
  5369. 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
  5370. 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
  5371. 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
  5372. 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
  5373. 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
  5374. 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
  5375. 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
  5376. 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
  5377. 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
  5378. 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
  5379. 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
  5380. 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
  5381. 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
  5382. 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
  5383. 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
  5384. 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
  5385. 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
  5386. 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
  5387. 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
  5388. 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
  5389. 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
  5390. 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
  5391. 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
  5392. const _hslA = { h: 0, s: 0, l: 0 };
  5393. const _hslB = { h: 0, s: 0, l: 0 };
  5394. function hue2rgb( p, q, t ) {
  5395. if ( t < 0 ) t += 1;
  5396. if ( t > 1 ) t -= 1;
  5397. if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
  5398. if ( t < 1 / 2 ) return q;
  5399. if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
  5400. return p;
  5401. }
  5402. function SRGBToLinear( c ) {
  5403. return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
  5404. }
  5405. function LinearToSRGB( c ) {
  5406. return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
  5407. }
  5408. class Color {
  5409. constructor( r, g, b ) {
  5410. Object.defineProperty( this, 'isColor', { value: true } );
  5411. if ( g === undefined && b === undefined ) {
  5412. // r is THREE.Color, hex or string
  5413. return this.set( r );
  5414. }
  5415. return this.setRGB( r, g, b );
  5416. }
  5417. set( value ) {
  5418. if ( value && value.isColor ) {
  5419. this.copy( value );
  5420. } else if ( typeof value === 'number' ) {
  5421. this.setHex( value );
  5422. } else if ( typeof value === 'string' ) {
  5423. this.setStyle( value );
  5424. }
  5425. return this;
  5426. }
  5427. setScalar( scalar ) {
  5428. this.r = scalar;
  5429. this.g = scalar;
  5430. this.b = scalar;
  5431. return this;
  5432. }
  5433. setHex( hex ) {
  5434. hex = Math.floor( hex );
  5435. this.r = ( hex >> 16 & 255 ) / 255;
  5436. this.g = ( hex >> 8 & 255 ) / 255;
  5437. this.b = ( hex & 255 ) / 255;
  5438. return this;
  5439. }
  5440. setRGB( r, g, b ) {
  5441. this.r = r;
  5442. this.g = g;
  5443. this.b = b;
  5444. return this;
  5445. }
  5446. setHSL( h, s, l ) {
  5447. // h,s,l ranges are in 0.0 - 1.0
  5448. h = MathUtils.euclideanModulo( h, 1 );
  5449. s = MathUtils.clamp( s, 0, 1 );
  5450. l = MathUtils.clamp( l, 0, 1 );
  5451. if ( s === 0 ) {
  5452. this.r = this.g = this.b = l;
  5453. } else {
  5454. const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
  5455. const q = ( 2 * l ) - p;
  5456. this.r = hue2rgb( q, p, h + 1 / 3 );
  5457. this.g = hue2rgb( q, p, h );
  5458. this.b = hue2rgb( q, p, h - 1 / 3 );
  5459. }
  5460. return this;
  5461. }
  5462. setStyle( style ) {
  5463. function handleAlpha( string ) {
  5464. if ( string === undefined ) return;
  5465. if ( parseFloat( string ) < 1 ) {
  5466. console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
  5467. }
  5468. }
  5469. let m;
  5470. if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
  5471. // rgb / hsl
  5472. let color;
  5473. const name = m[ 1 ];
  5474. const components = m[ 2 ];
  5475. switch ( name ) {
  5476. case 'rgb':
  5477. case 'rgba':
  5478. if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
  5479. // rgb(255,0,0) rgba(255,0,0,0.5)
  5480. this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
  5481. this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
  5482. this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
  5483. handleAlpha( color[ 4 ] );
  5484. return this;
  5485. }
  5486. if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
  5487. // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
  5488. this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
  5489. this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
  5490. this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
  5491. handleAlpha( color[ 4 ] );
  5492. return this;
  5493. }
  5494. break;
  5495. case 'hsl':
  5496. case 'hsla':
  5497. if ( color = /^(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
  5498. // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
  5499. const h = parseFloat( color[ 1 ] ) / 360;
  5500. const s = parseInt( color[ 2 ], 10 ) / 100;
  5501. const l = parseInt( color[ 3 ], 10 ) / 100;
  5502. handleAlpha( color[ 4 ] );
  5503. return this.setHSL( h, s, l );
  5504. }
  5505. break;
  5506. }
  5507. } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
  5508. // hex color
  5509. const hex = m[ 1 ];
  5510. const size = hex.length;
  5511. if ( size === 3 ) {
  5512. // #ff0
  5513. this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
  5514. this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
  5515. this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
  5516. return this;
  5517. } else if ( size === 6 ) {
  5518. // #ff0000
  5519. this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
  5520. this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
  5521. this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
  5522. return this;
  5523. }
  5524. }
  5525. if ( style && style.length > 0 ) {
  5526. return this.setColorName( style );
  5527. }
  5528. return this;
  5529. }
  5530. setColorName( style ) {
  5531. // color keywords
  5532. const hex = _colorKeywords[ style ];
  5533. if ( hex !== undefined ) {
  5534. // red
  5535. this.setHex( hex );
  5536. } else {
  5537. // unknown color
  5538. console.warn( 'THREE.Color: Unknown color ' + style );
  5539. }
  5540. return this;
  5541. }
  5542. clone() {
  5543. return new this.constructor( this.r, this.g, this.b );
  5544. }
  5545. copy( color ) {
  5546. this.r = color.r;
  5547. this.g = color.g;
  5548. this.b = color.b;
  5549. return this;
  5550. }
  5551. copyGammaToLinear( color, gammaFactor = 2.0 ) {
  5552. this.r = Math.pow( color.r, gammaFactor );
  5553. this.g = Math.pow( color.g, gammaFactor );
  5554. this.b = Math.pow( color.b, gammaFactor );
  5555. return this;
  5556. }
  5557. copyLinearToGamma( color, gammaFactor = 2.0 ) {
  5558. const safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
  5559. this.r = Math.pow( color.r, safeInverse );
  5560. this.g = Math.pow( color.g, safeInverse );
  5561. this.b = Math.pow( color.b, safeInverse );
  5562. return this;
  5563. }
  5564. convertGammaToLinear( gammaFactor ) {
  5565. this.copyGammaToLinear( this, gammaFactor );
  5566. return this;
  5567. }
  5568. convertLinearToGamma( gammaFactor ) {
  5569. this.copyLinearToGamma( this, gammaFactor );
  5570. return this;
  5571. }
  5572. copySRGBToLinear( color ) {
  5573. this.r = SRGBToLinear( color.r );
  5574. this.g = SRGBToLinear( color.g );
  5575. this.b = SRGBToLinear( color.b );
  5576. return this;
  5577. }
  5578. copyLinearToSRGB( color ) {
  5579. this.r = LinearToSRGB( color.r );
  5580. this.g = LinearToSRGB( color.g );
  5581. this.b = LinearToSRGB( color.b );
  5582. return this;
  5583. }
  5584. convertSRGBToLinear() {
  5585. this.copySRGBToLinear( this );
  5586. return this;
  5587. }
  5588. convertLinearToSRGB() {
  5589. this.copyLinearToSRGB( this );
  5590. return this;
  5591. }
  5592. getHex() {
  5593. return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
  5594. }
  5595. getHexString() {
  5596. return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
  5597. }
  5598. getHSL( target ) {
  5599. // h,s,l ranges are in 0.0 - 1.0
  5600. if ( target === undefined ) {
  5601. console.warn( 'THREE.Color: .getHSL() target is now required' );
  5602. target = { h: 0, s: 0, l: 0 };
  5603. }
  5604. const r = this.r, g = this.g, b = this.b;
  5605. const max = Math.max( r, g, b );
  5606. const min = Math.min( r, g, b );
  5607. let hue, saturation;
  5608. const lightness = ( min + max ) / 2.0;
  5609. if ( min === max ) {
  5610. hue = 0;
  5611. saturation = 0;
  5612. } else {
  5613. const delta = max - min;
  5614. saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
  5615. switch ( max ) {
  5616. case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
  5617. case g: hue = ( b - r ) / delta + 2; break;
  5618. case b: hue = ( r - g ) / delta + 4; break;
  5619. }
  5620. hue /= 6;
  5621. }
  5622. target.h = hue;
  5623. target.s = saturation;
  5624. target.l = lightness;
  5625. return target;
  5626. }
  5627. getStyle() {
  5628. return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
  5629. }
  5630. offsetHSL( h, s, l ) {
  5631. this.getHSL( _hslA );
  5632. _hslA.h += h; _hslA.s += s; _hslA.l += l;
  5633. this.setHSL( _hslA.h, _hslA.s, _hslA.l );
  5634. return this;
  5635. }
  5636. add( color ) {
  5637. this.r += color.r;
  5638. this.g += color.g;
  5639. this.b += color.b;
  5640. return this;
  5641. }
  5642. addColors( color1, color2 ) {
  5643. this.r = color1.r + color2.r;
  5644. this.g = color1.g + color2.g;
  5645. this.b = color1.b + color2.b;
  5646. return this;
  5647. }
  5648. addScalar( s ) {
  5649. this.r += s;
  5650. this.g += s;
  5651. this.b += s;
  5652. return this;
  5653. }
  5654. sub( color ) {
  5655. this.r = Math.max( 0, this.r - color.r );
  5656. this.g = Math.max( 0, this.g - color.g );
  5657. this.b = Math.max( 0, this.b - color.b );
  5658. return this;
  5659. }
  5660. multiply( color ) {
  5661. this.r *= color.r;
  5662. this.g *= color.g;
  5663. this.b *= color.b;
  5664. return this;
  5665. }
  5666. multiplyScalar( s ) {
  5667. this.r *= s;
  5668. this.g *= s;
  5669. this.b *= s;
  5670. return this;
  5671. }
  5672. lerp( color, alpha ) {
  5673. this.r += ( color.r - this.r ) * alpha;
  5674. this.g += ( color.g - this.g ) * alpha;
  5675. this.b += ( color.b - this.b ) * alpha;
  5676. return this;
  5677. }
  5678. lerpHSL( color, alpha ) {
  5679. this.getHSL( _hslA );
  5680. color.getHSL( _hslB );
  5681. const h = MathUtils.lerp( _hslA.h, _hslB.h, alpha );
  5682. const s = MathUtils.lerp( _hslA.s, _hslB.s, alpha );
  5683. const l = MathUtils.lerp( _hslA.l, _hslB.l, alpha );
  5684. this.setHSL( h, s, l );
  5685. return this;
  5686. }
  5687. equals( c ) {
  5688. return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
  5689. }
  5690. fromArray( array, offset = 0 ) {
  5691. this.r = array[ offset ];
  5692. this.g = array[ offset + 1 ];
  5693. this.b = array[ offset + 2 ];
  5694. return this;
  5695. }
  5696. toArray( array = [], offset = 0 ) {
  5697. array[ offset ] = this.r;
  5698. array[ offset + 1 ] = this.g;
  5699. array[ offset + 2 ] = this.b;
  5700. return array;
  5701. }
  5702. fromBufferAttribute( attribute, index ) {
  5703. this.r = attribute.getX( index );
  5704. this.g = attribute.getY( index );
  5705. this.b = attribute.getZ( index );
  5706. if ( attribute.normalized === true ) {
  5707. // assuming Uint8Array
  5708. this.r /= 255;
  5709. this.g /= 255;
  5710. this.b /= 255;
  5711. }
  5712. return this;
  5713. }
  5714. toJSON() {
  5715. return this.getHex();
  5716. }
  5717. }
  5718. Color.NAMES = _colorKeywords;
  5719. Color.prototype.r = 1;
  5720. Color.prototype.g = 1;
  5721. Color.prototype.b = 1;
  5722. class Face3 {
  5723. constructor( a, b, c, normal, color, materialIndex = 0 ) {
  5724. this.a = a;
  5725. this.b = b;
  5726. this.c = c;
  5727. this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
  5728. this.vertexNormals = Array.isArray( normal ) ? normal : [];
  5729. this.color = ( color && color.isColor ) ? color : new Color();
  5730. this.vertexColors = Array.isArray( color ) ? color : [];
  5731. this.materialIndex = materialIndex;
  5732. }
  5733. clone() {
  5734. return new this.constructor().copy( this );
  5735. }
  5736. copy( source ) {
  5737. this.a = source.a;
  5738. this.b = source.b;
  5739. this.c = source.c;
  5740. this.normal.copy( source.normal );
  5741. this.color.copy( source.color );
  5742. this.materialIndex = source.materialIndex;
  5743. for ( let i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
  5744. this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
  5745. }
  5746. for ( let i = 0, il = source.vertexColors.length; i < il; i ++ ) {
  5747. this.vertexColors[ i ] = source.vertexColors[ i ].clone();
  5748. }
  5749. return this;
  5750. }
  5751. }
  5752. let materialId = 0;
  5753. function Material() {
  5754. Object.defineProperty( this, 'id', { value: materialId ++ } );
  5755. this.uuid = MathUtils.generateUUID();
  5756. this.name = '';
  5757. this.type = 'Material';
  5758. this.fog = true;
  5759. this.blending = NormalBlending;
  5760. this.side = FrontSide;
  5761. this.flatShading = false;
  5762. this.vertexColors = false;
  5763. this.opacity = 1;
  5764. this.transparent = false;
  5765. this.blendSrc = SrcAlphaFactor;
  5766. this.blendDst = OneMinusSrcAlphaFactor;
  5767. this.blendEquation = AddEquation;
  5768. this.blendSrcAlpha = null;
  5769. this.blendDstAlpha = null;
  5770. this.blendEquationAlpha = null;
  5771. this.depthFunc = LessEqualDepth;
  5772. this.depthTest = true;
  5773. this.depthWrite = true;
  5774. this.stencilWriteMask = 0xff;
  5775. this.stencilFunc = AlwaysStencilFunc;
  5776. this.stencilRef = 0;
  5777. this.stencilFuncMask = 0xff;
  5778. this.stencilFail = KeepStencilOp;
  5779. this.stencilZFail = KeepStencilOp;
  5780. this.stencilZPass = KeepStencilOp;
  5781. this.stencilWrite = false;
  5782. this.clippingPlanes = null;
  5783. this.clipIntersection = false;
  5784. this.clipShadows = false;
  5785. this.shadowSide = null;
  5786. this.colorWrite = true;
  5787. this.precision = null; // override the renderer's default precision for this material
  5788. this.polygonOffset = false;
  5789. this.polygonOffsetFactor = 0;
  5790. this.polygonOffsetUnits = 0;
  5791. this.dithering = false;
  5792. this.alphaTest = 0;
  5793. this.premultipliedAlpha = false;
  5794. this.visible = true;
  5795. this.toneMapped = true;
  5796. this.userData = {};
  5797. this.version = 0;
  5798. }
  5799. Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  5800. constructor: Material,
  5801. isMaterial: true,
  5802. onBeforeCompile: function ( /* shaderobject, renderer */ ) {},
  5803. customProgramCacheKey: function () {
  5804. return this.onBeforeCompile.toString();
  5805. },
  5806. setValues: function ( values ) {
  5807. if ( values === undefined ) return;
  5808. for ( const key in values ) {
  5809. const newValue = values[ key ];
  5810. if ( newValue === undefined ) {
  5811. console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
  5812. continue;
  5813. }
  5814. // for backward compatability if shading is set in the constructor
  5815. if ( key === 'shading' ) {
  5816. console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
  5817. this.flatShading = ( newValue === FlatShading ) ? true : false;
  5818. continue;
  5819. }
  5820. const currentValue = this[ key ];
  5821. if ( currentValue === undefined ) {
  5822. console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' );
  5823. continue;
  5824. }
  5825. if ( currentValue && currentValue.isColor ) {
  5826. currentValue.set( newValue );
  5827. } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
  5828. currentValue.copy( newValue );
  5829. } else {
  5830. this[ key ] = newValue;
  5831. }
  5832. }
  5833. },
  5834. toJSON: function ( meta ) {
  5835. const isRoot = ( meta === undefined || typeof meta === 'string' );
  5836. if ( isRoot ) {
  5837. meta = {
  5838. textures: {},
  5839. images: {}
  5840. };
  5841. }
  5842. const data = {
  5843. metadata: {
  5844. version: 4.5,
  5845. type: 'Material',
  5846. generator: 'Material.toJSON'
  5847. }
  5848. };
  5849. // standard Material serialization
  5850. data.uuid = this.uuid;
  5851. data.type = this.type;
  5852. if ( this.name !== '' ) data.name = this.name;
  5853. if ( this.color && this.color.isColor ) data.color = this.color.getHex();
  5854. if ( this.roughness !== undefined ) data.roughness = this.roughness;
  5855. if ( this.metalness !== undefined ) data.metalness = this.metalness;
  5856. if ( this.sheen && this.sheen.isColor ) data.sheen = this.sheen.getHex();
  5857. if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
  5858. if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
  5859. if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
  5860. if ( this.shininess !== undefined ) data.shininess = this.shininess;
  5861. if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
  5862. if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
  5863. if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
  5864. data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
  5865. }
  5866. if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
  5867. data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
  5868. }
  5869. if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
  5870. data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
  5871. data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
  5872. }
  5873. if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
  5874. if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
  5875. if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
  5876. if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
  5877. if ( this.aoMap && this.aoMap.isTexture ) {
  5878. data.aoMap = this.aoMap.toJSON( meta ).uuid;
  5879. data.aoMapIntensity = this.aoMapIntensity;
  5880. }
  5881. if ( this.bumpMap && this.bumpMap.isTexture ) {
  5882. data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
  5883. data.bumpScale = this.bumpScale;
  5884. }
  5885. if ( this.normalMap && this.normalMap.isTexture ) {
  5886. data.normalMap = this.normalMap.toJSON( meta ).uuid;
  5887. data.normalMapType = this.normalMapType;
  5888. data.normalScale = this.normalScale.toArray();
  5889. }
  5890. if ( this.displacementMap && this.displacementMap.isTexture ) {
  5891. data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
  5892. data.displacementScale = this.displacementScale;
  5893. data.displacementBias = this.displacementBias;
  5894. }
  5895. if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
  5896. if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
  5897. if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
  5898. if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
  5899. if ( this.envMap && this.envMap.isTexture ) {
  5900. data.envMap = this.envMap.toJSON( meta ).uuid;
  5901. data.reflectivity = this.reflectivity; // Scale behind envMap
  5902. data.refractionRatio = this.refractionRatio;
  5903. if ( this.combine !== undefined ) data.combine = this.combine;
  5904. if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
  5905. }
  5906. if ( this.gradientMap && this.gradientMap.isTexture ) {
  5907. data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
  5908. }
  5909. if ( this.size !== undefined ) data.size = this.size;
  5910. if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
  5911. if ( this.blending !== NormalBlending ) data.blending = this.blending;
  5912. if ( this.flatShading === true ) data.flatShading = this.flatShading;
  5913. if ( this.side !== FrontSide ) data.side = this.side;
  5914. if ( this.vertexColors ) data.vertexColors = true;
  5915. if ( this.opacity < 1 ) data.opacity = this.opacity;
  5916. if ( this.transparent === true ) data.transparent = this.transparent;
  5917. data.depthFunc = this.depthFunc;
  5918. data.depthTest = this.depthTest;
  5919. data.depthWrite = this.depthWrite;
  5920. data.stencilWrite = this.stencilWrite;
  5921. data.stencilWriteMask = this.stencilWriteMask;
  5922. data.stencilFunc = this.stencilFunc;
  5923. data.stencilRef = this.stencilRef;
  5924. data.stencilFuncMask = this.stencilFuncMask;
  5925. data.stencilFail = this.stencilFail;
  5926. data.stencilZFail = this.stencilZFail;
  5927. data.stencilZPass = this.stencilZPass;
  5928. // rotation (SpriteMaterial)
  5929. if ( this.rotation && this.rotation !== 0 ) data.rotation = this.rotation;
  5930. if ( this.polygonOffset === true ) data.polygonOffset = true;
  5931. if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
  5932. if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
  5933. if ( this.lineWidth && this.lineWidth !== 1 ) data.lineWidth = this.lineWidth;
  5934. if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
  5935. if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
  5936. if ( this.scale !== undefined ) data.scale = this.scale;
  5937. if ( this.dithering === true ) data.dithering = true;
  5938. if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
  5939. if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
  5940. if ( this.wireframe === true ) data.wireframe = this.wireframe;
  5941. if ( this.wireframelineWidth > 1 ) data.wireframelineWidth = this.wireframelineWidth;
  5942. if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
  5943. if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
  5944. if ( this.morphTargets === true ) data.morphTargets = true;
  5945. if ( this.morphNormals === true ) data.morphNormals = true;
  5946. if ( this.skinning === true ) data.skinning = true;
  5947. if ( this.visible === false ) data.visible = false;
  5948. if ( this.toneMapped === false ) data.toneMapped = false;
  5949. if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
  5950. // TODO: Copied from Object3D.toJSON
  5951. function extractFromCache( cache ) {
  5952. const values = [];
  5953. for ( const key in cache ) {
  5954. const data = cache[ key ];
  5955. delete data.metadata;
  5956. values.push( data );
  5957. }
  5958. return values;
  5959. }
  5960. if ( isRoot ) {
  5961. const textures = extractFromCache( meta.textures );
  5962. const images = extractFromCache( meta.images );
  5963. if ( textures.length > 0 ) data.textures = textures;
  5964. if ( images.length > 0 ) data.images = images;
  5965. }
  5966. return data;
  5967. },
  5968. clone: function () {
  5969. return new this.constructor().copy( this );
  5970. },
  5971. copy: function ( source ) {
  5972. this.name = source.name;
  5973. this.fog = source.fog;
  5974. this.blending = source.blending;
  5975. this.side = source.side;
  5976. this.flatShading = source.flatShading;
  5977. this.vertexColors = source.vertexColors;
  5978. this.opacity = source.opacity;
  5979. this.transparent = source.transparent;
  5980. this.blendSrc = source.blendSrc;
  5981. this.blendDst = source.blendDst;
  5982. this.blendEquation = source.blendEquation;
  5983. this.blendSrcAlpha = source.blendSrcAlpha;
  5984. this.blendDstAlpha = source.blendDstAlpha;
  5985. this.blendEquationAlpha = source.blendEquationAlpha;
  5986. this.depthFunc = source.depthFunc;
  5987. this.depthTest = source.depthTest;
  5988. this.depthWrite = source.depthWrite;
  5989. this.stencilWriteMask = source.stencilWriteMask;
  5990. this.stencilFunc = source.stencilFunc;
  5991. this.stencilRef = source.stencilRef;
  5992. this.stencilFuncMask = source.stencilFuncMask;
  5993. this.stencilFail = source.stencilFail;
  5994. this.stencilZFail = source.stencilZFail;
  5995. this.stencilZPass = source.stencilZPass;
  5996. this.stencilWrite = source.stencilWrite;
  5997. const srcPlanes = source.clippingPlanes;
  5998. let dstPlanes = null;
  5999. if ( srcPlanes !== null ) {
  6000. const n = srcPlanes.length;
  6001. dstPlanes = new Array( n );
  6002. for ( let i = 0; i !== n; ++ i ) {
  6003. dstPlanes[ i ] = srcPlanes[ i ].clone();
  6004. }
  6005. }
  6006. this.clippingPlanes = dstPlanes;
  6007. this.clipIntersection = source.clipIntersection;
  6008. this.clipShadows = source.clipShadows;
  6009. this.shadowSide = source.shadowSide;
  6010. this.colorWrite = source.colorWrite;
  6011. this.precision = source.precision;
  6012. this.polygonOffset = source.polygonOffset;
  6013. this.polygonOffsetFactor = source.polygonOffsetFactor;
  6014. this.polygonOffsetUnits = source.polygonOffsetUnits;
  6015. this.dithering = source.dithering;
  6016. this.alphaTest = source.alphaTest;
  6017. this.premultipliedAlpha = source.premultipliedAlpha;
  6018. this.visible = source.visible;
  6019. this.toneMapped = source.toneMapped;
  6020. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  6021. return this;
  6022. },
  6023. dispose: function () {
  6024. this.dispatchEvent( { type: 'dispose' } );
  6025. }
  6026. } );
  6027. Object.defineProperty( Material.prototype, 'needsUpdate', {
  6028. set: function ( value ) {
  6029. if ( value === true ) this.version ++;
  6030. }
  6031. } );
  6032. /**
  6033. * parameters = {
  6034. * color: <hex>,
  6035. * opacity: <float>,
  6036. * map: new THREE.Texture( <Image> ),
  6037. *
  6038. * lightMap: new THREE.Texture( <Image> ),
  6039. * lightMapIntensity: <float>
  6040. *
  6041. * aoMap: new THREE.Texture( <Image> ),
  6042. * aoMapIntensity: <float>
  6043. *
  6044. * specularMap: new THREE.Texture( <Image> ),
  6045. *
  6046. * alphaMap: new THREE.Texture( <Image> ),
  6047. *
  6048. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  6049. * combine: THREE.Multiply,
  6050. * reflectivity: <float>,
  6051. * refractionRatio: <float>,
  6052. *
  6053. * depthTest: <bool>,
  6054. * depthWrite: <bool>,
  6055. *
  6056. * wireframe: <boolean>,
  6057. * wireframelineWidth: <float>,
  6058. *
  6059. * skinning: <bool>,
  6060. * morphTargets: <bool>
  6061. * }
  6062. */
  6063. function MeshBasicMaterial( parameters ) {
  6064. Material.call( this );
  6065. this.type = 'MeshBasicMaterial';
  6066. this.color = new Color( 0xffffff ); // emissive
  6067. this.map = null;
  6068. this.lightMap = null;
  6069. this.lightMapIntensity = 1.0;
  6070. this.aoMap = null;
  6071. this.aoMapIntensity = 1.0;
  6072. this.specularMap = null;
  6073. this.alphaMap = null;
  6074. this.envMap = null;
  6075. this.combine = MultiplyOperation;
  6076. this.reflectivity = 1;
  6077. this.refractionRatio = 0.98;
  6078. this.wireframe = false;
  6079. this.wireframelineWidth = 1;
  6080. this.wireframeLinecap = 'round';
  6081. this.wireframeLinejoin = 'round';
  6082. this.skinning = false;
  6083. this.morphTargets = false;
  6084. this.setValues( parameters );
  6085. }
  6086. MeshBasicMaterial.prototype = Object.create( Material.prototype );
  6087. MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
  6088. MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
  6089. MeshBasicMaterial.prototype.copy = function ( source ) {
  6090. Material.prototype.copy.call( this, source );
  6091. this.color.copy( source.color );
  6092. this.map = source.map;
  6093. this.lightMap = source.lightMap;
  6094. this.lightMapIntensity = source.lightMapIntensity;
  6095. this.aoMap = source.aoMap;
  6096. this.aoMapIntensity = source.aoMapIntensity;
  6097. this.specularMap = source.specularMap;
  6098. this.alphaMap = source.alphaMap;
  6099. this.envMap = source.envMap;
  6100. this.combine = source.combine;
  6101. this.reflectivity = source.reflectivity;
  6102. this.refractionRatio = source.refractionRatio;
  6103. this.wireframe = source.wireframe;
  6104. this.wireframelineWidth = source.wireframelineWidth;
  6105. this.wireframeLinecap = source.wireframeLinecap;
  6106. this.wireframeLinejoin = source.wireframeLinejoin;
  6107. this.skinning = source.skinning;
  6108. this.morphTargets = source.morphTargets;
  6109. return this;
  6110. };
  6111. const _vector$3 = new Vector3();
  6112. const _vector2$1 = new Vector2$1();
  6113. function BufferAttribute( array, itemSize, normalized ) {
  6114. if ( Array.isArray( array ) ) {
  6115. throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
  6116. }
  6117. this.name = '';
  6118. this.array = array;
  6119. this.itemSize = itemSize;
  6120. this.count = array !== undefined ? array.length / itemSize : 0;
  6121. this.normalized = normalized === true;
  6122. this.usage = StaticDrawUsage;
  6123. this.updateRange = { offset: 0, count: - 1 };
  6124. this.version = 0;
  6125. }
  6126. Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
  6127. set: function ( value ) {
  6128. if ( value === true ) this.version ++;
  6129. }
  6130. } );
  6131. Object.assign( BufferAttribute.prototype, {
  6132. isBufferAttribute: true,
  6133. onUploadCallback: function () {},
  6134. setUsage: function ( value ) {
  6135. this.usage = value;
  6136. return this;
  6137. },
  6138. copy: function ( source ) {
  6139. this.name = source.name;
  6140. this.array = new source.array.constructor( source.array );
  6141. this.itemSize = source.itemSize;
  6142. this.count = source.count;
  6143. this.normalized = source.normalized;
  6144. this.usage = source.usage;
  6145. return this;
  6146. },
  6147. copyAt: function ( index1, attribute, index2 ) {
  6148. index1 *= this.itemSize;
  6149. index2 *= attribute.itemSize;
  6150. for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
  6151. this.array[ index1 + i ] = attribute.array[ index2 + i ];
  6152. }
  6153. return this;
  6154. },
  6155. copyArray: function ( array ) {
  6156. this.array.set( array );
  6157. return this;
  6158. },
  6159. copyColorsArray: function ( colors ) {
  6160. const array = this.array;
  6161. let offset = 0;
  6162. for ( let i = 0, l = colors.length; i < l; i ++ ) {
  6163. let color = colors[ i ];
  6164. if ( color === undefined ) {
  6165. console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
  6166. color = new Color();
  6167. }
  6168. array[ offset ++ ] = color.r;
  6169. array[ offset ++ ] = color.g;
  6170. array[ offset ++ ] = color.b;
  6171. }
  6172. return this;
  6173. },
  6174. copyVector2sArray: function ( vectors ) {
  6175. const array = this.array;
  6176. let offset = 0;
  6177. for ( let i = 0, l = vectors.length; i < l; i ++ ) {
  6178. let vector = vectors[ i ];
  6179. if ( vector === undefined ) {
  6180. console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
  6181. vector = new Vector2$1();
  6182. }
  6183. array[ offset ++ ] = vector.x;
  6184. array[ offset ++ ] = vector.y;
  6185. }
  6186. return this;
  6187. },
  6188. copyVector3sArray: function ( vectors ) {
  6189. const array = this.array;
  6190. let offset = 0;
  6191. for ( let i = 0, l = vectors.length; i < l; i ++ ) {
  6192. let vector = vectors[ i ];
  6193. if ( vector === undefined ) {
  6194. console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
  6195. vector = new Vector3();
  6196. }
  6197. array[ offset ++ ] = vector.x;
  6198. array[ offset ++ ] = vector.y;
  6199. array[ offset ++ ] = vector.z;
  6200. }
  6201. return this;
  6202. },
  6203. copyVector4sArray: function ( vectors ) {
  6204. const array = this.array;
  6205. let offset = 0;
  6206. for ( let i = 0, l = vectors.length; i < l; i ++ ) {
  6207. let vector = vectors[ i ];
  6208. if ( vector === undefined ) {
  6209. console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
  6210. vector = new Vector4();
  6211. }
  6212. array[ offset ++ ] = vector.x;
  6213. array[ offset ++ ] = vector.y;
  6214. array[ offset ++ ] = vector.z;
  6215. array[ offset ++ ] = vector.w;
  6216. }
  6217. return this;
  6218. },
  6219. applyMatrix3: function ( m ) {
  6220. if ( this.itemSize === 2 ) {
  6221. for ( let i = 0, l = this.count; i < l; i ++ ) {
  6222. _vector2$1.fromBufferAttribute( this, i );
  6223. _vector2$1.applyMatrix3( m );
  6224. this.setXY( i, _vector2$1.x, _vector2$1.y );
  6225. }
  6226. } else if ( this.itemSize === 3 ) {
  6227. for ( let i = 0, l = this.count; i < l; i ++ ) {
  6228. _vector$3.fromBufferAttribute( this, i );
  6229. _vector$3.applyMatrix3( m );
  6230. this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
  6231. }
  6232. }
  6233. return this;
  6234. },
  6235. applyMatrix4: function ( m ) {
  6236. for ( let i = 0, l = this.count; i < l; i ++ ) {
  6237. _vector$3.x = this.getX( i );
  6238. _vector$3.y = this.getY( i );
  6239. _vector$3.z = this.getZ( i );
  6240. _vector$3.applyMatrix4( m );
  6241. this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
  6242. }
  6243. return this;
  6244. },
  6245. applyNormalMatrix: function ( m ) {
  6246. for ( let i = 0, l = this.count; i < l; i ++ ) {
  6247. _vector$3.x = this.getX( i );
  6248. _vector$3.y = this.getY( i );
  6249. _vector$3.z = this.getZ( i );
  6250. _vector$3.applyNormalMatrix( m );
  6251. this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
  6252. }
  6253. return this;
  6254. },
  6255. transformDirection: function ( m ) {
  6256. for ( let i = 0, l = this.count; i < l; i ++ ) {
  6257. _vector$3.x = this.getX( i );
  6258. _vector$3.y = this.getY( i );
  6259. _vector$3.z = this.getZ( i );
  6260. _vector$3.transformDirection( m );
  6261. this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
  6262. }
  6263. return this;
  6264. },
  6265. set: function ( value, offset = 0 ) {
  6266. this.array.set( value, offset );
  6267. return this;
  6268. },
  6269. getX: function ( index ) {
  6270. return this.array[ index * this.itemSize ];
  6271. },
  6272. setX: function ( index, x ) {
  6273. this.array[ index * this.itemSize ] = x;
  6274. return this;
  6275. },
  6276. getY: function ( index ) {
  6277. return this.array[ index * this.itemSize + 1 ];
  6278. },
  6279. setY: function ( index, y ) {
  6280. this.array[ index * this.itemSize + 1 ] = y;
  6281. return this;
  6282. },
  6283. getZ: function ( index ) {
  6284. return this.array[ index * this.itemSize + 2 ];
  6285. },
  6286. setZ: function ( index, z ) {
  6287. this.array[ index * this.itemSize + 2 ] = z;
  6288. return this;
  6289. },
  6290. getW: function ( index ) {
  6291. return this.array[ index * this.itemSize + 3 ];
  6292. },
  6293. setW: function ( index, w ) {
  6294. this.array[ index * this.itemSize + 3 ] = w;
  6295. return this;
  6296. },
  6297. setXY: function ( index, x, y ) {
  6298. index *= this.itemSize;
  6299. this.array[ index + 0 ] = x;
  6300. this.array[ index + 1 ] = y;
  6301. return this;
  6302. },
  6303. setXYZ: function ( index, x, y, z ) {
  6304. index *= this.itemSize;
  6305. this.array[ index + 0 ] = x;
  6306. this.array[ index + 1 ] = y;
  6307. this.array[ index + 2 ] = z;
  6308. return this;
  6309. },
  6310. setXYZW: function ( index, x, y, z, w ) {
  6311. index *= this.itemSize;
  6312. this.array[ index + 0 ] = x;
  6313. this.array[ index + 1 ] = y;
  6314. this.array[ index + 2 ] = z;
  6315. this.array[ index + 3 ] = w;
  6316. return this;
  6317. },
  6318. onUpload: function ( callback ) {
  6319. this.onUploadCallback = callback;
  6320. return this;
  6321. },
  6322. clone: function () {
  6323. return new this.constructor( this.array, this.itemSize ).copy( this );
  6324. },
  6325. toJSON: function () {
  6326. return {
  6327. itemSize: this.itemSize,
  6328. type: this.array.constructor.name,
  6329. array: Array.prototype.slice.call( this.array ),
  6330. normalized: this.normalized
  6331. };
  6332. }
  6333. } );
  6334. //
  6335. function Int8BufferAttribute( array, itemSize, normalized ) {
  6336. BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized );
  6337. }
  6338. Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6339. Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
  6340. function Uint8BufferAttribute( array, itemSize, normalized ) {
  6341. BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized );
  6342. }
  6343. Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6344. Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
  6345. function Uint8ClampedBufferAttribute( array, itemSize, normalized ) {
  6346. BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized );
  6347. }
  6348. Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6349. Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
  6350. function Int16BufferAttribute( array, itemSize, normalized ) {
  6351. BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized );
  6352. }
  6353. Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6354. Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
  6355. function Uint16BufferAttribute( array, itemSize, normalized ) {
  6356. BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
  6357. }
  6358. Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6359. Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
  6360. function Int32BufferAttribute( array, itemSize, normalized ) {
  6361. BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized );
  6362. }
  6363. Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6364. Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
  6365. function Uint32BufferAttribute( array, itemSize, normalized ) {
  6366. BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized );
  6367. }
  6368. Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6369. Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
  6370. function Float16BufferAttribute( array, itemSize, normalized ) {
  6371. BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
  6372. }
  6373. Float16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6374. Float16BufferAttribute.prototype.constructor = Float16BufferAttribute;
  6375. Float16BufferAttribute.prototype.isFloat16BufferAttribute = true;
  6376. function Float32BufferAttribute( array, itemSize, normalized ) {
  6377. BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized );
  6378. }
  6379. Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6380. Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
  6381. function Float64BufferAttribute( array, itemSize, normalized ) {
  6382. BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized );
  6383. }
  6384. Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
  6385. Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
  6386. class DirectGeometry {
  6387. constructor() {
  6388. this.vertices = [];
  6389. this.normals = [];
  6390. this.colors = [];
  6391. this.uvs = [];
  6392. this.uvs2 = [];
  6393. this.groups = [];
  6394. this.morphTargets = {};
  6395. this.skinWeights = [];
  6396. this.skinIndices = [];
  6397. // this.lineDistances = [];
  6398. this.boundingBox = null;
  6399. this.boundingSphere = null;
  6400. // update flags
  6401. this.verticesNeedUpdate = false;
  6402. this.normalsNeedUpdate = false;
  6403. this.colorsNeedUpdate = false;
  6404. this.uvsNeedUpdate = false;
  6405. this.groupsNeedUpdate = false;
  6406. }
  6407. computeGroups( geometry ) {
  6408. const groups = [];
  6409. let group, i;
  6410. let materialIndex = undefined;
  6411. const faces = geometry.faces;
  6412. for ( i = 0; i < faces.length; i ++ ) {
  6413. const face = faces[ i ];
  6414. // materials
  6415. if ( face.materialIndex !== materialIndex ) {
  6416. materialIndex = face.materialIndex;
  6417. if ( group !== undefined ) {
  6418. group.count = ( i * 3 ) - group.start;
  6419. groups.push( group );
  6420. }
  6421. group = {
  6422. start: i * 3,
  6423. materialIndex: materialIndex
  6424. };
  6425. }
  6426. }
  6427. if ( group !== undefined ) {
  6428. group.count = ( i * 3 ) - group.start;
  6429. groups.push( group );
  6430. }
  6431. this.groups = groups;
  6432. }
  6433. fromGeometry( geometry ) {
  6434. const faces = geometry.faces;
  6435. const vertices = geometry.vertices;
  6436. const faceVertexUvs = geometry.faceVertexUvs;
  6437. const hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
  6438. const hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
  6439. // morphs
  6440. const morphTargets = geometry.morphTargets;
  6441. const morphTargetsLength = morphTargets.length;
  6442. let morphTargetsPosition;
  6443. if ( morphTargetsLength > 0 ) {
  6444. morphTargetsPosition = [];
  6445. for ( let i = 0; i < morphTargetsLength; i ++ ) {
  6446. morphTargetsPosition[ i ] = {
  6447. name: morphTargets[ i ].name,
  6448. data: []
  6449. };
  6450. }
  6451. this.morphTargets.position = morphTargetsPosition;
  6452. }
  6453. const morphNormals = geometry.morphNormals;
  6454. const morphNormalsLength = morphNormals.length;
  6455. let morphTargetsNormal;
  6456. if ( morphNormalsLength > 0 ) {
  6457. morphTargetsNormal = [];
  6458. for ( let i = 0; i < morphNormalsLength; i ++ ) {
  6459. morphTargetsNormal[ i ] = {
  6460. name: morphNormals[ i ].name,
  6461. data: []
  6462. };
  6463. }
  6464. this.morphTargets.normal = morphTargetsNormal;
  6465. }
  6466. // skins
  6467. const skinIndices = geometry.skinIndices;
  6468. const skinWeights = geometry.skinWeights;
  6469. const hasSkinIndices = skinIndices.length === vertices.length;
  6470. const hasSkinWeights = skinWeights.length === vertices.length;
  6471. //
  6472. if ( vertices.length > 0 && faces.length === 0 ) {
  6473. console.error( 'THREE.DirectGeometry: Faceless geometries are not supported.' );
  6474. }
  6475. for ( let i = 0; i < faces.length; i ++ ) {
  6476. const face = faces[ i ];
  6477. this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );
  6478. const vertexNormals = face.vertexNormals;
  6479. if ( vertexNormals.length === 3 ) {
  6480. this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );
  6481. } else {
  6482. const normal = face.normal;
  6483. this.normals.push( normal, normal, normal );
  6484. }
  6485. const vertexColors = face.vertexColors;
  6486. if ( vertexColors.length === 3 ) {
  6487. this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
  6488. } else {
  6489. const color = face.color;
  6490. this.colors.push( color, color, color );
  6491. }
  6492. if ( hasFaceVertexUv === true ) {
  6493. const vertexUvs = faceVertexUvs[ 0 ][ i ];
  6494. if ( vertexUvs !== undefined ) {
  6495. this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
  6496. } else {
  6497. console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
  6498. this.uvs.push( new Vector2$1(), new Vector2$1(), new Vector2$1() );
  6499. }
  6500. }
  6501. if ( hasFaceVertexUv2 === true ) {
  6502. const vertexUvs = faceVertexUvs[ 1 ][ i ];
  6503. if ( vertexUvs !== undefined ) {
  6504. this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
  6505. } else {
  6506. console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
  6507. this.uvs2.push( new Vector2$1(), new Vector2$1(), new Vector2$1() );
  6508. }
  6509. }
  6510. // morphs
  6511. for ( let j = 0; j < morphTargetsLength; j ++ ) {
  6512. const morphTarget = morphTargets[ j ].vertices;
  6513. morphTargetsPosition[ j ].data.push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );
  6514. }
  6515. for ( let j = 0; j < morphNormalsLength; j ++ ) {
  6516. const morphNormal = morphNormals[ j ].vertexNormals[ i ];
  6517. morphTargetsNormal[ j ].data.push( morphNormal.a, morphNormal.b, morphNormal.c );
  6518. }
  6519. // skins
  6520. if ( hasSkinIndices ) {
  6521. this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );
  6522. }
  6523. if ( hasSkinWeights ) {
  6524. this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );
  6525. }
  6526. }
  6527. this.computeGroups( geometry );
  6528. this.verticesNeedUpdate = geometry.verticesNeedUpdate;
  6529. this.normalsNeedUpdate = geometry.normalsNeedUpdate;
  6530. this.colorsNeedUpdate = geometry.colorsNeedUpdate;
  6531. this.uvsNeedUpdate = geometry.uvsNeedUpdate;
  6532. this.groupsNeedUpdate = geometry.groupsNeedUpdate;
  6533. if ( geometry.boundingSphere !== null ) {
  6534. this.boundingSphere = geometry.boundingSphere.clone();
  6535. }
  6536. if ( geometry.boundingBox !== null ) {
  6537. this.boundingBox = geometry.boundingBox.clone();
  6538. }
  6539. return this;
  6540. }
  6541. }
  6542. function arrayMax( array ) {
  6543. if ( array.length === 0 ) return - Infinity;
  6544. let max = array[ 0 ];
  6545. for ( let i = 1, l = array.length; i < l; ++ i ) {
  6546. if ( array[ i ] > max ) max = array[ i ];
  6547. }
  6548. return max;
  6549. }
  6550. const TYPED_ARRAYS = {
  6551. Int8Array: Int8Array,
  6552. Uint8Array: Uint8Array,
  6553. // Workaround for IE11 pre KB2929437. See #11440
  6554. Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
  6555. Int16Array: Int16Array,
  6556. Uint16Array: Uint16Array,
  6557. Int32Array: Int32Array,
  6558. Uint32Array: Uint32Array,
  6559. Float32Array: Float32Array,
  6560. Float64Array: Float64Array
  6561. };
  6562. function getTypedArray( type, buffer ) {
  6563. return new TYPED_ARRAYS[ type ]( buffer );
  6564. }
  6565. let _bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
  6566. const _m1$2 = new Matrix4();
  6567. const _obj = new Object3D();
  6568. const _offset = new Vector3();
  6569. const _box$2 = new Box3();
  6570. const _boxMorphTargets = new Box3();
  6571. const _vector$4 = new Vector3();
  6572. function BufferGeometry() {
  6573. Object.defineProperty( this, 'id', { value: _bufferGeometryId += 2 } );
  6574. this.uuid = MathUtils.generateUUID();
  6575. this.name = '';
  6576. this.type = 'BufferGeometry';
  6577. this.index = null;
  6578. this.attributes = {};
  6579. this.morphAttributes = {};
  6580. this.morphTargetsRelative = false;
  6581. this.groups = [];
  6582. this.boundingBox = null;
  6583. this.boundingSphere = null;
  6584. this.drawRange = { start: 0, count: Infinity };
  6585. this.userData = {};
  6586. }
  6587. BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  6588. constructor: BufferGeometry,
  6589. isBufferGeometry: true,
  6590. getIndex: function () {
  6591. return this.index;
  6592. },
  6593. setIndex: function ( index ) {
  6594. if ( Array.isArray( index ) ) {
  6595. this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
  6596. } else {
  6597. this.index = index;
  6598. }
  6599. return this;
  6600. },
  6601. getAttribute: function ( name ) {
  6602. return this.attributes[ name ];
  6603. },
  6604. setAttribute: function ( name, attribute ) {
  6605. this.attributes[ name ] = attribute;
  6606. return this;
  6607. },
  6608. deleteAttribute: function ( name ) {
  6609. delete this.attributes[ name ];
  6610. return this;
  6611. },
  6612. hasAttribute: function ( name ) {
  6613. return this.attributes[ name ] !== undefined;
  6614. },
  6615. addGroup: function ( start, count, materialIndex = 0 ) {
  6616. this.groups.push( {
  6617. start: start,
  6618. count: count,
  6619. materialIndex: materialIndex
  6620. } );
  6621. },
  6622. clearGroups: function () {
  6623. this.groups = [];
  6624. },
  6625. setDrawRange: function ( start, count ) {
  6626. this.drawRange.start = start;
  6627. this.drawRange.count = count;
  6628. },
  6629. applyMatrix4: function ( matrix ) {
  6630. const position = this.attributes.position;
  6631. if ( position !== undefined ) {
  6632. position.applyMatrix4( matrix );
  6633. position.needsUpdate = true;
  6634. }
  6635. const normal = this.attributes.normal;
  6636. if ( normal !== undefined ) {
  6637. const normalMatrix = new Matrix3().getNormalMatrix( matrix );
  6638. normal.applyNormalMatrix( normalMatrix );
  6639. normal.needsUpdate = true;
  6640. }
  6641. const tangent = this.attributes.tangent;
  6642. if ( tangent !== undefined ) {
  6643. tangent.transformDirection( matrix );
  6644. tangent.needsUpdate = true;
  6645. }
  6646. if ( this.boundingBox !== null ) {
  6647. this.computeBoundingBox();
  6648. }
  6649. if ( this.boundingSphere !== null ) {
  6650. this.computeBoundingSphere();
  6651. }
  6652. return this;
  6653. },
  6654. rotateX: function ( angle ) {
  6655. // rotate geometry around world x-axis
  6656. _m1$2.makeRotationX( angle );
  6657. this.applyMatrix4( _m1$2 );
  6658. return this;
  6659. },
  6660. rotateY: function ( angle ) {
  6661. // rotate geometry around world y-axis
  6662. _m1$2.makeRotationY( angle );
  6663. this.applyMatrix4( _m1$2 );
  6664. return this;
  6665. },
  6666. rotateZ: function ( angle ) {
  6667. // rotate geometry around world z-axis
  6668. _m1$2.makeRotationZ( angle );
  6669. this.applyMatrix4( _m1$2 );
  6670. return this;
  6671. },
  6672. translate: function ( x, y, z ) {
  6673. // translate geometry
  6674. _m1$2.makeTranslation( x, y, z );
  6675. this.applyMatrix4( _m1$2 );
  6676. return this;
  6677. },
  6678. scale: function ( x, y, z ) {
  6679. // scale geometry
  6680. _m1$2.makeScale( x, y, z );
  6681. this.applyMatrix4( _m1$2 );
  6682. return this;
  6683. },
  6684. lookAt: function ( vector ) {
  6685. _obj.lookAt( vector );
  6686. _obj.updateMatrix();
  6687. this.applyMatrix4( _obj.matrix );
  6688. return this;
  6689. },
  6690. center: function () {
  6691. this.computeBoundingBox();
  6692. this.boundingBox.getCenter( _offset ).negate();
  6693. this.translate( _offset.x, _offset.y, _offset.z );
  6694. return this;
  6695. },
  6696. setFromObject: function ( object ) {
  6697. // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
  6698. const geometry = object.geometry;
  6699. if ( object.isPoints || object.isLine ) {
  6700. const positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
  6701. const colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
  6702. this.setAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
  6703. this.setAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
  6704. if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
  6705. const lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
  6706. this.setAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
  6707. }
  6708. if ( geometry.boundingSphere !== null ) {
  6709. this.boundingSphere = geometry.boundingSphere.clone();
  6710. }
  6711. if ( geometry.boundingBox !== null ) {
  6712. this.boundingBox = geometry.boundingBox.clone();
  6713. }
  6714. } else if ( object.isMesh ) {
  6715. if ( geometry && geometry.isGeometry ) {
  6716. this.fromGeometry( geometry );
  6717. }
  6718. }
  6719. return this;
  6720. },
  6721. setFromPoints: function ( points ) {
  6722. const position = [];
  6723. for ( let i = 0, l = points.length; i < l; i ++ ) {
  6724. const point = points[ i ];
  6725. position.push( point.x, point.y, point.z || 0 );
  6726. }
  6727. this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
  6728. return this;
  6729. },
  6730. updateFromObject: function ( object ) {
  6731. let geometry = object.geometry;
  6732. if ( object.isMesh ) {
  6733. let direct = geometry.__directGeometry;
  6734. if ( geometry.elementsNeedUpdate === true ) {
  6735. direct = undefined;
  6736. geometry.elementsNeedUpdate = false;
  6737. }
  6738. if ( direct === undefined ) {
  6739. return this.fromGeometry( geometry );
  6740. }
  6741. direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
  6742. direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
  6743. direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
  6744. direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
  6745. direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
  6746. geometry.verticesNeedUpdate = false;
  6747. geometry.normalsNeedUpdate = false;
  6748. geometry.colorsNeedUpdate = false;
  6749. geometry.uvsNeedUpdate = false;
  6750. geometry.groupsNeedUpdate = false;
  6751. geometry = direct;
  6752. }
  6753. if ( geometry.verticesNeedUpdate === true ) {
  6754. const attribute = this.attributes.position;
  6755. if ( attribute !== undefined ) {
  6756. attribute.copyVector3sArray( geometry.vertices );
  6757. attribute.needsUpdate = true;
  6758. }
  6759. geometry.verticesNeedUpdate = false;
  6760. }
  6761. if ( geometry.normalsNeedUpdate === true ) {
  6762. const attribute = this.attributes.normal;
  6763. if ( attribute !== undefined ) {
  6764. attribute.copyVector3sArray( geometry.normals );
  6765. attribute.needsUpdate = true;
  6766. }
  6767. geometry.normalsNeedUpdate = false;
  6768. }
  6769. if ( geometry.colorsNeedUpdate === true ) {
  6770. const attribute = this.attributes.color;
  6771. if ( attribute !== undefined ) {
  6772. attribute.copyColorsArray( geometry.colors );
  6773. attribute.needsUpdate = true;
  6774. }
  6775. geometry.colorsNeedUpdate = false;
  6776. }
  6777. if ( geometry.uvsNeedUpdate ) {
  6778. const attribute = this.attributes.uv;
  6779. if ( attribute !== undefined ) {
  6780. attribute.copyVector2sArray( geometry.uvs );
  6781. attribute.needsUpdate = true;
  6782. }
  6783. geometry.uvsNeedUpdate = false;
  6784. }
  6785. if ( geometry.lineDistancesNeedUpdate ) {
  6786. const attribute = this.attributes.lineDistance;
  6787. if ( attribute !== undefined ) {
  6788. attribute.copyArray( geometry.lineDistances );
  6789. attribute.needsUpdate = true;
  6790. }
  6791. geometry.lineDistancesNeedUpdate = false;
  6792. }
  6793. if ( geometry.groupsNeedUpdate ) {
  6794. geometry.computeGroups( object.geometry );
  6795. this.groups = geometry.groups;
  6796. geometry.groupsNeedUpdate = false;
  6797. }
  6798. return this;
  6799. },
  6800. fromGeometry: function ( geometry ) {
  6801. geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
  6802. return this.fromDirectGeometry( geometry.__directGeometry );
  6803. },
  6804. fromDirectGeometry: function ( geometry ) {
  6805. const positions = new Float32Array( geometry.vertices.length * 3 );
  6806. this.setAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
  6807. if ( geometry.normals.length > 0 ) {
  6808. const normals = new Float32Array( geometry.normals.length * 3 );
  6809. this.setAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
  6810. }
  6811. if ( geometry.colors.length > 0 ) {
  6812. const colors = new Float32Array( geometry.colors.length * 3 );
  6813. this.setAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
  6814. }
  6815. if ( geometry.uvs.length > 0 ) {
  6816. const uvs = new Float32Array( geometry.uvs.length * 2 );
  6817. this.setAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
  6818. }
  6819. if ( geometry.uvs2.length > 0 ) {
  6820. const uvs2 = new Float32Array( geometry.uvs2.length * 2 );
  6821. this.setAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
  6822. }
  6823. // groups
  6824. this.groups = geometry.groups;
  6825. // morphs
  6826. for ( const name in geometry.morphTargets ) {
  6827. const array = [];
  6828. const morphTargets = geometry.morphTargets[ name ];
  6829. for ( let i = 0, l = morphTargets.length; i < l; i ++ ) {
  6830. const morphTarget = morphTargets[ i ];
  6831. const attribute = new Float32BufferAttribute( morphTarget.data.length * 3, 3 );
  6832. attribute.name = morphTarget.name;
  6833. array.push( attribute.copyVector3sArray( morphTarget.data ) );
  6834. }
  6835. this.morphAttributes[ name ] = array;
  6836. }
  6837. // skinning
  6838. if ( geometry.skinIndices.length > 0 ) {
  6839. const skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
  6840. this.setAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
  6841. }
  6842. if ( geometry.skinWeights.length > 0 ) {
  6843. const skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
  6844. this.setAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
  6845. }
  6846. //
  6847. if ( geometry.boundingSphere !== null ) {
  6848. this.boundingSphere = geometry.boundingSphere.clone();
  6849. }
  6850. if ( geometry.boundingBox !== null ) {
  6851. this.boundingBox = geometry.boundingBox.clone();
  6852. }
  6853. return this;
  6854. },
  6855. computeBoundingBox: function () {
  6856. if ( this.boundingBox === null ) {
  6857. this.boundingBox = new Box3();
  6858. }
  6859. const position = this.attributes.position;
  6860. const morphAttributesPosition = this.morphAttributes.position;
  6861. if ( position && position.isGLBufferAttribute ) {
  6862. console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
  6863. this.boundingBox.set(
  6864. new Vector3( - Infinity, - Infinity, - Infinity ),
  6865. new Vector3( + Infinity, + Infinity, + Infinity )
  6866. );
  6867. return;
  6868. }
  6869. if ( position !== undefined ) {
  6870. this.boundingBox.setFromBufferAttribute( position );
  6871. // process morph attributes if present
  6872. if ( morphAttributesPosition ) {
  6873. for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
  6874. const morphAttribute = morphAttributesPosition[ i ];
  6875. _box$2.setFromBufferAttribute( morphAttribute );
  6876. if ( this.morphTargetsRelative ) {
  6877. _vector$4.addVectors( this.boundingBox.min, _box$2.min );
  6878. this.boundingBox.expandByPoint( _vector$4 );
  6879. _vector$4.addVectors( this.boundingBox.max, _box$2.max );
  6880. this.boundingBox.expandByPoint( _vector$4 );
  6881. } else {
  6882. this.boundingBox.expandByPoint( _box$2.min );
  6883. this.boundingBox.expandByPoint( _box$2.max );
  6884. }
  6885. }
  6886. }
  6887. } else {
  6888. this.boundingBox.makeEmpty();
  6889. }
  6890. if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
  6891. console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
  6892. }
  6893. },
  6894. computeBoundingSphere: function () {
  6895. if ( this.boundingSphere === null ) {
  6896. this.boundingSphere = new Sphere();
  6897. }
  6898. const position = this.attributes.position;
  6899. const morphAttributesPosition = this.morphAttributes.position;
  6900. if ( position && position.isGLBufferAttribute ) {
  6901. console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this );
  6902. this.boundingSphere.set( new Vector3(), Infinity );
  6903. return;
  6904. }
  6905. if ( position ) {
  6906. // first, find the center of the bounding sphere
  6907. const center = this.boundingSphere.center;
  6908. _box$2.setFromBufferAttribute( position );
  6909. // process morph attributes if present
  6910. if ( morphAttributesPosition ) {
  6911. for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
  6912. const morphAttribute = morphAttributesPosition[ i ];
  6913. _boxMorphTargets.setFromBufferAttribute( morphAttribute );
  6914. if ( this.morphTargetsRelative ) {
  6915. _vector$4.addVectors( _box$2.min, _boxMorphTargets.min );
  6916. _box$2.expandByPoint( _vector$4 );
  6917. _vector$4.addVectors( _box$2.max, _boxMorphTargets.max );
  6918. _box$2.expandByPoint( _vector$4 );
  6919. } else {
  6920. _box$2.expandByPoint( _boxMorphTargets.min );
  6921. _box$2.expandByPoint( _boxMorphTargets.max );
  6922. }
  6923. }
  6924. }
  6925. _box$2.getCenter( center );
  6926. // second, try to find a boundingSphere with a radius smaller than the
  6927. // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
  6928. let maxRadiusSq = 0;
  6929. for ( let i = 0, il = position.count; i < il; i ++ ) {
  6930. _vector$4.fromBufferAttribute( position, i );
  6931. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
  6932. }
  6933. // process morph attributes if present
  6934. if ( morphAttributesPosition ) {
  6935. for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
  6936. const morphAttribute = morphAttributesPosition[ i ];
  6937. const morphTargetsRelative = this.morphTargetsRelative;
  6938. for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
  6939. _vector$4.fromBufferAttribute( morphAttribute, j );
  6940. if ( morphTargetsRelative ) {
  6941. _offset.fromBufferAttribute( position, j );
  6942. _vector$4.add( _offset );
  6943. }
  6944. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
  6945. }
  6946. }
  6947. }
  6948. this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
  6949. if ( isNaN( this.boundingSphere.radius ) ) {
  6950. console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
  6951. }
  6952. }
  6953. },
  6954. computeFaceNormals: function () {
  6955. // backwards compatibility
  6956. },
  6957. computeVertexNormals: function () {
  6958. const index = this.index;
  6959. const positionAttribute = this.getAttribute( 'position' );
  6960. if ( positionAttribute !== undefined ) {
  6961. let normalAttribute = this.getAttribute( 'normal' );
  6962. if ( normalAttribute === undefined ) {
  6963. normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
  6964. this.setAttribute( 'normal', normalAttribute );
  6965. } else {
  6966. // reset existing normals to zero
  6967. for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
  6968. normalAttribute.setXYZ( i, 0, 0, 0 );
  6969. }
  6970. }
  6971. const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
  6972. const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
  6973. const cb = new Vector3(), ab = new Vector3();
  6974. // indexed elements
  6975. if ( index ) {
  6976. for ( let i = 0, il = index.count; i < il; i += 3 ) {
  6977. const vA = index.getX( i + 0 );
  6978. const vB = index.getX( i + 1 );
  6979. const vC = index.getX( i + 2 );
  6980. pA.fromBufferAttribute( positionAttribute, vA );
  6981. pB.fromBufferAttribute( positionAttribute, vB );
  6982. pC.fromBufferAttribute( positionAttribute, vC );
  6983. cb.subVectors( pC, pB );
  6984. ab.subVectors( pA, pB );
  6985. cb.cross( ab );
  6986. nA.fromBufferAttribute( normalAttribute, vA );
  6987. nB.fromBufferAttribute( normalAttribute, vB );
  6988. nC.fromBufferAttribute( normalAttribute, vC );
  6989. nA.add( cb );
  6990. nB.add( cb );
  6991. nC.add( cb );
  6992. normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
  6993. normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
  6994. normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
  6995. }
  6996. } else {
  6997. // non-indexed elements (unconnected triangle soup)
  6998. for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
  6999. pA.fromBufferAttribute( positionAttribute, i + 0 );
  7000. pB.fromBufferAttribute( positionAttribute, i + 1 );
  7001. pC.fromBufferAttribute( positionAttribute, i + 2 );
  7002. cb.subVectors( pC, pB );
  7003. ab.subVectors( pA, pB );
  7004. cb.cross( ab );
  7005. normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
  7006. normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
  7007. normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
  7008. }
  7009. }
  7010. this.normalizeNormals();
  7011. normalAttribute.needsUpdate = true;
  7012. }
  7013. },
  7014. merge: function ( geometry, offset ) {
  7015. if ( ! ( geometry && geometry.isBufferGeometry ) ) {
  7016. console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
  7017. return;
  7018. }
  7019. if ( offset === undefined ) {
  7020. offset = 0;
  7021. console.warn(
  7022. 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
  7023. + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
  7024. );
  7025. }
  7026. const attributes = this.attributes;
  7027. for ( const key in attributes ) {
  7028. if ( geometry.attributes[ key ] === undefined ) continue;
  7029. const attribute1 = attributes[ key ];
  7030. const attributeArray1 = attribute1.array;
  7031. const attribute2 = geometry.attributes[ key ];
  7032. const attributeArray2 = attribute2.array;
  7033. const attributeOffset = attribute2.itemSize * offset;
  7034. const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset );
  7035. for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) {
  7036. attributeArray1[ j ] = attributeArray2[ i ];
  7037. }
  7038. }
  7039. return this;
  7040. },
  7041. normalizeNormals: function () {
  7042. const normals = this.attributes.normal;
  7043. for ( let i = 0, il = normals.count; i < il; i ++ ) {
  7044. _vector$4.fromBufferAttribute( normals, i );
  7045. _vector$4.normalize();
  7046. normals.setXYZ( i, _vector$4.x, _vector$4.y, _vector$4.z );
  7047. }
  7048. },
  7049. toNonIndexed: function () {
  7050. function convertBufferAttribute( attribute, indices ) {
  7051. const array = attribute.array;
  7052. const itemSize = attribute.itemSize;
  7053. const normalized = attribute.normalized;
  7054. const array2 = new array.constructor( indices.length * itemSize );
  7055. let index = 0, index2 = 0;
  7056. for ( let i = 0, l = indices.length; i < l; i ++ ) {
  7057. index = indices[ i ] * itemSize;
  7058. for ( let j = 0; j < itemSize; j ++ ) {
  7059. array2[ index2 ++ ] = array[ index ++ ];
  7060. }
  7061. }
  7062. return new BufferAttribute( array2, itemSize, normalized );
  7063. }
  7064. //
  7065. if ( this.index === null ) {
  7066. console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
  7067. return this;
  7068. }
  7069. const geometry2 = new BufferGeometry();
  7070. const indices = this.index.array;
  7071. const attributes = this.attributes;
  7072. // attributes
  7073. for ( const name in attributes ) {
  7074. const attribute = attributes[ name ];
  7075. const newAttribute = convertBufferAttribute( attribute, indices );
  7076. geometry2.setAttribute( name, newAttribute );
  7077. }
  7078. // morph attributes
  7079. const morphAttributes = this.morphAttributes;
  7080. for ( const name in morphAttributes ) {
  7081. const morphArray = [];
  7082. const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
  7083. for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
  7084. const attribute = morphAttribute[ i ];
  7085. const newAttribute = convertBufferAttribute( attribute, indices );
  7086. morphArray.push( newAttribute );
  7087. }
  7088. geometry2.morphAttributes[ name ] = morphArray;
  7089. }
  7090. geometry2.morphTargetsRelative = this.morphTargetsRelative;
  7091. // groups
  7092. const groups = this.groups;
  7093. for ( let i = 0, l = groups.length; i < l; i ++ ) {
  7094. const group = groups[ i ];
  7095. geometry2.addGroup( group.start, group.count, group.materialIndex );
  7096. }
  7097. return geometry2;
  7098. },
  7099. toJSON: function () {
  7100. const data = {
  7101. metadata: {
  7102. version: 4.5,
  7103. type: 'BufferGeometry',
  7104. generator: 'BufferGeometry.toJSON'
  7105. }
  7106. };
  7107. // standard BufferGeometry serialization
  7108. data.uuid = this.uuid;
  7109. data.type = this.type;
  7110. if ( this.name !== '' ) data.name = this.name;
  7111. if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
  7112. if ( this.parameters !== undefined ) {
  7113. const parameters = this.parameters;
  7114. for ( const key in parameters ) {
  7115. if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
  7116. }
  7117. return data;
  7118. }
  7119. data.data = { attributes: {} };
  7120. const index = this.index;
  7121. if ( index !== null ) {
  7122. data.data.index = {
  7123. type: index.array.constructor.name,
  7124. array: Array.prototype.slice.call( index.array )
  7125. };
  7126. }
  7127. const attributes = this.attributes;
  7128. for ( const key in attributes ) {
  7129. const attribute = attributes[ key ];
  7130. const attributeData = attribute.toJSON( data.data );
  7131. if ( attribute.name !== '' ) attributeData.name = attribute.name;
  7132. data.data.attributes[ key ] = attributeData;
  7133. }
  7134. const morphAttributes = {};
  7135. let hasMorphAttributes = false;
  7136. for ( const key in this.morphAttributes ) {
  7137. const attributeArray = this.morphAttributes[ key ];
  7138. const array = [];
  7139. for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
  7140. const attribute = attributeArray[ i ];
  7141. const attributeData = attribute.toJSON( data.data );
  7142. if ( attribute.name !== '' ) attributeData.name = attribute.name;
  7143. array.push( attributeData );
  7144. }
  7145. if ( array.length > 0 ) {
  7146. morphAttributes[ key ] = array;
  7147. hasMorphAttributes = true;
  7148. }
  7149. }
  7150. if ( hasMorphAttributes ) {
  7151. data.data.morphAttributes = morphAttributes;
  7152. data.data.morphTargetsRelative = this.morphTargetsRelative;
  7153. }
  7154. const groups = this.groups;
  7155. if ( groups.length > 0 ) {
  7156. data.data.groups = JSON.parse( JSON.stringify( groups ) );
  7157. }
  7158. const boundingSphere = this.boundingSphere;
  7159. if ( boundingSphere !== null ) {
  7160. data.data.boundingSphere = {
  7161. center: boundingSphere.center.toArray(),
  7162. radius: boundingSphere.radius
  7163. };
  7164. }
  7165. return data;
  7166. },
  7167. clone: function () {
  7168. /*
  7169. // Handle primitives
  7170. const parameters = this.parameters;
  7171. if ( parameters !== undefined ) {
  7172. const values = [];
  7173. for ( const key in parameters ) {
  7174. values.push( parameters[ key ] );
  7175. }
  7176. const geometry = Object.create( this.constructor.prototype );
  7177. this.constructor.apply( geometry, values );
  7178. return geometry;
  7179. }
  7180. return new this.constructor().copy( this );
  7181. */
  7182. return new BufferGeometry().copy( this );
  7183. },
  7184. copy: function ( source ) {
  7185. // reset
  7186. this.index = null;
  7187. this.attributes = {};
  7188. this.morphAttributes = {};
  7189. this.groups = [];
  7190. this.boundingBox = null;
  7191. this.boundingSphere = null;
  7192. // used for storing cloned, shared data
  7193. const data = {};
  7194. // name
  7195. this.name = source.name;
  7196. // index
  7197. const index = source.index;
  7198. if ( index !== null ) {
  7199. this.setIndex( index.clone( data ) );
  7200. }
  7201. // attributes
  7202. const attributes = source.attributes;
  7203. for ( const name in attributes ) {
  7204. const attribute = attributes[ name ];
  7205. this.setAttribute( name, attribute.clone( data ) );
  7206. }
  7207. // morph attributes
  7208. const morphAttributes = source.morphAttributes;
  7209. for ( const name in morphAttributes ) {
  7210. const array = [];
  7211. const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
  7212. for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
  7213. array.push( morphAttribute[ i ].clone( data ) );
  7214. }
  7215. this.morphAttributes[ name ] = array;
  7216. }
  7217. this.morphTargetsRelative = source.morphTargetsRelative;
  7218. // groups
  7219. const groups = source.groups;
  7220. for ( let i = 0, l = groups.length; i < l; i ++ ) {
  7221. const group = groups[ i ];
  7222. this.addGroup( group.start, group.count, group.materialIndex );
  7223. }
  7224. // bounding box
  7225. const boundingBox = source.boundingBox;
  7226. if ( boundingBox !== null ) {
  7227. this.boundingBox = boundingBox.clone();
  7228. }
  7229. // bounding sphere
  7230. const boundingSphere = source.boundingSphere;
  7231. if ( boundingSphere !== null ) {
  7232. this.boundingSphere = boundingSphere.clone();
  7233. }
  7234. // draw range
  7235. this.drawRange.start = source.drawRange.start;
  7236. this.drawRange.count = source.drawRange.count;
  7237. // user data
  7238. this.userData = source.userData;
  7239. return this;
  7240. },
  7241. dispose: function () {
  7242. this.dispatchEvent( { type: 'dispose' } );
  7243. }
  7244. } );
  7245. const _inverseMatrix = new Matrix4();
  7246. const _ray = new Ray();
  7247. const _sphere = new Sphere();
  7248. const _vA = new Vector3();
  7249. const _vB = new Vector3();
  7250. const _vC = new Vector3();
  7251. const _tempA = new Vector3();
  7252. const _tempB = new Vector3();
  7253. const _tempC = new Vector3();
  7254. const _morphA = new Vector3();
  7255. const _morphB = new Vector3();
  7256. const _morphC = new Vector3();
  7257. const _uvA = new Vector2$1();
  7258. const _uvB = new Vector2$1();
  7259. const _uvC = new Vector2$1();
  7260. const _intersectionPoint = new Vector3();
  7261. const _intersectionPointWorld = new Vector3();
  7262. function Mesh( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
  7263. Object3D.call( this );
  7264. this.type = 'Mesh';
  7265. this.geometry = geometry;
  7266. this.material = material;
  7267. this.updateMorphTargets();
  7268. }
  7269. Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
  7270. constructor: Mesh,
  7271. isMesh: true,
  7272. copy: function ( source ) {
  7273. Object3D.prototype.copy.call( this, source );
  7274. if ( source.morphTargetInfluences !== undefined ) {
  7275. this.morphTargetInfluences = source.morphTargetInfluences.slice();
  7276. }
  7277. if ( source.morphTargetDictionary !== undefined ) {
  7278. this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
  7279. }
  7280. this.material = source.material;
  7281. this.geometry = source.geometry;
  7282. return this;
  7283. },
  7284. updateMorphTargets: function () {
  7285. const geometry = this.geometry;
  7286. if ( geometry.isBufferGeometry ) {
  7287. const morphAttributes = geometry.morphAttributes;
  7288. const keys = Object.keys( morphAttributes );
  7289. if ( keys.length > 0 ) {
  7290. const morphAttribute = morphAttributes[ keys[ 0 ] ];
  7291. if ( morphAttribute !== undefined ) {
  7292. this.morphTargetInfluences = [];
  7293. this.morphTargetDictionary = {};
  7294. for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
  7295. const name = morphAttribute[ m ].name || String( m );
  7296. this.morphTargetInfluences.push( 0 );
  7297. this.morphTargetDictionary[ name ] = m;
  7298. }
  7299. }
  7300. }
  7301. } else {
  7302. const morphTargets = geometry.morphTargets;
  7303. if ( morphTargets !== undefined && morphTargets.length > 0 ) {
  7304. console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
  7305. }
  7306. }
  7307. },
  7308. raycast: function ( raycaster, intersects ) {
  7309. const geometry = this.geometry;
  7310. const material = this.material;
  7311. const matrixWorld = this.matrixWorld;
  7312. if ( material === undefined ) return;
  7313. // Checking boundingSphere distance to ray
  7314. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  7315. _sphere.copy( geometry.boundingSphere );
  7316. _sphere.applyMatrix4( matrixWorld );
  7317. if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
  7318. //
  7319. _inverseMatrix.copy( matrixWorld ).invert();
  7320. _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
  7321. // Check boundingBox before continuing
  7322. if ( geometry.boundingBox !== null ) {
  7323. if ( _ray.intersectsBox( geometry.boundingBox ) === false ) return;
  7324. }
  7325. let intersection;
  7326. if ( geometry.isBufferGeometry ) {
  7327. const index = geometry.index;
  7328. const position = geometry.attributes.position;
  7329. const morphPosition = geometry.morphAttributes.position;
  7330. const morphTargetsRelative = geometry.morphTargetsRelative;
  7331. const uv = geometry.attributes.uv;
  7332. const uv2 = geometry.attributes.uv2;
  7333. const groups = geometry.groups;
  7334. const drawRange = geometry.drawRange;
  7335. if ( index !== null ) {
  7336. // indexed buffer geometry
  7337. if ( Array.isArray( material ) ) {
  7338. for ( let i = 0, il = groups.length; i < il; i ++ ) {
  7339. const group = groups[ i ];
  7340. const groupMaterial = material[ group.materialIndex ];
  7341. const start = Math.max( group.start, drawRange.start );
  7342. const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
  7343. for ( let j = start, jl = end; j < jl; j += 3 ) {
  7344. const a = index.getX( j );
  7345. const b = index.getX( j + 1 );
  7346. const c = index.getX( j + 2 );
  7347. intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
  7348. if ( intersection ) {
  7349. intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
  7350. intersection.face.materialIndex = group.materialIndex;
  7351. intersects.push( intersection );
  7352. }
  7353. }
  7354. }
  7355. } else {
  7356. const start = Math.max( 0, drawRange.start );
  7357. const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
  7358. for ( let i = start, il = end; i < il; i += 3 ) {
  7359. const a = index.getX( i );
  7360. const b = index.getX( i + 1 );
  7361. const c = index.getX( i + 2 );
  7362. intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
  7363. if ( intersection ) {
  7364. intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
  7365. intersects.push( intersection );
  7366. }
  7367. }
  7368. }
  7369. } else if ( position !== undefined ) {
  7370. // non-indexed buffer geometry
  7371. if ( Array.isArray( material ) ) {
  7372. for ( let i = 0, il = groups.length; i < il; i ++ ) {
  7373. const group = groups[ i ];
  7374. const groupMaterial = material[ group.materialIndex ];
  7375. const start = Math.max( group.start, drawRange.start );
  7376. const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
  7377. for ( let j = start, jl = end; j < jl; j += 3 ) {
  7378. const a = j;
  7379. const b = j + 1;
  7380. const c = j + 2;
  7381. intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
  7382. if ( intersection ) {
  7383. intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
  7384. intersection.face.materialIndex = group.materialIndex;
  7385. intersects.push( intersection );
  7386. }
  7387. }
  7388. }
  7389. } else {
  7390. const start = Math.max( 0, drawRange.start );
  7391. const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
  7392. for ( let i = start, il = end; i < il; i += 3 ) {
  7393. const a = i;
  7394. const b = i + 1;
  7395. const c = i + 2;
  7396. intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
  7397. if ( intersection ) {
  7398. intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
  7399. intersects.push( intersection );
  7400. }
  7401. }
  7402. }
  7403. }
  7404. } else if ( geometry.isGeometry ) {
  7405. const isMultiMaterial = Array.isArray( material );
  7406. const vertices = geometry.vertices;
  7407. const faces = geometry.faces;
  7408. let uvs;
  7409. const faceVertexUvs = geometry.faceVertexUvs[ 0 ];
  7410. if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;
  7411. for ( let f = 0, fl = faces.length; f < fl; f ++ ) {
  7412. const face = faces[ f ];
  7413. const faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;
  7414. if ( faceMaterial === undefined ) continue;
  7415. const fvA = vertices[ face.a ];
  7416. const fvB = vertices[ face.b ];
  7417. const fvC = vertices[ face.c ];
  7418. intersection = checkIntersection( this, faceMaterial, raycaster, _ray, fvA, fvB, fvC, _intersectionPoint );
  7419. if ( intersection ) {
  7420. if ( uvs && uvs[ f ] ) {
  7421. const uvs_f = uvs[ f ];
  7422. _uvA.copy( uvs_f[ 0 ] );
  7423. _uvB.copy( uvs_f[ 1 ] );
  7424. _uvC.copy( uvs_f[ 2 ] );
  7425. intersection.uv = Triangle.getUV( _intersectionPoint, fvA, fvB, fvC, _uvA, _uvB, _uvC, new Vector2$1() );
  7426. }
  7427. intersection.face = face;
  7428. intersection.faceIndex = f;
  7429. intersects.push( intersection );
  7430. }
  7431. }
  7432. }
  7433. }
  7434. } );
  7435. function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
  7436. let intersect;
  7437. if ( material.side === BackSide ) {
  7438. intersect = ray.intersectTriangle( pC, pB, pA, true, point );
  7439. } else {
  7440. intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
  7441. }
  7442. if ( intersect === null ) return null;
  7443. _intersectionPointWorld.copy( point );
  7444. _intersectionPointWorld.applyMatrix4( object.matrixWorld );
  7445. const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
  7446. if ( distance < raycaster.near || distance > raycaster.far ) return null;
  7447. return {
  7448. distance: distance,
  7449. point: _intersectionPointWorld.clone(),
  7450. object: object
  7451. };
  7452. }
  7453. function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
  7454. _vA.fromBufferAttribute( position, a );
  7455. _vB.fromBufferAttribute( position, b );
  7456. _vC.fromBufferAttribute( position, c );
  7457. const morphInfluences = object.morphTargetInfluences;
  7458. if ( material.morphTargets && morphPosition && morphInfluences ) {
  7459. _morphA.set( 0, 0, 0 );
  7460. _morphB.set( 0, 0, 0 );
  7461. _morphC.set( 0, 0, 0 );
  7462. for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
  7463. const influence = morphInfluences[ i ];
  7464. const morphAttribute = morphPosition[ i ];
  7465. if ( influence === 0 ) continue;
  7466. _tempA.fromBufferAttribute( morphAttribute, a );
  7467. _tempB.fromBufferAttribute( morphAttribute, b );
  7468. _tempC.fromBufferAttribute( morphAttribute, c );
  7469. if ( morphTargetsRelative ) {
  7470. _morphA.addScaledVector( _tempA, influence );
  7471. _morphB.addScaledVector( _tempB, influence );
  7472. _morphC.addScaledVector( _tempC, influence );
  7473. } else {
  7474. _morphA.addScaledVector( _tempA.sub( _vA ), influence );
  7475. _morphB.addScaledVector( _tempB.sub( _vB ), influence );
  7476. _morphC.addScaledVector( _tempC.sub( _vC ), influence );
  7477. }
  7478. }
  7479. _vA.add( _morphA );
  7480. _vB.add( _morphB );
  7481. _vC.add( _morphC );
  7482. }
  7483. if ( object.isSkinnedMesh ) {
  7484. object.boneTransform( a, _vA );
  7485. object.boneTransform( b, _vB );
  7486. object.boneTransform( c, _vC );
  7487. }
  7488. const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );
  7489. if ( intersection ) {
  7490. if ( uv ) {
  7491. _uvA.fromBufferAttribute( uv, a );
  7492. _uvB.fromBufferAttribute( uv, b );
  7493. _uvC.fromBufferAttribute( uv, c );
  7494. intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2$1() );
  7495. }
  7496. if ( uv2 ) {
  7497. _uvA.fromBufferAttribute( uv2, a );
  7498. _uvB.fromBufferAttribute( uv2, b );
  7499. _uvC.fromBufferAttribute( uv2, c );
  7500. intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2$1() );
  7501. }
  7502. const face = new Face3( a, b, c );
  7503. Triangle.getNormal( _vA, _vB, _vC, face.normal );
  7504. intersection.face = face;
  7505. }
  7506. return intersection;
  7507. }
  7508. class BoxBufferGeometry extends BufferGeometry {
  7509. constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
  7510. super();
  7511. this.type = 'BoxBufferGeometry';
  7512. this.parameters = {
  7513. width: width,
  7514. height: height,
  7515. depth: depth,
  7516. widthSegments: widthSegments,
  7517. heightSegments: heightSegments,
  7518. depthSegments: depthSegments
  7519. };
  7520. const scope = this;
  7521. // segments
  7522. widthSegments = Math.floor( widthSegments );
  7523. heightSegments = Math.floor( heightSegments );
  7524. depthSegments = Math.floor( depthSegments );
  7525. // buffers
  7526. const indices = [];
  7527. const vertices = [];
  7528. const normals = [];
  7529. const uvs = [];
  7530. // helper variables
  7531. let numberOfVertices = 0;
  7532. let groupStart = 0;
  7533. // build each side of the box geometry
  7534. buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
  7535. buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
  7536. buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
  7537. buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
  7538. buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
  7539. buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
  7540. // build geometry
  7541. this.setIndex( indices );
  7542. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  7543. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  7544. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  7545. function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
  7546. const segmentWidth = width / gridX;
  7547. const segmentHeight = height / gridY;
  7548. const widthHalf = width / 2;
  7549. const heightHalf = height / 2;
  7550. const depthHalf = depth / 2;
  7551. const gridX1 = gridX + 1;
  7552. const gridY1 = gridY + 1;
  7553. let vertexCounter = 0;
  7554. let groupCount = 0;
  7555. const vector = new Vector3();
  7556. // generate vertices, normals and uvs
  7557. for ( let iy = 0; iy < gridY1; iy ++ ) {
  7558. const y = iy * segmentHeight - heightHalf;
  7559. for ( let ix = 0; ix < gridX1; ix ++ ) {
  7560. const x = ix * segmentWidth - widthHalf;
  7561. // set values to correct vector component
  7562. vector[ u ] = x * udir;
  7563. vector[ v ] = y * vdir;
  7564. vector[ w ] = depthHalf;
  7565. // now apply vector to vertex buffer
  7566. vertices.push( vector.x, vector.y, vector.z );
  7567. // set values to correct vector component
  7568. vector[ u ] = 0;
  7569. vector[ v ] = 0;
  7570. vector[ w ] = depth > 0 ? 1 : - 1;
  7571. // now apply vector to normal buffer
  7572. normals.push( vector.x, vector.y, vector.z );
  7573. // uvs
  7574. uvs.push( ix / gridX );
  7575. uvs.push( 1 - ( iy / gridY ) );
  7576. // counters
  7577. vertexCounter += 1;
  7578. }
  7579. }
  7580. // indices
  7581. // 1. you need three indices to draw a single face
  7582. // 2. a single segment consists of two faces
  7583. // 3. so we need to generate six (2*3) indices per segment
  7584. for ( let iy = 0; iy < gridY; iy ++ ) {
  7585. for ( let ix = 0; ix < gridX; ix ++ ) {
  7586. const a = numberOfVertices + ix + gridX1 * iy;
  7587. const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
  7588. const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
  7589. const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
  7590. // faces
  7591. indices.push( a, b, d );
  7592. indices.push( b, c, d );
  7593. // increase counter
  7594. groupCount += 6;
  7595. }
  7596. }
  7597. // add a group to the geometry. this will ensure multi material support
  7598. scope.addGroup( groupStart, groupCount, materialIndex );
  7599. // calculate new start value for groups
  7600. groupStart += groupCount;
  7601. // update total number of vertices
  7602. numberOfVertices += vertexCounter;
  7603. }
  7604. }
  7605. }
  7606. /**
  7607. * Uniform Utilities
  7608. */
  7609. function cloneUniforms( src ) {
  7610. const dst = {};
  7611. for ( const u in src ) {
  7612. dst[ u ] = {};
  7613. for ( const p in src[ u ] ) {
  7614. const property = src[ u ][ p ];
  7615. if ( property && ( property.isColor ||
  7616. property.isMatrix3 || property.isMatrix4 ||
  7617. property.isVector2 || property.isVector3 || property.isVector4 ||
  7618. property.isTexture ) ) {
  7619. dst[ u ][ p ] = property.clone();
  7620. } else if ( Array.isArray( property ) ) {
  7621. dst[ u ][ p ] = property.slice();
  7622. } else {
  7623. dst[ u ][ p ] = property;
  7624. }
  7625. }
  7626. }
  7627. return dst;
  7628. }
  7629. function mergeUniforms( uniforms ) {
  7630. const merged = {};
  7631. for ( let u = 0; u < uniforms.length; u ++ ) {
  7632. const tmp = cloneUniforms( uniforms[ u ] );
  7633. for ( const p in tmp ) {
  7634. merged[ p ] = tmp[ p ];
  7635. }
  7636. }
  7637. return merged;
  7638. }
  7639. // Legacy
  7640. const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
  7641. var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
  7642. var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
  7643. /**
  7644. * parameters = {
  7645. * defines: { "label" : "value" },
  7646. * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
  7647. *
  7648. * fragmentShader: <string>,
  7649. * vertexShader: <string>,
  7650. *
  7651. * wireframe: <boolean>,
  7652. * wireframelineWidth: <float>,
  7653. *
  7654. * lights: <bool>,
  7655. *
  7656. * skinning: <bool>,
  7657. * morphTargets: <bool>,
  7658. * morphNormals: <bool>
  7659. * }
  7660. */
  7661. function ShaderMaterial( parameters ) {
  7662. Material.call( this );
  7663. this.type = 'ShaderMaterial';
  7664. this.defines = {};
  7665. this.uniforms = {};
  7666. this.vertexShader = default_vertex;
  7667. this.fragmentShader = default_fragment;
  7668. this.lineWidth = 1;
  7669. this.wireframe = false;
  7670. this.wireframelineWidth = 1;
  7671. this.fog = false; // set to use scene fog
  7672. this.lights = false; // set to use scene lights
  7673. this.clipping = false; // set to use user-defined clipping planes
  7674. this.skinning = false; // set to use skinning attribute streams
  7675. this.morphTargets = false; // set to use morph targets
  7676. this.morphNormals = false; // set to use morph normals
  7677. this.extensions = {
  7678. derivatives: false, // set to use derivatives
  7679. fragDepth: false, // set to use fragment depth values
  7680. drawBuffers: false, // set to use draw buffers
  7681. shaderTextureLOD: false // set to use shader texture LOD
  7682. };
  7683. // When rendered geometry doesn't include these attributes but the material does,
  7684. // use these default values in WebGL. This avoids errors when buffer data is missing.
  7685. this.defaultAttributeValues = {
  7686. 'color': [ 1, 1, 1 ],
  7687. 'uv': [ 0, 0 ],
  7688. 'uv2': [ 0, 0 ]
  7689. };
  7690. this.index0AttributeName = undefined;
  7691. this.uniformsNeedUpdate = false;
  7692. this.glslVersion = null;
  7693. if ( parameters !== undefined ) {
  7694. if ( parameters.attributes !== undefined ) {
  7695. console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
  7696. }
  7697. this.setValues( parameters );
  7698. }
  7699. }
  7700. ShaderMaterial.prototype = Object.create( Material.prototype );
  7701. ShaderMaterial.prototype.constructor = ShaderMaterial;
  7702. ShaderMaterial.prototype.isShaderMaterial = true;
  7703. ShaderMaterial.prototype.copy = function ( source ) {
  7704. Material.prototype.copy.call( this, source );
  7705. this.fragmentShader = source.fragmentShader;
  7706. this.vertexShader = source.vertexShader;
  7707. this.uniforms = cloneUniforms( source.uniforms );
  7708. this.defines = Object.assign( {}, source.defines );
  7709. this.wireframe = source.wireframe;
  7710. this.wireframelineWidth = source.wireframelineWidth;
  7711. this.lights = source.lights;
  7712. this.clipping = source.clipping;
  7713. this.skinning = source.skinning;
  7714. this.morphTargets = source.morphTargets;
  7715. this.morphNormals = source.morphNormals;
  7716. this.extensions = Object.assign( {}, source.extensions );
  7717. this.glslVersion = source.glslVersion;
  7718. return this;
  7719. };
  7720. ShaderMaterial.prototype.toJSON = function ( meta ) {
  7721. const data = Material.prototype.toJSON.call( this, meta );
  7722. data.glslVersion = this.glslVersion;
  7723. data.uniforms = {};
  7724. for ( const name in this.uniforms ) {
  7725. const uniform = this.uniforms[ name ];
  7726. const value = uniform.value;
  7727. if ( value && value.isTexture ) {
  7728. data.uniforms[ name ] = {
  7729. type: 't',
  7730. value: value.toJSON( meta ).uuid
  7731. };
  7732. } else if ( value && value.isColor ) {
  7733. data.uniforms[ name ] = {
  7734. type: 'c',
  7735. value: value.getHex()
  7736. };
  7737. } else if ( value && value.isVector2 ) {
  7738. data.uniforms[ name ] = {
  7739. type: 'v2',
  7740. value: value.toArray()
  7741. };
  7742. } else if ( value && value.isVector3 ) {
  7743. data.uniforms[ name ] = {
  7744. type: 'v3',
  7745. value: value.toArray()
  7746. };
  7747. } else if ( value && value.isVector4 ) {
  7748. data.uniforms[ name ] = {
  7749. type: 'v4',
  7750. value: value.toArray()
  7751. };
  7752. } else if ( value && value.isMatrix3 ) {
  7753. data.uniforms[ name ] = {
  7754. type: 'm3',
  7755. value: value.toArray()
  7756. };
  7757. } else if ( value && value.isMatrix4 ) {
  7758. data.uniforms[ name ] = {
  7759. type: 'm4',
  7760. value: value.toArray()
  7761. };
  7762. } else {
  7763. data.uniforms[ name ] = {
  7764. value: value
  7765. };
  7766. // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
  7767. }
  7768. }
  7769. if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
  7770. data.vertexShader = this.vertexShader;
  7771. data.fragmentShader = this.fragmentShader;
  7772. const extensions = {};
  7773. for ( const key in this.extensions ) {
  7774. if ( this.extensions[ key ] === true ) extensions[ key ] = true;
  7775. }
  7776. if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
  7777. return data;
  7778. };
  7779. function Camera() {
  7780. Object3D.call( this );
  7781. this.type = 'Camera';
  7782. this.matrixWorldInverse = new Matrix4();
  7783. this.projectionMatrix = new Matrix4();
  7784. this.projectionMatrixInverse = new Matrix4();
  7785. }
  7786. Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {
  7787. constructor: Camera,
  7788. isCamera: true,
  7789. copy: function ( source, recursive ) {
  7790. Object3D.prototype.copy.call( this, source, recursive );
  7791. this.matrixWorldInverse.copy( source.matrixWorldInverse );
  7792. this.projectionMatrix.copy( source.projectionMatrix );
  7793. this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
  7794. return this;
  7795. },
  7796. getWorldDirection: function ( target ) {
  7797. if ( target === undefined ) {
  7798. console.warn( 'THREE.Camera: .getWorldDirection() target is now required' );
  7799. target = new Vector3();
  7800. }
  7801. this.updateWorldMatrix( true, false );
  7802. const e = this.matrixWorld.elements;
  7803. return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize();
  7804. },
  7805. updateMatrixWorld: function ( force ) {
  7806. Object3D.prototype.updateMatrixWorld.call( this, force );
  7807. this.matrixWorldInverse.copy( this.matrixWorld ).invert();
  7808. },
  7809. updateWorldMatrix: function ( updateParents, updateChildren ) {
  7810. Object3D.prototype.updateWorldMatrix.call( this, updateParents, updateChildren );
  7811. this.matrixWorldInverse.copy( this.matrixWorld ).invert();
  7812. },
  7813. clone: function () {
  7814. return new this.constructor().copy( this );
  7815. }
  7816. } );
  7817. function PerspectiveCamera( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
  7818. Camera.call( this );
  7819. this.type = 'PerspectiveCamera';
  7820. this.fov = fov;
  7821. this.zoom = 1;
  7822. this.near = near;
  7823. this.far = far;
  7824. this.focus = 10;
  7825. this.aspect = aspect;
  7826. this.view = null;
  7827. this.filmGauge = 35; // width of the film (default in millimeters)
  7828. this.filmOffset = 0; // horizontal film offset (same unit as gauge)
  7829. this.updateProjectionMatrix();
  7830. }
  7831. PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
  7832. constructor: PerspectiveCamera,
  7833. isPerspectiveCamera: true,
  7834. copy: function ( source, recursive ) {
  7835. Camera.prototype.copy.call( this, source, recursive );
  7836. this.fov = source.fov;
  7837. this.zoom = source.zoom;
  7838. this.near = source.near;
  7839. this.far = source.far;
  7840. this.focus = source.focus;
  7841. this.aspect = source.aspect;
  7842. this.view = source.view === null ? null : Object.assign( {}, source.view );
  7843. this.filmGauge = source.filmGauge;
  7844. this.filmOffset = source.filmOffset;
  7845. return this;
  7846. },
  7847. /**
  7848. * Sets the FOV by focal length in respect to the current .filmGauge.
  7849. *
  7850. * The default film gauge is 35, so that the focal length can be specified for
  7851. * a 35mm (full frame) camera.
  7852. *
  7853. * Values for focal length and film gauge must have the same unit.
  7854. */
  7855. setFocalLength: function ( focalLength ) {
  7856. // see http://www.bobatkins.com/photography/technical/field_of_view.html
  7857. const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
  7858. this.fov = MathUtils.RAD2DEG * 2 * Math.atan( vExtentSlope );
  7859. this.updateProjectionMatrix();
  7860. },
  7861. /**
  7862. * Calculates the focal length from the current .fov and .filmGauge.
  7863. */
  7864. getFocalLength: function () {
  7865. const vExtentSlope = Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov );
  7866. return 0.5 * this.getFilmHeight() / vExtentSlope;
  7867. },
  7868. getEffectiveFOV: function () {
  7869. return MathUtils.RAD2DEG * 2 * Math.atan(
  7870. Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom );
  7871. },
  7872. getFilmWidth: function () {
  7873. // film not completely covered in portrait format (aspect < 1)
  7874. return this.filmGauge * Math.min( this.aspect, 1 );
  7875. },
  7876. getFilmHeight: function () {
  7877. // film not completely covered in landscape format (aspect > 1)
  7878. return this.filmGauge / Math.max( this.aspect, 1 );
  7879. },
  7880. /**
  7881. * Sets an offset in a larger frustum. This is useful for multi-window or
  7882. * multi-monitor/multi-machine setups.
  7883. *
  7884. * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
  7885. * the monitors are in grid like this
  7886. *
  7887. * +---+---+---+
  7888. * | A | B | C |
  7889. * +---+---+---+
  7890. * | D | E | F |
  7891. * +---+---+---+
  7892. *
  7893. * then for each monitor you would call it like this
  7894. *
  7895. * const w = 1920;
  7896. * const h = 1080;
  7897. * const fullWidth = w * 3;
  7898. * const fullHeight = h * 2;
  7899. *
  7900. * --A--
  7901. * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
  7902. * --B--
  7903. * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
  7904. * --C--
  7905. * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
  7906. * --D--
  7907. * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
  7908. * --E--
  7909. * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
  7910. * --F--
  7911. * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
  7912. *
  7913. * Note there is no reason monitors have to be the same size or in a grid.
  7914. */
  7915. setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
  7916. this.aspect = fullWidth / fullHeight;
  7917. if ( this.view === null ) {
  7918. this.view = {
  7919. enabled: true,
  7920. fullWidth: 1,
  7921. fullHeight: 1,
  7922. offsetX: 0,
  7923. offsetY: 0,
  7924. width: 1,
  7925. height: 1
  7926. };
  7927. }
  7928. this.view.enabled = true;
  7929. this.view.fullWidth = fullWidth;
  7930. this.view.fullHeight = fullHeight;
  7931. this.view.offsetX = x;
  7932. this.view.offsetY = y;
  7933. this.view.width = width;
  7934. this.view.height = height;
  7935. this.updateProjectionMatrix();
  7936. },
  7937. clearViewOffset: function () {
  7938. if ( this.view !== null ) {
  7939. this.view.enabled = false;
  7940. }
  7941. this.updateProjectionMatrix();
  7942. },
  7943. updateProjectionMatrix: function () {
  7944. const near = this.near;
  7945. let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom;
  7946. let height = 2 * top;
  7947. let width = this.aspect * height;
  7948. let left = - 0.5 * width;
  7949. const view = this.view;
  7950. if ( this.view !== null && this.view.enabled ) {
  7951. const fullWidth = view.fullWidth,
  7952. fullHeight = view.fullHeight;
  7953. left += view.offsetX * width / fullWidth;
  7954. top -= view.offsetY * height / fullHeight;
  7955. width *= view.width / fullWidth;
  7956. height *= view.height / fullHeight;
  7957. }
  7958. const skew = this.filmOffset;
  7959. if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
  7960. this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
  7961. this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
  7962. },
  7963. toJSON: function ( meta ) {
  7964. const data = Object3D.prototype.toJSON.call( this, meta );
  7965. data.object.fov = this.fov;
  7966. data.object.zoom = this.zoom;
  7967. data.object.near = this.near;
  7968. data.object.far = this.far;
  7969. data.object.focus = this.focus;
  7970. data.object.aspect = this.aspect;
  7971. if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
  7972. data.object.filmGauge = this.filmGauge;
  7973. data.object.filmOffset = this.filmOffset;
  7974. return data;
  7975. }
  7976. } );
  7977. const fov = 90, aspect = 1;
  7978. function CubeCamera( near, far, renderTarget ) {
  7979. Object3D.call( this );
  7980. this.type = 'CubeCamera';
  7981. if ( renderTarget.isWebGLCubeRenderTarget !== true ) {
  7982. console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' );
  7983. return;
  7984. }
  7985. this.renderTarget = renderTarget;
  7986. const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
  7987. cameraPX.layers = this.layers;
  7988. cameraPX.up.set( 0, - 1, 0 );
  7989. cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
  7990. this.add( cameraPX );
  7991. const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
  7992. cameraNX.layers = this.layers;
  7993. cameraNX.up.set( 0, - 1, 0 );
  7994. cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
  7995. this.add( cameraNX );
  7996. const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
  7997. cameraPY.layers = this.layers;
  7998. cameraPY.up.set( 0, 0, 1 );
  7999. cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
  8000. this.add( cameraPY );
  8001. const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
  8002. cameraNY.layers = this.layers;
  8003. cameraNY.up.set( 0, 0, - 1 );
  8004. cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
  8005. this.add( cameraNY );
  8006. const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
  8007. cameraPZ.layers = this.layers;
  8008. cameraPZ.up.set( 0, - 1, 0 );
  8009. cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
  8010. this.add( cameraPZ );
  8011. const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
  8012. cameraNZ.layers = this.layers;
  8013. cameraNZ.up.set( 0, - 1, 0 );
  8014. cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
  8015. this.add( cameraNZ );
  8016. this.update = function ( renderer, scene ) {
  8017. if ( this.parent === null ) this.updateMatrixWorld();
  8018. const currentXrEnabled = renderer.xr.enabled;
  8019. const currentRenderTarget = renderer.getRenderTarget();
  8020. renderer.xr.enabled = false;
  8021. const generateMipmaps = renderTarget.texture.generateMipmaps;
  8022. renderTarget.texture.generateMipmaps = false;
  8023. renderer.setRenderTarget( renderTarget, 0 );
  8024. renderer.render( scene, cameraPX );
  8025. renderer.setRenderTarget( renderTarget, 1 );
  8026. renderer.render( scene, cameraNX );
  8027. renderer.setRenderTarget( renderTarget, 2 );
  8028. renderer.render( scene, cameraPY );
  8029. renderer.setRenderTarget( renderTarget, 3 );
  8030. renderer.render( scene, cameraNY );
  8031. renderer.setRenderTarget( renderTarget, 4 );
  8032. renderer.render( scene, cameraPZ );
  8033. renderTarget.texture.generateMipmaps = generateMipmaps;
  8034. renderer.setRenderTarget( renderTarget, 5 );
  8035. renderer.render( scene, cameraNZ );
  8036. renderer.setRenderTarget( currentRenderTarget );
  8037. renderer.xr.enabled = currentXrEnabled;
  8038. };
  8039. }
  8040. CubeCamera.prototype = Object.create( Object3D.prototype );
  8041. CubeCamera.prototype.constructor = CubeCamera;
  8042. function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
  8043. images = images !== undefined ? images : [];
  8044. mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
  8045. format = format !== undefined ? format : RGBFormat;
  8046. Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
  8047. this.flipY = false;
  8048. // Why CubeTexture._needsFlipEnvMap is necessary:
  8049. //
  8050. // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
  8051. // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
  8052. // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
  8053. // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
  8054. // and the flag _needsFlipEnvMap controls this conversion. The flip is not required (and thus _needsFlipEnvMap is set to false)
  8055. // when using WebGLCubeRenderTarget.texture as a cube texture.
  8056. this._needsFlipEnvMap = true;
  8057. }
  8058. CubeTexture.prototype = Object.create( Texture.prototype );
  8059. CubeTexture.prototype.constructor = CubeTexture;
  8060. CubeTexture.prototype.isCubeTexture = true;
  8061. Object.defineProperty( CubeTexture.prototype, 'images', {
  8062. get: function () {
  8063. return this.image;
  8064. },
  8065. set: function ( value ) {
  8066. this.image = value;
  8067. }
  8068. } );
  8069. function WebGLCubeRenderTarget( size, options, dummy ) {
  8070. if ( Number.isInteger( options ) ) {
  8071. console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' );
  8072. options = dummy;
  8073. }
  8074. WebGLRenderTarget.call( this, size, size, options );
  8075. options = options || {};
  8076. this.texture = new CubeTexture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
  8077. this.texture._needsFlipEnvMap = false;
  8078. }
  8079. WebGLCubeRenderTarget.prototype = Object.create( WebGLRenderTarget.prototype );
  8080. WebGLCubeRenderTarget.prototype.constructor = WebGLCubeRenderTarget;
  8081. WebGLCubeRenderTarget.prototype.isWebGLCubeRenderTarget = true;
  8082. WebGLCubeRenderTarget.prototype.fromEquirectangularTexture = function ( renderer, texture ) {
  8083. this.texture.type = texture.type;
  8084. this.texture.format = RGBAFormat; // see #18859
  8085. this.texture.encoding = texture.encoding;
  8086. this.texture.generateMipmaps = texture.generateMipmaps;
  8087. this.texture.minFilter = texture.minFilter;
  8088. this.texture.magFilter = texture.magFilter;
  8089. const shader = {
  8090. uniforms: {
  8091. tEquirect: { value: null },
  8092. },
  8093. vertexShader: /* glsl */`
  8094. varying vec3 vWorldDirection;
  8095. vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
  8096. return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
  8097. }
  8098. void main() {
  8099. vWorldDirection = transformDirection( position, modelMatrix );
  8100. #include <begin_vertex>
  8101. #include <project_vertex>
  8102. }
  8103. `,
  8104. fragmentShader: /* glsl */`
  8105. uniform sampler2D tEquirect;
  8106. varying vec3 vWorldDirection;
  8107. #include <common>
  8108. void main() {
  8109. vec3 direction = normalize( vWorldDirection );
  8110. vec2 sampleUV = equirectUv( direction );
  8111. gl_FragColor = texture2D( tEquirect, sampleUV );
  8112. }
  8113. `
  8114. };
  8115. const geometry = new BoxBufferGeometry( 5, 5, 5 );
  8116. const material = new ShaderMaterial( {
  8117. name: 'CubemapFromEquirect',
  8118. uniforms: cloneUniforms( shader.uniforms ),
  8119. vertexShader: shader.vertexShader,
  8120. fragmentShader: shader.fragmentShader,
  8121. side: BackSide,
  8122. blending: NoBlending
  8123. } );
  8124. material.uniforms.tEquirect.value = texture;
  8125. const mesh = new Mesh( geometry, material );
  8126. const currentMinFilter = texture.minFilter;
  8127. // Avoid blurred poles
  8128. if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
  8129. const camera = new CubeCamera( 1, 10, this );
  8130. camera.update( renderer, mesh );
  8131. texture.minFilter = currentMinFilter;
  8132. mesh.geometry.dispose();
  8133. mesh.material.dispose();
  8134. return this;
  8135. };
  8136. WebGLCubeRenderTarget.prototype.clear = function ( renderer, color, depth, stencil ) {
  8137. const currentRenderTarget = renderer.getRenderTarget();
  8138. for ( let i = 0; i < 6; i ++ ) {
  8139. renderer.setRenderTarget( this, i );
  8140. renderer.clear( color, depth, stencil );
  8141. }
  8142. renderer.setRenderTarget( currentRenderTarget );
  8143. };
  8144. function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
  8145. Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
  8146. this.image = { data: data || null, width: width || 1, height: height || 1 };
  8147. this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
  8148. this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
  8149. this.generateMipmaps = false;
  8150. this.flipY = false;
  8151. this.unpackAlignment = 1;
  8152. this.needsUpdate = true;
  8153. }
  8154. DataTexture.prototype = Object.create( Texture.prototype );
  8155. DataTexture.prototype.constructor = DataTexture;
  8156. DataTexture.prototype.isDataTexture = true;
  8157. const _sphere$1 = /*@__PURE__*/ new Sphere();
  8158. const _vector$5 = /*@__PURE__*/ new Vector3();
  8159. class Frustum {
  8160. constructor( p0, p1, p2, p3, p4, p5 ) {
  8161. this.planes = [
  8162. ( p0 !== undefined ) ? p0 : new Plane(),
  8163. ( p1 !== undefined ) ? p1 : new Plane(),
  8164. ( p2 !== undefined ) ? p2 : new Plane(),
  8165. ( p3 !== undefined ) ? p3 : new Plane(),
  8166. ( p4 !== undefined ) ? p4 : new Plane(),
  8167. ( p5 !== undefined ) ? p5 : new Plane()
  8168. ];
  8169. }
  8170. set( p0, p1, p2, p3, p4, p5 ) {
  8171. const planes = this.planes;
  8172. planes[ 0 ].copy( p0 );
  8173. planes[ 1 ].copy( p1 );
  8174. planes[ 2 ].copy( p2 );
  8175. planes[ 3 ].copy( p3 );
  8176. planes[ 4 ].copy( p4 );
  8177. planes[ 5 ].copy( p5 );
  8178. return this;
  8179. }
  8180. clone() {
  8181. return new this.constructor().copy( this );
  8182. }
  8183. copy( frustum ) {
  8184. const planes = this.planes;
  8185. for ( let i = 0; i < 6; i ++ ) {
  8186. planes[ i ].copy( frustum.planes[ i ] );
  8187. }
  8188. return this;
  8189. }
  8190. setFromProjectionMatrix( m ) {
  8191. const planes = this.planes;
  8192. const me = m.elements;
  8193. const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
  8194. const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
  8195. const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
  8196. const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
  8197. planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
  8198. planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
  8199. planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
  8200. planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
  8201. planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
  8202. planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
  8203. return this;
  8204. }
  8205. intersectsObject( object ) {
  8206. const geometry = object.geometry;
  8207. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  8208. _sphere$1.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
  8209. return this.intersectsSphere( _sphere$1 );
  8210. }
  8211. intersectsSprite( sprite ) {
  8212. _sphere$1.center.set( 0, 0, 0 );
  8213. _sphere$1.radius = 0.7071067811865476;
  8214. _sphere$1.applyMatrix4( sprite.matrixWorld );
  8215. return this.intersectsSphere( _sphere$1 );
  8216. }
  8217. intersectsSphere( sphere ) {
  8218. const planes = this.planes;
  8219. const center = sphere.center;
  8220. const negRadius = - sphere.radius;
  8221. for ( let i = 0; i < 6; i ++ ) {
  8222. const distance = planes[ i ].distanceToPoint( center );
  8223. if ( distance < negRadius ) {
  8224. return false;
  8225. }
  8226. }
  8227. return true;
  8228. }
  8229. intersectsBox( box ) {
  8230. const planes = this.planes;
  8231. for ( let i = 0; i < 6; i ++ ) {
  8232. const plane = planes[ i ];
  8233. // corner at max distance
  8234. _vector$5.x = plane.normal.x > 0 ? box.max.x : box.min.x;
  8235. _vector$5.y = plane.normal.y > 0 ? box.max.y : box.min.y;
  8236. _vector$5.z = plane.normal.z > 0 ? box.max.z : box.min.z;
  8237. if ( plane.distanceToPoint( _vector$5 ) < 0 ) {
  8238. return false;
  8239. }
  8240. }
  8241. return true;
  8242. }
  8243. containsPoint( point ) {
  8244. const planes = this.planes;
  8245. for ( let i = 0; i < 6; i ++ ) {
  8246. if ( planes[ i ].distanceToPoint( point ) < 0 ) {
  8247. return false;
  8248. }
  8249. }
  8250. return true;
  8251. }
  8252. }
  8253. function WebGLAnimation() {
  8254. let context = null;
  8255. let isAnimating = false;
  8256. let animationLoop = null;
  8257. let requestId = null;
  8258. function onAnimationFrame( time, frame ) {
  8259. animationLoop( time, frame );
  8260. requestId = context.requestAnimationFrame( onAnimationFrame );
  8261. }
  8262. return {
  8263. start: function () {
  8264. if ( isAnimating === true ) return;
  8265. if ( animationLoop === null ) return;
  8266. requestId = context.requestAnimationFrame( onAnimationFrame );
  8267. isAnimating = true;
  8268. },
  8269. stop: function () {
  8270. context.cancelAnimationFrame( requestId );
  8271. isAnimating = false;
  8272. },
  8273. setAnimationLoop: function ( callback ) {
  8274. animationLoop = callback;
  8275. },
  8276. setContext: function ( value ) {
  8277. context = value;
  8278. }
  8279. };
  8280. }
  8281. function WebGLAttributes( gl, capabilities ) {
  8282. const isWebGL2 = capabilities.isWebGL2;
  8283. const buffers = new WeakMap();
  8284. function createBuffer( attribute, bufferType ) {
  8285. const array = attribute.array;
  8286. const usage = attribute.usage;
  8287. const buffer = gl.createBuffer();
  8288. gl.bindBuffer( bufferType, buffer );
  8289. gl.bufferData( bufferType, array, usage );
  8290. attribute.onUploadCallback();
  8291. let type = 5126;
  8292. if ( array instanceof Float32Array ) {
  8293. type = 5126;
  8294. } else if ( array instanceof Float64Array ) {
  8295. console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
  8296. } else if ( array instanceof Uint16Array ) {
  8297. if ( attribute.isFloat16BufferAttribute ) {
  8298. if ( isWebGL2 ) {
  8299. type = 5131;
  8300. } else {
  8301. console.warn( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
  8302. }
  8303. } else {
  8304. type = 5123;
  8305. }
  8306. } else if ( array instanceof Int16Array ) {
  8307. type = 5122;
  8308. } else if ( array instanceof Uint32Array ) {
  8309. type = 5125;
  8310. } else if ( array instanceof Int32Array ) {
  8311. type = 5124;
  8312. } else if ( array instanceof Int8Array ) {
  8313. type = 5120;
  8314. } else if ( array instanceof Uint8Array ) {
  8315. type = 5121;
  8316. }
  8317. return {
  8318. buffer: buffer,
  8319. type: type,
  8320. bytesPerElement: array.BYTES_PER_ELEMENT,
  8321. version: attribute.version
  8322. };
  8323. }
  8324. function updateBuffer( buffer, attribute, bufferType ) {
  8325. const array = attribute.array;
  8326. const updateRange = attribute.updateRange;
  8327. gl.bindBuffer( bufferType, buffer );
  8328. if ( updateRange.count === - 1 ) {
  8329. // Not using update ranges
  8330. gl.bufferSubData( bufferType, 0, array );
  8331. } else {
  8332. if ( isWebGL2 ) {
  8333. gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
  8334. array, updateRange.offset, updateRange.count );
  8335. } else {
  8336. gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
  8337. array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
  8338. }
  8339. updateRange.count = - 1; // reset range
  8340. }
  8341. }
  8342. //
  8343. function get( attribute ) {
  8344. if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
  8345. return buffers.get( attribute );
  8346. }
  8347. function remove( attribute ) {
  8348. if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
  8349. const data = buffers.get( attribute );
  8350. if ( data ) {
  8351. gl.deleteBuffer( data.buffer );
  8352. buffers.delete( attribute );
  8353. }
  8354. }
  8355. function update( attribute, bufferType ) {
  8356. if ( attribute.isGLBufferAttribute ) {
  8357. const cached = buffers.get( attribute );
  8358. if ( ! cached || cached.version < attribute.version ) {
  8359. buffers.set( attribute, {
  8360. buffer: attribute.buffer,
  8361. type: attribute.type,
  8362. bytesPerElement: attribute.elementSize,
  8363. version: attribute.version
  8364. } );
  8365. }
  8366. return;
  8367. }
  8368. if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
  8369. const data = buffers.get( attribute );
  8370. if ( data === undefined ) {
  8371. buffers.set( attribute, createBuffer( attribute, bufferType ) );
  8372. } else if ( data.version < attribute.version ) {
  8373. updateBuffer( data.buffer, attribute, bufferType );
  8374. data.version = attribute.version;
  8375. }
  8376. }
  8377. return {
  8378. get: get,
  8379. remove: remove,
  8380. update: update
  8381. };
  8382. }
  8383. class PlaneBufferGeometry extends BufferGeometry {
  8384. constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
  8385. super();
  8386. this.type = 'PlaneBufferGeometry';
  8387. this.parameters = {
  8388. width: width,
  8389. height: height,
  8390. widthSegments: widthSegments,
  8391. heightSegments: heightSegments
  8392. };
  8393. const width_half = width / 2;
  8394. const height_half = height / 2;
  8395. const gridX = Math.floor( widthSegments );
  8396. const gridY = Math.floor( heightSegments );
  8397. const gridX1 = gridX + 1;
  8398. const gridY1 = gridY + 1;
  8399. const segment_width = width / gridX;
  8400. const segment_height = height / gridY;
  8401. //
  8402. const indices = [];
  8403. const vertices = [];
  8404. const normals = [];
  8405. const uvs = [];
  8406. for ( let iy = 0; iy < gridY1; iy ++ ) {
  8407. const y = iy * segment_height - height_half;
  8408. for ( let ix = 0; ix < gridX1; ix ++ ) {
  8409. const x = ix * segment_width - width_half;
  8410. vertices.push( x, - y, 0 );
  8411. normals.push( 0, 0, 1 );
  8412. uvs.push( ix / gridX );
  8413. uvs.push( 1 - ( iy / gridY ) );
  8414. }
  8415. }
  8416. for ( let iy = 0; iy < gridY; iy ++ ) {
  8417. for ( let ix = 0; ix < gridX; ix ++ ) {
  8418. const a = ix + gridX1 * iy;
  8419. const b = ix + gridX1 * ( iy + 1 );
  8420. const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
  8421. const d = ( ix + 1 ) + gridX1 * iy;
  8422. indices.push( a, b, d );
  8423. indices.push( b, c, d );
  8424. }
  8425. }
  8426. this.setIndex( indices );
  8427. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  8428. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  8429. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  8430. }
  8431. }
  8432. var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif";
  8433. var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
  8434. var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif";
  8435. var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif";
  8436. var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
  8437. var begin_vertex = "vec3 transformed = vec3( position );";
  8438. var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
  8439. var bsdfs = "vec2 integrateSpecularBRDF( const in float dotNV, const in float roughness ) {\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\treturn vec2( -1.04, 1.04 ) * a004 + r.zw;\n}\nfloat punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif";
  8440. var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif";
  8441. var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif";
  8442. var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
  8443. var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
  8444. var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
  8445. var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
  8446. var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
  8447. var color_pars_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
  8448. var color_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor.xyz *= color.xyz;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
  8449. var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}";
  8450. var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif";
  8451. var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
  8452. var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
  8453. var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif";
  8454. var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
  8455. var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
  8456. var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
  8457. var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}";
  8458. var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif";
  8459. var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif";
  8460. var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif";
  8461. var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif";
  8462. var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif";
  8463. var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif";
  8464. var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif";
  8465. var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif";
  8466. var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif";
  8467. var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}";
  8468. var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif";
  8469. var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
  8470. var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif";
  8471. var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif";
  8472. var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif";
  8473. var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
  8474. var lights_toon_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)";
  8475. var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
  8476. var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)";
  8477. var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif";
  8478. var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat specularRoughness;\n\tvec3 specularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
  8479. var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
  8480. var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif";
  8481. var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif";
  8482. var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
  8483. var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
  8484. var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif";
  8485. var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif";
  8486. var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif";
  8487. var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
  8488. var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif";
  8489. var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
  8490. var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
  8491. var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
  8492. var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif";
  8493. var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
  8494. var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif";
  8495. var normal_fragment_begin = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;";
  8496. var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif";
  8497. var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
  8498. var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
  8499. var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif";
  8500. var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif";
  8501. var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}";
  8502. var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
  8503. var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;";
  8504. var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
  8505. var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif";
  8506. var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
  8507. var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
  8508. var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif";
  8509. var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif";
  8510. var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif";
  8511. var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}";
  8512. var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
  8513. var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif";
  8514. var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif";
  8515. var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif";
  8516. var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
  8517. var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
  8518. var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
  8519. var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }";
  8520. var transmissionmap_fragment = "#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif";
  8521. var transmissionmap_pars_fragment = "#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif";
  8522. var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif";
  8523. var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif";
  8524. var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
  8525. var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
  8526. var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif";
  8527. var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif";
  8528. var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif";
  8529. var background_frag = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
  8530. var background_vert = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
  8531. var cube_frag = "#include <envmap_common_pars_fragment>\nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include <envmap_fragment>\n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
  8532. var cube_vert = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
  8533. var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}";
  8534. var depth_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvHighPrecisionZW = gl_Position.zw;\n}";
  8535. var distanceRGBA_frag = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}";
  8536. var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}";
  8537. var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
  8538. var equirect_vert = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}";
  8539. var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
  8540. var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
  8541. var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
  8542. var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}";
  8543. var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
  8544. var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
  8545. var meshmatcap_frag = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
  8546. var meshmatcap_vert = "#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
  8547. var meshtoon_frag = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_toon_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_toon_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
  8548. var meshtoon_vert = "#define TOON\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
  8549. var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
  8550. var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
  8551. var meshphysical_frag = "#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSMISSION\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSMISSION\n\tuniform float transmission;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <transmissionmap_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#ifdef TRANSMISSION\n\t\tfloat totalTransmission = transmission;\n\t#endif\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <clearcoat_normal_fragment_begin>\n\t#include <clearcoat_normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <transmissionmap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#ifdef TRANSMISSION\n\t\tdiffuseColor.a *= mix( saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) ), 1.0, metalness );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
  8552. var meshphysical_vert = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
  8553. var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}";
  8554. var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}";
  8555. var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
  8556. var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}";
  8557. var shadow_frag = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
  8558. var shadow_vert = "#include <common>\n#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
  8559. var sprite_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
  8560. var sprite_vert = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
  8561. const ShaderChunk = {
  8562. alphamap_fragment: alphamap_fragment,
  8563. alphamap_pars_fragment: alphamap_pars_fragment,
  8564. alphatest_fragment: alphatest_fragment,
  8565. aomap_fragment: aomap_fragment,
  8566. aomap_pars_fragment: aomap_pars_fragment,
  8567. begin_vertex: begin_vertex,
  8568. beginnormal_vertex: beginnormal_vertex,
  8569. bsdfs: bsdfs,
  8570. bumpmap_pars_fragment: bumpmap_pars_fragment,
  8571. clipping_planes_fragment: clipping_planes_fragment,
  8572. clipping_planes_pars_fragment: clipping_planes_pars_fragment,
  8573. clipping_planes_pars_vertex: clipping_planes_pars_vertex,
  8574. clipping_planes_vertex: clipping_planes_vertex,
  8575. color_fragment: color_fragment,
  8576. color_pars_fragment: color_pars_fragment,
  8577. color_pars_vertex: color_pars_vertex,
  8578. color_vertex: color_vertex,
  8579. common: common,
  8580. cube_uv_reflection_fragment: cube_uv_reflection_fragment,
  8581. defaultnormal_vertex: defaultnormal_vertex,
  8582. displacementmap_pars_vertex: displacementmap_pars_vertex,
  8583. displacementmap_vertex: displacementmap_vertex,
  8584. emissivemap_fragment: emissivemap_fragment,
  8585. emissivemap_pars_fragment: emissivemap_pars_fragment,
  8586. encodings_fragment: encodings_fragment,
  8587. encodings_pars_fragment: encodings_pars_fragment,
  8588. envmap_fragment: envmap_fragment,
  8589. envmap_common_pars_fragment: envmap_common_pars_fragment,
  8590. envmap_pars_fragment: envmap_pars_fragment,
  8591. envmap_pars_vertex: envmap_pars_vertex,
  8592. envmap_physical_pars_fragment: envmap_physical_pars_fragment,
  8593. envmap_vertex: envmap_vertex,
  8594. fog_vertex: fog_vertex,
  8595. fog_pars_vertex: fog_pars_vertex,
  8596. fog_fragment: fog_fragment,
  8597. fog_pars_fragment: fog_pars_fragment,
  8598. gradientmap_pars_fragment: gradientmap_pars_fragment,
  8599. lightmap_fragment: lightmap_fragment,
  8600. lightmap_pars_fragment: lightmap_pars_fragment,
  8601. lights_lambert_vertex: lights_lambert_vertex,
  8602. lights_pars_begin: lights_pars_begin,
  8603. lights_toon_fragment: lights_toon_fragment,
  8604. lights_toon_pars_fragment: lights_toon_pars_fragment,
  8605. lights_phong_fragment: lights_phong_fragment,
  8606. lights_phong_pars_fragment: lights_phong_pars_fragment,
  8607. lights_physical_fragment: lights_physical_fragment,
  8608. lights_physical_pars_fragment: lights_physical_pars_fragment,
  8609. lights_fragment_begin: lights_fragment_begin,
  8610. lights_fragment_maps: lights_fragment_maps,
  8611. lights_fragment_end: lights_fragment_end,
  8612. logdepthbuf_fragment: logdepthbuf_fragment,
  8613. logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
  8614. logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
  8615. logdepthbuf_vertex: logdepthbuf_vertex,
  8616. map_fragment: map_fragment,
  8617. map_pars_fragment: map_pars_fragment,
  8618. map_particle_fragment: map_particle_fragment,
  8619. map_particle_pars_fragment: map_particle_pars_fragment,
  8620. metalnessmap_fragment: metalnessmap_fragment,
  8621. metalnessmap_pars_fragment: metalnessmap_pars_fragment,
  8622. morphnormal_vertex: morphnormal_vertex,
  8623. morphtarget_pars_vertex: morphtarget_pars_vertex,
  8624. morphtarget_vertex: morphtarget_vertex,
  8625. normal_fragment_begin: normal_fragment_begin,
  8626. normal_fragment_maps: normal_fragment_maps,
  8627. normalmap_pars_fragment: normalmap_pars_fragment,
  8628. clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
  8629. clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
  8630. clearcoat_pars_fragment: clearcoat_pars_fragment,
  8631. packing: packing,
  8632. premultiplied_alpha_fragment: premultiplied_alpha_fragment,
  8633. project_vertex: project_vertex,
  8634. dithering_fragment: dithering_fragment,
  8635. dithering_pars_fragment: dithering_pars_fragment,
  8636. roughnessmap_fragment: roughnessmap_fragment,
  8637. roughnessmap_pars_fragment: roughnessmap_pars_fragment,
  8638. shadowmap_pars_fragment: shadowmap_pars_fragment,
  8639. shadowmap_pars_vertex: shadowmap_pars_vertex,
  8640. shadowmap_vertex: shadowmap_vertex,
  8641. shadowmask_pars_fragment: shadowmask_pars_fragment,
  8642. skinbase_vertex: skinbase_vertex,
  8643. skinning_pars_vertex: skinning_pars_vertex,
  8644. skinning_vertex: skinning_vertex,
  8645. skinnormal_vertex: skinnormal_vertex,
  8646. specularmap_fragment: specularmap_fragment,
  8647. specularmap_pars_fragment: specularmap_pars_fragment,
  8648. tonemapping_fragment: tonemapping_fragment,
  8649. tonemapping_pars_fragment: tonemapping_pars_fragment,
  8650. transmissionmap_fragment: transmissionmap_fragment,
  8651. transmissionmap_pars_fragment: transmissionmap_pars_fragment,
  8652. uv_pars_fragment: uv_pars_fragment,
  8653. uv_pars_vertex: uv_pars_vertex,
  8654. uv_vertex: uv_vertex,
  8655. uv2_pars_fragment: uv2_pars_fragment,
  8656. uv2_pars_vertex: uv2_pars_vertex,
  8657. uv2_vertex: uv2_vertex,
  8658. worldpos_vertex: worldpos_vertex,
  8659. background_frag: background_frag,
  8660. background_vert: background_vert,
  8661. cube_frag: cube_frag,
  8662. cube_vert: cube_vert,
  8663. depth_frag: depth_frag,
  8664. depth_vert: depth_vert,
  8665. distanceRGBA_frag: distanceRGBA_frag,
  8666. distanceRGBA_vert: distanceRGBA_vert,
  8667. equirect_frag: equirect_frag,
  8668. equirect_vert: equirect_vert,
  8669. linedashed_frag: linedashed_frag,
  8670. linedashed_vert: linedashed_vert,
  8671. meshbasic_frag: meshbasic_frag,
  8672. meshbasic_vert: meshbasic_vert,
  8673. meshlambert_frag: meshlambert_frag,
  8674. meshlambert_vert: meshlambert_vert,
  8675. meshmatcap_frag: meshmatcap_frag,
  8676. meshmatcap_vert: meshmatcap_vert,
  8677. meshtoon_frag: meshtoon_frag,
  8678. meshtoon_vert: meshtoon_vert,
  8679. meshphong_frag: meshphong_frag,
  8680. meshphong_vert: meshphong_vert,
  8681. meshphysical_frag: meshphysical_frag,
  8682. meshphysical_vert: meshphysical_vert,
  8683. normal_frag: normal_frag,
  8684. normal_vert: normal_vert,
  8685. points_frag: points_frag,
  8686. points_vert: points_vert,
  8687. shadow_frag: shadow_frag,
  8688. shadow_vert: shadow_vert,
  8689. sprite_frag: sprite_frag,
  8690. sprite_vert: sprite_vert
  8691. };
  8692. /**
  8693. * Uniforms library for shared webgl shaders
  8694. */
  8695. const UniformsLib = {
  8696. common: {
  8697. diffuse: { value: new Color( 0xeeeeee ) },
  8698. opacity: { value: 1.0 },
  8699. map: { value: null },
  8700. uvTransform: { value: new Matrix3() },
  8701. uv2Transform: { value: new Matrix3() },
  8702. alphaMap: { value: null },
  8703. },
  8704. specularmap: {
  8705. specularMap: { value: null },
  8706. },
  8707. envmap: {
  8708. envMap: { value: null },
  8709. flipEnvMap: { value: - 1 },
  8710. reflectivity: { value: 1.0 },
  8711. refractionRatio: { value: 0.98 },
  8712. maxMipLevel: { value: 0 }
  8713. },
  8714. aomap: {
  8715. aoMap: { value: null },
  8716. aoMapIntensity: { value: 1 }
  8717. },
  8718. lightmap: {
  8719. lightMap: { value: null },
  8720. lightMapIntensity: { value: 1 }
  8721. },
  8722. emissivemap: {
  8723. emissiveMap: { value: null }
  8724. },
  8725. bumpmap: {
  8726. bumpMap: { value: null },
  8727. bumpScale: { value: 1 }
  8728. },
  8729. normalmap: {
  8730. normalMap: { value: null },
  8731. normalScale: { value: new Vector2$1( 1, 1 ) }
  8732. },
  8733. displacementmap: {
  8734. displacementMap: { value: null },
  8735. displacementScale: { value: 1 },
  8736. displacementBias: { value: 0 }
  8737. },
  8738. roughnessmap: {
  8739. roughnessMap: { value: null }
  8740. },
  8741. metalnessmap: {
  8742. metalnessMap: { value: null }
  8743. },
  8744. gradientmap: {
  8745. gradientMap: { value: null }
  8746. },
  8747. fog: {
  8748. fogDensity: { value: 0.00025 },
  8749. fogNear: { value: 1 },
  8750. fogFar: { value: 2000 },
  8751. fogColor: { value: new Color( 0xffffff ) }
  8752. },
  8753. lights: {
  8754. ambientLightColor: { value: [] },
  8755. lightProbe: { value: [] },
  8756. directionalLights: { value: [], properties: {
  8757. direction: {},
  8758. color: {}
  8759. } },
  8760. directionalLightShadows: { value: [], properties: {
  8761. shadowBias: {},
  8762. shadowNormalBias: {},
  8763. shadowRadius: {},
  8764. shadowMapSize: {}
  8765. } },
  8766. directionalShadowMap: { value: [] },
  8767. directionalShadowMatrix: { value: [] },
  8768. spotLights: { value: [], properties: {
  8769. color: {},
  8770. position: {},
  8771. direction: {},
  8772. distance: {},
  8773. coneCos: {},
  8774. penumbraCos: {},
  8775. decay: {}
  8776. } },
  8777. spotLightShadows: { value: [], properties: {
  8778. shadowBias: {},
  8779. shadowNormalBias: {},
  8780. shadowRadius: {},
  8781. shadowMapSize: {}
  8782. } },
  8783. spotShadowMap: { value: [] },
  8784. spotShadowMatrix: { value: [] },
  8785. pointLights: { value: [], properties: {
  8786. color: {},
  8787. position: {},
  8788. decay: {},
  8789. distance: {}
  8790. } },
  8791. pointLightShadows: { value: [], properties: {
  8792. shadowBias: {},
  8793. shadowNormalBias: {},
  8794. shadowRadius: {},
  8795. shadowMapSize: {},
  8796. shadowCameraNear: {},
  8797. shadowCameraFar: {}
  8798. } },
  8799. pointShadowMap: { value: [] },
  8800. pointShadowMatrix: { value: [] },
  8801. hemisphereLights: { value: [], properties: {
  8802. direction: {},
  8803. skyColor: {},
  8804. groundColor: {}
  8805. } },
  8806. // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
  8807. rectAreaLights: { value: [], properties: {
  8808. color: {},
  8809. position: {},
  8810. width: {},
  8811. height: {}
  8812. } },
  8813. ltc_1: { value: null },
  8814. ltc_2: { value: null }
  8815. },
  8816. points: {
  8817. diffuse: { value: new Color( 0xeeeeee ) },
  8818. opacity: { value: 1.0 },
  8819. size: { value: 1.0 },
  8820. scale: { value: 1.0 },
  8821. map: { value: null },
  8822. alphaMap: { value: null },
  8823. uvTransform: { value: new Matrix3() }
  8824. },
  8825. sprite: {
  8826. diffuse: { value: new Color( 0xeeeeee ) },
  8827. opacity: { value: 1.0 },
  8828. center: { value: new Vector2$1( 0.5, 0.5 ) },
  8829. rotation: { value: 0.0 },
  8830. map: { value: null },
  8831. alphaMap: { value: null },
  8832. uvTransform: { value: new Matrix3() }
  8833. }
  8834. };
  8835. const ShaderLib = {
  8836. basic: {
  8837. uniforms: mergeUniforms( [
  8838. UniformsLib.common,
  8839. UniformsLib.specularmap,
  8840. UniformsLib.envmap,
  8841. UniformsLib.aomap,
  8842. UniformsLib.lightmap,
  8843. UniformsLib.fog
  8844. ] ),
  8845. vertexShader: ShaderChunk.meshbasic_vert,
  8846. fragmentShader: ShaderChunk.meshbasic_frag
  8847. },
  8848. lambert: {
  8849. uniforms: mergeUniforms( [
  8850. UniformsLib.common,
  8851. UniformsLib.specularmap,
  8852. UniformsLib.envmap,
  8853. UniformsLib.aomap,
  8854. UniformsLib.lightmap,
  8855. UniformsLib.emissivemap,
  8856. UniformsLib.fog,
  8857. UniformsLib.lights,
  8858. {
  8859. emissive: { value: new Color( 0x000000 ) }
  8860. }
  8861. ] ),
  8862. vertexShader: ShaderChunk.meshlambert_vert,
  8863. fragmentShader: ShaderChunk.meshlambert_frag
  8864. },
  8865. phong: {
  8866. uniforms: mergeUniforms( [
  8867. UniformsLib.common,
  8868. UniformsLib.specularmap,
  8869. UniformsLib.envmap,
  8870. UniformsLib.aomap,
  8871. UniformsLib.lightmap,
  8872. UniformsLib.emissivemap,
  8873. UniformsLib.bumpmap,
  8874. UniformsLib.normalmap,
  8875. UniformsLib.displacementmap,
  8876. UniformsLib.fog,
  8877. UniformsLib.lights,
  8878. {
  8879. emissive: { value: new Color( 0x000000 ) },
  8880. specular: { value: new Color( 0x111111 ) },
  8881. shininess: { value: 30 }
  8882. }
  8883. ] ),
  8884. vertexShader: ShaderChunk.meshphong_vert,
  8885. fragmentShader: ShaderChunk.meshphong_frag
  8886. },
  8887. standard: {
  8888. uniforms: mergeUniforms( [
  8889. UniformsLib.common,
  8890. UniformsLib.envmap,
  8891. UniformsLib.aomap,
  8892. UniformsLib.lightmap,
  8893. UniformsLib.emissivemap,
  8894. UniformsLib.bumpmap,
  8895. UniformsLib.normalmap,
  8896. UniformsLib.displacementmap,
  8897. UniformsLib.roughnessmap,
  8898. UniformsLib.metalnessmap,
  8899. UniformsLib.fog,
  8900. UniformsLib.lights,
  8901. {
  8902. emissive: { value: new Color( 0x000000 ) },
  8903. roughness: { value: 1.0 },
  8904. metalness: { value: 0.0 },
  8905. envMapIntensity: { value: 1 } // temporary
  8906. }
  8907. ] ),
  8908. vertexShader: ShaderChunk.meshphysical_vert,
  8909. fragmentShader: ShaderChunk.meshphysical_frag
  8910. },
  8911. toon: {
  8912. uniforms: mergeUniforms( [
  8913. UniformsLib.common,
  8914. UniformsLib.aomap,
  8915. UniformsLib.lightmap,
  8916. UniformsLib.emissivemap,
  8917. UniformsLib.bumpmap,
  8918. UniformsLib.normalmap,
  8919. UniformsLib.displacementmap,
  8920. UniformsLib.gradientmap,
  8921. UniformsLib.fog,
  8922. UniformsLib.lights,
  8923. {
  8924. emissive: { value: new Color( 0x000000 ) }
  8925. }
  8926. ] ),
  8927. vertexShader: ShaderChunk.meshtoon_vert,
  8928. fragmentShader: ShaderChunk.meshtoon_frag
  8929. },
  8930. matcap: {
  8931. uniforms: mergeUniforms( [
  8932. UniformsLib.common,
  8933. UniformsLib.bumpmap,
  8934. UniformsLib.normalmap,
  8935. UniformsLib.displacementmap,
  8936. UniformsLib.fog,
  8937. {
  8938. matcap: { value: null }
  8939. }
  8940. ] ),
  8941. vertexShader: ShaderChunk.meshmatcap_vert,
  8942. fragmentShader: ShaderChunk.meshmatcap_frag
  8943. },
  8944. points: {
  8945. uniforms: mergeUniforms( [
  8946. UniformsLib.points,
  8947. UniformsLib.fog
  8948. ] ),
  8949. vertexShader: ShaderChunk.points_vert,
  8950. fragmentShader: ShaderChunk.points_frag
  8951. },
  8952. dashed: {
  8953. uniforms: mergeUniforms( [
  8954. UniformsLib.common,
  8955. UniformsLib.fog,
  8956. {
  8957. scale: { value: 1 },
  8958. dashSize: { value: 1 },
  8959. totalSize: { value: 2 }
  8960. }
  8961. ] ),
  8962. vertexShader: ShaderChunk.linedashed_vert,
  8963. fragmentShader: ShaderChunk.linedashed_frag
  8964. },
  8965. depth: {
  8966. uniforms: mergeUniforms( [
  8967. UniformsLib.common,
  8968. UniformsLib.displacementmap
  8969. ] ),
  8970. vertexShader: ShaderChunk.depth_vert,
  8971. fragmentShader: ShaderChunk.depth_frag
  8972. },
  8973. normal: {
  8974. uniforms: mergeUniforms( [
  8975. UniformsLib.common,
  8976. UniformsLib.bumpmap,
  8977. UniformsLib.normalmap,
  8978. UniformsLib.displacementmap,
  8979. {
  8980. opacity: { value: 1.0 }
  8981. }
  8982. ] ),
  8983. vertexShader: ShaderChunk.normal_vert,
  8984. fragmentShader: ShaderChunk.normal_frag
  8985. },
  8986. sprite: {
  8987. uniforms: mergeUniforms( [
  8988. UniformsLib.sprite,
  8989. UniformsLib.fog
  8990. ] ),
  8991. vertexShader: ShaderChunk.sprite_vert,
  8992. fragmentShader: ShaderChunk.sprite_frag
  8993. },
  8994. background: {
  8995. uniforms: {
  8996. uvTransform: { value: new Matrix3() },
  8997. t2D: { value: null },
  8998. },
  8999. vertexShader: ShaderChunk.background_vert,
  9000. fragmentShader: ShaderChunk.background_frag
  9001. },
  9002. /* -------------------------------------------------------------------------
  9003. // Cube map shader
  9004. ------------------------------------------------------------------------- */
  9005. cube: {
  9006. uniforms: mergeUniforms( [
  9007. UniformsLib.envmap,
  9008. {
  9009. opacity: { value: 1.0 }
  9010. }
  9011. ] ),
  9012. vertexShader: ShaderChunk.cube_vert,
  9013. fragmentShader: ShaderChunk.cube_frag
  9014. },
  9015. equirect: {
  9016. uniforms: {
  9017. tEquirect: { value: null },
  9018. },
  9019. vertexShader: ShaderChunk.equirect_vert,
  9020. fragmentShader: ShaderChunk.equirect_frag
  9021. },
  9022. distanceRGBA: {
  9023. uniforms: mergeUniforms( [
  9024. UniformsLib.common,
  9025. UniformsLib.displacementmap,
  9026. {
  9027. referencePosition: { value: new Vector3() },
  9028. nearDistance: { value: 1 },
  9029. farDistance: { value: 1000 }
  9030. }
  9031. ] ),
  9032. vertexShader: ShaderChunk.distanceRGBA_vert,
  9033. fragmentShader: ShaderChunk.distanceRGBA_frag
  9034. },
  9035. shadow: {
  9036. uniforms: mergeUniforms( [
  9037. UniformsLib.lights,
  9038. UniformsLib.fog,
  9039. {
  9040. color: { value: new Color( 0x00000 ) },
  9041. opacity: { value: 1.0 }
  9042. },
  9043. ] ),
  9044. vertexShader: ShaderChunk.shadow_vert,
  9045. fragmentShader: ShaderChunk.shadow_frag
  9046. }
  9047. };
  9048. ShaderLib.physical = {
  9049. uniforms: mergeUniforms( [
  9050. ShaderLib.standard.uniforms,
  9051. {
  9052. clearcoat: { value: 0 },
  9053. clearcoatMap: { value: null },
  9054. clearcoatRoughness: { value: 0 },
  9055. clearcoatRoughnessMap: { value: null },
  9056. clearcoatNormalScale: { value: new Vector2$1( 1, 1 ) },
  9057. clearcoatNormalMap: { value: null },
  9058. sheen: { value: new Color( 0x000000 ) },
  9059. transmission: { value: 0 },
  9060. transmissionMap: { value: null },
  9061. }
  9062. ] ),
  9063. vertexShader: ShaderChunk.meshphysical_vert,
  9064. fragmentShader: ShaderChunk.meshphysical_frag
  9065. };
  9066. function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) {
  9067. const clearColor = new Color( 0x000000 );
  9068. let clearAlpha = 0;
  9069. let planeMesh;
  9070. let boxMesh;
  9071. let currentBackground = null;
  9072. let currentBackgroundVersion = 0;
  9073. let currentTonemapping = null;
  9074. function render( renderList, scene, camera, forceClear ) {
  9075. let background = scene.isScene === true ? scene.background : null;
  9076. if ( background && background.isTexture ) {
  9077. background = cubemaps.get( background );
  9078. }
  9079. // Ignore background in AR
  9080. // TODO: Reconsider this.
  9081. const xr = renderer.xr;
  9082. const session = xr.getSession && xr.getSession();
  9083. if ( session && session.environmentBlendMode === 'additive' ) {
  9084. background = null;
  9085. }
  9086. if ( background === null ) {
  9087. setClear( clearColor, clearAlpha );
  9088. } else if ( background && background.isColor ) {
  9089. setClear( background, 1 );
  9090. forceClear = true;
  9091. }
  9092. if ( renderer.autoClear || forceClear ) {
  9093. renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
  9094. }
  9095. if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.mapping === CubeUVReflectionMapping ) ) {
  9096. if ( boxMesh === undefined ) {
  9097. boxMesh = new Mesh(
  9098. new BoxBufferGeometry( 1, 1, 1 ),
  9099. new ShaderMaterial( {
  9100. name: 'BackgroundCubeMaterial',
  9101. uniforms: cloneUniforms( ShaderLib.cube.uniforms ),
  9102. vertexShader: ShaderLib.cube.vertexShader,
  9103. fragmentShader: ShaderLib.cube.fragmentShader,
  9104. side: BackSide,
  9105. depthTest: false,
  9106. depthWrite: false,
  9107. fog: false
  9108. } )
  9109. );
  9110. boxMesh.geometry.deleteAttribute( 'normal' );
  9111. boxMesh.geometry.deleteAttribute( 'uv' );
  9112. boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
  9113. this.matrixWorld.copyPosition( camera.matrixWorld );
  9114. };
  9115. // enable code injection for non-built-in material
  9116. Object.defineProperty( boxMesh.material, 'envMap', {
  9117. get: function () {
  9118. return this.uniforms.envMap.value;
  9119. }
  9120. } );
  9121. objects.update( boxMesh );
  9122. }
  9123. if ( background.isWebGLCubeRenderTarget ) {
  9124. // TODO Deprecate
  9125. background = background.texture;
  9126. }
  9127. boxMesh.material.uniforms.envMap.value = background;
  9128. boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background._needsFlipEnvMap ) ? - 1 : 1;
  9129. if ( currentBackground !== background ||
  9130. currentBackgroundVersion !== background.version ||
  9131. currentTonemapping !== renderer.toneMapping ) {
  9132. boxMesh.material.needsUpdate = true;
  9133. currentBackground = background;
  9134. currentBackgroundVersion = background.version;
  9135. currentTonemapping = renderer.toneMapping;
  9136. }
  9137. // push to the pre-sorted opaque render list
  9138. renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
  9139. } else if ( background && background.isTexture ) {
  9140. if ( planeMesh === undefined ) {
  9141. planeMesh = new Mesh(
  9142. new PlaneBufferGeometry( 2, 2 ),
  9143. new ShaderMaterial( {
  9144. name: 'BackgroundMaterial',
  9145. uniforms: cloneUniforms( ShaderLib.background.uniforms ),
  9146. vertexShader: ShaderLib.background.vertexShader,
  9147. fragmentShader: ShaderLib.background.fragmentShader,
  9148. side: FrontSide,
  9149. depthTest: false,
  9150. depthWrite: false,
  9151. fog: false
  9152. } )
  9153. );
  9154. planeMesh.geometry.deleteAttribute( 'normal' );
  9155. // enable code injection for non-built-in material
  9156. Object.defineProperty( planeMesh.material, 'map', {
  9157. get: function () {
  9158. return this.uniforms.t2D.value;
  9159. }
  9160. } );
  9161. objects.update( planeMesh );
  9162. }
  9163. planeMesh.material.uniforms.t2D.value = background;
  9164. if ( background.matrixAutoUpdate === true ) {
  9165. background.updateMatrix();
  9166. }
  9167. planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
  9168. if ( currentBackground !== background ||
  9169. currentBackgroundVersion !== background.version ||
  9170. currentTonemapping !== renderer.toneMapping ) {
  9171. planeMesh.material.needsUpdate = true;
  9172. currentBackground = background;
  9173. currentBackgroundVersion = background.version;
  9174. currentTonemapping = renderer.toneMapping;
  9175. }
  9176. // push to the pre-sorted opaque render list
  9177. renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
  9178. }
  9179. }
  9180. function setClear( color, alpha ) {
  9181. state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
  9182. }
  9183. return {
  9184. getClearColor: function () {
  9185. return clearColor;
  9186. },
  9187. setClearColor: function ( color, alpha = 1 ) {
  9188. clearColor.set( color );
  9189. clearAlpha = alpha;
  9190. setClear( clearColor, clearAlpha );
  9191. },
  9192. getClearAlpha: function () {
  9193. return clearAlpha;
  9194. },
  9195. setClearAlpha: function ( alpha ) {
  9196. clearAlpha = alpha;
  9197. setClear( clearColor, clearAlpha );
  9198. },
  9199. render: render
  9200. };
  9201. }
  9202. function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
  9203. const maxVertexAttributes = gl.getParameter( 34921 );
  9204. const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
  9205. const vaoAvailable = capabilities.isWebGL2 || extension !== null;
  9206. const bindingStates = {};
  9207. const defaultState = createBindingState( null );
  9208. let currentState = defaultState;
  9209. function setup( object, material, program, geometry, index ) {
  9210. let updateBuffers = false;
  9211. if ( vaoAvailable ) {
  9212. const state = getBindingState( geometry, program, material );
  9213. if ( currentState !== state ) {
  9214. currentState = state;
  9215. bindVertexArrayObject( currentState.object );
  9216. }
  9217. updateBuffers = needsUpdate( geometry, index );
  9218. if ( updateBuffers ) saveCache( geometry, index );
  9219. } else {
  9220. const wireframe = ( material.wireframe === true );
  9221. if ( currentState.geometry !== geometry.id ||
  9222. currentState.program !== program.id ||
  9223. currentState.wireframe !== wireframe ) {
  9224. currentState.geometry = geometry.id;
  9225. currentState.program = program.id;
  9226. currentState.wireframe = wireframe;
  9227. updateBuffers = true;
  9228. }
  9229. }
  9230. if ( object.isInstancedMesh === true ) {
  9231. updateBuffers = true;
  9232. }
  9233. if ( index !== null ) {
  9234. attributes.update( index, 34963 );
  9235. }
  9236. if ( updateBuffers ) {
  9237. setupVertexAttributes( object, material, program, geometry );
  9238. if ( index !== null ) {
  9239. gl.bindBuffer( 34963, attributes.get( index ).buffer );
  9240. }
  9241. }
  9242. }
  9243. function createVertexArrayObject() {
  9244. if ( capabilities.isWebGL2 ) return gl.createVertexArray();
  9245. return extension.createVertexArrayOES();
  9246. }
  9247. function bindVertexArrayObject( vao ) {
  9248. if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
  9249. return extension.bindVertexArrayOES( vao );
  9250. }
  9251. function deleteVertexArrayObject( vao ) {
  9252. if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
  9253. return extension.deleteVertexArrayOES( vao );
  9254. }
  9255. function getBindingState( geometry, program, material ) {
  9256. const wireframe = ( material.wireframe === true );
  9257. let programMap = bindingStates[ geometry.id ];
  9258. if ( programMap === undefined ) {
  9259. programMap = {};
  9260. bindingStates[ geometry.id ] = programMap;
  9261. }
  9262. let stateMap = programMap[ program.id ];
  9263. if ( stateMap === undefined ) {
  9264. stateMap = {};
  9265. programMap[ program.id ] = stateMap;
  9266. }
  9267. let state = stateMap[ wireframe ];
  9268. if ( state === undefined ) {
  9269. state = createBindingState( createVertexArrayObject() );
  9270. stateMap[ wireframe ] = state;
  9271. }
  9272. return state;
  9273. }
  9274. function createBindingState( vao ) {
  9275. const newAttributes = [];
  9276. const enabledAttributes = [];
  9277. const attributeDivisors = [];
  9278. for ( let i = 0; i < maxVertexAttributes; i ++ ) {
  9279. newAttributes[ i ] = 0;
  9280. enabledAttributes[ i ] = 0;
  9281. attributeDivisors[ i ] = 0;
  9282. }
  9283. return {
  9284. // for backward compatibility on non-VAO support browser
  9285. geometry: null,
  9286. program: null,
  9287. wireframe: false,
  9288. newAttributes: newAttributes,
  9289. enabledAttributes: enabledAttributes,
  9290. attributeDivisors: attributeDivisors,
  9291. object: vao,
  9292. attributes: {},
  9293. index: null
  9294. };
  9295. }
  9296. function needsUpdate( geometry, index ) {
  9297. const cachedAttributes = currentState.attributes;
  9298. const geometryAttributes = geometry.attributes;
  9299. let attributesNum = 0;
  9300. for ( const key in geometryAttributes ) {
  9301. const cachedAttribute = cachedAttributes[ key ];
  9302. const geometryAttribute = geometryAttributes[ key ];
  9303. if ( cachedAttribute === undefined ) return true;
  9304. if ( cachedAttribute.attribute !== geometryAttribute ) return true;
  9305. if ( cachedAttribute.data !== geometryAttribute.data ) return true;
  9306. attributesNum ++;
  9307. }
  9308. if ( currentState.attributesNum !== attributesNum ) return true;
  9309. if ( currentState.index !== index ) return true;
  9310. return false;
  9311. }
  9312. function saveCache( geometry, index ) {
  9313. const cache = {};
  9314. const attributes = geometry.attributes;
  9315. let attributesNum = 0;
  9316. for ( const key in attributes ) {
  9317. const attribute = attributes[ key ];
  9318. const data = {};
  9319. data.attribute = attribute;
  9320. if ( attribute.data ) {
  9321. data.data = attribute.data;
  9322. }
  9323. cache[ key ] = data;
  9324. attributesNum ++;
  9325. }
  9326. currentState.attributes = cache;
  9327. currentState.attributesNum = attributesNum;
  9328. currentState.index = index;
  9329. }
  9330. function initAttributes() {
  9331. const newAttributes = currentState.newAttributes;
  9332. for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
  9333. newAttributes[ i ] = 0;
  9334. }
  9335. }
  9336. function enableAttribute( attribute ) {
  9337. enableAttributeAndDivisor( attribute, 0 );
  9338. }
  9339. function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
  9340. const newAttributes = currentState.newAttributes;
  9341. const enabledAttributes = currentState.enabledAttributes;
  9342. const attributeDivisors = currentState.attributeDivisors;
  9343. newAttributes[ attribute ] = 1;
  9344. if ( enabledAttributes[ attribute ] === 0 ) {
  9345. gl.enableVertexAttribArray( attribute );
  9346. enabledAttributes[ attribute ] = 1;
  9347. }
  9348. if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
  9349. const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
  9350. extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
  9351. attributeDivisors[ attribute ] = meshPerAttribute;
  9352. }
  9353. }
  9354. function disableUnusedAttributes() {
  9355. const newAttributes = currentState.newAttributes;
  9356. const enabledAttributes = currentState.enabledAttributes;
  9357. for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
  9358. if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
  9359. gl.disableVertexAttribArray( i );
  9360. enabledAttributes[ i ] = 0;
  9361. }
  9362. }
  9363. }
  9364. function vertexAttribPointer( index, size, type, normalized, stride, offset ) {
  9365. if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) {
  9366. gl.vertexAttribIPointer( index, size, type, stride, offset );
  9367. } else {
  9368. gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
  9369. }
  9370. }
  9371. function setupVertexAttributes( object, material, program, geometry ) {
  9372. if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
  9373. if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
  9374. }
  9375. initAttributes();
  9376. const geometryAttributes = geometry.attributes;
  9377. const programAttributes = program.getAttributes();
  9378. const materialDefaultAttributeValues = material.defaultAttributeValues;
  9379. for ( const name in programAttributes ) {
  9380. const programAttribute = programAttributes[ name ];
  9381. if ( programAttribute >= 0 ) {
  9382. const geometryAttribute = geometryAttributes[ name ];
  9383. if ( geometryAttribute !== undefined ) {
  9384. const normalized = geometryAttribute.normalized;
  9385. const size = geometryAttribute.itemSize;
  9386. const attribute = attributes.get( geometryAttribute );
  9387. // TODO Attribute may not be available on context restore
  9388. if ( attribute === undefined ) continue;
  9389. const buffer = attribute.buffer;
  9390. const type = attribute.type;
  9391. const bytesPerElement = attribute.bytesPerElement;
  9392. if ( geometryAttribute.isInterleavedBufferAttribute ) {
  9393. const data = geometryAttribute.data;
  9394. const stride = data.stride;
  9395. const offset = geometryAttribute.offset;
  9396. if ( data && data.isInstancedInterleavedBuffer ) {
  9397. enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
  9398. if ( geometry._maxInstanceCount === undefined ) {
  9399. geometry._maxInstanceCount = data.meshPerAttribute * data.count;
  9400. }
  9401. } else {
  9402. enableAttribute( programAttribute );
  9403. }
  9404. gl.bindBuffer( 34962, buffer );
  9405. vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement );
  9406. } else {
  9407. if ( geometryAttribute.isInstancedBufferAttribute ) {
  9408. enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
  9409. if ( geometry._maxInstanceCount === undefined ) {
  9410. geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
  9411. }
  9412. } else {
  9413. enableAttribute( programAttribute );
  9414. }
  9415. gl.bindBuffer( 34962, buffer );
  9416. vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 );
  9417. }
  9418. } else if ( name === 'instanceMatrix' ) {
  9419. const attribute = attributes.get( object.instanceMatrix );
  9420. // TODO Attribute may not be available on context restore
  9421. if ( attribute === undefined ) continue;
  9422. const buffer = attribute.buffer;
  9423. const type = attribute.type;
  9424. enableAttributeAndDivisor( programAttribute + 0, 1 );
  9425. enableAttributeAndDivisor( programAttribute + 1, 1 );
  9426. enableAttributeAndDivisor( programAttribute + 2, 1 );
  9427. enableAttributeAndDivisor( programAttribute + 3, 1 );
  9428. gl.bindBuffer( 34962, buffer );
  9429. gl.vertexAttribPointer( programAttribute + 0, 4, type, false, 64, 0 );
  9430. gl.vertexAttribPointer( programAttribute + 1, 4, type, false, 64, 16 );
  9431. gl.vertexAttribPointer( programAttribute + 2, 4, type, false, 64, 32 );
  9432. gl.vertexAttribPointer( programAttribute + 3, 4, type, false, 64, 48 );
  9433. } else if ( name === 'instanceColor' ) {
  9434. const attribute = attributes.get( object.instanceColor );
  9435. // TODO Attribute may not be available on context restore
  9436. if ( attribute === undefined ) continue;
  9437. const buffer = attribute.buffer;
  9438. const type = attribute.type;
  9439. enableAttributeAndDivisor( programAttribute, 1 );
  9440. gl.bindBuffer( 34962, buffer );
  9441. gl.vertexAttribPointer( programAttribute, 3, type, false, 12, 0 );
  9442. } else if ( materialDefaultAttributeValues !== undefined ) {
  9443. const value = materialDefaultAttributeValues[ name ];
  9444. if ( value !== undefined ) {
  9445. switch ( value.length ) {
  9446. case 2:
  9447. gl.vertexAttrib2fv( programAttribute, value );
  9448. break;
  9449. case 3:
  9450. gl.vertexAttrib3fv( programAttribute, value );
  9451. break;
  9452. case 4:
  9453. gl.vertexAttrib4fv( programAttribute, value );
  9454. break;
  9455. default:
  9456. gl.vertexAttrib1fv( programAttribute, value );
  9457. }
  9458. }
  9459. }
  9460. }
  9461. }
  9462. disableUnusedAttributes();
  9463. }
  9464. function dispose() {
  9465. reset();
  9466. for ( const geometryId in bindingStates ) {
  9467. const programMap = bindingStates[ geometryId ];
  9468. for ( const programId in programMap ) {
  9469. const stateMap = programMap[ programId ];
  9470. for ( const wireframe in stateMap ) {
  9471. deleteVertexArrayObject( stateMap[ wireframe ].object );
  9472. delete stateMap[ wireframe ];
  9473. }
  9474. delete programMap[ programId ];
  9475. }
  9476. delete bindingStates[ geometryId ];
  9477. }
  9478. }
  9479. function releaseStatesOfGeometry( geometry ) {
  9480. if ( bindingStates[ geometry.id ] === undefined ) return;
  9481. const programMap = bindingStates[ geometry.id ];
  9482. for ( const programId in programMap ) {
  9483. const stateMap = programMap[ programId ];
  9484. for ( const wireframe in stateMap ) {
  9485. deleteVertexArrayObject( stateMap[ wireframe ].object );
  9486. delete stateMap[ wireframe ];
  9487. }
  9488. delete programMap[ programId ];
  9489. }
  9490. delete bindingStates[ geometry.id ];
  9491. }
  9492. function releaseStatesOfProgram( program ) {
  9493. for ( const geometryId in bindingStates ) {
  9494. const programMap = bindingStates[ geometryId ];
  9495. if ( programMap[ program.id ] === undefined ) continue;
  9496. const stateMap = programMap[ program.id ];
  9497. for ( const wireframe in stateMap ) {
  9498. deleteVertexArrayObject( stateMap[ wireframe ].object );
  9499. delete stateMap[ wireframe ];
  9500. }
  9501. delete programMap[ program.id ];
  9502. }
  9503. }
  9504. function reset() {
  9505. resetDefaultState();
  9506. if ( currentState === defaultState ) return;
  9507. currentState = defaultState;
  9508. bindVertexArrayObject( currentState.object );
  9509. }
  9510. // for backward-compatilibity
  9511. function resetDefaultState() {
  9512. defaultState.geometry = null;
  9513. defaultState.program = null;
  9514. defaultState.wireframe = false;
  9515. }
  9516. return {
  9517. setup: setup,
  9518. reset: reset,
  9519. resetDefaultState: resetDefaultState,
  9520. dispose: dispose,
  9521. releaseStatesOfGeometry: releaseStatesOfGeometry,
  9522. releaseStatesOfProgram: releaseStatesOfProgram,
  9523. initAttributes: initAttributes,
  9524. enableAttribute: enableAttribute,
  9525. disableUnusedAttributes: disableUnusedAttributes
  9526. };
  9527. }
  9528. function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
  9529. const isWebGL2 = capabilities.isWebGL2;
  9530. let mode;
  9531. function setMode( value ) {
  9532. mode = value;
  9533. }
  9534. function render( start, count ) {
  9535. gl.drawArrays( mode, start, count );
  9536. info.update( count, mode, 1 );
  9537. }
  9538. function renderInstances( start, count, primcount ) {
  9539. if ( primcount === 0 ) return;
  9540. let extension, methodName;
  9541. if ( isWebGL2 ) {
  9542. extension = gl;
  9543. methodName = 'drawArraysInstanced';
  9544. } else {
  9545. extension = extensions.get( 'ANGLE_instanced_arrays' );
  9546. methodName = 'drawArraysInstancedANGLE';
  9547. if ( extension === null ) {
  9548. console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
  9549. return;
  9550. }
  9551. }
  9552. extension[ methodName ]( mode, start, count, primcount );
  9553. info.update( count, mode, primcount );
  9554. }
  9555. //
  9556. this.setMode = setMode;
  9557. this.render = render;
  9558. this.renderInstances = renderInstances;
  9559. }
  9560. function WebGLCapabilities( gl, extensions, parameters ) {
  9561. let maxAnisotropy;
  9562. function getMaxAnisotropy() {
  9563. if ( maxAnisotropy !== undefined ) return maxAnisotropy;
  9564. const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
  9565. if ( extension !== null ) {
  9566. maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
  9567. } else {
  9568. maxAnisotropy = 0;
  9569. }
  9570. return maxAnisotropy;
  9571. }
  9572. function getMaxPrecision( precision ) {
  9573. if ( precision === 'highp' ) {
  9574. if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 &&
  9575. gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) {
  9576. return 'highp';
  9577. }
  9578. precision = 'mediump';
  9579. }
  9580. if ( precision === 'mediump' ) {
  9581. if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 &&
  9582. gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) {
  9583. return 'mediump';
  9584. }
  9585. }
  9586. return 'lowp';
  9587. }
  9588. /* eslint-disable no-undef */
  9589. const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) ||
  9590. ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext );
  9591. /* eslint-enable no-undef */
  9592. let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
  9593. const maxPrecision = getMaxPrecision( precision );
  9594. if ( maxPrecision !== precision ) {
  9595. console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
  9596. precision = maxPrecision;
  9597. }
  9598. const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
  9599. const maxTextures = gl.getParameter( 34930 );
  9600. const maxVertexTextures = gl.getParameter( 35660 );
  9601. const maxTextureSize = gl.getParameter( 3379 );
  9602. const maxCubemapSize = gl.getParameter( 34076 );
  9603. const maxAttributes = gl.getParameter( 34921 );
  9604. const maxVertexUniforms = gl.getParameter( 36347 );
  9605. const maxVaryings = gl.getParameter( 36348 );
  9606. const maxFragmentUniforms = gl.getParameter( 36349 );
  9607. const vertexTextures = maxVertexTextures > 0;
  9608. const floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' );
  9609. const floatVertexTextures = vertexTextures && floatFragmentTextures;
  9610. const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0;
  9611. return {
  9612. isWebGL2: isWebGL2,
  9613. getMaxAnisotropy: getMaxAnisotropy,
  9614. getMaxPrecision: getMaxPrecision,
  9615. precision: precision,
  9616. logarithmicDepthBuffer: logarithmicDepthBuffer,
  9617. maxTextures: maxTextures,
  9618. maxVertexTextures: maxVertexTextures,
  9619. maxTextureSize: maxTextureSize,
  9620. maxCubemapSize: maxCubemapSize,
  9621. maxAttributes: maxAttributes,
  9622. maxVertexUniforms: maxVertexUniforms,
  9623. maxVaryings: maxVaryings,
  9624. maxFragmentUniforms: maxFragmentUniforms,
  9625. vertexTextures: vertexTextures,
  9626. floatFragmentTextures: floatFragmentTextures,
  9627. floatVertexTextures: floatVertexTextures,
  9628. maxSamples: maxSamples
  9629. };
  9630. }
  9631. function WebGLClipping( properties ) {
  9632. const scope = this;
  9633. let globalState = null,
  9634. numGlobalPlanes = 0,
  9635. localClippingEnabled = false,
  9636. renderingShadows = false;
  9637. const plane = new Plane(),
  9638. viewNormalMatrix = new Matrix3(),
  9639. uniform = { value: null, needsUpdate: false };
  9640. this.uniform = uniform;
  9641. this.numPlanes = 0;
  9642. this.numIntersection = 0;
  9643. this.init = function ( planes, enableLocalClipping, camera ) {
  9644. const enabled =
  9645. planes.length !== 0 ||
  9646. enableLocalClipping ||
  9647. // enable state of previous frame - the clipping code has to
  9648. // run another frame in order to reset the state:
  9649. numGlobalPlanes !== 0 ||
  9650. localClippingEnabled;
  9651. localClippingEnabled = enableLocalClipping;
  9652. globalState = projectPlanes( planes, camera, 0 );
  9653. numGlobalPlanes = planes.length;
  9654. return enabled;
  9655. };
  9656. this.beginShadows = function () {
  9657. renderingShadows = true;
  9658. projectPlanes( null );
  9659. };
  9660. this.endShadows = function () {
  9661. renderingShadows = false;
  9662. resetGlobalState();
  9663. };
  9664. this.setState = function ( material, camera, useCache ) {
  9665. const planes = material.clippingPlanes,
  9666. clipIntersection = material.clipIntersection,
  9667. clipShadows = material.clipShadows;
  9668. const materialProperties = properties.get( material );
  9669. if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
  9670. // there's no local clipping
  9671. if ( renderingShadows ) {
  9672. // there's no global clipping
  9673. projectPlanes( null );
  9674. } else {
  9675. resetGlobalState();
  9676. }
  9677. } else {
  9678. const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
  9679. lGlobal = nGlobal * 4;
  9680. let dstArray = materialProperties.clippingState || null;
  9681. uniform.value = dstArray; // ensure unique state
  9682. dstArray = projectPlanes( planes, camera, lGlobal, useCache );
  9683. for ( let i = 0; i !== lGlobal; ++ i ) {
  9684. dstArray[ i ] = globalState[ i ];
  9685. }
  9686. materialProperties.clippingState = dstArray;
  9687. this.numIntersection = clipIntersection ? this.numPlanes : 0;
  9688. this.numPlanes += nGlobal;
  9689. }
  9690. };
  9691. function resetGlobalState() {
  9692. if ( uniform.value !== globalState ) {
  9693. uniform.value = globalState;
  9694. uniform.needsUpdate = numGlobalPlanes > 0;
  9695. }
  9696. scope.numPlanes = numGlobalPlanes;
  9697. scope.numIntersection = 0;
  9698. }
  9699. function projectPlanes( planes, camera, dstOffset, skipTransform ) {
  9700. const nPlanes = planes !== null ? planes.length : 0;
  9701. let dstArray = null;
  9702. if ( nPlanes !== 0 ) {
  9703. dstArray = uniform.value;
  9704. if ( skipTransform !== true || dstArray === null ) {
  9705. const flatSize = dstOffset + nPlanes * 4,
  9706. viewMatrix = camera.matrixWorldInverse;
  9707. viewNormalMatrix.getNormalMatrix( viewMatrix );
  9708. if ( dstArray === null || dstArray.length < flatSize ) {
  9709. dstArray = new Float32Array( flatSize );
  9710. }
  9711. for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
  9712. plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
  9713. plane.normal.toArray( dstArray, i4 );
  9714. dstArray[ i4 + 3 ] = plane.constant;
  9715. }
  9716. }
  9717. uniform.value = dstArray;
  9718. uniform.needsUpdate = true;
  9719. }
  9720. scope.numPlanes = nPlanes;
  9721. scope.numIntersection = 0;
  9722. return dstArray;
  9723. }
  9724. }
  9725. function WebGLCubeMaps( renderer ) {
  9726. let cubemaps = new WeakMap();
  9727. function mapTextureMapping( texture, mapping ) {
  9728. if ( mapping === EquirectangularReflectionMapping ) {
  9729. texture.mapping = CubeReflectionMapping;
  9730. } else if ( mapping === EquirectangularRefractionMapping ) {
  9731. texture.mapping = CubeRefractionMapping;
  9732. }
  9733. return texture;
  9734. }
  9735. function get( texture ) {
  9736. if ( texture && texture.isTexture ) {
  9737. const mapping = texture.mapping;
  9738. if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
  9739. if ( cubemaps.has( texture ) ) {
  9740. const cubemap = cubemaps.get( texture ).texture;
  9741. return mapTextureMapping( cubemap, texture.mapping );
  9742. } else {
  9743. const image = texture.image;
  9744. if ( image && image.height > 0 ) {
  9745. const currentRenderList = renderer.getRenderList();
  9746. const currentRenderTarget = renderer.getRenderTarget();
  9747. const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
  9748. renderTarget.fromEquirectangularTexture( renderer, texture );
  9749. cubemaps.set( texture, renderTarget );
  9750. renderer.setRenderTarget( currentRenderTarget );
  9751. renderer.setRenderList( currentRenderList );
  9752. texture.addEventListener( 'dispose', onTextureDispose );
  9753. return mapTextureMapping( renderTarget.texture, texture.mapping );
  9754. } else {
  9755. // image not yet ready. try the conversion next frame
  9756. return null;
  9757. }
  9758. }
  9759. }
  9760. }
  9761. return texture;
  9762. }
  9763. function onTextureDispose( event ) {
  9764. const texture = event.target;
  9765. texture.removeEventListener( 'dispose', onTextureDispose );
  9766. const cubemap = cubemaps.get( texture );
  9767. if ( cubemap !== undefined ) {
  9768. cubemaps.delete( texture );
  9769. cubemap.dispose();
  9770. }
  9771. }
  9772. function dispose() {
  9773. cubemaps = new WeakMap();
  9774. }
  9775. return {
  9776. get: get,
  9777. dispose: dispose
  9778. };
  9779. }
  9780. function WebGLExtensions( gl ) {
  9781. const extensions = {};
  9782. return {
  9783. has: function ( name ) {
  9784. if ( extensions[ name ] !== undefined ) {
  9785. return extensions[ name ] !== null;
  9786. }
  9787. let extension;
  9788. switch ( name ) {
  9789. case 'WEBGL_depth_texture':
  9790. extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
  9791. break;
  9792. case 'EXT_texture_filter_anisotropic':
  9793. extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
  9794. break;
  9795. case 'WEBGL_compressed_texture_s3tc':
  9796. extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
  9797. break;
  9798. case 'WEBGL_compressed_texture_pvrtc':
  9799. extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
  9800. break;
  9801. default:
  9802. extension = gl.getExtension( name );
  9803. }
  9804. extensions[ name ] = extension;
  9805. return extension !== null;
  9806. },
  9807. get: function ( name ) {
  9808. if ( ! this.has( name ) ) {
  9809. console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
  9810. }
  9811. return extensions[ name ];
  9812. }
  9813. };
  9814. }
  9815. function WebGLGeometries( gl, attributes, info, bindingStates ) {
  9816. const geometries = new WeakMap();
  9817. const wireframeAttributes = new WeakMap();
  9818. function onGeometryDispose( event ) {
  9819. const geometry = event.target;
  9820. const buffergeometry = geometries.get( geometry );
  9821. if ( buffergeometry.index !== null ) {
  9822. attributes.remove( buffergeometry.index );
  9823. }
  9824. for ( const name in buffergeometry.attributes ) {
  9825. attributes.remove( buffergeometry.attributes[ name ] );
  9826. }
  9827. geometry.removeEventListener( 'dispose', onGeometryDispose );
  9828. geometries.delete( geometry );
  9829. const attribute = wireframeAttributes.get( buffergeometry );
  9830. if ( attribute ) {
  9831. attributes.remove( attribute );
  9832. wireframeAttributes.delete( buffergeometry );
  9833. }
  9834. bindingStates.releaseStatesOfGeometry( buffergeometry );
  9835. if ( geometry.isInstancedBufferGeometry === true ) {
  9836. delete geometry._maxInstanceCount;
  9837. }
  9838. //
  9839. info.memory.geometries --;
  9840. }
  9841. function get( object, geometry ) {
  9842. let buffergeometry = geometries.get( geometry );
  9843. if ( buffergeometry ) return buffergeometry;
  9844. geometry.addEventListener( 'dispose', onGeometryDispose );
  9845. if ( geometry.isBufferGeometry ) {
  9846. buffergeometry = geometry;
  9847. } else if ( geometry.isGeometry ) {
  9848. if ( geometry._bufferGeometry === undefined ) {
  9849. geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
  9850. }
  9851. buffergeometry = geometry._bufferGeometry;
  9852. }
  9853. geometries.set( geometry, buffergeometry );
  9854. info.memory.geometries ++;
  9855. return buffergeometry;
  9856. }
  9857. function update( geometry ) {
  9858. const geometryAttributes = geometry.attributes;
  9859. // Updating index buffer in VAO now. See WebGLBindingStates.
  9860. for ( const name in geometryAttributes ) {
  9861. attributes.update( geometryAttributes[ name ], 34962 );
  9862. }
  9863. // morph targets
  9864. const morphAttributes = geometry.morphAttributes;
  9865. for ( const name in morphAttributes ) {
  9866. const array = morphAttributes[ name ];
  9867. for ( let i = 0, l = array.length; i < l; i ++ ) {
  9868. attributes.update( array[ i ], 34962 );
  9869. }
  9870. }
  9871. }
  9872. function updateWireframeAttribute( geometry ) {
  9873. const indices = [];
  9874. const geometryIndex = geometry.index;
  9875. const geometryPosition = geometry.attributes.position;
  9876. let version = 0;
  9877. if ( geometryIndex !== null ) {
  9878. const array = geometryIndex.array;
  9879. version = geometryIndex.version;
  9880. for ( let i = 0, l = array.length; i < l; i += 3 ) {
  9881. const a = array[ i + 0 ];
  9882. const b = array[ i + 1 ];
  9883. const c = array[ i + 2 ];
  9884. indices.push( a, b, b, c, c, a );
  9885. }
  9886. } else {
  9887. const array = geometryPosition.array;
  9888. version = geometryPosition.version;
  9889. for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
  9890. const a = i + 0;
  9891. const b = i + 1;
  9892. const c = i + 2;
  9893. indices.push( a, b, b, c, c, a );
  9894. }
  9895. }
  9896. const attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
  9897. attribute.version = version;
  9898. // Updating index buffer in VAO now. See WebGLBindingStates
  9899. //
  9900. const previousAttribute = wireframeAttributes.get( geometry );
  9901. if ( previousAttribute ) attributes.remove( previousAttribute );
  9902. //
  9903. wireframeAttributes.set( geometry, attribute );
  9904. }
  9905. function getWireframeAttribute( geometry ) {
  9906. const currentAttribute = wireframeAttributes.get( geometry );
  9907. if ( currentAttribute ) {
  9908. const geometryIndex = geometry.index;
  9909. if ( geometryIndex !== null ) {
  9910. // if the attribute is obsolete, create a new one
  9911. if ( currentAttribute.version < geometryIndex.version ) {
  9912. updateWireframeAttribute( geometry );
  9913. }
  9914. }
  9915. } else {
  9916. updateWireframeAttribute( geometry );
  9917. }
  9918. return wireframeAttributes.get( geometry );
  9919. }
  9920. return {
  9921. get: get,
  9922. update: update,
  9923. getWireframeAttribute: getWireframeAttribute
  9924. };
  9925. }
  9926. function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
  9927. const isWebGL2 = capabilities.isWebGL2;
  9928. let mode;
  9929. function setMode( value ) {
  9930. mode = value;
  9931. }
  9932. let type, bytesPerElement;
  9933. function setIndex( value ) {
  9934. type = value.type;
  9935. bytesPerElement = value.bytesPerElement;
  9936. }
  9937. function render( start, count ) {
  9938. gl.drawElements( mode, count, type, start * bytesPerElement );
  9939. info.update( count, mode, 1 );
  9940. }
  9941. function renderInstances( start, count, primcount ) {
  9942. if ( primcount === 0 ) return;
  9943. let extension, methodName;
  9944. if ( isWebGL2 ) {
  9945. extension = gl;
  9946. methodName = 'drawElementsInstanced';
  9947. } else {
  9948. extension = extensions.get( 'ANGLE_instanced_arrays' );
  9949. methodName = 'drawElementsInstancedANGLE';
  9950. if ( extension === null ) {
  9951. console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
  9952. return;
  9953. }
  9954. }
  9955. extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
  9956. info.update( count, mode, primcount );
  9957. }
  9958. //
  9959. this.setMode = setMode;
  9960. this.setIndex = setIndex;
  9961. this.render = render;
  9962. this.renderInstances = renderInstances;
  9963. }
  9964. function WebGLInfo( gl ) {
  9965. const memory = {
  9966. geometries: 0,
  9967. textures: 0
  9968. };
  9969. const render = {
  9970. frame: 0,
  9971. calls: 0,
  9972. triangles: 0,
  9973. points: 0,
  9974. lines: 0
  9975. };
  9976. function update( count, mode, instanceCount ) {
  9977. render.calls ++;
  9978. switch ( mode ) {
  9979. case 4:
  9980. render.triangles += instanceCount * ( count / 3 );
  9981. break;
  9982. case 1:
  9983. render.lines += instanceCount * ( count / 2 );
  9984. break;
  9985. case 3:
  9986. render.lines += instanceCount * ( count - 1 );
  9987. break;
  9988. case 2:
  9989. render.lines += instanceCount * count;
  9990. break;
  9991. case 0:
  9992. render.points += instanceCount * count;
  9993. break;
  9994. default:
  9995. console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
  9996. break;
  9997. }
  9998. }
  9999. function reset() {
  10000. render.frame ++;
  10001. render.calls = 0;
  10002. render.triangles = 0;
  10003. render.points = 0;
  10004. render.lines = 0;
  10005. }
  10006. return {
  10007. memory: memory,
  10008. render: render,
  10009. programs: null,
  10010. autoReset: true,
  10011. reset: reset,
  10012. update: update
  10013. };
  10014. }
  10015. function numericalSort( a, b ) {
  10016. return a[ 0 ] - b[ 0 ];
  10017. }
  10018. function absNumericalSort( a, b ) {
  10019. return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
  10020. }
  10021. function WebGLMorphtargets( gl ) {
  10022. const influencesList = {};
  10023. const morphInfluences = new Float32Array( 8 );
  10024. const workInfluences = [];
  10025. for ( let i = 0; i < 8; i ++ ) {
  10026. workInfluences[ i ] = [ i, 0 ];
  10027. }
  10028. function update( object, geometry, material, program ) {
  10029. const objectInfluences = object.morphTargetInfluences;
  10030. // When object doesn't have morph target influences defined, we treat it as a 0-length array
  10031. // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
  10032. const length = objectInfluences === undefined ? 0 : objectInfluences.length;
  10033. let influences = influencesList[ geometry.id ];
  10034. if ( influences === undefined ) {
  10035. // initialise list
  10036. influences = [];
  10037. for ( let i = 0; i < length; i ++ ) {
  10038. influences[ i ] = [ i, 0 ];
  10039. }
  10040. influencesList[ geometry.id ] = influences;
  10041. }
  10042. // Collect influences
  10043. for ( let i = 0; i < length; i ++ ) {
  10044. const influence = influences[ i ];
  10045. influence[ 0 ] = i;
  10046. influence[ 1 ] = objectInfluences[ i ];
  10047. }
  10048. influences.sort( absNumericalSort );
  10049. for ( let i = 0; i < 8; i ++ ) {
  10050. if ( i < length && influences[ i ][ 1 ] ) {
  10051. workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
  10052. workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
  10053. } else {
  10054. workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
  10055. workInfluences[ i ][ 1 ] = 0;
  10056. }
  10057. }
  10058. workInfluences.sort( numericalSort );
  10059. const morphTargets = material.morphTargets && geometry.morphAttributes.position;
  10060. const morphNormals = material.morphNormals && geometry.morphAttributes.normal;
  10061. let morphInfluencesSum = 0;
  10062. for ( let i = 0; i < 8; i ++ ) {
  10063. const influence = workInfluences[ i ];
  10064. const index = influence[ 0 ];
  10065. const value = influence[ 1 ];
  10066. if ( index !== Number.MAX_SAFE_INTEGER && value ) {
  10067. if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
  10068. geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
  10069. }
  10070. if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
  10071. geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
  10072. }
  10073. morphInfluences[ i ] = value;
  10074. morphInfluencesSum += value;
  10075. } else {
  10076. if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
  10077. geometry.deleteAttribute( 'morphTarget' + i );
  10078. }
  10079. if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
  10080. geometry.deleteAttribute( 'morphNormal' + i );
  10081. }
  10082. morphInfluences[ i ] = 0;
  10083. }
  10084. }
  10085. // GLSL shader uses formula baseinfluence * base + sum(target * influence)
  10086. // This allows us to switch between absolute morphs and relative morphs without changing shader code
  10087. // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
  10088. const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
  10089. program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
  10090. program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
  10091. }
  10092. return {
  10093. update: update
  10094. };
  10095. }
  10096. function WebGLObjects( gl, geometries, attributes, info ) {
  10097. let updateMap = new WeakMap();
  10098. function update( object ) {
  10099. const frame = info.render.frame;
  10100. const geometry = object.geometry;
  10101. const buffergeometry = geometries.get( object, geometry );
  10102. // Update once per frame
  10103. if ( updateMap.get( buffergeometry ) !== frame ) {
  10104. if ( geometry.isGeometry ) {
  10105. buffergeometry.updateFromObject( object );
  10106. }
  10107. geometries.update( buffergeometry );
  10108. updateMap.set( buffergeometry, frame );
  10109. }
  10110. if ( object.isInstancedMesh ) {
  10111. if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
  10112. object.addEventListener( 'dispose', onInstancedMeshDispose );
  10113. }
  10114. attributes.update( object.instanceMatrix, 34962 );
  10115. if ( object.instanceColor !== null ) {
  10116. attributes.update( object.instanceColor, 34962 );
  10117. }
  10118. }
  10119. return buffergeometry;
  10120. }
  10121. function dispose() {
  10122. updateMap = new WeakMap();
  10123. }
  10124. function onInstancedMeshDispose( event ) {
  10125. const instancedMesh = event.target;
  10126. instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
  10127. attributes.remove( instancedMesh.instanceMatrix );
  10128. if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
  10129. }
  10130. return {
  10131. update: update,
  10132. dispose: dispose
  10133. };
  10134. }
  10135. function DataTexture2DArray( data = null, width = 1, height = 1, depth = 1 ) {
  10136. Texture.call( this, null );
  10137. this.image = { data, width, height, depth };
  10138. this.magFilter = NearestFilter;
  10139. this.minFilter = NearestFilter;
  10140. this.wrapR = ClampToEdgeWrapping;
  10141. this.generateMipmaps = false;
  10142. this.flipY = false;
  10143. this.needsUpdate = true;
  10144. }
  10145. DataTexture2DArray.prototype = Object.create( Texture.prototype );
  10146. DataTexture2DArray.prototype.constructor = DataTexture2DArray;
  10147. DataTexture2DArray.prototype.isDataTexture2DArray = true;
  10148. function DataTexture3D( data = null, width = 1, height = 1, depth = 1 ) {
  10149. // We're going to add .setXXX() methods for setting properties later.
  10150. // Users can still set in DataTexture3D directly.
  10151. //
  10152. // const texture = new THREE.DataTexture3D( data, width, height, depth );
  10153. // texture.anisotropy = 16;
  10154. //
  10155. // See #14839
  10156. Texture.call( this, null );
  10157. this.image = { data, width, height, depth };
  10158. this.magFilter = NearestFilter;
  10159. this.minFilter = NearestFilter;
  10160. this.wrapR = ClampToEdgeWrapping;
  10161. this.generateMipmaps = false;
  10162. this.flipY = false;
  10163. this.needsUpdate = true;
  10164. }
  10165. DataTexture3D.prototype = Object.create( Texture.prototype );
  10166. DataTexture3D.prototype.constructor = DataTexture3D;
  10167. DataTexture3D.prototype.isDataTexture3D = true;
  10168. /**
  10169. * Uniforms of a program.
  10170. * Those form a tree structure with a special top-level container for the root,
  10171. * which you get by calling 'new WebGLUniforms( gl, program )'.
  10172. *
  10173. *
  10174. * Properties of inner nodes including the top-level container:
  10175. *
  10176. * .seq - array of nested uniforms
  10177. * .map - nested uniforms by name
  10178. *
  10179. *
  10180. * Methods of all nodes except the top-level container:
  10181. *
  10182. * .setValue( gl, value, [textures] )
  10183. *
  10184. * uploads a uniform value(s)
  10185. * the 'textures' parameter is needed for sampler uniforms
  10186. *
  10187. *
  10188. * Static methods of the top-level container (textures factorizations):
  10189. *
  10190. * .upload( gl, seq, values, textures )
  10191. *
  10192. * sets uniforms in 'seq' to 'values[id].value'
  10193. *
  10194. * .seqWithValue( seq, values ) : filteredSeq
  10195. *
  10196. * filters 'seq' entries with corresponding entry in values
  10197. *
  10198. *
  10199. * Methods of the top-level container (textures factorizations):
  10200. *
  10201. * .setValue( gl, name, value, textures )
  10202. *
  10203. * sets uniform with name 'name' to 'value'
  10204. *
  10205. * .setOptional( gl, obj, prop )
  10206. *
  10207. * like .set for an optional property of the object
  10208. *
  10209. */
  10210. const emptyTexture = new Texture();
  10211. const emptyTexture2dArray = new DataTexture2DArray();
  10212. const emptyTexture3d = new DataTexture3D();
  10213. const emptyCubeTexture = new CubeTexture();
  10214. // --- Utilities ---
  10215. // Array Caches (provide typed arrays for temporary by size)
  10216. const arrayCacheF32 = [];
  10217. const arrayCacheI32 = [];
  10218. // Float32Array caches used for uploading Matrix uniforms
  10219. const mat4array = new Float32Array( 16 );
  10220. const mat3array = new Float32Array( 9 );
  10221. const mat2array = new Float32Array( 4 );
  10222. // Flattening for arrays of vectors and matrices
  10223. function flatten( array, nBlocks, blockSize ) {
  10224. const firstElem = array[ 0 ];
  10225. if ( firstElem <= 0 || firstElem > 0 ) return array;
  10226. // unoptimized: ! isNaN( firstElem )
  10227. // see http://jacksondunstan.com/articles/983
  10228. const n = nBlocks * blockSize;
  10229. let r = arrayCacheF32[ n ];
  10230. if ( r === undefined ) {
  10231. r = new Float32Array( n );
  10232. arrayCacheF32[ n ] = r;
  10233. }
  10234. if ( nBlocks !== 0 ) {
  10235. firstElem.toArray( r, 0 );
  10236. for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
  10237. offset += blockSize;
  10238. array[ i ].toArray( r, offset );
  10239. }
  10240. }
  10241. return r;
  10242. }
  10243. function arraysEqual( a, b ) {
  10244. if ( a.length !== b.length ) return false;
  10245. for ( let i = 0, l = a.length; i < l; i ++ ) {
  10246. if ( a[ i ] !== b[ i ] ) return false;
  10247. }
  10248. return true;
  10249. }
  10250. function copyArray( a, b ) {
  10251. for ( let i = 0, l = b.length; i < l; i ++ ) {
  10252. a[ i ] = b[ i ];
  10253. }
  10254. }
  10255. // Texture unit allocation
  10256. function allocTexUnits( textures, n ) {
  10257. let r = arrayCacheI32[ n ];
  10258. if ( r === undefined ) {
  10259. r = new Int32Array( n );
  10260. arrayCacheI32[ n ] = r;
  10261. }
  10262. for ( let i = 0; i !== n; ++ i ) {
  10263. r[ i ] = textures.allocateTextureUnit();
  10264. }
  10265. return r;
  10266. }
  10267. // --- Setters ---
  10268. // Note: Defining these methods externally, because they come in a bunch
  10269. // and this way their names minify.
  10270. // Single scalar
  10271. function setValueV1f( gl, v ) {
  10272. const cache = this.cache;
  10273. if ( cache[ 0 ] === v ) return;
  10274. gl.uniform1f( this.addr, v );
  10275. cache[ 0 ] = v;
  10276. }
  10277. // Single float vector (from flat array or THREE.VectorN)
  10278. function setValueV2f( gl, v ) {
  10279. const cache = this.cache;
  10280. if ( v.x !== undefined ) {
  10281. if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
  10282. gl.uniform2f( this.addr, v.x, v.y );
  10283. cache[ 0 ] = v.x;
  10284. cache[ 1 ] = v.y;
  10285. }
  10286. } else {
  10287. if ( arraysEqual( cache, v ) ) return;
  10288. gl.uniform2fv( this.addr, v );
  10289. copyArray( cache, v );
  10290. }
  10291. }
  10292. function setValueV3f( gl, v ) {
  10293. const cache = this.cache;
  10294. if ( v.x !== undefined ) {
  10295. if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
  10296. gl.uniform3f( this.addr, v.x, v.y, v.z );
  10297. cache[ 0 ] = v.x;
  10298. cache[ 1 ] = v.y;
  10299. cache[ 2 ] = v.z;
  10300. }
  10301. } else if ( v.r !== undefined ) {
  10302. if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
  10303. gl.uniform3f( this.addr, v.r, v.g, v.b );
  10304. cache[ 0 ] = v.r;
  10305. cache[ 1 ] = v.g;
  10306. cache[ 2 ] = v.b;
  10307. }
  10308. } else {
  10309. if ( arraysEqual( cache, v ) ) return;
  10310. gl.uniform3fv( this.addr, v );
  10311. copyArray( cache, v );
  10312. }
  10313. }
  10314. function setValueV4f( gl, v ) {
  10315. const cache = this.cache;
  10316. if ( v.x !== undefined ) {
  10317. if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
  10318. gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
  10319. cache[ 0 ] = v.x;
  10320. cache[ 1 ] = v.y;
  10321. cache[ 2 ] = v.z;
  10322. cache[ 3 ] = v.w;
  10323. }
  10324. } else {
  10325. if ( arraysEqual( cache, v ) ) return;
  10326. gl.uniform4fv( this.addr, v );
  10327. copyArray( cache, v );
  10328. }
  10329. }
  10330. // Single matrix (from flat array or MatrixN)
  10331. function setValueM2( gl, v ) {
  10332. const cache = this.cache;
  10333. const elements = v.elements;
  10334. if ( elements === undefined ) {
  10335. if ( arraysEqual( cache, v ) ) return;
  10336. gl.uniformMatrix2fv( this.addr, false, v );
  10337. copyArray( cache, v );
  10338. } else {
  10339. if ( arraysEqual( cache, elements ) ) return;
  10340. mat2array.set( elements );
  10341. gl.uniformMatrix2fv( this.addr, false, mat2array );
  10342. copyArray( cache, elements );
  10343. }
  10344. }
  10345. function setValueM3( gl, v ) {
  10346. const cache = this.cache;
  10347. const elements = v.elements;
  10348. if ( elements === undefined ) {
  10349. if ( arraysEqual( cache, v ) ) return;
  10350. gl.uniformMatrix3fv( this.addr, false, v );
  10351. copyArray( cache, v );
  10352. } else {
  10353. if ( arraysEqual( cache, elements ) ) return;
  10354. mat3array.set( elements );
  10355. gl.uniformMatrix3fv( this.addr, false, mat3array );
  10356. copyArray( cache, elements );
  10357. }
  10358. }
  10359. function setValueM4( gl, v ) {
  10360. const cache = this.cache;
  10361. const elements = v.elements;
  10362. if ( elements === undefined ) {
  10363. if ( arraysEqual( cache, v ) ) return;
  10364. gl.uniformMatrix4fv( this.addr, false, v );
  10365. copyArray( cache, v );
  10366. } else {
  10367. if ( arraysEqual( cache, elements ) ) return;
  10368. mat4array.set( elements );
  10369. gl.uniformMatrix4fv( this.addr, false, mat4array );
  10370. copyArray( cache, elements );
  10371. }
  10372. }
  10373. // Single texture (2D / Cube)
  10374. function setValueT1( gl, v, textures ) {
  10375. const cache = this.cache;
  10376. const unit = textures.allocateTextureUnit();
  10377. if ( cache[ 0 ] !== unit ) {
  10378. gl.uniform1i( this.addr, unit );
  10379. cache[ 0 ] = unit;
  10380. }
  10381. textures.safeSetTexture2D( v || emptyTexture, unit );
  10382. }
  10383. function setValueT2DArray1( gl, v, textures ) {
  10384. const cache = this.cache;
  10385. const unit = textures.allocateTextureUnit();
  10386. if ( cache[ 0 ] !== unit ) {
  10387. gl.uniform1i( this.addr, unit );
  10388. cache[ 0 ] = unit;
  10389. }
  10390. textures.setTexture2DArray( v || emptyTexture2dArray, unit );
  10391. }
  10392. function setValueT3D1( gl, v, textures ) {
  10393. const cache = this.cache;
  10394. const unit = textures.allocateTextureUnit();
  10395. if ( cache[ 0 ] !== unit ) {
  10396. gl.uniform1i( this.addr, unit );
  10397. cache[ 0 ] = unit;
  10398. }
  10399. textures.setTexture3D( v || emptyTexture3d, unit );
  10400. }
  10401. function setValueT6( gl, v, textures ) {
  10402. const cache = this.cache;
  10403. const unit = textures.allocateTextureUnit();
  10404. if ( cache[ 0 ] !== unit ) {
  10405. gl.uniform1i( this.addr, unit );
  10406. cache[ 0 ] = unit;
  10407. }
  10408. textures.safeSetTextureCube( v || emptyCubeTexture, unit );
  10409. }
  10410. // Integer / Boolean vectors or arrays thereof (always flat arrays)
  10411. function setValueV1i( gl, v ) {
  10412. const cache = this.cache;
  10413. if ( cache[ 0 ] === v ) return;
  10414. gl.uniform1i( this.addr, v );
  10415. cache[ 0 ] = v;
  10416. }
  10417. function setValueV2i( gl, v ) {
  10418. const cache = this.cache;
  10419. if ( arraysEqual( cache, v ) ) return;
  10420. gl.uniform2iv( this.addr, v );
  10421. copyArray( cache, v );
  10422. }
  10423. function setValueV3i( gl, v ) {
  10424. const cache = this.cache;
  10425. if ( arraysEqual( cache, v ) ) return;
  10426. gl.uniform3iv( this.addr, v );
  10427. copyArray( cache, v );
  10428. }
  10429. function setValueV4i( gl, v ) {
  10430. const cache = this.cache;
  10431. if ( arraysEqual( cache, v ) ) return;
  10432. gl.uniform4iv( this.addr, v );
  10433. copyArray( cache, v );
  10434. }
  10435. // uint
  10436. function setValueV1ui( gl, v ) {
  10437. const cache = this.cache;
  10438. if ( cache[ 0 ] === v ) return;
  10439. gl.uniform1ui( this.addr, v );
  10440. cache[ 0 ] = v;
  10441. }
  10442. // Helper to pick the right setter for the singular case
  10443. function getSingularSetter( type ) {
  10444. switch ( type ) {
  10445. case 0x1406: return setValueV1f; // FLOAT
  10446. case 0x8b50: return setValueV2f; // _VEC2
  10447. case 0x8b51: return setValueV3f; // _VEC3
  10448. case 0x8b52: return setValueV4f; // _VEC4
  10449. case 0x8b5a: return setValueM2; // _MAT2
  10450. case 0x8b5b: return setValueM3; // _MAT3
  10451. case 0x8b5c: return setValueM4; // _MAT4
  10452. case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
  10453. case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
  10454. case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
  10455. case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
  10456. case 0x1405: return setValueV1ui; // UINT
  10457. case 0x8b5e: // SAMPLER_2D
  10458. case 0x8d66: // SAMPLER_EXTERNAL_OES
  10459. case 0x8dca: // INT_SAMPLER_2D
  10460. case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
  10461. case 0x8b62: // SAMPLER_2D_SHADOW
  10462. return setValueT1;
  10463. case 0x8b5f: // SAMPLER_3D
  10464. case 0x8dcb: // INT_SAMPLER_3D
  10465. case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
  10466. return setValueT3D1;
  10467. case 0x8b60: // SAMPLER_CUBE
  10468. case 0x8dcc: // INT_SAMPLER_CUBE
  10469. case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
  10470. case 0x8dc5: // SAMPLER_CUBE_SHADOW
  10471. return setValueT6;
  10472. case 0x8dc1: // SAMPLER_2D_ARRAY
  10473. case 0x8dcf: // INT_SAMPLER_2D_ARRAY
  10474. case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
  10475. case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
  10476. return setValueT2DArray1;
  10477. }
  10478. }
  10479. // Array of scalars
  10480. function setValueV1fArray( gl, v ) {
  10481. gl.uniform1fv( this.addr, v );
  10482. }
  10483. // Integer / Boolean vectors or arrays thereof (always flat arrays)
  10484. function setValueV1iArray( gl, v ) {
  10485. gl.uniform1iv( this.addr, v );
  10486. }
  10487. function setValueV2iArray( gl, v ) {
  10488. gl.uniform2iv( this.addr, v );
  10489. }
  10490. function setValueV3iArray( gl, v ) {
  10491. gl.uniform3iv( this.addr, v );
  10492. }
  10493. function setValueV4iArray( gl, v ) {
  10494. gl.uniform4iv( this.addr, v );
  10495. }
  10496. // Array of vectors (flat or from THREE classes)
  10497. function setValueV2fArray( gl, v ) {
  10498. const data = flatten( v, this.size, 2 );
  10499. gl.uniform2fv( this.addr, data );
  10500. }
  10501. function setValueV3fArray( gl, v ) {
  10502. const data = flatten( v, this.size, 3 );
  10503. gl.uniform3fv( this.addr, data );
  10504. }
  10505. function setValueV4fArray( gl, v ) {
  10506. const data = flatten( v, this.size, 4 );
  10507. gl.uniform4fv( this.addr, data );
  10508. }
  10509. // Array of matrices (flat or from THREE clases)
  10510. function setValueM2Array( gl, v ) {
  10511. const data = flatten( v, this.size, 4 );
  10512. gl.uniformMatrix2fv( this.addr, false, data );
  10513. }
  10514. function setValueM3Array( gl, v ) {
  10515. const data = flatten( v, this.size, 9 );
  10516. gl.uniformMatrix3fv( this.addr, false, data );
  10517. }
  10518. function setValueM4Array( gl, v ) {
  10519. const data = flatten( v, this.size, 16 );
  10520. gl.uniformMatrix4fv( this.addr, false, data );
  10521. }
  10522. // Array of textures (2D / Cube)
  10523. function setValueT1Array( gl, v, textures ) {
  10524. const n = v.length;
  10525. const units = allocTexUnits( textures, n );
  10526. gl.uniform1iv( this.addr, units );
  10527. for ( let i = 0; i !== n; ++ i ) {
  10528. textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] );
  10529. }
  10530. }
  10531. function setValueT6Array( gl, v, textures ) {
  10532. const n = v.length;
  10533. const units = allocTexUnits( textures, n );
  10534. gl.uniform1iv( this.addr, units );
  10535. for ( let i = 0; i !== n; ++ i ) {
  10536. textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
  10537. }
  10538. }
  10539. // Helper to pick the right setter for a pure (bottom-level) array
  10540. function getPureArraySetter( type ) {
  10541. switch ( type ) {
  10542. case 0x1406: return setValueV1fArray; // FLOAT
  10543. case 0x8b50: return setValueV2fArray; // _VEC2
  10544. case 0x8b51: return setValueV3fArray; // _VEC3
  10545. case 0x8b52: return setValueV4fArray; // _VEC4
  10546. case 0x8b5a: return setValueM2Array; // _MAT2
  10547. case 0x8b5b: return setValueM3Array; // _MAT3
  10548. case 0x8b5c: return setValueM4Array; // _MAT4
  10549. case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
  10550. case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
  10551. case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
  10552. case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
  10553. case 0x8b5e: // SAMPLER_2D
  10554. case 0x8d66: // SAMPLER_EXTERNAL_OES
  10555. case 0x8dca: // INT_SAMPLER_2D
  10556. case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
  10557. case 0x8b62: // SAMPLER_2D_SHADOW
  10558. return setValueT1Array;
  10559. case 0x8b60: // SAMPLER_CUBE
  10560. case 0x8dcc: // INT_SAMPLER_CUBE
  10561. case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
  10562. case 0x8dc5: // SAMPLER_CUBE_SHADOW
  10563. return setValueT6Array;
  10564. }
  10565. }
  10566. // --- Uniform Classes ---
  10567. function SingleUniform( id, activeInfo, addr ) {
  10568. this.id = id;
  10569. this.addr = addr;
  10570. this.cache = [];
  10571. this.setValue = getSingularSetter( activeInfo.type );
  10572. // this.path = activeInfo.name; // DEBUG
  10573. }
  10574. function PureArrayUniform( id, activeInfo, addr ) {
  10575. this.id = id;
  10576. this.addr = addr;
  10577. this.cache = [];
  10578. this.size = activeInfo.size;
  10579. this.setValue = getPureArraySetter( activeInfo.type );
  10580. // this.path = activeInfo.name; // DEBUG
  10581. }
  10582. PureArrayUniform.prototype.updateCache = function ( data ) {
  10583. const cache = this.cache;
  10584. if ( data instanceof Float32Array && cache.length !== data.length ) {
  10585. this.cache = new Float32Array( data.length );
  10586. }
  10587. copyArray( cache, data );
  10588. };
  10589. function StructuredUniform( id ) {
  10590. this.id = id;
  10591. this.seq = [];
  10592. this.map = {};
  10593. }
  10594. StructuredUniform.prototype.setValue = function ( gl, value, textures ) {
  10595. const seq = this.seq;
  10596. for ( let i = 0, n = seq.length; i !== n; ++ i ) {
  10597. const u = seq[ i ];
  10598. u.setValue( gl, value[ u.id ], textures );
  10599. }
  10600. };
  10601. // --- Top-level ---
  10602. // Parser - builds up the property tree from the path strings
  10603. const RePathPart = /(\w+)(\])?(\[|\.)?/g;
  10604. // extracts
  10605. // - the identifier (member name or array index)
  10606. // - followed by an optional right bracket (found when array index)
  10607. // - followed by an optional left bracket or dot (type of subscript)
  10608. //
  10609. // Note: These portions can be read in a non-overlapping fashion and
  10610. // allow straightforward parsing of the hierarchy that WebGL encodes
  10611. // in the uniform names.
  10612. function addUniform( container, uniformObject ) {
  10613. container.seq.push( uniformObject );
  10614. container.map[ uniformObject.id ] = uniformObject;
  10615. }
  10616. function parseUniform( activeInfo, addr, container ) {
  10617. const path = activeInfo.name,
  10618. pathLength = path.length;
  10619. // reset RegExp object, because of the early exit of a previous run
  10620. RePathPart.lastIndex = 0;
  10621. while ( true ) {
  10622. const match = RePathPart.exec( path ),
  10623. matchEnd = RePathPart.lastIndex;
  10624. let id = match[ 1 ];
  10625. const idIsIndex = match[ 2 ] === ']',
  10626. subscript = match[ 3 ];
  10627. if ( idIsIndex ) id = id | 0; // convert to integer
  10628. if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
  10629. // bare name or "pure" bottom-level array "[0]" suffix
  10630. addUniform( container, subscript === undefined ?
  10631. new SingleUniform( id, activeInfo, addr ) :
  10632. new PureArrayUniform( id, activeInfo, addr ) );
  10633. break;
  10634. } else {
  10635. // step into inner node / create it in case it doesn't exist
  10636. const map = container.map;
  10637. let next = map[ id ];
  10638. if ( next === undefined ) {
  10639. next = new StructuredUniform( id );
  10640. addUniform( container, next );
  10641. }
  10642. container = next;
  10643. }
  10644. }
  10645. }
  10646. // Root Container
  10647. function WebGLUniforms( gl, program ) {
  10648. this.seq = [];
  10649. this.map = {};
  10650. const n = gl.getProgramParameter( program, 35718 );
  10651. for ( let i = 0; i < n; ++ i ) {
  10652. const info = gl.getActiveUniform( program, i ),
  10653. addr = gl.getUniformLocation( program, info.name );
  10654. parseUniform( info, addr, this );
  10655. }
  10656. }
  10657. WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) {
  10658. const u = this.map[ name ];
  10659. if ( u !== undefined ) u.setValue( gl, value, textures );
  10660. };
  10661. WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
  10662. const v = object[ name ];
  10663. if ( v !== undefined ) this.setValue( gl, name, v );
  10664. };
  10665. // Static interface
  10666. WebGLUniforms.upload = function ( gl, seq, values, textures ) {
  10667. for ( let i = 0, n = seq.length; i !== n; ++ i ) {
  10668. const u = seq[ i ],
  10669. v = values[ u.id ];
  10670. if ( v.needsUpdate !== false ) {
  10671. // note: always updating when .needsUpdate is undefined
  10672. u.setValue( gl, v.value, textures );
  10673. }
  10674. }
  10675. };
  10676. WebGLUniforms.seqWithValue = function ( seq, values ) {
  10677. const r = [];
  10678. for ( let i = 0, n = seq.length; i !== n; ++ i ) {
  10679. const u = seq[ i ];
  10680. if ( u.id in values ) r.push( u );
  10681. }
  10682. return r;
  10683. };
  10684. function WebGLShader( gl, type, string ) {
  10685. const shader = gl.createShader( type );
  10686. gl.shaderSource( shader, string );
  10687. gl.compileShader( shader );
  10688. return shader;
  10689. }
  10690. let programIdCount = 0;
  10691. function addLineNumbers( string ) {
  10692. const lines = string.split( '\n' );
  10693. for ( let i = 0; i < lines.length; i ++ ) {
  10694. lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
  10695. }
  10696. return lines.join( '\n' );
  10697. }
  10698. function getEncodingComponents( encoding ) {
  10699. switch ( encoding ) {
  10700. case LinearEncoding:
  10701. return [ 'Linear', '( value )' ];
  10702. case sRGBEncoding:
  10703. return [ 'sRGB', '( value )' ];
  10704. case RGBEEncoding:
  10705. return [ 'RGBE', '( value )' ];
  10706. case RGBM7Encoding:
  10707. return [ 'RGBM', '( value, 7.0 )' ];
  10708. case RGBM16Encoding:
  10709. return [ 'RGBM', '( value, 16.0 )' ];
  10710. case RGBDEncoding:
  10711. return [ 'RGBD', '( value, 256.0 )' ];
  10712. case GammaEncoding:
  10713. return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
  10714. case LogLuvEncoding:
  10715. return [ 'LogLuv', '( value )' ];
  10716. default:
  10717. console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding );
  10718. return [ 'Linear', '( value )' ];
  10719. }
  10720. }
  10721. function getShaderErrors( gl, shader, type ) {
  10722. const status = gl.getShaderParameter( shader, 35713 );
  10723. const log = gl.getShaderInfoLog( shader ).trim();
  10724. if ( status && log === '' ) return '';
  10725. // --enable-privileged-webgl-extension
  10726. // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
  10727. const source = gl.getShaderSource( shader );
  10728. return 'THREE.WebGLShader: gl.getShaderInfoLog() ' + type + '\n' + log + addLineNumbers( source );
  10729. }
  10730. function getTexelDecodingFunction( functionName, encoding ) {
  10731. const components = getEncodingComponents( encoding );
  10732. return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
  10733. }
  10734. function getTexelEncodingFunction( functionName, encoding ) {
  10735. const components = getEncodingComponents( encoding );
  10736. return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
  10737. }
  10738. function getToneMappingFunction( functionName, toneMapping ) {
  10739. let toneMappingName;
  10740. switch ( toneMapping ) {
  10741. case LinearToneMapping:
  10742. toneMappingName = 'Linear';
  10743. break;
  10744. case ReinhardToneMapping:
  10745. toneMappingName = 'Reinhard';
  10746. break;
  10747. case CineonToneMapping:
  10748. toneMappingName = 'OptimizedCineon';
  10749. break;
  10750. case ACESFilmicToneMapping:
  10751. toneMappingName = 'ACESFilmic';
  10752. break;
  10753. case CustomToneMapping:
  10754. toneMappingName = 'Custom';
  10755. break;
  10756. default:
  10757. console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
  10758. toneMappingName = 'Linear';
  10759. }
  10760. return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
  10761. }
  10762. function generateExtensions( parameters ) {
  10763. const chunks = [
  10764. ( parameters.extensionDerivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
  10765. ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
  10766. ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
  10767. ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
  10768. ];
  10769. return chunks.filter( filterEmptyLine ).join( '\n' );
  10770. }
  10771. function generateDefines( defines ) {
  10772. const chunks = [];
  10773. for ( const name in defines ) {
  10774. const value = defines[ name ];
  10775. if ( value === false ) continue;
  10776. chunks.push( '#define ' + name + ' ' + value );
  10777. }
  10778. return chunks.join( '\n' );
  10779. }
  10780. function fetchAttributeLocations( gl, program ) {
  10781. const attributes = {};
  10782. const n = gl.getProgramParameter( program, 35721 );
  10783. for ( let i = 0; i < n; i ++ ) {
  10784. const info = gl.getActiveAttrib( program, i );
  10785. const name = info.name;
  10786. // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
  10787. attributes[ name ] = gl.getAttribLocation( program, name );
  10788. }
  10789. return attributes;
  10790. }
  10791. function filterEmptyLine( string ) {
  10792. return string !== '';
  10793. }
  10794. function replaceLightNums( string, parameters ) {
  10795. return string
  10796. .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
  10797. .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
  10798. .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
  10799. .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
  10800. .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
  10801. .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
  10802. .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
  10803. .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
  10804. }
  10805. function replaceClippingPlaneNums( string, parameters ) {
  10806. return string
  10807. .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
  10808. .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
  10809. }
  10810. // Resolve Includes
  10811. const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
  10812. function resolveIncludes( string ) {
  10813. return string.replace( includePattern, includeReplacer );
  10814. }
  10815. function includeReplacer( match, include ) {
  10816. const string = ShaderChunk[ include ];
  10817. if ( string === undefined ) {
  10818. throw new Error( 'Can not resolve #include <' + include + '>' );
  10819. }
  10820. return resolveIncludes( string );
  10821. }
  10822. // Unroll Loops
  10823. const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
  10824. const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;
  10825. function unrollLoops( string ) {
  10826. return string
  10827. .replace( unrollLoopPattern, loopReplacer )
  10828. .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer );
  10829. }
  10830. function deprecatedLoopReplacer( match, start, end, snippet ) {
  10831. console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' );
  10832. return loopReplacer( match, start, end, snippet );
  10833. }
  10834. function loopReplacer( match, start, end, snippet ) {
  10835. let string = '';
  10836. for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
  10837. string += snippet
  10838. .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
  10839. .replace( /UNROLLED_LOOP_INDEX/g, i );
  10840. }
  10841. return string;
  10842. }
  10843. //
  10844. function generatePrecision( parameters ) {
  10845. let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
  10846. if ( parameters.precision === 'highp' ) {
  10847. precisionstring += '\n#define HIGH_PRECISION';
  10848. } else if ( parameters.precision === 'mediump' ) {
  10849. precisionstring += '\n#define MEDIUM_PRECISION';
  10850. } else if ( parameters.precision === 'lowp' ) {
  10851. precisionstring += '\n#define LOW_PRECISION';
  10852. }
  10853. return precisionstring;
  10854. }
  10855. function generateShadowMapTypeDefine( parameters ) {
  10856. let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
  10857. if ( parameters.shadowMapType === PCFShadowMap ) {
  10858. shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
  10859. } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
  10860. shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
  10861. } else if ( parameters.shadowMapType === VSMShadowMap ) {
  10862. shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
  10863. }
  10864. return shadowMapTypeDefine;
  10865. }
  10866. function generateEnvMapTypeDefine( parameters ) {
  10867. let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
  10868. if ( parameters.envMap ) {
  10869. switch ( parameters.envMapMode ) {
  10870. case CubeReflectionMapping:
  10871. case CubeRefractionMapping:
  10872. envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
  10873. break;
  10874. case CubeUVReflectionMapping:
  10875. case CubeUVRefractionMapping:
  10876. envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
  10877. break;
  10878. }
  10879. }
  10880. return envMapTypeDefine;
  10881. }
  10882. function generateEnvMapModeDefine( parameters ) {
  10883. let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
  10884. if ( parameters.envMap ) {
  10885. switch ( parameters.envMapMode ) {
  10886. case CubeRefractionMapping:
  10887. case CubeUVRefractionMapping:
  10888. envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
  10889. break;
  10890. }
  10891. }
  10892. return envMapModeDefine;
  10893. }
  10894. function generateEnvMapBlendingDefine( parameters ) {
  10895. let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
  10896. if ( parameters.envMap ) {
  10897. switch ( parameters.combine ) {
  10898. case MultiplyOperation:
  10899. envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
  10900. break;
  10901. case MixOperation:
  10902. envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
  10903. break;
  10904. case AddOperation:
  10905. envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
  10906. break;
  10907. }
  10908. }
  10909. return envMapBlendingDefine;
  10910. }
  10911. function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
  10912. const gl = renderer.getContext();
  10913. const defines = parameters.defines;
  10914. let vertexShader = parameters.vertexShader;
  10915. let fragmentShader = parameters.fragmentShader;
  10916. const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
  10917. const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
  10918. const envMapModeDefine = generateEnvMapModeDefine( parameters );
  10919. const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
  10920. const gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
  10921. const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
  10922. const customDefines = generateDefines( defines );
  10923. const program = gl.createProgram();
  10924. let prefixVertex, prefixFragment;
  10925. let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
  10926. if ( parameters.isRawShaderMaterial ) {
  10927. prefixVertex = [
  10928. customDefines
  10929. ].filter( filterEmptyLine ).join( '\n' );
  10930. if ( prefixVertex.length > 0 ) {
  10931. prefixVertex += '\n';
  10932. }
  10933. prefixFragment = [
  10934. customExtensions,
  10935. customDefines
  10936. ].filter( filterEmptyLine ).join( '\n' );
  10937. if ( prefixFragment.length > 0 ) {
  10938. prefixFragment += '\n';
  10939. }
  10940. } else {
  10941. prefixVertex = [
  10942. generatePrecision( parameters ),
  10943. '#define SHADER_NAME ' + parameters.shaderName,
  10944. customDefines,
  10945. parameters.instancing ? '#define USE_INSTANCING' : '',
  10946. parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
  10947. parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
  10948. '#define GAMMA_FACTOR ' + gammaFactorDefine,
  10949. '#define MAX_BONES ' + parameters.maxBones,
  10950. ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
  10951. ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
  10952. parameters.map ? '#define USE_MAP' : '',
  10953. parameters.envMap ? '#define USE_ENVMAP' : '',
  10954. parameters.envMap ? '#define ' + envMapModeDefine : '',
  10955. parameters.lightMap ? '#define USE_LIGHTMAP' : '',
  10956. parameters.aoMap ? '#define USE_AOMAP' : '',
  10957. parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
  10958. parameters.bumpMap ? '#define USE_BUMPMAP' : '',
  10959. parameters.normalMap ? '#define USE_NORMALMAP' : '',
  10960. ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
  10961. ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
  10962. parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
  10963. parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
  10964. parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
  10965. parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
  10966. parameters.specularMap ? '#define USE_SPECULARMAP' : '',
  10967. parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
  10968. parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
  10969. parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
  10970. parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
  10971. parameters.vertexTangents ? '#define USE_TANGENT' : '',
  10972. parameters.vertexColors ? '#define USE_COLOR' : '',
  10973. parameters.vertexUvs ? '#define USE_UV' : '',
  10974. parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
  10975. parameters.flatShading ? '#define FLAT_SHADED' : '',
  10976. parameters.skinning ? '#define USE_SKINNING' : '',
  10977. parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
  10978. parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
  10979. parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
  10980. parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
  10981. parameters.flipSided ? '#define FLIP_SIDED' : '',
  10982. parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
  10983. parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
  10984. parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
  10985. parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
  10986. ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
  10987. 'uniform mat4 modelMatrix;',
  10988. 'uniform mat4 modelViewMatrix;',
  10989. 'uniform mat4 projectionMatrix;',
  10990. 'uniform mat4 viewMatrix;',
  10991. 'uniform mat3 normalMatrix;',
  10992. 'uniform vec3 cameraPosition;',
  10993. 'uniform bool isOrthographic;',
  10994. '#ifdef USE_INSTANCING',
  10995. ' attribute mat4 instanceMatrix;',
  10996. '#endif',
  10997. '#ifdef USE_INSTANCING_COLOR',
  10998. ' attribute vec3 instanceColor;',
  10999. '#endif',
  11000. 'attribute vec3 position;',
  11001. 'attribute vec3 normal;',
  11002. 'attribute vec2 uv;',
  11003. '#ifdef USE_TANGENT',
  11004. ' attribute vec4 tangent;',
  11005. '#endif',
  11006. '#ifdef USE_COLOR',
  11007. ' attribute vec3 color;',
  11008. '#endif',
  11009. '#ifdef USE_MORPHTARGETS',
  11010. ' attribute vec3 morphTarget0;',
  11011. ' attribute vec3 morphTarget1;',
  11012. ' attribute vec3 morphTarget2;',
  11013. ' attribute vec3 morphTarget3;',
  11014. ' #ifdef USE_MORPHNORMALS',
  11015. ' attribute vec3 morphNormal0;',
  11016. ' attribute vec3 morphNormal1;',
  11017. ' attribute vec3 morphNormal2;',
  11018. ' attribute vec3 morphNormal3;',
  11019. ' #else',
  11020. ' attribute vec3 morphTarget4;',
  11021. ' attribute vec3 morphTarget5;',
  11022. ' attribute vec3 morphTarget6;',
  11023. ' attribute vec3 morphTarget7;',
  11024. ' #endif',
  11025. '#endif',
  11026. '#ifdef USE_SKINNING',
  11027. ' attribute vec4 skinIndex;',
  11028. ' attribute vec4 skinWeight;',
  11029. '#endif',
  11030. '\n'
  11031. ].filter( filterEmptyLine ).join( '\n' );
  11032. prefixFragment = [
  11033. customExtensions,
  11034. generatePrecision( parameters ),
  11035. '#define SHADER_NAME ' + parameters.shaderName,
  11036. customDefines,
  11037. parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer
  11038. '#define GAMMA_FACTOR ' + gammaFactorDefine,
  11039. ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
  11040. ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
  11041. parameters.map ? '#define USE_MAP' : '',
  11042. parameters.matcap ? '#define USE_MATCAP' : '',
  11043. parameters.envMap ? '#define USE_ENVMAP' : '',
  11044. parameters.envMap ? '#define ' + envMapTypeDefine : '',
  11045. parameters.envMap ? '#define ' + envMapModeDefine : '',
  11046. parameters.envMap ? '#define ' + envMapBlendingDefine : '',
  11047. parameters.lightMap ? '#define USE_LIGHTMAP' : '',
  11048. parameters.aoMap ? '#define USE_AOMAP' : '',
  11049. parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
  11050. parameters.bumpMap ? '#define USE_BUMPMAP' : '',
  11051. parameters.normalMap ? '#define USE_NORMALMAP' : '',
  11052. ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
  11053. ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
  11054. parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
  11055. parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
  11056. parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
  11057. parameters.specularMap ? '#define USE_SPECULARMAP' : '',
  11058. parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
  11059. parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
  11060. parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
  11061. parameters.sheen ? '#define USE_SHEEN' : '',
  11062. parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
  11063. parameters.vertexTangents ? '#define USE_TANGENT' : '',
  11064. parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
  11065. parameters.vertexUvs ? '#define USE_UV' : '',
  11066. parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
  11067. parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
  11068. parameters.flatShading ? '#define FLAT_SHADED' : '',
  11069. parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
  11070. parameters.flipSided ? '#define FLIP_SIDED' : '',
  11071. parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
  11072. parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
  11073. parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
  11074. parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
  11075. parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
  11076. ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
  11077. ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '',
  11078. 'uniform mat4 viewMatrix;',
  11079. 'uniform vec3 cameraPosition;',
  11080. 'uniform bool isOrthographic;',
  11081. ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
  11082. ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
  11083. ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
  11084. parameters.dithering ? '#define DITHERING' : '',
  11085. ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
  11086. parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
  11087. parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
  11088. parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
  11089. parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
  11090. parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '',
  11091. getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ),
  11092. parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
  11093. '\n'
  11094. ].filter( filterEmptyLine ).join( '\n' );
  11095. }
  11096. vertexShader = resolveIncludes( vertexShader );
  11097. vertexShader = replaceLightNums( vertexShader, parameters );
  11098. vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
  11099. fragmentShader = resolveIncludes( fragmentShader );
  11100. fragmentShader = replaceLightNums( fragmentShader, parameters );
  11101. fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
  11102. vertexShader = unrollLoops( vertexShader );
  11103. fragmentShader = unrollLoops( fragmentShader );
  11104. if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
  11105. // GLSL 3.0 conversion for built-in materials and ShaderMaterial
  11106. versionString = '#version 300 es\n';
  11107. prefixVertex = [
  11108. '#define attribute in',
  11109. '#define varying out',
  11110. '#define texture2D texture'
  11111. ].join( '\n' ) + '\n' + prefixVertex;
  11112. prefixFragment = [
  11113. '#define varying in',
  11114. ( parameters.glslVersion === GLSL3 ) ? '' : 'out highp vec4 pc_fragColor;',
  11115. ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
  11116. '#define gl_FragDepthEXT gl_FragDepth',
  11117. '#define texture2D texture',
  11118. '#define textureCube texture',
  11119. '#define texture2DProj textureProj',
  11120. '#define texture2DLodEXT textureLod',
  11121. '#define texture2DProjLodEXT textureProjLod',
  11122. '#define textureCubeLodEXT textureLod',
  11123. '#define texture2DGradEXT textureGrad',
  11124. '#define texture2DProjGradEXT textureProjGrad',
  11125. '#define textureCubeGradEXT textureGrad'
  11126. ].join( '\n' ) + '\n' + prefixFragment;
  11127. }
  11128. const vertexGlsl = versionString + prefixVertex + vertexShader;
  11129. const fragmentGlsl = versionString + prefixFragment + fragmentShader;
  11130. // console.log( '*VERTEX*', vertexGlsl );
  11131. // console.log( '*FRAGMENT*', fragmentGlsl );
  11132. const glVertexShader = WebGLShader( gl, 35633, vertexGlsl );
  11133. const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl );
  11134. gl.attachShader( program, glVertexShader );
  11135. gl.attachShader( program, glFragmentShader );
  11136. // Force a particular attribute to index 0.
  11137. if ( parameters.index0AttributeName !== undefined ) {
  11138. gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
  11139. } else if ( parameters.morphTargets === true ) {
  11140. // programs with morphTargets displace position out of attribute 0
  11141. gl.bindAttribLocation( program, 0, 'position' );
  11142. }
  11143. gl.linkProgram( program );
  11144. // check for link errors
  11145. if ( renderer.debug.checkShaderErrors ) {
  11146. const programLog = gl.getProgramInfoLog( program ).trim();
  11147. const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
  11148. const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
  11149. let runnable = true;
  11150. let haveDiagnostics = true;
  11151. if ( gl.getProgramParameter( program, 35714 ) === false ) {
  11152. runnable = false;
  11153. const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
  11154. const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
  11155. console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexErrors, fragmentErrors );
  11156. //add:
  11157. if(fragmentErrors){
  11158. console.log(fragmentGlsl.split("\n").map((a, i) => `${i + 1}`.padEnd(5) + a).join("\n") );
  11159. }else {
  11160. console.log(vertexGlsl.split("\n").map((a, i) => `${i + 1}`.padEnd(5) + a).join("\n") );
  11161. }
  11162. } else if ( programLog !== '' ) {
  11163. console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
  11164. } else if ( vertexLog === '' || fragmentLog === '' ) {
  11165. haveDiagnostics = false;
  11166. }
  11167. if ( haveDiagnostics ) {
  11168. this.diagnostics = {
  11169. runnable: runnable,
  11170. programLog: programLog,
  11171. vertexShader: {
  11172. log: vertexLog,
  11173. prefix: prefixVertex
  11174. },
  11175. fragmentShader: {
  11176. log: fragmentLog,
  11177. prefix: prefixFragment
  11178. }
  11179. };
  11180. }
  11181. }
  11182. // Clean up
  11183. // Crashes in iOS9 and iOS10. #18402
  11184. // gl.detachShader( program, glVertexShader );
  11185. // gl.detachShader( program, glFragmentShader );
  11186. gl.deleteShader( glVertexShader );
  11187. gl.deleteShader( glFragmentShader );
  11188. // set up caching for uniform locations
  11189. let cachedUniforms;
  11190. this.getUniforms = function () {
  11191. if ( cachedUniforms === undefined ) {
  11192. cachedUniforms = new WebGLUniforms( gl, program );
  11193. }
  11194. return cachedUniforms;
  11195. };
  11196. // set up caching for attribute locations
  11197. let cachedAttributes;
  11198. this.getAttributes = function () {
  11199. if ( cachedAttributes === undefined ) {
  11200. cachedAttributes = fetchAttributeLocations( gl, program );
  11201. }
  11202. return cachedAttributes;
  11203. };
  11204. // free resource
  11205. this.destroy = function () {
  11206. bindingStates.releaseStatesOfProgram( this );
  11207. gl.deleteProgram( program );
  11208. this.program = undefined;
  11209. };
  11210. //
  11211. this.name = parameters.shaderName;
  11212. this.id = programIdCount ++;
  11213. this.cacheKey = cacheKey;
  11214. this.usedTimes = 1;
  11215. this.program = program;
  11216. this.vertexShader = glVertexShader;
  11217. this.fragmentShader = glFragmentShader;
  11218. return this;
  11219. }
  11220. function WebGLPrograms( renderer, cubemaps, extensions, capabilities, bindingStates, clipping ) {
  11221. const programs = [];
  11222. const isWebGL2 = capabilities.isWebGL2;
  11223. const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
  11224. const floatVertexTextures = capabilities.floatVertexTextures;
  11225. const maxVertexUniforms = capabilities.maxVertexUniforms;
  11226. const vertexTextures = capabilities.vertexTextures;
  11227. let precision = capabilities.precision;
  11228. const shaderIDs = {
  11229. MeshDepthMaterial: 'depth',
  11230. MeshDistanceMaterial: 'distanceRGBA',
  11231. MeshNormalMaterial: 'normal',
  11232. MeshBasicMaterial: 'basic',
  11233. MeshLambertMaterial: 'lambert',
  11234. MeshPhongMaterial: 'phong',
  11235. MeshToonMaterial: 'toon',
  11236. MeshStandardMaterial: 'physical',
  11237. MeshPhysicalMaterial: 'physical',
  11238. MeshMatcapMaterial: 'matcap',
  11239. LineBasicMaterial: 'basic',
  11240. LineDashedMaterial: 'dashed',
  11241. PointsMaterial: 'points',
  11242. ShadowMaterial: 'shadow',
  11243. SpriteMaterial: 'sprite'
  11244. };
  11245. const parameterNames = [
  11246. 'precision', 'isWebGL2', 'supportsVertexTextures', 'outputEncoding', 'instancing', 'instancingColor',
  11247. 'map', 'mapEncoding', 'matcap', 'matcapEncoding', 'envMap', 'envMapMode', 'envMapEncoding', 'envMapCubeUV',
  11248. 'lightMap', 'lightMapEncoding', 'aoMap', 'emissiveMap', 'emissiveMapEncoding', 'bumpMap', 'normalMap', 'objectSpaceNormalMap', 'tangentSpaceNormalMap', 'clearcoatMap', 'clearcoatRoughnessMap', 'clearcoatNormalMap', 'displacementMap', 'specularMap',
  11249. 'roughnessMap', 'metalnessMap', 'gradientMap',
  11250. 'alphaMap', 'combine', 'vertexColors', 'vertexTangents', 'vertexUvs', 'uvsVertexOnly', 'fog', 'useFog', 'fogExp2',
  11251. 'flatShading', 'sizeAttenuation', 'logarithmicDepthBuffer', 'skinning',
  11252. 'maxBones', 'useVertexTexture', 'morphTargets', 'morphNormals',
  11253. 'maxMorphTargets', 'maxMorphNormals', 'premultipliedAlpha',
  11254. 'numDirLights', 'numPointLights', 'numSpotLights', 'numHemiLights', 'numRectAreaLights',
  11255. 'numDirLightShadows', 'numPointLightShadows', 'numSpotLightShadows',
  11256. 'shadowMapEnabled', 'shadowMapType', 'toneMapping', 'physicallyCorrectLights',
  11257. 'alphaTest', 'doubleSided', 'flipSided', 'numClippingPlanes', 'numClipIntersection', 'depthPacking', 'dithering',
  11258. 'sheen', 'transmissionMap'
  11259. ];
  11260. function getMaxBones( object ) {
  11261. const skeleton = object.skeleton;
  11262. const bones = skeleton.bones;
  11263. if ( floatVertexTextures ) {
  11264. return 1024;
  11265. } else {
  11266. // default for when object is not specified
  11267. // ( for example when prebuilding shader to be used with multiple objects )
  11268. //
  11269. // - leave some extra space for other uniforms
  11270. // - limit here is ANGLE's 254 max uniform vectors
  11271. // (up to 54 should be safe)
  11272. const nVertexUniforms = maxVertexUniforms;
  11273. const nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
  11274. const maxBones = Math.min( nVertexMatrices, bones.length );
  11275. if ( maxBones < bones.length ) {
  11276. console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
  11277. return 0;
  11278. }
  11279. return maxBones;
  11280. }
  11281. }
  11282. function getTextureEncodingFromMap( map ) {
  11283. let encoding;
  11284. if ( map && map.isTexture ) {
  11285. encoding = map.encoding;
  11286. } else if ( map && map.isWebGLRenderTarget ) {
  11287. console.warn( 'THREE.WebGLPrograms.getTextureEncodingFromMap: don\'t use render targets as textures. Use their .texture property instead.' );
  11288. encoding = map.texture.encoding;
  11289. } else {
  11290. encoding = LinearEncoding;
  11291. }
  11292. return encoding;
  11293. }
  11294. function getParameters( material, lights, shadows, scene, object ) {
  11295. const fog = scene.fog;
  11296. const environment = material.isMeshStandardMaterial ? scene.environment : null;
  11297. const envMap = cubemaps.get( material.envMap || environment );
  11298. const shaderID = shaderIDs[ material.type ];
  11299. // heuristics to create shader parameters according to lights in the scene
  11300. // (not to blow over maxLights budget)
  11301. const maxBones = object.isSkinnedMesh ? getMaxBones( object ) : 0;
  11302. if ( material.precision !== null ) {
  11303. precision = capabilities.getMaxPrecision( material.precision );
  11304. if ( precision !== material.precision ) {
  11305. console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
  11306. }
  11307. }
  11308. let vertexShader, fragmentShader;
  11309. if ( shaderID ) {
  11310. const shader = ShaderLib[ shaderID ];
  11311. vertexShader = shader.vertexShader;
  11312. fragmentShader = shader.fragmentShader;
  11313. } else {
  11314. vertexShader = material.vertexShader;
  11315. fragmentShader = material.fragmentShader;
  11316. }
  11317. const currentRenderTarget = renderer.getRenderTarget();
  11318. const parameters = {
  11319. isWebGL2: isWebGL2,
  11320. shaderID: shaderID,
  11321. shaderName: material.type,
  11322. vertexShader: vertexShader,
  11323. fragmentShader: fragmentShader,
  11324. defines: material.defines,
  11325. isRawShaderMaterial: material.isRawShaderMaterial === true,
  11326. glslVersion: material.glslVersion,
  11327. precision: precision,
  11328. instancing: object.isInstancedMesh === true,
  11329. instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
  11330. supportsVertexTextures: vertexTextures,
  11331. outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding,
  11332. map: !! material.map,
  11333. mapEncoding: getTextureEncodingFromMap( material.map ),
  11334. matcap: !! material.matcap,
  11335. matcapEncoding: getTextureEncodingFromMap( material.matcap ),
  11336. envMap: !! envMap,
  11337. envMapMode: envMap && envMap.mapping,
  11338. envMapEncoding: getTextureEncodingFromMap( envMap ),
  11339. envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ),
  11340. lightMap: !! material.lightMap,
  11341. lightMapEncoding: getTextureEncodingFromMap( material.lightMap ),
  11342. aoMap: !! material.aoMap,
  11343. emissiveMap: !! material.emissiveMap,
  11344. emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ),
  11345. bumpMap: !! material.bumpMap,
  11346. normalMap: !! material.normalMap,
  11347. objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
  11348. tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
  11349. clearcoatMap: !! material.clearcoatMap,
  11350. clearcoatRoughnessMap: !! material.clearcoatRoughnessMap,
  11351. clearcoatNormalMap: !! material.clearcoatNormalMap,
  11352. displacementMap: !! material.displacementMap,
  11353. roughnessMap: !! material.roughnessMap,
  11354. metalnessMap: !! material.metalnessMap,
  11355. specularMap: !! material.specularMap,
  11356. alphaMap: !! material.alphaMap,
  11357. gradientMap: !! material.gradientMap,
  11358. sheen: !! material.sheen,
  11359. transmissionMap: !! material.transmissionMap,
  11360. combine: material.combine,
  11361. vertexTangents: ( material.normalMap && material.vertexTangents ),
  11362. vertexColors: material.vertexColors,
  11363. vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.displacementMap || !! material.transmissionMap,
  11364. uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.transmissionMap ) && !! material.displacementMap,
  11365. fog: !! fog,
  11366. useFog: material.fog,
  11367. fogExp2: ( fog && fog.isFogExp2 ),
  11368. flatShading: material.flatShading,
  11369. sizeAttenuation: material.sizeAttenuation,
  11370. logarithmicDepthBuffer: logarithmicDepthBuffer,
  11371. skinning: material.skinning && maxBones > 0,
  11372. maxBones: maxBones,
  11373. useVertexTexture: floatVertexTextures,
  11374. morphTargets: material.morphTargets,
  11375. morphNormals: material.morphNormals,
  11376. maxMorphTargets: renderer.maxMorphTargets,
  11377. maxMorphNormals: renderer.maxMorphNormals,
  11378. numDirLights: lights.directional.length,
  11379. numPointLights: lights.point.length,
  11380. numSpotLights: lights.spot.length,
  11381. numRectAreaLights: lights.rectArea.length,
  11382. numHemiLights: lights.hemi.length,
  11383. numDirLightShadows: lights.directionalShadowMap.length,
  11384. numPointLightShadows: lights.pointShadowMap.length,
  11385. numSpotLightShadows: lights.spotShadowMap.length,
  11386. numClippingPlanes: clipping.numPlanes,
  11387. numClipIntersection: clipping.numIntersection,
  11388. dithering: material.dithering,
  11389. shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
  11390. shadowMapType: renderer.shadowMap.type,
  11391. toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping,
  11392. physicallyCorrectLights: renderer.physicallyCorrectLights,
  11393. premultipliedAlpha: material.premultipliedAlpha,
  11394. alphaTest: material.alphaTest,
  11395. doubleSided: material.side === DoubleSide,
  11396. flipSided: material.side === BackSide,
  11397. depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false,
  11398. index0AttributeName: material.index0AttributeName,
  11399. extensionDerivatives: material.extensions && material.extensions.derivatives,
  11400. extensionFragDepth: material.extensions && material.extensions.fragDepth,
  11401. extensionDrawBuffers: material.extensions && material.extensions.drawBuffers,
  11402. extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD,
  11403. rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ),
  11404. rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ),
  11405. rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ),
  11406. customProgramCacheKey: material.customProgramCacheKey()
  11407. };
  11408. return parameters;
  11409. }
  11410. function getProgramCacheKey( parameters ) {
  11411. const array = [];
  11412. if ( parameters.shaderID ) {
  11413. array.push( parameters.shaderID );
  11414. } else {
  11415. array.push( parameters.fragmentShader );
  11416. array.push( parameters.vertexShader );
  11417. }
  11418. if ( parameters.defines !== undefined ) {
  11419. for ( const name in parameters.defines ) {
  11420. array.push( name );
  11421. array.push( parameters.defines[ name ] );
  11422. }
  11423. }
  11424. if ( parameters.isRawShaderMaterial === false ) {
  11425. for ( let i = 0; i < parameterNames.length; i ++ ) {
  11426. array.push( parameters[ parameterNames[ i ] ] );
  11427. }
  11428. array.push( renderer.outputEncoding );
  11429. array.push( renderer.gammaFactor );
  11430. }
  11431. array.push( parameters.customProgramCacheKey );
  11432. return array.join();
  11433. }
  11434. function getUniforms( material ) {
  11435. const shaderID = shaderIDs[ material.type ];
  11436. let uniforms;
  11437. if ( shaderID ) {
  11438. const shader = ShaderLib[ shaderID ];
  11439. uniforms = UniformsUtils.clone( shader.uniforms );
  11440. } else {
  11441. uniforms = material.uniforms;
  11442. }
  11443. return uniforms;
  11444. }
  11445. function acquireProgram( parameters, cacheKey ) {
  11446. let program;
  11447. // Check if code has been already compiled
  11448. for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
  11449. const preexistingProgram = programs[ p ];
  11450. if ( preexistingProgram.cacheKey === cacheKey ) {
  11451. program = preexistingProgram;
  11452. ++ program.usedTimes;
  11453. break;
  11454. }
  11455. }
  11456. if ( program === undefined ) {
  11457. program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
  11458. programs.push( program );
  11459. }
  11460. return program;
  11461. }
  11462. function releaseProgram( program ) {
  11463. if ( -- program.usedTimes === 0 ) {
  11464. // Remove from unordered set
  11465. const i = programs.indexOf( program );
  11466. programs[ i ] = programs[ programs.length - 1 ];
  11467. programs.pop();
  11468. // Free WebGL resources
  11469. program.destroy();
  11470. }
  11471. }
  11472. return {
  11473. getParameters: getParameters,
  11474. getProgramCacheKey: getProgramCacheKey,
  11475. getUniforms: getUniforms,
  11476. acquireProgram: acquireProgram,
  11477. releaseProgram: releaseProgram,
  11478. // Exposed for resource monitoring & error feedback via renderer.info:
  11479. programs: programs
  11480. };
  11481. }
  11482. function WebGLProperties() {
  11483. let properties = new WeakMap();
  11484. function get( object ) {
  11485. let map = properties.get( object );
  11486. if ( map === undefined ) {
  11487. map = {};
  11488. properties.set( object, map );
  11489. }
  11490. return map;
  11491. }
  11492. function remove( object ) {
  11493. properties.delete( object );
  11494. }
  11495. function update( object, key, value ) {
  11496. properties.get( object )[ key ] = value;
  11497. }
  11498. function dispose() {
  11499. properties = new WeakMap();
  11500. }
  11501. return {
  11502. get: get,
  11503. remove: remove,
  11504. update: update,
  11505. dispose: dispose
  11506. };
  11507. }
  11508. function painterSortStable( a, b ) {
  11509. if ( a.groupOrder !== b.groupOrder ) {
  11510. return a.groupOrder - b.groupOrder;
  11511. } else if ( a.renderOrder !== b.renderOrder ) {
  11512. return a.renderOrder - b.renderOrder;
  11513. } else if ( a.program !== b.program ) {
  11514. return a.program.id - b.program.id;
  11515. } else if ( a.material.id !== b.material.id ) {
  11516. return a.material.id - b.material.id;
  11517. } else if ( a.z !== b.z ) {
  11518. return a.z - b.z;
  11519. } else {
  11520. return a.id - b.id;
  11521. }
  11522. }
  11523. function reversePainterSortStable( a, b ) {
  11524. if ( a.groupOrder !== b.groupOrder ) {
  11525. return a.groupOrder - b.groupOrder;
  11526. } else if ( a.renderOrder !== b.renderOrder ) {
  11527. return a.renderOrder - b.renderOrder;
  11528. } else if ( a.z !== b.z ) {
  11529. return b.z - a.z;
  11530. } else {
  11531. return a.id - b.id;
  11532. }
  11533. }
  11534. function WebGLRenderList( properties ) {
  11535. const renderItems = [];
  11536. let renderItemsIndex = 0;
  11537. const opaque = [];
  11538. const transparent = [];
  11539. const defaultProgram = { id: - 1 };
  11540. function init() {
  11541. renderItemsIndex = 0;
  11542. opaque.length = 0;
  11543. transparent.length = 0;
  11544. }
  11545. function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
  11546. let renderItem = renderItems[ renderItemsIndex ];
  11547. const materialProperties = properties.get( material );
  11548. if ( renderItem === undefined ) {
  11549. renderItem = {
  11550. id: object.id,
  11551. object: object,
  11552. geometry: geometry,
  11553. material: material,
  11554. program: materialProperties.program || defaultProgram,
  11555. groupOrder: groupOrder,
  11556. renderOrder: object.renderOrder,
  11557. z: z,
  11558. group: group
  11559. };
  11560. renderItems[ renderItemsIndex ] = renderItem;
  11561. } else {
  11562. renderItem.id = object.id;
  11563. renderItem.object = object;
  11564. renderItem.geometry = geometry;
  11565. renderItem.material = material;
  11566. renderItem.program = materialProperties.program || defaultProgram;
  11567. renderItem.groupOrder = groupOrder;
  11568. renderItem.renderOrder = object.renderOrder;
  11569. renderItem.z = z;
  11570. renderItem.group = group;
  11571. }
  11572. renderItemsIndex ++;
  11573. return renderItem;
  11574. }
  11575. function push( object, geometry, material, groupOrder, z, group ) {
  11576. const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
  11577. ( material.transparent === true ? transparent : opaque ).push( renderItem );
  11578. }
  11579. function unshift( object, geometry, material, groupOrder, z, group ) {
  11580. const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
  11581. ( material.transparent === true ? transparent : opaque ).unshift( renderItem );
  11582. }
  11583. function sort( customOpaqueSort, customTransparentSort ) {
  11584. if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
  11585. if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
  11586. }
  11587. function finish() {
  11588. // Clear references from inactive renderItems in the list
  11589. for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
  11590. const renderItem = renderItems[ i ];
  11591. if ( renderItem.id === null ) break;
  11592. renderItem.id = null;
  11593. renderItem.object = null;
  11594. renderItem.geometry = null;
  11595. renderItem.material = null;
  11596. renderItem.program = null;
  11597. renderItem.group = null;
  11598. }
  11599. }
  11600. return {
  11601. opaque: opaque,
  11602. transparent: transparent,
  11603. init: init,
  11604. push: push,
  11605. unshift: unshift,
  11606. finish: finish,
  11607. sort: sort
  11608. };
  11609. }
  11610. function WebGLRenderLists( properties ) {
  11611. let lists = new WeakMap();
  11612. function get( scene, camera ) {
  11613. const cameras = lists.get( scene );
  11614. let list;
  11615. if ( cameras === undefined ) {
  11616. list = new WebGLRenderList( properties );
  11617. lists.set( scene, new WeakMap() );
  11618. lists.get( scene ).set( camera, list );
  11619. } else {
  11620. list = cameras.get( camera );
  11621. if ( list === undefined ) {
  11622. list = new WebGLRenderList( properties );
  11623. cameras.set( camera, list );
  11624. }
  11625. }
  11626. return list;
  11627. }
  11628. function dispose() {
  11629. lists = new WeakMap();
  11630. }
  11631. return {
  11632. get: get,
  11633. dispose: dispose
  11634. };
  11635. }
  11636. function UniformsCache() {
  11637. const lights = {};
  11638. return {
  11639. get: function ( light ) {
  11640. if ( lights[ light.id ] !== undefined ) {
  11641. return lights[ light.id ];
  11642. }
  11643. let uniforms;
  11644. switch ( light.type ) {
  11645. case 'DirectionalLight':
  11646. uniforms = {
  11647. direction: new Vector3(),
  11648. color: new Color()
  11649. };
  11650. break;
  11651. case 'SpotLight':
  11652. uniforms = {
  11653. position: new Vector3(),
  11654. direction: new Vector3(),
  11655. color: new Color(),
  11656. distance: 0,
  11657. coneCos: 0,
  11658. penumbraCos: 0,
  11659. decay: 0
  11660. };
  11661. break;
  11662. case 'PointLight':
  11663. uniforms = {
  11664. position: new Vector3(),
  11665. color: new Color(),
  11666. distance: 0,
  11667. decay: 0
  11668. };
  11669. break;
  11670. case 'HemisphereLight':
  11671. uniforms = {
  11672. direction: new Vector3(),
  11673. skyColor: new Color(),
  11674. groundColor: new Color()
  11675. };
  11676. break;
  11677. case 'RectAreaLight':
  11678. uniforms = {
  11679. color: new Color(),
  11680. position: new Vector3(),
  11681. halfWidth: new Vector3(),
  11682. halfHeight: new Vector3()
  11683. };
  11684. break;
  11685. }
  11686. lights[ light.id ] = uniforms;
  11687. return uniforms;
  11688. }
  11689. };
  11690. }
  11691. function ShadowUniformsCache() {
  11692. const lights = {};
  11693. return {
  11694. get: function ( light ) {
  11695. if ( lights[ light.id ] !== undefined ) {
  11696. return lights[ light.id ];
  11697. }
  11698. let uniforms;
  11699. switch ( light.type ) {
  11700. case 'DirectionalLight':
  11701. uniforms = {
  11702. shadowBias: 0,
  11703. shadowNormalBias: 0,
  11704. shadowRadius: 1,
  11705. shadowMapSize: new Vector2$1()
  11706. };
  11707. break;
  11708. case 'SpotLight':
  11709. uniforms = {
  11710. shadowBias: 0,
  11711. shadowNormalBias: 0,
  11712. shadowRadius: 1,
  11713. shadowMapSize: new Vector2$1()
  11714. };
  11715. break;
  11716. case 'PointLight':
  11717. uniforms = {
  11718. shadowBias: 0,
  11719. shadowNormalBias: 0,
  11720. shadowRadius: 1,
  11721. shadowMapSize: new Vector2$1(),
  11722. shadowCameraNear: 1,
  11723. shadowCameraFar: 1000
  11724. };
  11725. break;
  11726. // TODO (abelnation): set RectAreaLight shadow uniforms
  11727. }
  11728. lights[ light.id ] = uniforms;
  11729. return uniforms;
  11730. }
  11731. };
  11732. }
  11733. let nextVersion = 0;
  11734. function shadowCastingLightsFirst( lightA, lightB ) {
  11735. return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
  11736. }
  11737. function WebGLLights( extensions, capabilities ) {
  11738. const cache = new UniformsCache();
  11739. const shadowCache = ShadowUniformsCache();
  11740. const state = {
  11741. version: 0,
  11742. hash: {
  11743. directionalLength: - 1,
  11744. pointLength: - 1,
  11745. spotLength: - 1,
  11746. rectAreaLength: - 1,
  11747. hemiLength: - 1,
  11748. numDirectionalShadows: - 1,
  11749. numPointShadows: - 1,
  11750. numSpotShadows: - 1
  11751. },
  11752. ambient: [ 0, 0, 0 ],
  11753. probe: [],
  11754. directional: [],
  11755. directionalShadow: [],
  11756. directionalShadowMap: [],
  11757. directionalShadowMatrix: [],
  11758. spot: [],
  11759. spotShadow: [],
  11760. spotShadowMap: [],
  11761. spotShadowMatrix: [],
  11762. rectArea: [],
  11763. rectAreaLTC1: null,
  11764. rectAreaLTC2: null,
  11765. point: [],
  11766. pointShadow: [],
  11767. pointShadowMap: [],
  11768. pointShadowMatrix: [],
  11769. hemi: []
  11770. };
  11771. for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
  11772. const vector3 = new Vector3();
  11773. const matrix4 = new Matrix4();
  11774. const matrix42 = new Matrix4();
  11775. function setup( lights ) {
  11776. let r = 0, g = 0, b = 0;
  11777. for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
  11778. let directionalLength = 0;
  11779. let pointLength = 0;
  11780. let spotLength = 0;
  11781. let rectAreaLength = 0;
  11782. let hemiLength = 0;
  11783. let numDirectionalShadows = 0;
  11784. let numPointShadows = 0;
  11785. let numSpotShadows = 0;
  11786. lights.sort( shadowCastingLightsFirst );
  11787. for ( let i = 0, l = lights.length; i < l; i ++ ) {
  11788. const light = lights[ i ];
  11789. const color = light.color;
  11790. const intensity = light.intensity;
  11791. const distance = light.distance;
  11792. const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
  11793. if ( light.isAmbientLight ) {
  11794. r += color.r * intensity;
  11795. g += color.g * intensity;
  11796. b += color.b * intensity;
  11797. } else if ( light.isLightProbe ) {
  11798. for ( let j = 0; j < 9; j ++ ) {
  11799. state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
  11800. }
  11801. } else if ( light.isDirectionalLight ) {
  11802. const uniforms = cache.get( light );
  11803. uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
  11804. if ( light.castShadow ) {
  11805. const shadow = light.shadow;
  11806. const shadowUniforms = shadowCache.get( light );
  11807. shadowUniforms.shadowBias = shadow.bias;
  11808. shadowUniforms.shadowNormalBias = shadow.normalBias;
  11809. shadowUniforms.shadowRadius = shadow.radius;
  11810. shadowUniforms.shadowMapSize = shadow.mapSize;
  11811. state.directionalShadow[ directionalLength ] = shadowUniforms;
  11812. state.directionalShadowMap[ directionalLength ] = shadowMap;
  11813. state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
  11814. numDirectionalShadows ++;
  11815. }
  11816. state.directional[ directionalLength ] = uniforms;
  11817. directionalLength ++;
  11818. } else if ( light.isSpotLight ) {
  11819. const uniforms = cache.get( light );
  11820. uniforms.position.setFromMatrixPosition( light.matrixWorld );
  11821. uniforms.color.copy( color ).multiplyScalar( intensity );
  11822. uniforms.distance = distance;
  11823. uniforms.coneCos = Math.cos( light.angle );
  11824. uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
  11825. uniforms.decay = light.decay;
  11826. if ( light.castShadow ) {
  11827. const shadow = light.shadow;
  11828. const shadowUniforms = shadowCache.get( light );
  11829. shadowUniforms.shadowBias = shadow.bias;
  11830. shadowUniforms.shadowNormalBias = shadow.normalBias;
  11831. shadowUniforms.shadowRadius = shadow.radius;
  11832. shadowUniforms.shadowMapSize = shadow.mapSize;
  11833. state.spotShadow[ spotLength ] = shadowUniforms;
  11834. state.spotShadowMap[ spotLength ] = shadowMap;
  11835. state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
  11836. numSpotShadows ++;
  11837. }
  11838. state.spot[ spotLength ] = uniforms;
  11839. spotLength ++;
  11840. } else if ( light.isRectAreaLight ) {
  11841. const uniforms = cache.get( light );
  11842. // (a) intensity is the total visible light emitted
  11843. //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
  11844. // (b) intensity is the brightness of the light
  11845. uniforms.color.copy( color ).multiplyScalar( intensity );
  11846. uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
  11847. uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
  11848. state.rectArea[ rectAreaLength ] = uniforms;
  11849. rectAreaLength ++;
  11850. } else if ( light.isPointLight ) {
  11851. const uniforms = cache.get( light );
  11852. uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
  11853. uniforms.distance = light.distance;
  11854. uniforms.decay = light.decay;
  11855. if ( light.castShadow ) {
  11856. const shadow = light.shadow;
  11857. const shadowUniforms = shadowCache.get( light );
  11858. shadowUniforms.shadowBias = shadow.bias;
  11859. shadowUniforms.shadowNormalBias = shadow.normalBias;
  11860. shadowUniforms.shadowRadius = shadow.radius;
  11861. shadowUniforms.shadowMapSize = shadow.mapSize;
  11862. shadowUniforms.shadowCameraNear = shadow.camera.near;
  11863. shadowUniforms.shadowCameraFar = shadow.camera.far;
  11864. state.pointShadow[ pointLength ] = shadowUniforms;
  11865. state.pointShadowMap[ pointLength ] = shadowMap;
  11866. state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
  11867. numPointShadows ++;
  11868. }
  11869. state.point[ pointLength ] = uniforms;
  11870. pointLength ++;
  11871. } else if ( light.isHemisphereLight ) {
  11872. const uniforms = cache.get( light );
  11873. uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
  11874. uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
  11875. state.hemi[ hemiLength ] = uniforms;
  11876. hemiLength ++;
  11877. }
  11878. }
  11879. if ( rectAreaLength > 0 ) {
  11880. if ( capabilities.isWebGL2 ) {
  11881. // WebGL 2
  11882. state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
  11883. state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
  11884. } else {
  11885. // WebGL 1
  11886. if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
  11887. state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
  11888. state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
  11889. } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
  11890. state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
  11891. state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
  11892. } else {
  11893. console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
  11894. }
  11895. }
  11896. }
  11897. state.ambient[ 0 ] = r;
  11898. state.ambient[ 1 ] = g;
  11899. state.ambient[ 2 ] = b;
  11900. const hash = state.hash;
  11901. if ( hash.directionalLength !== directionalLength ||
  11902. hash.pointLength !== pointLength ||
  11903. hash.spotLength !== spotLength ||
  11904. hash.rectAreaLength !== rectAreaLength ||
  11905. hash.hemiLength !== hemiLength ||
  11906. hash.numDirectionalShadows !== numDirectionalShadows ||
  11907. hash.numPointShadows !== numPointShadows ||
  11908. hash.numSpotShadows !== numSpotShadows ) {
  11909. state.directional.length = directionalLength;
  11910. state.spot.length = spotLength;
  11911. state.rectArea.length = rectAreaLength;
  11912. state.point.length = pointLength;
  11913. state.hemi.length = hemiLength;
  11914. state.directionalShadow.length = numDirectionalShadows;
  11915. state.directionalShadowMap.length = numDirectionalShadows;
  11916. state.pointShadow.length = numPointShadows;
  11917. state.pointShadowMap.length = numPointShadows;
  11918. state.spotShadow.length = numSpotShadows;
  11919. state.spotShadowMap.length = numSpotShadows;
  11920. state.directionalShadowMatrix.length = numDirectionalShadows;
  11921. state.pointShadowMatrix.length = numPointShadows;
  11922. state.spotShadowMatrix.length = numSpotShadows;
  11923. hash.directionalLength = directionalLength;
  11924. hash.pointLength = pointLength;
  11925. hash.spotLength = spotLength;
  11926. hash.rectAreaLength = rectAreaLength;
  11927. hash.hemiLength = hemiLength;
  11928. hash.numDirectionalShadows = numDirectionalShadows;
  11929. hash.numPointShadows = numPointShadows;
  11930. hash.numSpotShadows = numSpotShadows;
  11931. state.version = nextVersion ++;
  11932. }
  11933. }
  11934. function setupView( lights, camera ) {
  11935. let directionalLength = 0;
  11936. let pointLength = 0;
  11937. let spotLength = 0;
  11938. let rectAreaLength = 0;
  11939. let hemiLength = 0;
  11940. const viewMatrix = camera.matrixWorldInverse;
  11941. for ( let i = 0, l = lights.length; i < l; i ++ ) {
  11942. const light = lights[ i ];
  11943. if ( light.isDirectionalLight ) {
  11944. const uniforms = state.directional[ directionalLength ];
  11945. uniforms.direction.setFromMatrixPosition( light.matrixWorld );
  11946. vector3.setFromMatrixPosition( light.target.matrixWorld );
  11947. uniforms.direction.sub( vector3 );
  11948. uniforms.direction.transformDirection( viewMatrix );
  11949. directionalLength ++;
  11950. } else if ( light.isSpotLight ) {
  11951. const uniforms = state.spot[ spotLength ];
  11952. uniforms.position.setFromMatrixPosition( light.matrixWorld );
  11953. uniforms.position.applyMatrix4( viewMatrix );
  11954. uniforms.direction.setFromMatrixPosition( light.matrixWorld );
  11955. vector3.setFromMatrixPosition( light.target.matrixWorld );
  11956. uniforms.direction.sub( vector3 );
  11957. uniforms.direction.transformDirection( viewMatrix );
  11958. spotLength ++;
  11959. } else if ( light.isRectAreaLight ) {
  11960. const uniforms = state.rectArea[ rectAreaLength ];
  11961. uniforms.position.setFromMatrixPosition( light.matrixWorld );
  11962. uniforms.position.applyMatrix4( viewMatrix );
  11963. // extract local rotation of light to derive width/height half vectors
  11964. matrix42.identity();
  11965. matrix4.copy( light.matrixWorld );
  11966. matrix4.premultiply( viewMatrix );
  11967. matrix42.extractRotation( matrix4 );
  11968. uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
  11969. uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
  11970. uniforms.halfWidth.applyMatrix4( matrix42 );
  11971. uniforms.halfHeight.applyMatrix4( matrix42 );
  11972. rectAreaLength ++;
  11973. } else if ( light.isPointLight ) {
  11974. const uniforms = state.point[ pointLength ];
  11975. uniforms.position.setFromMatrixPosition( light.matrixWorld );
  11976. uniforms.position.applyMatrix4( viewMatrix );
  11977. pointLength ++;
  11978. } else if ( light.isHemisphereLight ) {
  11979. const uniforms = state.hemi[ hemiLength ];
  11980. uniforms.direction.setFromMatrixPosition( light.matrixWorld );
  11981. uniforms.direction.transformDirection( viewMatrix );
  11982. uniforms.direction.normalize();
  11983. hemiLength ++;
  11984. }
  11985. }
  11986. }
  11987. return {
  11988. setup: setup,
  11989. setupView: setupView,
  11990. state: state
  11991. };
  11992. }
  11993. function WebGLRenderState( extensions, capabilities ) {
  11994. const lights = new WebGLLights( extensions, capabilities );
  11995. const lightsArray = [];
  11996. const shadowsArray = [];
  11997. function init() {
  11998. lightsArray.length = 0;
  11999. shadowsArray.length = 0;
  12000. }
  12001. function pushLight( light ) {
  12002. lightsArray.push( light );
  12003. }
  12004. function pushShadow( shadowLight ) {
  12005. shadowsArray.push( shadowLight );
  12006. }
  12007. function setupLights() {
  12008. lights.setup( lightsArray );
  12009. }
  12010. function setupLightsView( camera ) {
  12011. lights.setupView( lightsArray, camera );
  12012. }
  12013. const state = {
  12014. lightsArray: lightsArray,
  12015. shadowsArray: shadowsArray,
  12016. lights: lights
  12017. };
  12018. return {
  12019. init: init,
  12020. state: state,
  12021. setupLights: setupLights,
  12022. setupLightsView: setupLightsView,
  12023. pushLight: pushLight,
  12024. pushShadow: pushShadow
  12025. };
  12026. }
  12027. function WebGLRenderStates( extensions, capabilities ) {
  12028. let renderStates = new WeakMap();
  12029. function get( scene, renderCallDepth = 0 ) {
  12030. let renderState;
  12031. if ( renderStates.has( scene ) === false ) {
  12032. renderState = new WebGLRenderState( extensions, capabilities );
  12033. renderStates.set( scene, [] );
  12034. renderStates.get( scene ).push( renderState );
  12035. } else {
  12036. if ( renderCallDepth >= renderStates.get( scene ).length ) {
  12037. renderState = new WebGLRenderState( extensions, capabilities );
  12038. renderStates.get( scene ).push( renderState );
  12039. } else {
  12040. renderState = renderStates.get( scene )[ renderCallDepth ];
  12041. }
  12042. }
  12043. return renderState;
  12044. }
  12045. function dispose() {
  12046. renderStates = new WeakMap();
  12047. }
  12048. return {
  12049. get: get,
  12050. dispose: dispose
  12051. };
  12052. }
  12053. /**
  12054. * parameters = {
  12055. *
  12056. * opacity: <float>,
  12057. *
  12058. * map: new THREE.Texture( <Image> ),
  12059. *
  12060. * alphaMap: new THREE.Texture( <Image> ),
  12061. *
  12062. * displacementMap: new THREE.Texture( <Image> ),
  12063. * displacementScale: <float>,
  12064. * displacementBias: <float>,
  12065. *
  12066. * wireframe: <boolean>,
  12067. * wireframelineWidth: <float>
  12068. * }
  12069. */
  12070. function MeshDepthMaterial( parameters ) {
  12071. Material.call( this );
  12072. this.type = 'MeshDepthMaterial';
  12073. this.depthPacking = BasicDepthPacking;
  12074. this.skinning = false;
  12075. this.morphTargets = false;
  12076. this.map = null;
  12077. this.alphaMap = null;
  12078. this.displacementMap = null;
  12079. this.displacementScale = 1;
  12080. this.displacementBias = 0;
  12081. this.wireframe = false;
  12082. this.wireframelineWidth = 1;
  12083. this.fog = false;
  12084. this.setValues( parameters );
  12085. }
  12086. MeshDepthMaterial.prototype = Object.create( Material.prototype );
  12087. MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
  12088. MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
  12089. MeshDepthMaterial.prototype.copy = function ( source ) {
  12090. Material.prototype.copy.call( this, source );
  12091. this.depthPacking = source.depthPacking;
  12092. this.skinning = source.skinning;
  12093. this.morphTargets = source.morphTargets;
  12094. this.map = source.map;
  12095. this.alphaMap = source.alphaMap;
  12096. this.displacementMap = source.displacementMap;
  12097. this.displacementScale = source.displacementScale;
  12098. this.displacementBias = source.displacementBias;
  12099. this.wireframe = source.wireframe;
  12100. this.wireframelineWidth = source.wireframelineWidth;
  12101. return this;
  12102. };
  12103. /**
  12104. * parameters = {
  12105. *
  12106. * referencePosition: <float>,
  12107. * nearDistance: <float>,
  12108. * farDistance: <float>,
  12109. *
  12110. * skinning: <bool>,
  12111. * morphTargets: <bool>,
  12112. *
  12113. * map: new THREE.Texture( <Image> ),
  12114. *
  12115. * alphaMap: new THREE.Texture( <Image> ),
  12116. *
  12117. * displacementMap: new THREE.Texture( <Image> ),
  12118. * displacementScale: <float>,
  12119. * displacementBias: <float>
  12120. *
  12121. * }
  12122. */
  12123. function MeshDistanceMaterial( parameters ) {
  12124. Material.call( this );
  12125. this.type = 'MeshDistanceMaterial';
  12126. this.referencePosition = new Vector3();
  12127. this.nearDistance = 1;
  12128. this.farDistance = 1000;
  12129. this.skinning = false;
  12130. this.morphTargets = false;
  12131. this.map = null;
  12132. this.alphaMap = null;
  12133. this.displacementMap = null;
  12134. this.displacementScale = 1;
  12135. this.displacementBias = 0;
  12136. this.fog = false;
  12137. this.setValues( parameters );
  12138. }
  12139. MeshDistanceMaterial.prototype = Object.create( Material.prototype );
  12140. MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
  12141. MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
  12142. MeshDistanceMaterial.prototype.copy = function ( source ) {
  12143. Material.prototype.copy.call( this, source );
  12144. this.referencePosition.copy( source.referencePosition );
  12145. this.nearDistance = source.nearDistance;
  12146. this.farDistance = source.farDistance;
  12147. this.skinning = source.skinning;
  12148. this.morphTargets = source.morphTargets;
  12149. this.map = source.map;
  12150. this.alphaMap = source.alphaMap;
  12151. this.displacementMap = source.displacementMap;
  12152. this.displacementScale = source.displacementScale;
  12153. this.displacementBias = source.displacementBias;
  12154. return this;
  12155. };
  12156. var vsm_frag = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n\tfor ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean * HALF_SAMPLE_RATE;\n\tsquared_mean = squared_mean * HALF_SAMPLE_RATE;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}";
  12157. var vsm_vert = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
  12158. function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
  12159. let _frustum = new Frustum();
  12160. const _shadowMapSize = new Vector2$1(),
  12161. _viewportSize = new Vector2$1(),
  12162. _viewport = new Vector4(),
  12163. _depthMaterials = [],
  12164. _distanceMaterials = [],
  12165. _materialCache = {};
  12166. const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
  12167. const shadowMaterialVertical = new ShaderMaterial( {
  12168. defines: {
  12169. SAMPLE_RATE: 2.0 / 8.0,
  12170. HALF_SAMPLE_RATE: 1.0 / 8.0
  12171. },
  12172. uniforms: {
  12173. shadow_pass: { value: null },
  12174. resolution: { value: new Vector2$1() },
  12175. radius: { value: 4.0 }
  12176. },
  12177. vertexShader: vsm_vert,
  12178. fragmentShader: vsm_frag
  12179. } );
  12180. const shadowMaterialHorizontal = shadowMaterialVertical.clone();
  12181. shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
  12182. const fullScreenTri = new BufferGeometry();
  12183. fullScreenTri.setAttribute(
  12184. 'position',
  12185. new BufferAttribute(
  12186. new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
  12187. 3
  12188. )
  12189. );
  12190. const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
  12191. const scope = this;
  12192. this.enabled = false;
  12193. this.autoUpdate = true;
  12194. this.needsUpdate = false;
  12195. this.type = PCFShadowMap;
  12196. this.render = function ( lights, scene, camera ) {
  12197. if ( scope.enabled === false ) return;
  12198. if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
  12199. if ( lights.length === 0 ) return;
  12200. const currentRenderTarget = _renderer.getRenderTarget();
  12201. const activeCubeFace = _renderer.getActiveCubeFace();
  12202. const activeMipmapLevel = _renderer.getActiveMipmapLevel();
  12203. const _state = _renderer.state;
  12204. // Set GL state for depth map.
  12205. _state.setBlending( NoBlending );
  12206. _state.buffers.color.setClear( 1, 1, 1, 1 );
  12207. _state.buffers.depth.setTest( true );
  12208. _state.setScissorTest( false );
  12209. // render depth map
  12210. for ( let i = 0, il = lights.length; i < il; i ++ ) {
  12211. const light = lights[ i ];
  12212. const shadow = light.shadow;
  12213. if ( shadow === undefined ) {
  12214. console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
  12215. continue;
  12216. }
  12217. if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
  12218. _shadowMapSize.copy( shadow.mapSize );
  12219. const shadowFrameExtents = shadow.getFrameExtents();
  12220. _shadowMapSize.multiply( shadowFrameExtents );
  12221. _viewportSize.copy( shadow.mapSize );
  12222. if ( _shadowMapSize.x > maxTextureSize || _shadowMapSize.y > maxTextureSize ) {
  12223. if ( _shadowMapSize.x > maxTextureSize ) {
  12224. _viewportSize.x = Math.floor( maxTextureSize / shadowFrameExtents.x );
  12225. _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
  12226. shadow.mapSize.x = _viewportSize.x;
  12227. }
  12228. if ( _shadowMapSize.y > maxTextureSize ) {
  12229. _viewportSize.y = Math.floor( maxTextureSize / shadowFrameExtents.y );
  12230. _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
  12231. shadow.mapSize.y = _viewportSize.y;
  12232. }
  12233. }
  12234. if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
  12235. const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
  12236. shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
  12237. shadow.map.texture.name = light.name + '.shadowMap';
  12238. shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
  12239. shadow.camera.updateProjectionMatrix();
  12240. }
  12241. if ( shadow.map === null ) {
  12242. const pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
  12243. shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
  12244. shadow.map.texture.name = light.name + '.shadowMap';
  12245. shadow.camera.updateProjectionMatrix();
  12246. }
  12247. _renderer.setRenderTarget( shadow.map );
  12248. _renderer.clear();
  12249. const viewportCount = shadow.getViewportCount();
  12250. for ( let vp = 0; vp < viewportCount; vp ++ ) {
  12251. const viewport = shadow.getViewport( vp );
  12252. _viewport.set(
  12253. _viewportSize.x * viewport.x,
  12254. _viewportSize.y * viewport.y,
  12255. _viewportSize.x * viewport.z,
  12256. _viewportSize.y * viewport.w
  12257. );
  12258. _state.viewport( _viewport );
  12259. shadow.updateMatrices( light, vp );
  12260. _frustum = shadow.getFrustum();
  12261. renderObject( scene, camera, shadow.camera, light, this.type );
  12262. }
  12263. // do blur pass for VSM
  12264. if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
  12265. VSMPass( shadow, camera );
  12266. }
  12267. shadow.needsUpdate = false;
  12268. }
  12269. scope.needsUpdate = false;
  12270. _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
  12271. };
  12272. function VSMPass( shadow, camera ) {
  12273. const geometry = _objects.update( fullScreenMesh );
  12274. // vertical pass
  12275. shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
  12276. shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
  12277. shadowMaterialVertical.uniforms.radius.value = shadow.radius;
  12278. _renderer.setRenderTarget( shadow.mapPass );
  12279. _renderer.clear();
  12280. _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
  12281. // horizontal pass
  12282. shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
  12283. shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
  12284. shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
  12285. _renderer.setRenderTarget( shadow.map );
  12286. _renderer.clear();
  12287. _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
  12288. }
  12289. function getDepthMaterialVariant( useMorphing, useSkinning, useInstancing ) {
  12290. const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
  12291. let material = _depthMaterials[ index ];
  12292. if ( material === undefined ) {
  12293. material = new MeshDepthMaterial( {
  12294. depthPacking: RGBADepthPacking,
  12295. morphTargets: useMorphing,
  12296. skinning: useSkinning
  12297. } );
  12298. _depthMaterials[ index ] = material;
  12299. }
  12300. return material;
  12301. }
  12302. function getDistanceMaterialVariant( useMorphing, useSkinning, useInstancing ) {
  12303. const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
  12304. let material = _distanceMaterials[ index ];
  12305. if ( material === undefined ) {
  12306. material = new MeshDistanceMaterial( {
  12307. morphTargets: useMorphing,
  12308. skinning: useSkinning
  12309. } );
  12310. _distanceMaterials[ index ] = material;
  12311. }
  12312. return material;
  12313. }
  12314. function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) {
  12315. let result = null;
  12316. let getMaterialVariant = getDepthMaterialVariant;
  12317. let customMaterial = object.customDepthMaterial;
  12318. if ( light.isPointLight === true ) {
  12319. getMaterialVariant = getDistanceMaterialVariant;
  12320. customMaterial = object.customDistanceMaterial;
  12321. }
  12322. if ( customMaterial === undefined ) {
  12323. let useMorphing = false;
  12324. if ( material.morphTargets === true ) {
  12325. useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
  12326. }
  12327. let useSkinning = false;
  12328. if ( object.isSkinnedMesh === true ) {
  12329. if ( material.skinning === true ) {
  12330. useSkinning = true;
  12331. } else {
  12332. console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
  12333. }
  12334. }
  12335. const useInstancing = object.isInstancedMesh === true;
  12336. result = getMaterialVariant( useMorphing, useSkinning, useInstancing );
  12337. } else {
  12338. result = customMaterial;
  12339. }
  12340. if ( _renderer.localClippingEnabled &&
  12341. material.clipShadows === true &&
  12342. material.clippingPlanes.length !== 0 ) {
  12343. // in this case we need a unique material instance reflecting the
  12344. // appropriate state
  12345. const keyA = result.uuid, keyB = material.uuid;
  12346. let materialsForVariant = _materialCache[ keyA ];
  12347. if ( materialsForVariant === undefined ) {
  12348. materialsForVariant = {};
  12349. _materialCache[ keyA ] = materialsForVariant;
  12350. }
  12351. let cachedMaterial = materialsForVariant[ keyB ];
  12352. if ( cachedMaterial === undefined ) {
  12353. cachedMaterial = result.clone();
  12354. materialsForVariant[ keyB ] = cachedMaterial;
  12355. }
  12356. result = cachedMaterial;
  12357. }
  12358. result.visible = material.visible;
  12359. result.wireframe = material.wireframe;
  12360. if ( type === VSMShadowMap ) {
  12361. result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
  12362. } else {
  12363. result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
  12364. }
  12365. result.clipShadows = material.clipShadows;
  12366. result.clippingPlanes = material.clippingPlanes;
  12367. result.clipIntersection = material.clipIntersection;
  12368. result.wireframelineWidth = material.wireframelineWidth;
  12369. result.lineWidth = material.lineWidth;
  12370. if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
  12371. result.referencePosition.setFromMatrixPosition( light.matrixWorld );
  12372. result.nearDistance = shadowCameraNear;
  12373. result.farDistance = shadowCameraFar;
  12374. }
  12375. return result;
  12376. }
  12377. function renderObject( object, camera, shadowCamera, light, type ) {
  12378. if ( object.visible === false ) return;
  12379. const visible = object.layers.test( camera.layers );
  12380. if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
  12381. if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
  12382. object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
  12383. const geometry = _objects.update( object );
  12384. const material = object.material;
  12385. if ( Array.isArray( material ) ) {
  12386. const groups = geometry.groups;
  12387. for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
  12388. const group = groups[ k ];
  12389. const groupMaterial = material[ group.materialIndex ];
  12390. if ( groupMaterial && groupMaterial.visible ) {
  12391. const depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type );
  12392. _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
  12393. }
  12394. }
  12395. } else if ( material.visible ) {
  12396. const depthMaterial = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type );
  12397. _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
  12398. }
  12399. }
  12400. }
  12401. const children = object.children;
  12402. for ( let i = 0, l = children.length; i < l; i ++ ) {
  12403. renderObject( children[ i ], camera, shadowCamera, light, type );
  12404. }
  12405. }
  12406. }
  12407. function WebGLState( gl, extensions, capabilities ) {
  12408. const isWebGL2 = capabilities.isWebGL2;
  12409. function ColorBuffer() {
  12410. let locked = false;
  12411. const color = new Vector4();
  12412. let currentColorMask = null;
  12413. const currentColorClear = new Vector4( 0, 0, 0, 0 );
  12414. return {
  12415. setMask: function ( colorMask ) {
  12416. if ( currentColorMask !== colorMask && ! locked ) {
  12417. gl.colorMask( colorMask, colorMask, colorMask, colorMask );
  12418. currentColorMask = colorMask;
  12419. }
  12420. },
  12421. setLocked: function ( lock ) {
  12422. locked = lock;
  12423. },
  12424. setClear: function ( r, g, b, a, premultipliedAlpha ) {
  12425. if ( premultipliedAlpha === true ) {
  12426. r *= a; g *= a; b *= a;
  12427. }
  12428. color.set( r, g, b, a );
  12429. if ( currentColorClear.equals( color ) === false ) {
  12430. gl.clearColor( r, g, b, a );
  12431. currentColorClear.copy( color );
  12432. }
  12433. },
  12434. reset: function () {
  12435. locked = false;
  12436. currentColorMask = null;
  12437. currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
  12438. }
  12439. };
  12440. }
  12441. function DepthBuffer() {
  12442. let locked = false;
  12443. let currentDepthMask = null;
  12444. let currentDepthFunc = null;
  12445. let currentDepthClear = null;
  12446. return {
  12447. setTest: function ( depthTest ) {
  12448. if ( depthTest ) {
  12449. enable( 2929 );
  12450. } else {
  12451. disable( 2929 );
  12452. }
  12453. },
  12454. setMask: function ( depthMask ) {
  12455. if ( currentDepthMask !== depthMask && ! locked ) {
  12456. gl.depthMask( depthMask );
  12457. currentDepthMask = depthMask;
  12458. }
  12459. },
  12460. setFunc: function ( depthFunc ) {
  12461. if ( currentDepthFunc !== depthFunc ) {
  12462. if ( depthFunc ) {
  12463. switch ( depthFunc ) {
  12464. case NeverDepth:
  12465. gl.depthFunc( 512 );
  12466. break;
  12467. case AlwaysDepth:
  12468. gl.depthFunc( 519 );
  12469. break;
  12470. case LessDepth:
  12471. gl.depthFunc( 513 );
  12472. break;
  12473. case LessEqualDepth:
  12474. gl.depthFunc( 515 );
  12475. break;
  12476. case EqualDepth:
  12477. gl.depthFunc( 514 );
  12478. break;
  12479. case GreaterEqualDepth:
  12480. gl.depthFunc( 518 );
  12481. break;
  12482. case GreaterDepth:
  12483. gl.depthFunc( 516 );
  12484. break;
  12485. case NotEqualDepth:
  12486. gl.depthFunc( 517 );
  12487. break;
  12488. default:
  12489. gl.depthFunc( 515 );
  12490. }
  12491. } else {
  12492. gl.depthFunc( 515 );
  12493. }
  12494. currentDepthFunc = depthFunc;
  12495. }
  12496. },
  12497. setLocked: function ( lock ) {
  12498. locked = lock;
  12499. },
  12500. setClear: function ( depth ) {
  12501. if ( currentDepthClear !== depth ) {
  12502. gl.clearDepth( depth );
  12503. currentDepthClear = depth;
  12504. }
  12505. },
  12506. reset: function () {
  12507. locked = false;
  12508. currentDepthMask = null;
  12509. currentDepthFunc = null;
  12510. currentDepthClear = null;
  12511. }
  12512. };
  12513. }
  12514. function StencilBuffer() {
  12515. let locked = false;
  12516. let currentStencilMask = null;
  12517. let currentStencilFunc = null;
  12518. let currentStencilRef = null;
  12519. let currentStencilFuncMask = null;
  12520. let currentStencilFail = null;
  12521. let currentStencilZFail = null;
  12522. let currentStencilZPass = null;
  12523. let currentStencilClear = null;
  12524. return {
  12525. setTest: function ( stencilTest ) {
  12526. if ( ! locked ) {
  12527. if ( stencilTest ) {
  12528. enable( 2960 );
  12529. } else {
  12530. disable( 2960 );
  12531. }
  12532. }
  12533. },
  12534. setMask: function ( stencilMask ) {
  12535. if ( currentStencilMask !== stencilMask && ! locked ) {
  12536. gl.stencilMask( stencilMask );
  12537. currentStencilMask = stencilMask;
  12538. }
  12539. },
  12540. setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
  12541. if ( currentStencilFunc !== stencilFunc ||
  12542. currentStencilRef !== stencilRef ||
  12543. currentStencilFuncMask !== stencilMask ) {
  12544. gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
  12545. currentStencilFunc = stencilFunc;
  12546. currentStencilRef = stencilRef;
  12547. currentStencilFuncMask = stencilMask;
  12548. }
  12549. },
  12550. setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
  12551. if ( currentStencilFail !== stencilFail ||
  12552. currentStencilZFail !== stencilZFail ||
  12553. currentStencilZPass !== stencilZPass ) {
  12554. gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
  12555. currentStencilFail = stencilFail;
  12556. currentStencilZFail = stencilZFail;
  12557. currentStencilZPass = stencilZPass;
  12558. }
  12559. },
  12560. setLocked: function ( lock ) {
  12561. locked = lock;
  12562. },
  12563. setClear: function ( stencil ) {
  12564. if ( currentStencilClear !== stencil ) {
  12565. gl.clearStencil( stencil );
  12566. currentStencilClear = stencil;
  12567. }
  12568. },
  12569. reset: function () {
  12570. locked = false;
  12571. currentStencilMask = null;
  12572. currentStencilFunc = null;
  12573. currentStencilRef = null;
  12574. currentStencilFuncMask = null;
  12575. currentStencilFail = null;
  12576. currentStencilZFail = null;
  12577. currentStencilZPass = null;
  12578. currentStencilClear = null;
  12579. }
  12580. };
  12581. }
  12582. //
  12583. const colorBuffer = new ColorBuffer();
  12584. const depthBuffer = new DepthBuffer();
  12585. const stencilBuffer = new StencilBuffer();
  12586. let enabledCapabilities = {};
  12587. let currentProgram = null;
  12588. let currentBlendingEnabled = null;
  12589. let currentBlending = null;
  12590. let currentBlendEquation = null;
  12591. let currentBlendSrc = null;
  12592. let currentBlendDst = null;
  12593. let currentBlendEquationAlpha = null;
  12594. let currentBlendSrcAlpha = null;
  12595. let currentBlendDstAlpha = null;
  12596. let currentPremultipledAlpha = false;
  12597. let currentFlipSided = null;
  12598. let currentCullFace = null;
  12599. let currentlineWidth = null;
  12600. let currentPolygonOffsetFactor = null;
  12601. let currentPolygonOffsetUnits = null;
  12602. const maxTextures = gl.getParameter( 35661 );
  12603. let lineWidthAvailable = false;
  12604. let version = 0;
  12605. const glVersion = gl.getParameter( 7938 );
  12606. if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
  12607. version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
  12608. lineWidthAvailable = ( version >= 1.0 );
  12609. } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
  12610. version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
  12611. lineWidthAvailable = ( version >= 2.0 );
  12612. }
  12613. let currentTextureSlot = null;
  12614. let currentBoundTextures = {};
  12615. const currentScissor = new Vector4();
  12616. const currentViewport = new Vector4();
  12617. function createTexture( type, target, count ) {
  12618. const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
  12619. const texture = gl.createTexture();
  12620. gl.bindTexture( type, texture );
  12621. gl.texParameteri( type, 10241, 9728 );
  12622. gl.texParameteri( type, 10240, 9728 );
  12623. for ( let i = 0; i < count; i ++ ) {
  12624. gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data );
  12625. }
  12626. return texture;
  12627. }
  12628. const emptyTextures = {};
  12629. emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 );
  12630. emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 );
  12631. // init
  12632. colorBuffer.setClear( 0, 0, 0, 1 );
  12633. depthBuffer.setClear( 1 );
  12634. stencilBuffer.setClear( 0 );
  12635. enable( 2929 );
  12636. depthBuffer.setFunc( LessEqualDepth );
  12637. setFlipSided( false );
  12638. setCullFace( CullFaceBack );
  12639. enable( 2884 );
  12640. setBlending( NoBlending );
  12641. //
  12642. function enable( id ) {
  12643. if ( enabledCapabilities[ id ] !== true ) {
  12644. gl.enable( id );
  12645. enabledCapabilities[ id ] = true;
  12646. }
  12647. }
  12648. function disable( id ) {
  12649. if ( enabledCapabilities[ id ] !== false ) {
  12650. gl.disable( id );
  12651. enabledCapabilities[ id ] = false;
  12652. }
  12653. }
  12654. function useProgram( program ) {
  12655. if ( currentProgram !== program ) {
  12656. gl.useProgram( program );
  12657. currentProgram = program;
  12658. return true;
  12659. }
  12660. return false;
  12661. }
  12662. const equationToGL = {
  12663. [ AddEquation ]: 32774,
  12664. [ SubtractEquation ]: 32778,
  12665. [ ReverseSubtractEquation ]: 32779
  12666. };
  12667. if ( isWebGL2 ) {
  12668. equationToGL[ MinEquation ] = 32775;
  12669. equationToGL[ MaxEquation ] = 32776;
  12670. } else {
  12671. const extension = extensions.get( 'EXT_blend_minmax' );
  12672. if ( extension !== null ) {
  12673. equationToGL[ MinEquation ] = extension.MIN_EXT;
  12674. equationToGL[ MaxEquation ] = extension.MAX_EXT;
  12675. }
  12676. }
  12677. const factorToGL = {
  12678. [ ZeroFactor ]: 0,
  12679. [ OneFactor ]: 1,
  12680. [ SrcColorFactor ]: 768,
  12681. [ SrcAlphaFactor ]: 770,
  12682. [ SrcAlphaSaturateFactor ]: 776,
  12683. [ DstColorFactor ]: 774,
  12684. [ DstAlphaFactor ]: 772,
  12685. [ OneMinusSrcColorFactor ]: 769,
  12686. [ OneMinusSrcAlphaFactor ]: 771,
  12687. [ OneMinusDstColorFactor ]: 775,
  12688. [ OneMinusDstAlphaFactor ]: 773
  12689. };
  12690. function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
  12691. if ( blending === NoBlending ) {
  12692. if ( currentBlendingEnabled ) {
  12693. disable( 3042 );
  12694. currentBlendingEnabled = false;
  12695. }
  12696. return;
  12697. }
  12698. if ( ! currentBlendingEnabled ) {
  12699. enable( 3042 );
  12700. currentBlendingEnabled = true;
  12701. }
  12702. if ( blending !== CustomBlending ) {
  12703. if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
  12704. if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
  12705. gl.blendEquation( 32774 );
  12706. currentBlendEquation = AddEquation;
  12707. currentBlendEquationAlpha = AddEquation;
  12708. }
  12709. if ( premultipliedAlpha ) {
  12710. switch ( blending ) {
  12711. case NormalBlending:
  12712. gl.blendFuncSeparate( 1, 771, 1, 771 );
  12713. break;
  12714. case AdditiveBlending:
  12715. gl.blendFunc( 1, 1 );
  12716. break;
  12717. case SubtractiveBlending:
  12718. gl.blendFuncSeparate( 0, 0, 769, 771 );
  12719. break;
  12720. case MultiplyBlending:
  12721. gl.blendFuncSeparate( 0, 768, 0, 770 );
  12722. break;
  12723. default:
  12724. console.error( 'THREE.WebGLState: Invalid blending: ', blending );
  12725. break;
  12726. }
  12727. } else {
  12728. switch ( blending ) {
  12729. case NormalBlending:
  12730. gl.blendFuncSeparate( 770, 771, 1, 771 );
  12731. break;
  12732. case AdditiveBlending:
  12733. gl.blendFunc( 770, 1 );
  12734. break;
  12735. case SubtractiveBlending:
  12736. gl.blendFunc( 0, 769 );
  12737. break;
  12738. case MultiplyBlending:
  12739. gl.blendFunc( 0, 768 );
  12740. break;
  12741. default:
  12742. console.error( 'THREE.WebGLState: Invalid blending: ', blending );
  12743. break;
  12744. }
  12745. }
  12746. currentBlendSrc = null;
  12747. currentBlendDst = null;
  12748. currentBlendSrcAlpha = null;
  12749. currentBlendDstAlpha = null;
  12750. currentBlending = blending;
  12751. currentPremultipledAlpha = premultipliedAlpha;
  12752. }
  12753. return;
  12754. }
  12755. // custom blending
  12756. blendEquationAlpha = blendEquationAlpha || blendEquation;
  12757. blendSrcAlpha = blendSrcAlpha || blendSrc;
  12758. blendDstAlpha = blendDstAlpha || blendDst;
  12759. if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
  12760. gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
  12761. currentBlendEquation = blendEquation;
  12762. currentBlendEquationAlpha = blendEquationAlpha;
  12763. }
  12764. if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
  12765. gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
  12766. currentBlendSrc = blendSrc;
  12767. currentBlendDst = blendDst;
  12768. currentBlendSrcAlpha = blendSrcAlpha;
  12769. currentBlendDstAlpha = blendDstAlpha;
  12770. }
  12771. currentBlending = blending;
  12772. currentPremultipledAlpha = null;
  12773. }
  12774. function setMaterial( material, frontFaceCW ) {
  12775. material.side === DoubleSide
  12776. ? disable( 2884 )
  12777. : enable( 2884 );
  12778. let flipSided = ( material.side === BackSide );
  12779. if ( frontFaceCW ) flipSided = ! flipSided;
  12780. setFlipSided( flipSided );
  12781. ( material.blending === NormalBlending && material.transparent === false )
  12782. ? setBlending( NoBlending )
  12783. : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
  12784. depthBuffer.setFunc( material.depthFunc );
  12785. depthBuffer.setTest( material.depthTest );
  12786. depthBuffer.setMask( material.depthWrite );
  12787. colorBuffer.setMask( material.colorWrite );
  12788. const stencilWrite = material.stencilWrite;
  12789. stencilBuffer.setTest( stencilWrite );
  12790. if ( stencilWrite ) {
  12791. stencilBuffer.setMask( material.stencilWriteMask );
  12792. stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
  12793. stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
  12794. }
  12795. setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
  12796. }
  12797. //
  12798. function setFlipSided( flipSided ) {
  12799. if ( currentFlipSided !== flipSided ) {
  12800. if ( flipSided ) {
  12801. gl.frontFace( 2304 );
  12802. } else {
  12803. gl.frontFace( 2305 );
  12804. }
  12805. currentFlipSided = flipSided;
  12806. }
  12807. }
  12808. function setCullFace( cullFace ) {
  12809. if ( cullFace !== CullFaceNone ) {
  12810. enable( 2884 );
  12811. if ( cullFace !== currentCullFace ) {
  12812. if ( cullFace === CullFaceBack ) {
  12813. gl.cullFace( 1029 );
  12814. } else if ( cullFace === CullFaceFront ) {
  12815. gl.cullFace( 1028 );
  12816. } else {
  12817. gl.cullFace( 1032 );
  12818. }
  12819. }
  12820. } else {
  12821. disable( 2884 );
  12822. }
  12823. currentCullFace = cullFace;
  12824. }
  12825. function setlineWidth( width ) {
  12826. if ( width !== currentlineWidth ) {
  12827. if ( lineWidthAvailable ) gl.lineWidth( width );
  12828. currentlineWidth = width;
  12829. }
  12830. }
  12831. function setPolygonOffset( polygonOffset, factor, units ) {
  12832. if ( polygonOffset ) {
  12833. enable( 32823 );
  12834. if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
  12835. gl.polygonOffset( factor, units );
  12836. currentPolygonOffsetFactor = factor;
  12837. currentPolygonOffsetUnits = units;
  12838. }
  12839. } else {
  12840. disable( 32823 );
  12841. }
  12842. }
  12843. function setScissorTest( scissorTest ) {
  12844. if ( scissorTest ) {
  12845. enable( 3089 );
  12846. } else {
  12847. disable( 3089 );
  12848. }
  12849. }
  12850. // texture
  12851. function activeTexture( webglSlot ) {
  12852. if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1;
  12853. if ( currentTextureSlot !== webglSlot ) {
  12854. gl.activeTexture( webglSlot );
  12855. currentTextureSlot = webglSlot;
  12856. }
  12857. }
  12858. function bindTexture( webglType, webglTexture ) {
  12859. if ( currentTextureSlot === null ) {
  12860. activeTexture();
  12861. }
  12862. let boundTexture = currentBoundTextures[ currentTextureSlot ];
  12863. if ( boundTexture === undefined ) {
  12864. boundTexture = { type: undefined, texture: undefined };
  12865. currentBoundTextures[ currentTextureSlot ] = boundTexture;
  12866. }
  12867. if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
  12868. gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
  12869. boundTexture.type = webglType;
  12870. boundTexture.texture = webglTexture;
  12871. }
  12872. }
  12873. function unbindTexture() {
  12874. const boundTexture = currentBoundTextures[ currentTextureSlot ];
  12875. if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
  12876. gl.bindTexture( boundTexture.type, null );
  12877. boundTexture.type = undefined;
  12878. boundTexture.texture = undefined;
  12879. }
  12880. }
  12881. function compressedTexImage2D() {
  12882. try {
  12883. gl.compressedTexImage2D.apply( gl, arguments );
  12884. } catch ( error ) {
  12885. console.error( 'THREE.WebGLState:', error );
  12886. }
  12887. }
  12888. function texImage2D() {
  12889. try {
  12890. gl.texImage2D.apply( gl, arguments );
  12891. } catch ( error ) {
  12892. console.error( 'THREE.WebGLState:', error );
  12893. }
  12894. }
  12895. function texImage3D() {
  12896. try {
  12897. gl.texImage3D.apply( gl, arguments );
  12898. } catch ( error ) {
  12899. console.error( 'THREE.WebGLState:', error );
  12900. }
  12901. }
  12902. //
  12903. function scissor( scissor ) {
  12904. if ( currentScissor.equals( scissor ) === false ) {
  12905. gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
  12906. currentScissor.copy( scissor );
  12907. }
  12908. }
  12909. function viewport( viewport ) {
  12910. if ( currentViewport.equals( viewport ) === false ) {
  12911. gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
  12912. currentViewport.copy( viewport );
  12913. }
  12914. }
  12915. //
  12916. function reset() {
  12917. enabledCapabilities = {};
  12918. currentTextureSlot = null;
  12919. currentBoundTextures = {};
  12920. currentProgram = null;
  12921. currentBlendingEnabled = null;
  12922. currentBlending = null;
  12923. currentBlendEquation = null;
  12924. currentBlendSrc = null;
  12925. currentBlendDst = null;
  12926. currentBlendEquationAlpha = null;
  12927. currentBlendSrcAlpha = null;
  12928. currentBlendDstAlpha = null;
  12929. currentPremultipledAlpha = false;
  12930. currentFlipSided = null;
  12931. currentCullFace = null;
  12932. currentlineWidth = null;
  12933. currentPolygonOffsetFactor = null;
  12934. currentPolygonOffsetUnits = null;
  12935. colorBuffer.reset();
  12936. depthBuffer.reset();
  12937. stencilBuffer.reset();
  12938. }
  12939. return {
  12940. buffers: {
  12941. color: colorBuffer,
  12942. depth: depthBuffer,
  12943. stencil: stencilBuffer
  12944. },
  12945. enable: enable,
  12946. disable: disable,
  12947. useProgram: useProgram,
  12948. setBlending: setBlending,
  12949. setMaterial: setMaterial,
  12950. setFlipSided: setFlipSided,
  12951. setCullFace: setCullFace,
  12952. setlineWidth: setlineWidth,
  12953. setPolygonOffset: setPolygonOffset,
  12954. setScissorTest: setScissorTest,
  12955. activeTexture: activeTexture,
  12956. bindTexture: bindTexture,
  12957. unbindTexture: unbindTexture,
  12958. compressedTexImage2D: compressedTexImage2D,
  12959. texImage2D: texImage2D,
  12960. texImage3D: texImage3D,
  12961. scissor: scissor,
  12962. viewport: viewport,
  12963. reset: reset
  12964. };
  12965. }
  12966. function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
  12967. const isWebGL2 = capabilities.isWebGL2;
  12968. const maxTextures = capabilities.maxTextures;
  12969. const maxCubemapSize = capabilities.maxCubemapSize;
  12970. const maxTextureSize = capabilities.maxTextureSize;
  12971. const maxSamples = capabilities.maxSamples;
  12972. const _videoTextures = new WeakMap();
  12973. let _canvas;
  12974. // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
  12975. // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
  12976. // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
  12977. let useOffscreenCanvas = false;
  12978. try {
  12979. useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
  12980. && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
  12981. } catch ( err ) {
  12982. // Ignore any errors
  12983. }
  12984. function createCanvas( width, height ) {
  12985. // Use OffscreenCanvas when available. Specially needed in web workers
  12986. return useOffscreenCanvas ?
  12987. new OffscreenCanvas( width, height ) :
  12988. document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
  12989. }
  12990. function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
  12991. let scale = 1;
  12992. // handle case if texture exceeds max size
  12993. if ( image.width > maxSize || image.height > maxSize ) {
  12994. scale = maxSize / Math.max( image.width, image.height );
  12995. }
  12996. // only perform resize if necessary
  12997. if ( scale < 1 || needsPowerOfTwo === true ) {
  12998. // only perform resize for certain image types
  12999. if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
  13000. ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
  13001. ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
  13002. const floor = needsPowerOfTwo ? MathUtils.floorPowerOfTwo : Math.floor;
  13003. const width = floor( scale * image.width );
  13004. const height = floor( scale * image.height );
  13005. if ( _canvas === undefined ) _canvas = createCanvas( width, height );
  13006. // cube textures can't reuse the same canvas
  13007. const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
  13008. canvas.width = width;
  13009. canvas.height = height;
  13010. const context = canvas.getContext( '2d' );
  13011. context.drawImage( image, 0, 0, width, height );
  13012. console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
  13013. return canvas;
  13014. } else {
  13015. if ( 'data' in image ) {
  13016. console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
  13017. }
  13018. return image;
  13019. }
  13020. }
  13021. return image;
  13022. }
  13023. function isPowerOfTwo( image ) {
  13024. return MathUtils.isPowerOfTwo( image.width ) && MathUtils.isPowerOfTwo( image.height );
  13025. }
  13026. function textureNeedsPowerOfTwo( texture ) {
  13027. if ( isWebGL2 ) return false;
  13028. return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
  13029. ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
  13030. }
  13031. function textureNeedsGenerateMipmaps( texture, supportsMips ) {
  13032. return texture.generateMipmaps && supportsMips &&
  13033. texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
  13034. }
  13035. function generateMipmap( target, texture, width, height ) {
  13036. _gl.generateMipmap( target );
  13037. const textureProperties = properties.get( texture );
  13038. // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
  13039. textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
  13040. }
  13041. function getInternalFormat( internalFormatName, glFormat, glType ) {
  13042. if ( isWebGL2 === false ) return glFormat;
  13043. if ( internalFormatName !== null ) {
  13044. if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
  13045. console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
  13046. }
  13047. let internalFormat = glFormat;
  13048. if ( glFormat === 6403 ) {
  13049. if ( glType === 5126 ) internalFormat = 33326;
  13050. if ( glType === 5131 ) internalFormat = 33325;
  13051. if ( glType === 5121 ) internalFormat = 33321;
  13052. }
  13053. if ( glFormat === 6407 ) {
  13054. if ( glType === 5126 ) internalFormat = 34837;
  13055. if ( glType === 5131 ) internalFormat = 34843;
  13056. if ( glType === 5121 ) internalFormat = 32849;
  13057. }
  13058. if ( glFormat === 6408 ) {
  13059. if ( glType === 5126 ) internalFormat = 34836;
  13060. if ( glType === 5131 ) internalFormat = 34842;
  13061. if ( glType === 5121 ) internalFormat = 32856;
  13062. }
  13063. if ( internalFormat === 33325 || internalFormat === 33326 ||
  13064. internalFormat === 34842 || internalFormat === 34836 ) {
  13065. extensions.get( 'EXT_color_buffer_float' );
  13066. }
  13067. return internalFormat;
  13068. }
  13069. // Fallback filters for non-power-of-2 textures
  13070. function filterFallback( f ) {
  13071. if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
  13072. return 9728;
  13073. }
  13074. return 9729;
  13075. }
  13076. //
  13077. function onTextureDispose( event ) {
  13078. const texture = event.target;
  13079. texture.removeEventListener( 'dispose', onTextureDispose );
  13080. deallocateTexture( texture );
  13081. if ( texture.isVideoTexture ) {
  13082. _videoTextures.delete( texture );
  13083. }
  13084. info.memory.textures --;
  13085. }
  13086. function onRenderTargetDispose( event ) {
  13087. const renderTarget = event.target;
  13088. renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
  13089. deallocateRenderTarget( renderTarget );
  13090. info.memory.textures --;
  13091. }
  13092. //
  13093. function deallocateTexture( texture ) {
  13094. const textureProperties = properties.get( texture );
  13095. if ( textureProperties.__webglInit === undefined ) return;
  13096. _gl.deleteTexture( textureProperties.__webglTexture );
  13097. properties.remove( texture );
  13098. }
  13099. function deallocateRenderTarget( renderTarget ) {
  13100. const renderTargetProperties = properties.get( renderTarget );
  13101. const textureProperties = properties.get( renderTarget.texture );
  13102. if ( ! renderTarget ) return;
  13103. if ( textureProperties.__webglTexture !== undefined ) {
  13104. _gl.deleteTexture( textureProperties.__webglTexture );
  13105. }
  13106. if ( renderTarget.depthTexture ) {
  13107. renderTarget.depthTexture.dispose();
  13108. }
  13109. if ( renderTarget.isWebGLCubeRenderTarget ) {
  13110. for ( let i = 0; i < 6; i ++ ) {
  13111. _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
  13112. if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
  13113. }
  13114. } else {
  13115. _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
  13116. if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
  13117. if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
  13118. if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer );
  13119. if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
  13120. }
  13121. properties.remove( renderTarget.texture );
  13122. properties.remove( renderTarget );
  13123. }
  13124. //
  13125. let textureUnits = 0;
  13126. function resetTextureUnits() {
  13127. textureUnits = 0;
  13128. }
  13129. function allocateTextureUnit() {
  13130. const textureUnit = textureUnits;
  13131. if ( textureUnit >= maxTextures ) {
  13132. console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures );
  13133. }
  13134. textureUnits += 1;
  13135. return textureUnit;
  13136. }
  13137. //
  13138. function setTexture2D( texture, slot ) {
  13139. const textureProperties = properties.get( texture );
  13140. if ( texture.isVideoTexture ) updateVideoTexture( texture );
  13141. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  13142. const image = texture.image;
  13143. if ( image === undefined ) {
  13144. console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
  13145. } else if ( image.complete === false ) {
  13146. console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
  13147. } else {
  13148. uploadTexture( textureProperties, texture, slot );
  13149. return;
  13150. }
  13151. }
  13152. state.activeTexture( 33984 + slot );
  13153. state.bindTexture( 3553, textureProperties.__webglTexture );
  13154. }
  13155. function setTexture2DArray( texture, slot ) {
  13156. const textureProperties = properties.get( texture );
  13157. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  13158. uploadTexture( textureProperties, texture, slot );
  13159. return;
  13160. }
  13161. state.activeTexture( 33984 + slot );
  13162. state.bindTexture( 35866, textureProperties.__webglTexture );
  13163. }
  13164. function setTexture3D( texture, slot ) {
  13165. const textureProperties = properties.get( texture );
  13166. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  13167. uploadTexture( textureProperties, texture, slot );
  13168. return;
  13169. }
  13170. state.activeTexture( 33984 + slot );
  13171. state.bindTexture( 32879, textureProperties.__webglTexture );
  13172. }
  13173. function setTextureCube( texture, slot ) {
  13174. const textureProperties = properties.get( texture );
  13175. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  13176. uploadCubeTexture( textureProperties, texture, slot );
  13177. return;
  13178. }
  13179. state.activeTexture( 33984 + slot );
  13180. state.bindTexture( 34067, textureProperties.__webglTexture );
  13181. }
  13182. const wrappingToGL = {
  13183. [ RepeatWrapping ]: 10497,
  13184. [ ClampToEdgeWrapping ]: 33071,
  13185. [ MirroredRepeatWrapping ]: 33648
  13186. };
  13187. const filterToGL = {
  13188. [ NearestFilter ]: 9728,
  13189. [ NearestMipmapNearestFilter ]: 9984,
  13190. [ NearestMipmapLinearFilter ]: 9986,
  13191. [ LinearFilter ]: 9729,
  13192. [ LinearMipmapNearestFilter ]: 9985,
  13193. [ LinearMipmapLinearFilter ]: 9987
  13194. };
  13195. function setTextureParameters( textureType, texture, supportsMips ) {
  13196. if ( supportsMips ) {
  13197. _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] );
  13198. _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] );
  13199. if ( textureType === 32879 || textureType === 35866 ) {
  13200. _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] );
  13201. }
  13202. _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] );
  13203. _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] );
  13204. } else {
  13205. _gl.texParameteri( textureType, 10242, 33071 );
  13206. _gl.texParameteri( textureType, 10243, 33071 );
  13207. if ( textureType === 32879 || textureType === 35866 ) {
  13208. _gl.texParameteri( textureType, 32882, 33071 );
  13209. }
  13210. if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
  13211. console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
  13212. }
  13213. _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) );
  13214. _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) );
  13215. if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
  13216. console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
  13217. }
  13218. }
  13219. const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
  13220. if ( extension ) {
  13221. if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
  13222. if ( texture.type === HalfFloatType && ( isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return;
  13223. if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
  13224. _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
  13225. properties.get( texture ).__currentAnisotropy = texture.anisotropy;
  13226. }
  13227. }
  13228. }
  13229. function initTexture( textureProperties, texture ) {
  13230. if ( textureProperties.__webglInit === undefined ) {
  13231. textureProperties.__webglInit = true;
  13232. texture.addEventListener( 'dispose', onTextureDispose );
  13233. textureProperties.__webglTexture = _gl.createTexture();
  13234. info.memory.textures ++;
  13235. }
  13236. }
  13237. function uploadTexture( textureProperties, texture, slot ) {
  13238. let textureType = 3553;
  13239. if ( texture.isDataTexture2DArray ) textureType = 35866;
  13240. if ( texture.isDataTexture3D ) textureType = 32879;
  13241. initTexture( textureProperties, texture );
  13242. state.activeTexture( 33984 + slot );
  13243. state.bindTexture( textureType, textureProperties.__webglTexture );
  13244. _gl.pixelStorei( 37440, texture.flipY );
  13245. _gl.pixelStorei( 37441, texture.premultiplyAlpha );
  13246. _gl.pixelStorei( 3317, texture.unpackAlignment );
  13247. const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
  13248. const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
  13249. const supportsMips = isPowerOfTwo( image ) || isWebGL2,
  13250. glFormat = utils.convert( texture.format );
  13251. let glType = utils.convert( texture.type ),
  13252. glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
  13253. setTextureParameters( textureType, texture, supportsMips );
  13254. let mipmap;
  13255. const mipmaps = texture.mipmaps;
  13256. if ( texture.isDepthTexture ) {
  13257. // populate depth texture with dummy data
  13258. glInternalFormat = 6402;
  13259. if ( isWebGL2 ) {
  13260. if ( texture.type === FloatType ) {
  13261. glInternalFormat = 36012;
  13262. } else if ( texture.type === UnsignedIntType ) {
  13263. glInternalFormat = 33190;
  13264. } else if ( texture.type === UnsignedInt248Type$1 ) {
  13265. glInternalFormat = 35056;
  13266. } else {
  13267. glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D
  13268. }
  13269. } else {
  13270. if ( texture.type === FloatType ) {
  13271. console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
  13272. }
  13273. }
  13274. // validation checks for WebGL 1
  13275. if ( texture.format === DepthFormat && glInternalFormat === 6402 ) {
  13276. // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
  13277. // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
  13278. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  13279. if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
  13280. console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
  13281. texture.type = UnsignedShortType;
  13282. glType = utils.convert( texture.type );
  13283. }
  13284. }
  13285. if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) {
  13286. // Depth stencil textures need the DEPTH_STENCIL internal format
  13287. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  13288. glInternalFormat = 34041;
  13289. // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
  13290. // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
  13291. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  13292. if ( texture.type !== UnsignedInt248Type$1 ) {
  13293. console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
  13294. texture.type = UnsignedInt248Type$1;
  13295. glType = utils.convert( texture.type );
  13296. }
  13297. }
  13298. //
  13299. state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
  13300. } else if ( texture.isDataTexture ) {
  13301. // use manually created mipmaps if available
  13302. // if there are no manual mipmaps
  13303. // set 0 level mipmap and then use GL to generate other mipmap levels
  13304. if ( mipmaps.length > 0 && supportsMips ) {
  13305. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  13306. mipmap = mipmaps[ i ];
  13307. state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
  13308. }
  13309. texture.generateMipmaps = false;
  13310. textureProperties.__maxMipLevel = mipmaps.length - 1;
  13311. } else {
  13312. state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
  13313. textureProperties.__maxMipLevel = 0;
  13314. }
  13315. } else if ( texture.isCompressedTexture ) {
  13316. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  13317. mipmap = mipmaps[ i ];
  13318. if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
  13319. if ( glFormat !== null ) {
  13320. state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
  13321. } else {
  13322. console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
  13323. }
  13324. } else {
  13325. state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
  13326. }
  13327. }
  13328. textureProperties.__maxMipLevel = mipmaps.length - 1;
  13329. } else if ( texture.isDataTexture2DArray ) {
  13330. state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
  13331. textureProperties.__maxMipLevel = 0;
  13332. } else if ( texture.isDataTexture3D ) {
  13333. state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
  13334. textureProperties.__maxMipLevel = 0;
  13335. } else {
  13336. // regular Texture (image, video, canvas)
  13337. // use manually created mipmaps if available
  13338. // if there are no manual mipmaps
  13339. // set 0 level mipmap and then use GL to generate other mipmap levels
  13340. if ( mipmaps.length > 0 && supportsMips ) {
  13341. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  13342. mipmap = mipmaps[ i ];
  13343. state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap );
  13344. }
  13345. texture.generateMipmaps = false;
  13346. textureProperties.__maxMipLevel = mipmaps.length - 1;
  13347. } else {
  13348. state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image );
  13349. textureProperties.__maxMipLevel = 0;
  13350. }
  13351. }
  13352. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  13353. generateMipmap( textureType, texture, image.width, image.height );
  13354. }
  13355. textureProperties.__version = texture.version;
  13356. if ( texture.onUpdate ) texture.onUpdate( texture );
  13357. }
  13358. function uploadCubeTexture( textureProperties, texture, slot ) {
  13359. if ( texture.image.length !== 6 ) return;
  13360. initTexture( textureProperties, texture );
  13361. state.activeTexture( 33984 + slot );
  13362. state.bindTexture( 34067, textureProperties.__webglTexture );
  13363. _gl.pixelStorei( 37440, texture.flipY );
  13364. const isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) );
  13365. const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
  13366. const cubeImage = [];
  13367. for ( let i = 0; i < 6; i ++ ) {
  13368. if ( ! isCompressed && ! isDataTexture ) {
  13369. cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize );
  13370. } else {
  13371. cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
  13372. }
  13373. }
  13374. const image = cubeImage[ 0 ],
  13375. supportsMips = isPowerOfTwo( image ) || isWebGL2,
  13376. glFormat = utils.convert( texture.format ),
  13377. glType = utils.convert( texture.type ),
  13378. glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
  13379. setTextureParameters( 34067, texture, supportsMips );
  13380. let mipmaps;
  13381. if ( isCompressed ) {
  13382. for ( let i = 0; i < 6; i ++ ) {
  13383. mipmaps = cubeImage[ i ].mipmaps;
  13384. for ( let j = 0; j < mipmaps.length; j ++ ) {
  13385. const mipmap = mipmaps[ j ];
  13386. if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
  13387. if ( glFormat !== null ) {
  13388. state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
  13389. } else {
  13390. console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
  13391. }
  13392. } else {
  13393. state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
  13394. }
  13395. }
  13396. }
  13397. textureProperties.__maxMipLevel = mipmaps.length - 1;
  13398. } else {
  13399. mipmaps = texture.mipmaps;
  13400. for ( let i = 0; i < 6; i ++ ) {
  13401. if ( isDataTexture ) {
  13402. state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
  13403. for ( let j = 0; j < mipmaps.length; j ++ ) {
  13404. const mipmap = mipmaps[ j ];
  13405. const mipmapImage = mipmap.image[ i ].image;
  13406. state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
  13407. }
  13408. } else {
  13409. state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
  13410. for ( let j = 0; j < mipmaps.length; j ++ ) {
  13411. const mipmap = mipmaps[ j ];
  13412. state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
  13413. }
  13414. }
  13415. }
  13416. textureProperties.__maxMipLevel = mipmaps.length;
  13417. }
  13418. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  13419. // We assume images for cube map have the same size.
  13420. generateMipmap( 34067, texture, image.width, image.height );
  13421. }
  13422. textureProperties.__version = texture.version;
  13423. if ( texture.onUpdate ) texture.onUpdate( texture );
  13424. }
  13425. // Render targets
  13426. // Setup storage for target texture and bind it to correct framebuffer
  13427. function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
  13428. const glFormat = utils.convert( renderTarget.texture.format );
  13429. const glType = utils.convert( renderTarget.texture.type );
  13430. const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
  13431. state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
  13432. _gl.bindFramebuffer( 36160, framebuffer );
  13433. _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
  13434. _gl.bindFramebuffer( 36160, null );
  13435. }
  13436. // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
  13437. function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
  13438. _gl.bindRenderbuffer( 36161, renderbuffer );
  13439. if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
  13440. let glInternalFormat = 33189;
  13441. if ( isMultisample ) {
  13442. const depthTexture = renderTarget.depthTexture;
  13443. if ( depthTexture && depthTexture.isDepthTexture ) {
  13444. if ( depthTexture.type === FloatType ) {
  13445. glInternalFormat = 36012;
  13446. } else if ( depthTexture.type === UnsignedIntType ) {
  13447. glInternalFormat = 33190;
  13448. }
  13449. }
  13450. const samples = getRenderTargetSamples( renderTarget );
  13451. _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  13452. } else {
  13453. _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
  13454. }
  13455. _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer );
  13456. } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
  13457. if ( isMultisample ) {
  13458. const samples = getRenderTargetSamples( renderTarget );
  13459. _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height );
  13460. } else {
  13461. _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
  13462. }
  13463. _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer );
  13464. } else {
  13465. const glFormat = utils.convert( renderTarget.texture.format );
  13466. const glType = utils.convert( renderTarget.texture.type );
  13467. const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
  13468. if ( isMultisample ) {
  13469. const samples = getRenderTargetSamples( renderTarget );
  13470. _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  13471. } else {
  13472. _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
  13473. }
  13474. }
  13475. _gl.bindRenderbuffer( 36161, null );
  13476. }
  13477. // Setup resources for a Depth Texture for a FBO (needs an extension)
  13478. function setupDepthTexture( framebuffer, renderTarget ) {
  13479. const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
  13480. if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
  13481. _gl.bindFramebuffer( 36160, framebuffer );
  13482. if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
  13483. throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
  13484. }
  13485. // upload an empty depth texture with framebuffer size
  13486. if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
  13487. renderTarget.depthTexture.image.width !== renderTarget.width ||
  13488. renderTarget.depthTexture.image.height !== renderTarget.height ) {
  13489. renderTarget.depthTexture.image.width = renderTarget.width;
  13490. renderTarget.depthTexture.image.height = renderTarget.height;
  13491. renderTarget.depthTexture.needsUpdate = true;
  13492. }
  13493. setTexture2D( renderTarget.depthTexture, 0 );
  13494. const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
  13495. if ( renderTarget.depthTexture.format === DepthFormat ) {
  13496. _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 );
  13497. } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
  13498. _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 );
  13499. } else {
  13500. throw new Error( 'Unknown depthTexture format' );
  13501. }
  13502. }
  13503. // Setup GL resources for a non-texture depth buffer
  13504. function setupDepthRenderbuffer( renderTarget ) {
  13505. const renderTargetProperties = properties.get( renderTarget );
  13506. const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
  13507. if ( renderTarget.depthTexture ) {
  13508. if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
  13509. setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
  13510. } else {
  13511. if ( isCube ) {
  13512. renderTargetProperties.__webglDepthbuffer = [];
  13513. for ( let i = 0; i < 6; i ++ ) {
  13514. _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] );
  13515. renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
  13516. setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
  13517. }
  13518. } else {
  13519. _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer );
  13520. renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
  13521. setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
  13522. }
  13523. }
  13524. _gl.bindFramebuffer( 36160, null );
  13525. }
  13526. // Set up GL resources for the render target
  13527. function setupRenderTarget( renderTarget ) {
  13528. const renderTargetProperties = properties.get( renderTarget );
  13529. const textureProperties = properties.get( renderTarget.texture );
  13530. renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
  13531. textureProperties.__webglTexture = _gl.createTexture();
  13532. info.memory.textures ++;
  13533. const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
  13534. const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
  13535. const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
  13536. // Handles WebGL2 RGBFormat fallback - #18858
  13537. if ( isWebGL2 && renderTarget.texture.format === RGBFormat && ( renderTarget.texture.type === FloatType || renderTarget.texture.type === HalfFloatType ) ) {
  13538. renderTarget.texture.format = RGBAFormat;
  13539. console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' );
  13540. }
  13541. // Setup framebuffer
  13542. if ( isCube ) {
  13543. renderTargetProperties.__webglFramebuffer = [];
  13544. for ( let i = 0; i < 6; i ++ ) {
  13545. renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
  13546. }
  13547. } else {
  13548. renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
  13549. if ( isMultisample ) {
  13550. if ( isWebGL2 ) {
  13551. renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
  13552. renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
  13553. _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer );
  13554. const glFormat = utils.convert( renderTarget.texture.format );
  13555. const glType = utils.convert( renderTarget.texture.type );
  13556. const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
  13557. const samples = getRenderTargetSamples( renderTarget );
  13558. _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  13559. _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer );
  13560. _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer );
  13561. _gl.bindRenderbuffer( 36161, null );
  13562. if ( renderTarget.depthBuffer ) {
  13563. renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
  13564. setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
  13565. }
  13566. _gl.bindFramebuffer( 36160, null );
  13567. } else {
  13568. console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
  13569. }
  13570. }
  13571. }
  13572. // Setup color buffer
  13573. if ( isCube ) {
  13574. state.bindTexture( 34067, textureProperties.__webglTexture );
  13575. setTextureParameters( 34067, renderTarget.texture, supportsMips );
  13576. for ( let i = 0; i < 6; i ++ ) {
  13577. setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, 36064, 34069 + i );
  13578. }
  13579. if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
  13580. generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height );
  13581. }
  13582. state.bindTexture( 34067, null );
  13583. } else {
  13584. state.bindTexture( 3553, textureProperties.__webglTexture );
  13585. setTextureParameters( 3553, renderTarget.texture, supportsMips );
  13586. setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 );
  13587. if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
  13588. generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height );
  13589. }
  13590. state.bindTexture( 3553, null );
  13591. }
  13592. // Setup depth and stencil buffers
  13593. if ( renderTarget.depthBuffer ) {
  13594. setupDepthRenderbuffer( renderTarget );
  13595. }
  13596. }
  13597. function updateRenderTargetMipmap( renderTarget ) {
  13598. const texture = renderTarget.texture;
  13599. const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
  13600. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  13601. const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553;
  13602. const webglTexture = properties.get( texture ).__webglTexture;
  13603. state.bindTexture( target, webglTexture );
  13604. generateMipmap( target, texture, renderTarget.width, renderTarget.height );
  13605. state.bindTexture( target, null );
  13606. }
  13607. }
  13608. function updateMultisampleRenderTarget( renderTarget ) {
  13609. if ( renderTarget.isWebGLMultisampleRenderTarget ) {
  13610. if ( isWebGL2 ) {
  13611. const renderTargetProperties = properties.get( renderTarget );
  13612. _gl.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer );
  13613. _gl.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer );
  13614. const width = renderTarget.width;
  13615. const height = renderTarget.height;
  13616. let mask = 16384;
  13617. if ( renderTarget.depthBuffer ) mask |= 256;
  13618. if ( renderTarget.stencilBuffer ) mask |= 1024;
  13619. _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 );
  13620. _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); // see #18905
  13621. } else {
  13622. console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
  13623. }
  13624. }
  13625. }
  13626. function getRenderTargetSamples( renderTarget ) {
  13627. return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
  13628. Math.min( maxSamples, renderTarget.samples ) : 0;
  13629. }
  13630. function updateVideoTexture( texture ) {
  13631. const frame = info.render.frame;
  13632. // Check the last frame we updated the VideoTexture
  13633. if ( _videoTextures.get( texture ) !== frame ) {
  13634. _videoTextures.set( texture, frame );
  13635. texture.update();
  13636. }
  13637. }
  13638. // backwards compatibility
  13639. let warnedTexture2D = false;
  13640. let warnedTextureCube = false;
  13641. function safeSetTexture2D( texture, slot ) {
  13642. if ( texture && texture.isWebGLRenderTarget ) {
  13643. if ( warnedTexture2D === false ) {
  13644. console.warn( 'THREE.WebGLTextures.safeSetTexture2D: don\'t use render targets as textures. Use their .texture property instead.' );
  13645. warnedTexture2D = true;
  13646. }
  13647. texture = texture.texture;
  13648. }
  13649. setTexture2D( texture, slot );
  13650. }
  13651. function safeSetTextureCube( texture, slot ) {
  13652. if ( texture && texture.isWebGLCubeRenderTarget ) {
  13653. if ( warnedTextureCube === false ) {
  13654. console.warn( 'THREE.WebGLTextures.safeSetTextureCube: don\'t use cube render targets as textures. Use their .texture property instead.' );
  13655. warnedTextureCube = true;
  13656. }
  13657. texture = texture.texture;
  13658. }
  13659. setTextureCube( texture, slot );
  13660. }
  13661. //
  13662. this.allocateTextureUnit = allocateTextureUnit;
  13663. this.resetTextureUnits = resetTextureUnits;
  13664. this.setTexture2D = setTexture2D;
  13665. this.setTexture2DArray = setTexture2DArray;
  13666. this.setTexture3D = setTexture3D;
  13667. this.setTextureCube = setTextureCube;
  13668. this.setupRenderTarget = setupRenderTarget;
  13669. this.updateRenderTargetMipmap = updateRenderTargetMipmap;
  13670. this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
  13671. this.safeSetTexture2D = safeSetTexture2D;
  13672. this.safeSetTextureCube = safeSetTextureCube;
  13673. }
  13674. function WebGLUtils( gl, extensions, capabilities ) {
  13675. const isWebGL2 = capabilities.isWebGL2;
  13676. function convert( p ) {
  13677. let extension;
  13678. if ( p === UnsignedByteType ) return 5121;
  13679. if ( p === UnsignedShort4444Type ) return 32819;
  13680. if ( p === UnsignedShort5551Type ) return 32820;
  13681. if ( p === UnsignedShort565Type ) return 33635;
  13682. if ( p === ByteType ) return 5120;
  13683. if ( p === ShortType ) return 5122;
  13684. if ( p === UnsignedShortType ) return 5123;
  13685. if ( p === IntType ) return 5124;
  13686. if ( p === UnsignedIntType ) return 5125;
  13687. if ( p === FloatType ) return 5126;
  13688. if ( p === HalfFloatType ) {
  13689. if ( isWebGL2 ) return 5131;
  13690. extension = extensions.get( 'OES_texture_half_float' );
  13691. if ( extension !== null ) {
  13692. return extension.HALF_FLOAT_OES;
  13693. } else {
  13694. return null;
  13695. }
  13696. }
  13697. if ( p === AlphaFormat ) return 6406;
  13698. if ( p === RGBFormat ) return 6407;
  13699. if ( p === RGBAFormat ) return 6408;
  13700. if ( p === LuminanceFormat ) return 6409;
  13701. if ( p === LuminanceAlphaFormat ) return 6410;
  13702. if ( p === DepthFormat ) return 6402;
  13703. if ( p === DepthStencilFormat ) return 34041;
  13704. if ( p === RedFormat ) return 6403;
  13705. // WebGL2 formats.
  13706. if ( p === RedIntegerFormat ) return 36244;
  13707. if ( p === RGFormat ) return 33319;
  13708. if ( p === RGIntegerFormat ) return 33320;
  13709. if ( p === RGBIntegerFormat ) return 36248;
  13710. if ( p === RGBAIntegerFormat ) return 36249;
  13711. if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format$1 ||
  13712. p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format$1 ) {
  13713. extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
  13714. if ( extension !== null ) {
  13715. if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
  13716. if ( p === RGBA_S3TC_DXT1_Format$1 ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
  13717. if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
  13718. if ( p === RGBA_S3TC_DXT5_Format$1 ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
  13719. } else {
  13720. return null;
  13721. }
  13722. }
  13723. if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
  13724. p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
  13725. extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
  13726. if ( extension !== null ) {
  13727. if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
  13728. if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  13729. if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
  13730. if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
  13731. } else {
  13732. return null;
  13733. }
  13734. }
  13735. if ( p === RGB_ETC1_Format ) {
  13736. extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
  13737. if ( extension !== null ) {
  13738. return extension.COMPRESSED_RGB_ETC1_WEBGL;
  13739. } else {
  13740. return null;
  13741. }
  13742. }
  13743. if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
  13744. extension = extensions.get( 'WEBGL_compressed_texture_etc' );
  13745. if ( extension !== null ) {
  13746. if ( p === RGB_ETC2_Format ) return extension.COMPRESSED_RGB8_ETC2;
  13747. if ( p === RGBA_ETC2_EAC_Format ) return extension.COMPRESSED_RGBA8_ETC2_EAC;
  13748. }
  13749. }
  13750. if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
  13751. p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
  13752. p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
  13753. p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
  13754. p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ||
  13755. p === SRGB8_ALPHA8_ASTC_4x4_Format || p === SRGB8_ALPHA8_ASTC_5x4_Format || p === SRGB8_ALPHA8_ASTC_5x5_Format ||
  13756. p === SRGB8_ALPHA8_ASTC_6x5_Format || p === SRGB8_ALPHA8_ASTC_6x6_Format || p === SRGB8_ALPHA8_ASTC_8x5_Format ||
  13757. p === SRGB8_ALPHA8_ASTC_8x6_Format || p === SRGB8_ALPHA8_ASTC_8x8_Format || p === SRGB8_ALPHA8_ASTC_10x5_Format ||
  13758. p === SRGB8_ALPHA8_ASTC_10x6_Format || p === SRGB8_ALPHA8_ASTC_10x8_Format || p === SRGB8_ALPHA8_ASTC_10x10_Format ||
  13759. p === SRGB8_ALPHA8_ASTC_12x10_Format || p === SRGB8_ALPHA8_ASTC_12x12_Format ) {
  13760. extension = extensions.get( 'WEBGL_compressed_texture_astc' );
  13761. if ( extension !== null ) {
  13762. // TODO Complete?
  13763. return p;
  13764. } else {
  13765. return null;
  13766. }
  13767. }
  13768. if ( p === RGBA_BPTC_Format ) {
  13769. extension = extensions.get( 'EXT_texture_compression_bptc' );
  13770. if ( extension !== null ) {
  13771. // TODO Complete?
  13772. return p;
  13773. } else {
  13774. return null;
  13775. }
  13776. }
  13777. if ( p === UnsignedInt248Type$1 ) {
  13778. if ( isWebGL2 ) return 34042;
  13779. extension = extensions.get( 'WEBGL_depth_texture' );
  13780. if ( extension !== null ) {
  13781. return extension.UNSIGNED_INT_24_8_WEBGL;
  13782. } else {
  13783. return null;
  13784. }
  13785. }
  13786. }
  13787. return { convert: convert };
  13788. }
  13789. function ArrayCamera( array = [] ) {
  13790. PerspectiveCamera.call( this );
  13791. this.cameras = array;
  13792. }
  13793. ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
  13794. constructor: ArrayCamera,
  13795. isArrayCamera: true
  13796. } );
  13797. function Group() {
  13798. Object3D.call( this );
  13799. this.type = 'Group';
  13800. }
  13801. Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
  13802. constructor: Group,
  13803. isGroup: true
  13804. } );
  13805. function WebXRController() {
  13806. this._targetRay = null;
  13807. this._grip = null;
  13808. this._hand = null;
  13809. }
  13810. Object.assign( WebXRController.prototype, {
  13811. constructor: WebXRController,
  13812. getHandSpace: function () {
  13813. if ( this._hand === null ) {
  13814. this._hand = new Group();
  13815. this._hand.matrixAutoUpdate = false;
  13816. this._hand.visible = false;
  13817. this._hand.joints = [];
  13818. this._hand.inputState = { pinching: false };
  13819. if ( window.XRHand ) {
  13820. for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
  13821. // The transform of this joint will be updated with the joint pose on each frame
  13822. const joint = new Group();
  13823. joint.matrixAutoUpdate = false;
  13824. joint.visible = false;
  13825. this._hand.joints.push( joint );
  13826. // ??
  13827. this._hand.add( joint );
  13828. }
  13829. }
  13830. }
  13831. return this._hand;
  13832. },
  13833. getTargetRaySpace: function () {
  13834. if ( this._targetRay === null ) {
  13835. this._targetRay = new Group();
  13836. this._targetRay.matrixAutoUpdate = false;
  13837. this._targetRay.visible = false;
  13838. }
  13839. return this._targetRay;
  13840. },
  13841. getGripSpace: function () {
  13842. if ( this._grip === null ) {
  13843. this._grip = new Group();
  13844. this._grip.matrixAutoUpdate = false;
  13845. this._grip.visible = false;
  13846. }
  13847. return this._grip;
  13848. },
  13849. dispatchEvent: function ( event ) {
  13850. if ( this._targetRay !== null ) {
  13851. this._targetRay.dispatchEvent( event );
  13852. }
  13853. if ( this._grip !== null ) {
  13854. this._grip.dispatchEvent( event );
  13855. }
  13856. if ( this._hand !== null ) {
  13857. this._hand.dispatchEvent( event );
  13858. }
  13859. return this;
  13860. },
  13861. disconnect: function ( inputSource ) {
  13862. this.dispatchEvent( { type: 'disconnected', data: inputSource } );
  13863. if ( this._targetRay !== null ) {
  13864. this._targetRay.visible = false;
  13865. }
  13866. if ( this._grip !== null ) {
  13867. this._grip.visible = false;
  13868. }
  13869. if ( this._hand !== null ) {
  13870. this._hand.visible = false;
  13871. }
  13872. return this;
  13873. },
  13874. update: function ( inputSource, frame, referenceSpace ) {
  13875. let inputPose = null;
  13876. let gripPose = null;
  13877. let handPose = null;
  13878. const targetRay = this._targetRay;
  13879. const grip = this._grip;
  13880. const hand = this._hand;
  13881. if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
  13882. if ( hand && inputSource.hand ) {
  13883. handPose = true;
  13884. for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
  13885. if ( inputSource.hand[ i ] ) {
  13886. // Update the joints groups with the XRJoint poses
  13887. const jointPose = frame.getJointPose( inputSource.hand[ i ], referenceSpace );
  13888. const joint = hand.joints[ i ];
  13889. if ( jointPose !== null ) {
  13890. joint.matrix.fromArray( jointPose.transform.matrix );
  13891. joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
  13892. joint.jointRadius = jointPose.radius;
  13893. }
  13894. joint.visible = jointPose !== null;
  13895. // Custom events
  13896. // Check pinch
  13897. const indexTip = hand.joints[ window.XRHand.INDEX_PHALANX_TIP ];
  13898. const thumbTip = hand.joints[ window.XRHand.THUMB_PHALANX_TIP ];
  13899. const distance = indexTip.position.distanceTo( thumbTip.position );
  13900. const distanceToPinch = 0.02;
  13901. const threshold = 0.005;
  13902. if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
  13903. hand.inputState.pinching = false;
  13904. this.dispatchEvent( {
  13905. type: 'pinchend',
  13906. handedness: inputSource.handedness,
  13907. target: this
  13908. } );
  13909. } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
  13910. hand.inputState.pinching = true;
  13911. this.dispatchEvent( {
  13912. type: 'pinchstart',
  13913. handedness: inputSource.handedness,
  13914. target: this
  13915. } );
  13916. }
  13917. }
  13918. }
  13919. } else {
  13920. if ( targetRay !== null ) {
  13921. inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
  13922. if ( inputPose !== null ) {
  13923. targetRay.matrix.fromArray( inputPose.transform.matrix );
  13924. targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
  13925. }
  13926. }
  13927. if ( grip !== null && inputSource.gripSpace ) {
  13928. gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
  13929. if ( gripPose !== null ) {
  13930. grip.matrix.fromArray( gripPose.transform.matrix );
  13931. grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
  13932. }
  13933. }
  13934. }
  13935. }
  13936. if ( targetRay !== null ) {
  13937. targetRay.visible = ( inputPose !== null );
  13938. }
  13939. if ( grip !== null ) {
  13940. grip.visible = ( gripPose !== null );
  13941. }
  13942. if ( hand !== null ) {
  13943. hand.visible = ( handPose !== null );
  13944. }
  13945. return this;
  13946. }
  13947. } );
  13948. function WebXRManager( renderer, gl ) {
  13949. const scope = this;
  13950. let session = null;
  13951. let framebufferScaleFactor = 1.0;
  13952. let referenceSpace = null;
  13953. let referenceSpaceType = 'local-floor';
  13954. let pose = null;
  13955. const controllers = [];
  13956. const inputSourcesMap = new Map();
  13957. //
  13958. const cameraL = new PerspectiveCamera();
  13959. cameraL.layers.enable( 1 );
  13960. cameraL.viewport = new Vector4();
  13961. const cameraR = new PerspectiveCamera();
  13962. cameraR.layers.enable( 2 );
  13963. cameraR.viewport = new Vector4();
  13964. const cameras = [ cameraL, cameraR ];
  13965. const cameraVR = new ArrayCamera();
  13966. cameraVR.layers.enable( 1 );
  13967. cameraVR.layers.enable( 2 );
  13968. let _currentDepthNear = null;
  13969. let _currentDepthFar = null;
  13970. //
  13971. this.enabled = false;
  13972. this.isPresenting = false;
  13973. this.getController = function ( index ) {
  13974. let controller = controllers[ index ];
  13975. if ( controller === undefined ) {
  13976. controller = new WebXRController();
  13977. controllers[ index ] = controller;
  13978. }
  13979. return controller.getTargetRaySpace();
  13980. };
  13981. this.getControllerGrip = function ( index ) {
  13982. let controller = controllers[ index ];
  13983. if ( controller === undefined ) {
  13984. controller = new WebXRController();
  13985. controllers[ index ] = controller;
  13986. }
  13987. return controller.getGripSpace();
  13988. };
  13989. this.getHand = function ( index ) {
  13990. let controller = controllers[ index ];
  13991. if ( controller === undefined ) {
  13992. controller = new WebXRController();
  13993. controllers[ index ] = controller;
  13994. }
  13995. return controller.getHandSpace();
  13996. };
  13997. //
  13998. function onSessionEvent( event ) {
  13999. const controller = inputSourcesMap.get( event.inputSource );
  14000. if ( controller ) {
  14001. controller.dispatchEvent( { type: event.type, data: event.inputSource } );
  14002. }
  14003. }
  14004. function onSessionEnd() {
  14005. inputSourcesMap.forEach( function ( controller, inputSource ) {
  14006. controller.disconnect( inputSource );
  14007. } );
  14008. inputSourcesMap.clear();
  14009. //
  14010. renderer.setFramebuffer( null );
  14011. renderer.setRenderTarget( renderer.getRenderTarget() ); // Hack #15830
  14012. animation.stop();
  14013. scope.isPresenting = false;
  14014. scope.dispatchEvent( { type: 'sessionend' } );
  14015. }
  14016. function onRequestReferenceSpace( value ) {
  14017. referenceSpace = value;
  14018. animation.setContext( session );
  14019. animation.start();
  14020. scope.isPresenting = true;
  14021. scope.dispatchEvent( { type: 'sessionstart' } );
  14022. }
  14023. this.setFramebufferScaleFactor = function ( value ) {
  14024. framebufferScaleFactor = value;
  14025. if ( scope.isPresenting === true ) {
  14026. console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
  14027. }
  14028. };
  14029. this.setReferenceSpaceType = function ( value ) {
  14030. referenceSpaceType = value;
  14031. if ( scope.isPresenting === true ) {
  14032. console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
  14033. }
  14034. };
  14035. this.getReferenceSpace = function () {
  14036. return referenceSpace;
  14037. };
  14038. this.getSession = function () {
  14039. return session;
  14040. };
  14041. this.setSession = function ( value ) {
  14042. session = value;
  14043. if ( session !== null ) {
  14044. session.addEventListener( 'select', onSessionEvent );
  14045. session.addEventListener( 'selectstart', onSessionEvent );
  14046. session.addEventListener( 'selectend', onSessionEvent );
  14047. session.addEventListener( 'squeeze', onSessionEvent );
  14048. session.addEventListener( 'squeezestart', onSessionEvent );
  14049. session.addEventListener( 'squeezeend', onSessionEvent );
  14050. session.addEventListener( 'end', onSessionEnd );
  14051. const attributes = gl.getContextAttributes();
  14052. if ( attributes.xrCompatible !== true ) {
  14053. gl.makeXRCompatible();
  14054. }
  14055. const layerInit = {
  14056. antialias: attributes.antialias,
  14057. alpha: attributes.alpha,
  14058. depth: attributes.depth,
  14059. stencil: attributes.stencil,
  14060. framebufferScaleFactor: framebufferScaleFactor
  14061. };
  14062. // eslint-disable-next-line no-undef
  14063. const baseLayer = new XRWebGLLayer( session, gl, layerInit );
  14064. session.updateRenderState( { baseLayer: baseLayer } );
  14065. session.requestReferenceSpace( referenceSpaceType ).then( onRequestReferenceSpace );
  14066. //
  14067. session.addEventListener( 'inputsourceschange', updateInputSources );
  14068. }
  14069. };
  14070. function updateInputSources( event ) {
  14071. const inputSources = session.inputSources;
  14072. // Assign inputSources to available controllers
  14073. for ( let i = 0; i < controllers.length; i ++ ) {
  14074. inputSourcesMap.set( inputSources[ i ], controllers[ i ] );
  14075. }
  14076. // Notify disconnected
  14077. for ( let i = 0; i < event.removed.length; i ++ ) {
  14078. const inputSource = event.removed[ i ];
  14079. const controller = inputSourcesMap.get( inputSource );
  14080. if ( controller ) {
  14081. controller.dispatchEvent( { type: 'disconnected', data: inputSource } );
  14082. inputSourcesMap.delete( inputSource );
  14083. }
  14084. }
  14085. // Notify connected
  14086. for ( let i = 0; i < event.added.length; i ++ ) {
  14087. const inputSource = event.added[ i ];
  14088. const controller = inputSourcesMap.get( inputSource );
  14089. if ( controller ) {
  14090. controller.dispatchEvent( { type: 'connected', data: inputSource } );
  14091. }
  14092. }
  14093. }
  14094. //
  14095. const cameraLPos = new Vector3();
  14096. const cameraRPos = new Vector3();
  14097. /**
  14098. * Assumes 2 cameras that are parallel and share an X-axis, and that
  14099. * the cameras' projection and world matrices have already been set.
  14100. * And that near and far planes are identical for both cameras.
  14101. * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
  14102. */
  14103. function setProjectionFromUnion( camera, cameraL, cameraR ) {
  14104. cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
  14105. cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
  14106. const ipd = cameraLPos.distanceTo( cameraRPos );
  14107. const projL = cameraL.projectionMatrix.elements;
  14108. const projR = cameraR.projectionMatrix.elements;
  14109. // VR systems will have identical far and near planes, and
  14110. // most likely identical top and bottom frustum extents.
  14111. // Use the left camera for these values.
  14112. const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
  14113. const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
  14114. const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
  14115. const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
  14116. const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
  14117. const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
  14118. const left = near * leftFov;
  14119. const right = near * rightFov;
  14120. // Calculate the new camera's position offset from the
  14121. // left camera. xOffset should be roughly half `ipd`.
  14122. const zOffset = ipd / ( - leftFov + rightFov );
  14123. const xOffset = zOffset * - leftFov;
  14124. // TODO: Better way to apply this offset?
  14125. cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
  14126. camera.translateX( xOffset );
  14127. camera.translateZ( zOffset );
  14128. camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
  14129. camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
  14130. // Find the union of the frustum values of the cameras and scale
  14131. // the values so that the near plane's position does not change in world space,
  14132. // although must now be relative to the new union camera.
  14133. const near2 = near + zOffset;
  14134. const far2 = far + zOffset;
  14135. const left2 = left - xOffset;
  14136. const right2 = right + ( ipd - xOffset );
  14137. const top2 = topFov * far / far2 * near2;
  14138. const bottom2 = bottomFov * far / far2 * near2;
  14139. camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
  14140. }
  14141. function updateCamera( camera, parent ) {
  14142. if ( parent === null ) {
  14143. camera.matrixWorld.copy( camera.matrix );
  14144. } else {
  14145. camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
  14146. }
  14147. camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
  14148. }
  14149. this.getCamera = function ( camera ) {
  14150. cameraVR.near = cameraR.near = cameraL.near = camera.near;
  14151. cameraVR.far = cameraR.far = cameraL.far = camera.far;
  14152. if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) {
  14153. // Note that the new renderState won't apply until the next frame. See #18320
  14154. session.updateRenderState( {
  14155. depthNear: cameraVR.near,
  14156. depthFar: cameraVR.far
  14157. } );
  14158. _currentDepthNear = cameraVR.near;
  14159. _currentDepthFar = cameraVR.far;
  14160. }
  14161. const parent = camera.parent;
  14162. const cameras = cameraVR.cameras;
  14163. updateCamera( cameraVR, parent );
  14164. for ( let i = 0; i < cameras.length; i ++ ) {
  14165. updateCamera( cameras[ i ], parent );
  14166. }
  14167. // update camera and its children
  14168. camera.matrixWorld.copy( cameraVR.matrixWorld );
  14169. const children = camera.children;
  14170. for ( let i = 0, l = children.length; i < l; i ++ ) {
  14171. children[ i ].updateMatrixWorld( true );
  14172. }
  14173. // update projection matrix for proper view frustum culling
  14174. if ( cameras.length === 2 ) {
  14175. setProjectionFromUnion( cameraVR, cameraL, cameraR );
  14176. } else {
  14177. // assume single camera setup (AR)
  14178. cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
  14179. }
  14180. return cameraVR;
  14181. };
  14182. // Animation Loop
  14183. let onAnimationFrameCallback = null;
  14184. function onAnimationFrame( time, frame ) {
  14185. pose = frame.getViewerPose( referenceSpace );
  14186. if ( pose !== null ) {
  14187. const views = pose.views;
  14188. const baseLayer = session.renderState.baseLayer;
  14189. renderer.setFramebuffer( baseLayer.framebuffer );
  14190. let cameraVRNeedsUpdate = false;
  14191. // check if it's necessary to rebuild cameraVR's camera list
  14192. if ( views.length !== cameraVR.cameras.length ) {
  14193. cameraVR.cameras.length = 0;
  14194. cameraVRNeedsUpdate = true;
  14195. }
  14196. for ( let i = 0; i < views.length; i ++ ) {
  14197. const view = views[ i ];
  14198. const viewport = baseLayer.getViewport( view );
  14199. const camera = cameras[ i ];
  14200. camera.matrix.fromArray( view.transform.matrix );
  14201. camera.projectionMatrix.fromArray( view.projectionMatrix );
  14202. camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
  14203. if ( i === 0 ) {
  14204. cameraVR.matrix.copy( camera.matrix );
  14205. }
  14206. if ( cameraVRNeedsUpdate === true ) {
  14207. cameraVR.cameras.push( camera );
  14208. }
  14209. }
  14210. }
  14211. //
  14212. const inputSources = session.inputSources;
  14213. for ( let i = 0; i < controllers.length; i ++ ) {
  14214. const controller = controllers[ i ];
  14215. const inputSource = inputSources[ i ];
  14216. controller.update( inputSource, frame, referenceSpace );
  14217. }
  14218. if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
  14219. }
  14220. const animation = new WebGLAnimation();
  14221. animation.setAnimationLoop( onAnimationFrame );
  14222. this.setAnimationLoop = function ( callback ) {
  14223. onAnimationFrameCallback = callback;
  14224. };
  14225. this.dispose = function () {};
  14226. }
  14227. Object.assign( WebXRManager.prototype, EventDispatcher.prototype );
  14228. function WebGLMaterials( properties ) {
  14229. function refreshFogUniforms( uniforms, fog ) {
  14230. uniforms.fogColor.value.copy( fog.color );
  14231. if ( fog.isFog ) {
  14232. uniforms.fogNear.value = fog.near;
  14233. uniforms.fogFar.value = fog.far;
  14234. } else if ( fog.isFogExp2 ) {
  14235. uniforms.fogDensity.value = fog.density;
  14236. }
  14237. }
  14238. function refreshMaterialUniforms( uniforms, material, pixelRatio, height ) {
  14239. if ( material.isMeshBasicMaterial ) {
  14240. refreshUniformsCommon( uniforms, material );
  14241. } else if ( material.isMeshLambertMaterial ) {
  14242. refreshUniformsCommon( uniforms, material );
  14243. refreshUniformsLambert( uniforms, material );
  14244. } else if ( material.isMeshToonMaterial ) {
  14245. refreshUniformsCommon( uniforms, material );
  14246. refreshUniformsToon( uniforms, material );
  14247. } else if ( material.isMeshPhongMaterial ) {
  14248. refreshUniformsCommon( uniforms, material );
  14249. refreshUniformsPhong( uniforms, material );
  14250. } else if ( material.isMeshStandardMaterial ) {
  14251. refreshUniformsCommon( uniforms, material );
  14252. if ( material.isMeshPhysicalMaterial ) {
  14253. refreshUniformsPhysical( uniforms, material );
  14254. } else {
  14255. refreshUniformsStandard( uniforms, material );
  14256. }
  14257. } else if ( material.isMeshMatcapMaterial ) {
  14258. refreshUniformsCommon( uniforms, material );
  14259. refreshUniformsMatcap( uniforms, material );
  14260. } else if ( material.isMeshDepthMaterial ) {
  14261. refreshUniformsCommon( uniforms, material );
  14262. refreshUniformsDepth( uniforms, material );
  14263. } else if ( material.isMeshDistanceMaterial ) {
  14264. refreshUniformsCommon( uniforms, material );
  14265. refreshUniformsDistance( uniforms, material );
  14266. } else if ( material.isMeshNormalMaterial ) {
  14267. refreshUniformsCommon( uniforms, material );
  14268. refreshUniformsNormal( uniforms, material );
  14269. } else if ( material.isLineBasicMaterial ) {
  14270. refreshUniformsLine( uniforms, material );
  14271. if ( material.isLineDashedMaterial ) {
  14272. refreshUniformsDash( uniforms, material );
  14273. }
  14274. } else if ( material.isPointsMaterial ) {
  14275. refreshUniformsPoints( uniforms, material, pixelRatio, height );
  14276. } else if ( material.isSpriteMaterial ) {
  14277. refreshUniformsSprites( uniforms, material );
  14278. } else if ( material.isShadowMaterial ) {
  14279. uniforms.color.value.copy( material.color );
  14280. uniforms.opacity.value = material.opacity;
  14281. } else if ( material.isShaderMaterial ) {
  14282. material.uniformsNeedUpdate = false; // #15581
  14283. }
  14284. }
  14285. function refreshUniformsCommon( uniforms, material ) {
  14286. uniforms.opacity.value = material.opacity;
  14287. if ( material.color ) {
  14288. uniforms.diffuse.value.copy( material.color );
  14289. }
  14290. if ( material.emissive ) {
  14291. uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
  14292. }
  14293. if ( material.map ) {
  14294. uniforms.map.value = material.map;
  14295. }
  14296. if ( material.alphaMap ) {
  14297. uniforms.alphaMap.value = material.alphaMap;
  14298. }
  14299. if ( material.specularMap ) {
  14300. uniforms.specularMap.value = material.specularMap;
  14301. }
  14302. const envMap = properties.get( material ).envMap;
  14303. if ( envMap ) {
  14304. uniforms.envMap.value = envMap;
  14305. uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap._needsFlipEnvMap ) ? - 1 : 1;
  14306. uniforms.reflectivity.value = material.reflectivity;
  14307. uniforms.refractionRatio.value = material.refractionRatio;
  14308. const maxMipLevel = properties.get( envMap ).__maxMipLevel;
  14309. if ( maxMipLevel !== undefined ) {
  14310. uniforms.maxMipLevel.value = maxMipLevel;
  14311. }
  14312. }
  14313. if ( material.lightMap ) {
  14314. uniforms.lightMap.value = material.lightMap;
  14315. uniforms.lightMapIntensity.value = material.lightMapIntensity;
  14316. }
  14317. if ( material.aoMap ) {
  14318. uniforms.aoMap.value = material.aoMap;
  14319. uniforms.aoMapIntensity.value = material.aoMapIntensity;
  14320. }
  14321. // uv repeat and offset setting priorities
  14322. // 1. color map
  14323. // 2. specular map
  14324. // 3. displacementMap map
  14325. // 4. normal map
  14326. // 5. bump map
  14327. // 6. roughnessMap map
  14328. // 7. metalnessMap map
  14329. // 8. alphaMap map
  14330. // 9. emissiveMap map
  14331. // 10. clearcoat map
  14332. // 11. clearcoat normal map
  14333. // 12. clearcoat roughnessMap map
  14334. let uvScaleMap;
  14335. if ( material.map ) {
  14336. uvScaleMap = material.map;
  14337. } else if ( material.specularMap ) {
  14338. uvScaleMap = material.specularMap;
  14339. } else if ( material.displacementMap ) {
  14340. uvScaleMap = material.displacementMap;
  14341. } else if ( material.normalMap ) {
  14342. uvScaleMap = material.normalMap;
  14343. } else if ( material.bumpMap ) {
  14344. uvScaleMap = material.bumpMap;
  14345. } else if ( material.roughnessMap ) {
  14346. uvScaleMap = material.roughnessMap;
  14347. } else if ( material.metalnessMap ) {
  14348. uvScaleMap = material.metalnessMap;
  14349. } else if ( material.alphaMap ) {
  14350. uvScaleMap = material.alphaMap;
  14351. } else if ( material.emissiveMap ) {
  14352. uvScaleMap = material.emissiveMap;
  14353. } else if ( material.clearcoatMap ) {
  14354. uvScaleMap = material.clearcoatMap;
  14355. } else if ( material.clearcoatNormalMap ) {
  14356. uvScaleMap = material.clearcoatNormalMap;
  14357. } else if ( material.clearcoatRoughnessMap ) {
  14358. uvScaleMap = material.clearcoatRoughnessMap;
  14359. }
  14360. if ( uvScaleMap !== undefined ) {
  14361. // backwards compatibility
  14362. if ( uvScaleMap.isWebGLRenderTarget ) {
  14363. uvScaleMap = uvScaleMap.texture;
  14364. }
  14365. if ( uvScaleMap.matrixAutoUpdate === true ) {
  14366. uvScaleMap.updateMatrix();
  14367. }
  14368. uniforms.uvTransform.value.copy( uvScaleMap.matrix );
  14369. }
  14370. // uv repeat and offset setting priorities for uv2
  14371. // 1. ao map
  14372. // 2. light map
  14373. let uv2ScaleMap;
  14374. if ( material.aoMap ) {
  14375. uv2ScaleMap = material.aoMap;
  14376. } else if ( material.lightMap ) {
  14377. uv2ScaleMap = material.lightMap;
  14378. }
  14379. if ( uv2ScaleMap !== undefined ) {
  14380. // backwards compatibility
  14381. if ( uv2ScaleMap.isWebGLRenderTarget ) {
  14382. uv2ScaleMap = uv2ScaleMap.texture;
  14383. }
  14384. if ( uv2ScaleMap.matrixAutoUpdate === true ) {
  14385. uv2ScaleMap.updateMatrix();
  14386. }
  14387. uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix );
  14388. }
  14389. }
  14390. function refreshUniformsLine( uniforms, material ) {
  14391. uniforms.diffuse.value.copy( material.color );
  14392. uniforms.opacity.value = material.opacity;
  14393. }
  14394. function refreshUniformsDash( uniforms, material ) {
  14395. uniforms.dashSize.value = material.dashSize;
  14396. uniforms.totalSize.value = material.dashSize + material.gapSize;
  14397. uniforms.scale.value = material.scale;
  14398. }
  14399. function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
  14400. uniforms.diffuse.value.copy( material.color );
  14401. uniforms.opacity.value = material.opacity;
  14402. uniforms.size.value = material.size * pixelRatio;
  14403. uniforms.scale.value = height * 0.5;
  14404. if ( material.map ) {
  14405. uniforms.map.value = material.map;
  14406. }
  14407. if ( material.alphaMap ) {
  14408. uniforms.alphaMap.value = material.alphaMap;
  14409. }
  14410. // uv repeat and offset setting priorities
  14411. // 1. color map
  14412. // 2. alpha map
  14413. let uvScaleMap;
  14414. if ( material.map ) {
  14415. uvScaleMap = material.map;
  14416. } else if ( material.alphaMap ) {
  14417. uvScaleMap = material.alphaMap;
  14418. }
  14419. if ( uvScaleMap !== undefined ) {
  14420. if ( uvScaleMap.matrixAutoUpdate === true ) {
  14421. uvScaleMap.updateMatrix();
  14422. }
  14423. uniforms.uvTransform.value.copy( uvScaleMap.matrix );
  14424. }
  14425. }
  14426. function refreshUniformsSprites( uniforms, material ) {
  14427. uniforms.diffuse.value.copy( material.color );
  14428. uniforms.opacity.value = material.opacity;
  14429. uniforms.rotation.value = material.rotation;
  14430. if ( material.map ) {
  14431. uniforms.map.value = material.map;
  14432. }
  14433. if ( material.alphaMap ) {
  14434. uniforms.alphaMap.value = material.alphaMap;
  14435. }
  14436. // uv repeat and offset setting priorities
  14437. // 1. color map
  14438. // 2. alpha map
  14439. let uvScaleMap;
  14440. if ( material.map ) {
  14441. uvScaleMap = material.map;
  14442. } else if ( material.alphaMap ) {
  14443. uvScaleMap = material.alphaMap;
  14444. }
  14445. if ( uvScaleMap !== undefined ) {
  14446. if ( uvScaleMap.matrixAutoUpdate === true ) {
  14447. uvScaleMap.updateMatrix();
  14448. }
  14449. uniforms.uvTransform.value.copy( uvScaleMap.matrix );
  14450. }
  14451. }
  14452. function refreshUniformsLambert( uniforms, material ) {
  14453. if ( material.emissiveMap ) {
  14454. uniforms.emissiveMap.value = material.emissiveMap;
  14455. }
  14456. }
  14457. function refreshUniformsPhong( uniforms, material ) {
  14458. uniforms.specular.value.copy( material.specular );
  14459. uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
  14460. if ( material.emissiveMap ) {
  14461. uniforms.emissiveMap.value = material.emissiveMap;
  14462. }
  14463. if ( material.bumpMap ) {
  14464. uniforms.bumpMap.value = material.bumpMap;
  14465. uniforms.bumpScale.value = material.bumpScale;
  14466. if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
  14467. }
  14468. if ( material.normalMap ) {
  14469. uniforms.normalMap.value = material.normalMap;
  14470. uniforms.normalScale.value.copy( material.normalScale );
  14471. if ( material.side === BackSide ) uniforms.normalScale.value.negate();
  14472. }
  14473. if ( material.displacementMap ) {
  14474. uniforms.displacementMap.value = material.displacementMap;
  14475. uniforms.displacementScale.value = material.displacementScale;
  14476. uniforms.displacementBias.value = material.displacementBias;
  14477. }
  14478. }
  14479. function refreshUniformsToon( uniforms, material ) {
  14480. if ( material.gradientMap ) {
  14481. uniforms.gradientMap.value = material.gradientMap;
  14482. }
  14483. if ( material.emissiveMap ) {
  14484. uniforms.emissiveMap.value = material.emissiveMap;
  14485. }
  14486. if ( material.bumpMap ) {
  14487. uniforms.bumpMap.value = material.bumpMap;
  14488. uniforms.bumpScale.value = material.bumpScale;
  14489. if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
  14490. }
  14491. if ( material.normalMap ) {
  14492. uniforms.normalMap.value = material.normalMap;
  14493. uniforms.normalScale.value.copy( material.normalScale );
  14494. if ( material.side === BackSide ) uniforms.normalScale.value.negate();
  14495. }
  14496. if ( material.displacementMap ) {
  14497. uniforms.displacementMap.value = material.displacementMap;
  14498. uniforms.displacementScale.value = material.displacementScale;
  14499. uniforms.displacementBias.value = material.displacementBias;
  14500. }
  14501. }
  14502. function refreshUniformsStandard( uniforms, material ) {
  14503. uniforms.roughness.value = material.roughness;
  14504. uniforms.metalness.value = material.metalness;
  14505. if ( material.roughnessMap ) {
  14506. uniforms.roughnessMap.value = material.roughnessMap;
  14507. }
  14508. if ( material.metalnessMap ) {
  14509. uniforms.metalnessMap.value = material.metalnessMap;
  14510. }
  14511. if ( material.emissiveMap ) {
  14512. uniforms.emissiveMap.value = material.emissiveMap;
  14513. }
  14514. if ( material.bumpMap ) {
  14515. uniforms.bumpMap.value = material.bumpMap;
  14516. uniforms.bumpScale.value = material.bumpScale;
  14517. if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
  14518. }
  14519. if ( material.normalMap ) {
  14520. uniforms.normalMap.value = material.normalMap;
  14521. uniforms.normalScale.value.copy( material.normalScale );
  14522. if ( material.side === BackSide ) uniforms.normalScale.value.negate();
  14523. }
  14524. if ( material.displacementMap ) {
  14525. uniforms.displacementMap.value = material.displacementMap;
  14526. uniforms.displacementScale.value = material.displacementScale;
  14527. uniforms.displacementBias.value = material.displacementBias;
  14528. }
  14529. const envMap = properties.get( material ).envMap;
  14530. if ( envMap ) {
  14531. //uniforms.envMap.value = material.envMap; // part of uniforms common
  14532. uniforms.envMapIntensity.value = material.envMapIntensity;
  14533. }
  14534. }
  14535. function refreshUniformsPhysical( uniforms, material ) {
  14536. refreshUniformsStandard( uniforms, material );
  14537. uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common
  14538. uniforms.clearcoat.value = material.clearcoat;
  14539. uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
  14540. if ( material.sheen ) uniforms.sheen.value.copy( material.sheen );
  14541. if ( material.clearcoatMap ) {
  14542. uniforms.clearcoatMap.value = material.clearcoatMap;
  14543. }
  14544. if ( material.clearcoatRoughnessMap ) {
  14545. uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
  14546. }
  14547. if ( material.clearcoatNormalMap ) {
  14548. uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
  14549. uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
  14550. if ( material.side === BackSide ) {
  14551. uniforms.clearcoatNormalScale.value.negate();
  14552. }
  14553. }
  14554. uniforms.transmission.value = material.transmission;
  14555. if ( material.transmissionMap ) {
  14556. uniforms.transmissionMap.value = material.transmissionMap;
  14557. }
  14558. }
  14559. function refreshUniformsMatcap( uniforms, material ) {
  14560. if ( material.matcap ) {
  14561. uniforms.matcap.value = material.matcap;
  14562. }
  14563. if ( material.bumpMap ) {
  14564. uniforms.bumpMap.value = material.bumpMap;
  14565. uniforms.bumpScale.value = material.bumpScale;
  14566. if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
  14567. }
  14568. if ( material.normalMap ) {
  14569. uniforms.normalMap.value = material.normalMap;
  14570. uniforms.normalScale.value.copy( material.normalScale );
  14571. if ( material.side === BackSide ) uniforms.normalScale.value.negate();
  14572. }
  14573. if ( material.displacementMap ) {
  14574. uniforms.displacementMap.value = material.displacementMap;
  14575. uniforms.displacementScale.value = material.displacementScale;
  14576. uniforms.displacementBias.value = material.displacementBias;
  14577. }
  14578. }
  14579. function refreshUniformsDepth( uniforms, material ) {
  14580. if ( material.displacementMap ) {
  14581. uniforms.displacementMap.value = material.displacementMap;
  14582. uniforms.displacementScale.value = material.displacementScale;
  14583. uniforms.displacementBias.value = material.displacementBias;
  14584. }
  14585. }
  14586. function refreshUniformsDistance( uniforms, material ) {
  14587. if ( material.displacementMap ) {
  14588. uniforms.displacementMap.value = material.displacementMap;
  14589. uniforms.displacementScale.value = material.displacementScale;
  14590. uniforms.displacementBias.value = material.displacementBias;
  14591. }
  14592. uniforms.referencePosition.value.copy( material.referencePosition );
  14593. uniforms.nearDistance.value = material.nearDistance;
  14594. uniforms.farDistance.value = material.farDistance;
  14595. }
  14596. function refreshUniformsNormal( uniforms, material ) {
  14597. if ( material.bumpMap ) {
  14598. uniforms.bumpMap.value = material.bumpMap;
  14599. uniforms.bumpScale.value = material.bumpScale;
  14600. if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
  14601. }
  14602. if ( material.normalMap ) {
  14603. uniforms.normalMap.value = material.normalMap;
  14604. uniforms.normalScale.value.copy( material.normalScale );
  14605. if ( material.side === BackSide ) uniforms.normalScale.value.negate();
  14606. }
  14607. if ( material.displacementMap ) {
  14608. uniforms.displacementMap.value = material.displacementMap;
  14609. uniforms.displacementScale.value = material.displacementScale;
  14610. uniforms.displacementBias.value = material.displacementBias;
  14611. }
  14612. }
  14613. return {
  14614. refreshFogUniforms: refreshFogUniforms,
  14615. refreshMaterialUniforms: refreshMaterialUniforms
  14616. };
  14617. }
  14618. function createCanvasElement() {
  14619. const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
  14620. canvas.style.display = 'block';
  14621. return canvas;
  14622. }
  14623. function WebGLRenderer( parameters ) {
  14624. parameters = parameters || {};
  14625. const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(),
  14626. _context = parameters.context !== undefined ? parameters.context : null,
  14627. _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
  14628. _depth = parameters.depth !== undefined ? parameters.depth : true,
  14629. _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
  14630. _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
  14631. _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
  14632. _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
  14633. _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default',
  14634. _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false;
  14635. let currentRenderList = null;
  14636. let currentRenderState = null;
  14637. // render() can be called from within a callback triggered by another render.
  14638. // We track this so that the nested render call gets its state isolated from the parent render call.
  14639. const renderStateStack = [];
  14640. // public properties
  14641. this.domElement = _canvas;
  14642. // Debug configuration container
  14643. this.debug = {
  14644. /**
  14645. * Enables error checking and reporting when shader programs are being compiled
  14646. * @type {boolean}
  14647. */
  14648. checkShaderErrors: true
  14649. };
  14650. // clearing
  14651. this.autoClear = true;
  14652. this.autoClearColor = true;
  14653. this.autoClearDepth = true;
  14654. this.autoClearStencil = true;
  14655. // scene graph
  14656. this.sortObjects = true;
  14657. // user-defined clipping
  14658. this.clippingPlanes = [];
  14659. this.localClippingEnabled = false;
  14660. // physically based shading
  14661. this.gammaFactor = 2.0; // for backwards compatibility
  14662. this.outputEncoding = LinearEncoding;
  14663. // physical lights
  14664. this.physicallyCorrectLights = false;
  14665. // tone mapping
  14666. this.toneMapping = NoToneMapping;
  14667. this.toneMappingExposure = 1.0;
  14668. // morphs
  14669. this.maxMorphTargets = 8;
  14670. this.maxMorphNormals = 4;
  14671. // internal properties
  14672. const _this = this;
  14673. let _isContextLost = false;
  14674. // internal state cache
  14675. let _framebuffer = null;
  14676. let _currentActiveCubeFace = 0;
  14677. let _currentActiveMipmapLevel = 0;
  14678. let _currentRenderTarget = null;
  14679. let _currentFramebuffer = null;
  14680. let _currentMaterialId = - 1;
  14681. let _currentCamera = null;
  14682. const _currentViewport = new Vector4();
  14683. const _currentScissor = new Vector4();
  14684. let _currentScissorTest = null;
  14685. //
  14686. let _width = _canvas.width;
  14687. let _height = _canvas.height;
  14688. let _pixelRatio = 1;
  14689. let _opaqueSort = null;
  14690. let _transparentSort = null;
  14691. const _viewport = new Vector4( 0, 0, _width, _height );
  14692. const _scissor = new Vector4( 0, 0, _width, _height );
  14693. let _scissorTest = false;
  14694. // frustum
  14695. const _frustum = new Frustum();
  14696. // clipping
  14697. let _clippingEnabled = false;
  14698. let _localClippingEnabled = false;
  14699. // camera matrices cache
  14700. const _projScreenMatrix = new Matrix4();
  14701. const _vector3 = new Vector3();
  14702. const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
  14703. function getTargetPixelRatio() {
  14704. return _currentRenderTarget === null ? _pixelRatio : 1;
  14705. }
  14706. // initialize
  14707. let _gl = _context;
  14708. function getContext( contextNames, contextAttributes ) {
  14709. for ( let i = 0; i < contextNames.length; i ++ ) {
  14710. const contextName = contextNames[ i ];
  14711. const context = _canvas.getContext( contextName, contextAttributes );
  14712. if ( context !== null ) return context;
  14713. }
  14714. return null;
  14715. }
  14716. try {
  14717. const contextAttributes = {
  14718. alpha: _alpha,
  14719. depth: _depth,
  14720. stencil: _stencil,
  14721. antialias: _antialias,
  14722. premultipliedAlpha: _premultipliedAlpha,
  14723. preserveDrawingBuffer: _preserveDrawingBuffer,
  14724. powerPreference: _powerPreference,
  14725. failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat
  14726. };
  14727. // event listeners must be registered before WebGL context is created, see #12753
  14728. _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
  14729. _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
  14730. if ( _gl === null ) {
  14731. const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
  14732. if ( _this.isWebGL1Renderer === true ) {
  14733. contextNames.shift();
  14734. }
  14735. _gl = getContext( contextNames, contextAttributes );
  14736. if ( _gl === null ) {
  14737. if ( getContext( contextNames ) ) {
  14738. throw new Error( 'Error creating WebGL context with your selected attributes.' );
  14739. } else {
  14740. throw new Error( 'Error creating WebGL context.' );
  14741. }
  14742. }
  14743. }
  14744. // Some experimental-webgl implementations do not have getShaderPrecisionFormat
  14745. if ( _gl.getShaderPrecisionFormat === undefined ) {
  14746. _gl.getShaderPrecisionFormat = function () {
  14747. return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
  14748. };
  14749. }
  14750. } catch ( error ) {
  14751. console.error( 'THREE.WebGLRenderer: ' + error.message );
  14752. throw error;
  14753. }
  14754. let extensions, capabilities, state, info;
  14755. let properties, textures, cubemaps, attributes, geometries, objects;
  14756. let programCache, materials, renderLists, renderStates, clipping;
  14757. let background, morphtargets, bufferRenderer, indexedBufferRenderer;
  14758. let utils, bindingStates;
  14759. function initGLContext() {
  14760. extensions = new WebGLExtensions( _gl );
  14761. capabilities = new WebGLCapabilities( _gl, extensions, parameters );
  14762. if ( capabilities.isWebGL2 === false ) {
  14763. extensions.get( 'WEBGL_depth_texture' );
  14764. extensions.get( 'OES_texture_float' );
  14765. extensions.get( 'OES_texture_half_float' );
  14766. extensions.get( 'OES_texture_half_float_linear' );
  14767. extensions.get( 'OES_standard_derivatives' );
  14768. extensions.get( 'OES_element_index_uint' );
  14769. extensions.get( 'OES_vertex_array_object' );
  14770. extensions.get( 'ANGLE_instanced_arrays' );
  14771. }
  14772. extensions.get( 'OES_texture_float_linear' );
  14773. utils = new WebGLUtils( _gl, extensions, capabilities );
  14774. state = new WebGLState( _gl, extensions, capabilities );
  14775. state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
  14776. state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
  14777. info = new WebGLInfo( _gl );
  14778. properties = new WebGLProperties();
  14779. textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
  14780. cubemaps = new WebGLCubeMaps( _this );
  14781. attributes = new WebGLAttributes( _gl, capabilities );
  14782. bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
  14783. geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
  14784. objects = new WebGLObjects( _gl, geometries, attributes, info );
  14785. morphtargets = new WebGLMorphtargets( _gl );
  14786. clipping = new WebGLClipping( properties );
  14787. programCache = new WebGLPrograms( _this, cubemaps, extensions, capabilities, bindingStates, clipping );
  14788. materials = new WebGLMaterials( properties );
  14789. renderLists = new WebGLRenderLists( properties );
  14790. renderStates = new WebGLRenderStates( extensions, capabilities );
  14791. background = new WebGLBackground( _this, cubemaps, state, objects, _premultipliedAlpha );
  14792. bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
  14793. indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
  14794. info.programs = programCache.programs;
  14795. _this.capabilities = capabilities;
  14796. _this.extensions = extensions;
  14797. _this.properties = properties;
  14798. _this.renderLists = renderLists;
  14799. _this.state = state;
  14800. _this.info = info;
  14801. _this._textures = textures;//add
  14802. }
  14803. initGLContext();
  14804. // xr
  14805. const xr = new WebXRManager( _this, _gl );
  14806. this.xr = xr;
  14807. // shadow map
  14808. const shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
  14809. this.shadowMap = shadowMap;
  14810. // API
  14811. this.getContext = function () {
  14812. return _gl;
  14813. };
  14814. this.getContextAttributes = function () {
  14815. return _gl.getContextAttributes();
  14816. };
  14817. this.forceContextLoss = function () {
  14818. const extension = extensions.get( 'WEBGL_lose_context' );
  14819. if ( extension ) extension.loseContext();
  14820. };
  14821. this.forceContextRestore = function () {
  14822. const extension = extensions.get( 'WEBGL_lose_context' );
  14823. if ( extension ) extension.restoreContext();
  14824. };
  14825. this.getPixelRatio = function () {
  14826. return _pixelRatio;
  14827. };
  14828. this.setPixelRatio = function ( value ) {
  14829. if ( value === undefined ) return;
  14830. _pixelRatio = value;
  14831. this.setSize( _width, _height, false );
  14832. };
  14833. this.getSize = function ( target ) {
  14834. if ( target === undefined ) {
  14835. console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' );
  14836. target = new Vector2$1();
  14837. }
  14838. return target.set( _width, _height );
  14839. };
  14840. this.setSize = function ( width, height, updateStyle, devicePixelRatio ) {//改
  14841. if (devicePixelRatio != void 0) _pixelRatio = devicePixelRatio; //add
  14842. if ( xr.isPresenting ) {
  14843. console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
  14844. return;
  14845. }
  14846. _width = width;
  14847. _height = height;
  14848. //if(!window.unableSetSize){
  14849. _canvas.width = Math.floor( width * _pixelRatio );
  14850. _canvas.height = Math.floor( height * _pixelRatio );
  14851. if ( updateStyle !== false ) {
  14852. _canvas.style.width = width + 'px';
  14853. _canvas.style.height = height + 'px';
  14854. }
  14855. this.setViewport( 0, 0, width, height );
  14856. //}
  14857. };
  14858. this.getDrawingBufferSize = function ( target ) {
  14859. if ( target === undefined ) {
  14860. console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' );
  14861. target = new Vector2$1();
  14862. }
  14863. return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
  14864. };
  14865. this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
  14866. _width = width;
  14867. _height = height;
  14868. _pixelRatio = pixelRatio;
  14869. _canvas.width = Math.floor( width * pixelRatio );
  14870. _canvas.height = Math.floor( height * pixelRatio );
  14871. this.setViewport( 0, 0, width, height );
  14872. };
  14873. this.getCurrentViewport = function ( target ) {
  14874. if ( target === undefined ) {
  14875. console.warn( 'WebGLRenderer: .getCurrentViewport() now requires a Vector4 as an argument' );
  14876. target = new Vector4();
  14877. }
  14878. return target.copy( _currentViewport );
  14879. };
  14880. this.getViewport = function ( target ) {
  14881. return target.copy( _viewport );
  14882. };
  14883. this.setViewport = function ( x, y, width, height ) {
  14884. if ( x.isVector4 ) {
  14885. _viewport.set( x.x, x.y, x.z, x.w );
  14886. } else {
  14887. _viewport.set( x, y, width, height );
  14888. }
  14889. state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
  14890. };
  14891. this.getScissor = function ( target ) {
  14892. return target.copy( _scissor );
  14893. };
  14894. this.setScissor = function ( x, y, width, height ) {
  14895. if ( x.isVector4 ) {
  14896. _scissor.set( x.x, x.y, x.z, x.w );
  14897. } else {
  14898. _scissor.set( x, y, width, height );
  14899. }
  14900. state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
  14901. };
  14902. this.getScissorTest = function () {
  14903. return _scissorTest;
  14904. };
  14905. this.setScissorTest = function ( boolean ) {
  14906. state.setScissorTest( _scissorTest = boolean );
  14907. };
  14908. this.setOpaqueSort = function ( method ) {
  14909. _opaqueSort = method;
  14910. };
  14911. this.setTransparentSort = function ( method ) {
  14912. _transparentSort = method;
  14913. };
  14914. // Clearing
  14915. this.getClearColor = function ( target ) {
  14916. if ( target === undefined ) {
  14917. console.warn( 'WebGLRenderer: .getClearColor() now requires a Color as an argument' );
  14918. target = new Color();
  14919. }
  14920. return target.copy( background.getClearColor() );
  14921. };
  14922. this.setClearColor = function () {
  14923. background.setClearColor.apply( background, arguments );
  14924. };
  14925. this.getClearAlpha = function () {
  14926. return background.getClearAlpha();
  14927. };
  14928. this.setClearAlpha = function () {
  14929. background.setClearAlpha.apply( background, arguments );
  14930. };
  14931. this.clear = function ( color, depth, stencil ) {
  14932. let bits = 0;
  14933. if ( color === undefined || color ) bits |= 16384;
  14934. if ( depth === undefined || depth ) bits |= 256;
  14935. if ( stencil === undefined || stencil ) bits |= 1024;
  14936. _gl.clear( bits );
  14937. };
  14938. this.clearColor = function () {
  14939. this.clear( true, false, false );
  14940. };
  14941. this.clearDepth = function () {
  14942. this.clear( false, true, false );
  14943. };
  14944. this.clearStencil = function () {
  14945. this.clear( false, false, true );
  14946. };
  14947. //
  14948. this.dispose = function () {
  14949. _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
  14950. _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
  14951. renderLists.dispose();
  14952. renderStates.dispose();
  14953. properties.dispose();
  14954. cubemaps.dispose();
  14955. objects.dispose();
  14956. bindingStates.dispose();
  14957. xr.dispose();
  14958. animation.stop();
  14959. };
  14960. // Events
  14961. function onContextLost( event ) {
  14962. event.preventDefault();
  14963. console.log( 'THREE.WebGLRenderer: Context Lost.' );
  14964. _isContextLost = true;
  14965. }
  14966. function onContextRestore( /* event */ ) {
  14967. console.log( 'THREE.WebGLRenderer: Context Restored.' );
  14968. _isContextLost = false;
  14969. initGLContext();
  14970. }
  14971. function onMaterialDispose( event ) {
  14972. const material = event.target;
  14973. material.removeEventListener( 'dispose', onMaterialDispose );
  14974. deallocateMaterial( material );
  14975. }
  14976. // Buffer deallocation
  14977. function deallocateMaterial( material ) {
  14978. releaseMaterialProgramReference( material );
  14979. properties.remove( material );
  14980. }
  14981. function releaseMaterialProgramReference( material ) {
  14982. const programInfo = properties.get( material ).program;
  14983. if ( programInfo !== undefined ) {
  14984. programCache.releaseProgram( programInfo );
  14985. }
  14986. }
  14987. // Buffer rendering
  14988. function renderObjectImmediate( object, program ) {
  14989. object.render( function ( object ) {
  14990. _this.renderBufferImmediate( object, program );
  14991. } );
  14992. }
  14993. this.renderBufferImmediate = function ( object, program ) {
  14994. bindingStates.initAttributes();
  14995. const buffers = properties.get( object );
  14996. if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
  14997. if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
  14998. if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
  14999. if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
  15000. const programAttributes = program.getAttributes();
  15001. if ( object.hasPositions ) {
  15002. _gl.bindBuffer( 34962, buffers.position );
  15003. _gl.bufferData( 34962, object.positionArray, 35048 );
  15004. bindingStates.enableAttribute( programAttributes.position );
  15005. _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 );
  15006. }
  15007. if ( object.hasNormals ) {
  15008. _gl.bindBuffer( 34962, buffers.normal );
  15009. _gl.bufferData( 34962, object.normalArray, 35048 );
  15010. bindingStates.enableAttribute( programAttributes.normal );
  15011. _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 );
  15012. }
  15013. if ( object.hasUvs ) {
  15014. _gl.bindBuffer( 34962, buffers.uv );
  15015. _gl.bufferData( 34962, object.uvArray, 35048 );
  15016. bindingStates.enableAttribute( programAttributes.uv );
  15017. _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 );
  15018. }
  15019. if ( object.hasColors ) {
  15020. _gl.bindBuffer( 34962, buffers.color );
  15021. _gl.bufferData( 34962, object.colorArray, 35048 );
  15022. bindingStates.enableAttribute( programAttributes.color );
  15023. _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 );
  15024. }
  15025. bindingStates.disableUnusedAttributes();
  15026. _gl.drawArrays( 4, 0, object.count );
  15027. object.count = 0;
  15028. };
  15029. this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
  15030. if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
  15031. const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
  15032. const program = setProgram( camera, scene, material, object );
  15033. state.setMaterial( material, frontFaceCW );
  15034. //
  15035. let index = geometry.index;
  15036. const position = geometry.attributes.position;
  15037. //
  15038. if ( index === null ) {
  15039. if ( position === undefined || position.count === 0 ) return;
  15040. } else if ( index.count === 0 ) {
  15041. return;
  15042. }
  15043. //
  15044. let rangeFactor = 1;
  15045. if ( material.wireframe === true ) {
  15046. index = geometries.getWireframeAttribute( geometry );
  15047. rangeFactor = 2;
  15048. }
  15049. if ( material.morphTargets || material.morphNormals ) {
  15050. morphtargets.update( object, geometry, material, program );
  15051. }
  15052. bindingStates.setup( object, material, program, geometry, index );
  15053. let attribute;
  15054. let renderer = bufferRenderer;
  15055. if ( index !== null ) {
  15056. attribute = attributes.get( index );
  15057. renderer = indexedBufferRenderer;
  15058. renderer.setIndex( attribute );
  15059. }
  15060. //
  15061. const dataCount = ( index !== null ) ? index.count : position.count;
  15062. const rangeStart = geometry.drawRange.start * rangeFactor;
  15063. const rangeCount = geometry.drawRange.count * rangeFactor;
  15064. const groupStart = group !== null ? group.start * rangeFactor : 0;
  15065. const groupCount = group !== null ? group.count * rangeFactor : Infinity;
  15066. const drawStart = Math.max( rangeStart, groupStart );
  15067. const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
  15068. const drawCount = Math.max( 0, drawEnd - drawStart + 1 );
  15069. if ( drawCount === 0 ) return;
  15070. //
  15071. if ( object.isMesh ) {
  15072. if ( material.wireframe === true ) {
  15073. state.setlineWidth( material.wireframelineWidth * getTargetPixelRatio() );
  15074. renderer.setMode( 1 );
  15075. } else {
  15076. renderer.setMode( 4 );
  15077. }
  15078. } else if ( object.isLine ) {
  15079. let lineWidth = material.lineWidth;
  15080. if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
  15081. state.setlineWidth( lineWidth * getTargetPixelRatio() );
  15082. if ( object.isLineSegments ) {
  15083. renderer.setMode( 1 );
  15084. } else if ( object.isLineLoop ) {
  15085. renderer.setMode( 2 );
  15086. } else {
  15087. renderer.setMode( 3 );
  15088. }
  15089. } else if ( object.isPoints ) {
  15090. renderer.setMode( 0 );
  15091. } else if ( object.isSprite ) {
  15092. renderer.setMode( 4 );
  15093. }
  15094. if ( object.isInstancedMesh ) {
  15095. renderer.renderInstances( drawStart, drawCount, object.count );
  15096. } else if ( geometry.isInstancedBufferGeometry ) {
  15097. const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount );
  15098. renderer.renderInstances( drawStart, drawCount, instanceCount );
  15099. } else {
  15100. renderer.render( drawStart, drawCount );
  15101. }
  15102. };
  15103. // Compile
  15104. this.compile = function ( scene, camera ) {
  15105. currentRenderState = renderStates.get( scene );
  15106. currentRenderState.init();
  15107. scene.traverseVisible( function ( object ) {
  15108. if ( object.isLight && object.layers.test( camera.layers ) ) {
  15109. currentRenderState.pushLight( object );
  15110. if ( object.castShadow ) {
  15111. currentRenderState.pushShadow( object );
  15112. }
  15113. }
  15114. } );
  15115. currentRenderState.setupLights();
  15116. const compiled = new WeakMap();
  15117. scene.traverse( function ( object ) {
  15118. const material = object.material;
  15119. if ( material ) {
  15120. if ( Array.isArray( material ) ) {
  15121. for ( let i = 0; i < material.length; i ++ ) {
  15122. const material2 = material[ i ];
  15123. if ( compiled.has( material2 ) === false ) {
  15124. initMaterial( material2, scene, object );
  15125. compiled.set( material2 );
  15126. }
  15127. }
  15128. } else if ( compiled.has( material ) === false ) {
  15129. initMaterial( material, scene, object );
  15130. compiled.set( material );
  15131. }
  15132. }
  15133. } );
  15134. };
  15135. // Animation Loop
  15136. let onAnimationFrameCallback = null;
  15137. function onAnimationFrame( time ) {
  15138. if ( xr.isPresenting ) return;
  15139. if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
  15140. }
  15141. const animation = new WebGLAnimation();
  15142. animation.setAnimationLoop( onAnimationFrame );
  15143. if ( typeof window !== 'undefined' ) animation.setContext( window );
  15144. this.setAnimationLoop = function ( callback ) {
  15145. onAnimationFrameCallback = callback;
  15146. xr.setAnimationLoop( callback );
  15147. ( callback === null ) ? animation.stop() : animation.start();
  15148. };
  15149. // Rendering
  15150. this.render = function ( scene, camera ) {
  15151. let renderTarget, forceClear;
  15152. if ( arguments[ 2 ] !== undefined ) {
  15153. console.warn( 'THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' );
  15154. renderTarget = arguments[ 2 ];
  15155. }
  15156. if ( arguments[ 3 ] !== undefined ) {
  15157. console.warn( 'THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead.' );
  15158. forceClear = arguments[ 3 ];
  15159. }
  15160. if ( camera !== undefined && camera.isCamera !== true ) {
  15161. console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
  15162. return;
  15163. }
  15164. if ( _isContextLost === true ) return;
  15165. // reset caching for this frame
  15166. bindingStates.resetDefaultState();
  15167. _currentMaterialId = - 1;
  15168. _currentCamera = null;
  15169. // update scene graph
  15170. if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
  15171. // update camera matrices and frustum
  15172. if ( camera.parent === null ) camera.updateMatrixWorld();
  15173. if ( xr.enabled === true && xr.isPresenting === true ) {
  15174. camera = xr.getCamera( camera );
  15175. }
  15176. //
  15177. if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget );
  15178. currentRenderState = renderStates.get( scene, renderStateStack.length );
  15179. currentRenderState.init();
  15180. renderStateStack.push( currentRenderState );
  15181. _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
  15182. _frustum.setFromProjectionMatrix( _projScreenMatrix );
  15183. _localClippingEnabled = this.localClippingEnabled;
  15184. _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
  15185. currentRenderList = renderLists.get( scene, camera );
  15186. currentRenderList.init();
  15187. projectObject( scene, camera, 0, _this.sortObjects );
  15188. currentRenderList.finish();
  15189. if ( _this.sortObjects === true ) {
  15190. currentRenderList.sort( _opaqueSort, _transparentSort );
  15191. }
  15192. //
  15193. if ( _clippingEnabled === true ) clipping.beginShadows();
  15194. const shadowsArray = currentRenderState.state.shadowsArray;
  15195. shadowMap.render( shadowsArray, scene, camera );
  15196. currentRenderState.setupLights();
  15197. currentRenderState.setupLightsView( camera );
  15198. if ( _clippingEnabled === true ) clipping.endShadows();
  15199. //
  15200. if ( this.info.autoReset === true ) this.info.reset();
  15201. if ( renderTarget !== undefined ) {
  15202. this.setRenderTarget( renderTarget );
  15203. }
  15204. //
  15205. background.render( currentRenderList, scene, camera, forceClear );
  15206. // render scene
  15207. const opaqueObjects = currentRenderList.opaque;
  15208. const transparentObjects = currentRenderList.transparent;
  15209. if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
  15210. if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
  15211. //
  15212. if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
  15213. //
  15214. if ( _currentRenderTarget !== null ) {
  15215. // Generate mipmap if we're using any kind of mipmap filtering
  15216. textures.updateRenderTargetMipmap( _currentRenderTarget );
  15217. // resolve multisample renderbuffers to a single-sample texture if necessary
  15218. textures.updateMultisampleRenderTarget( _currentRenderTarget );
  15219. }
  15220. // Ensure depth buffer writing is enabled so it can be cleared on next render
  15221. state.buffers.depth.setTest( true );
  15222. state.buffers.depth.setMask( true );
  15223. state.buffers.color.setMask( true );
  15224. state.setPolygonOffset( false );
  15225. // _gl.finish();
  15226. renderStateStack.pop();
  15227. if ( renderStateStack.length > 0 ) {
  15228. currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
  15229. } else {
  15230. currentRenderState = null;
  15231. }
  15232. currentRenderList = null;
  15233. };
  15234. function projectObject( object, camera, groupOrder, sortObjects ) {
  15235. if ( object.visible === false ) return;
  15236. const visible = object.layers.test( camera.layers );
  15237. if ( visible ) {
  15238. if ( object.isGroup ) {
  15239. groupOrder = object.renderOrder;
  15240. } else if ( object.isLOD ) {
  15241. if ( object.autoUpdate === true ) object.update( camera );
  15242. } else if ( object.isLight ) {
  15243. currentRenderState.pushLight( object );
  15244. if ( object.castShadow ) {
  15245. currentRenderState.pushShadow( object );
  15246. }
  15247. } else if ( object.isSprite ) {
  15248. if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
  15249. if ( sortObjects ) {
  15250. _vector3.setFromMatrixPosition( object.matrixWorld )
  15251. .applyMatrix4( _projScreenMatrix );
  15252. }
  15253. const geometry = objects.update( object );
  15254. const material = object.material;
  15255. if ( material.visible ) {
  15256. currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
  15257. }
  15258. }
  15259. } else if ( object.isImmediateRenderObject ) {
  15260. if ( sortObjects ) {
  15261. _vector3.setFromMatrixPosition( object.matrixWorld )
  15262. .applyMatrix4( _projScreenMatrix );
  15263. }
  15264. currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null );
  15265. } else if ( object.isMesh || object.isLine || object.isPoints ) {
  15266. if ( object.isSkinnedMesh ) {
  15267. // update skeleton only once in a frame
  15268. if ( object.skeleton.frame !== info.render.frame ) {
  15269. object.skeleton.update();
  15270. object.skeleton.frame = info.render.frame;
  15271. }
  15272. }
  15273. if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
  15274. if ( sortObjects ) {
  15275. _vector3.setFromMatrixPosition( object.matrixWorld )
  15276. .applyMatrix4( _projScreenMatrix );
  15277. }
  15278. const geometry = objects.update( object );
  15279. const material = object.material;
  15280. if ( Array.isArray( material ) ) {
  15281. const groups = geometry.groups;
  15282. for ( let i = 0, l = groups.length; i < l; i ++ ) {
  15283. const group = groups[ i ];
  15284. const groupMaterial = material[ group.materialIndex ];
  15285. if ( groupMaterial && groupMaterial.visible ) {
  15286. currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
  15287. }
  15288. }
  15289. } else if ( material.visible ) {
  15290. currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
  15291. }
  15292. }
  15293. }
  15294. }
  15295. const children = object.children;
  15296. for ( let i = 0, l = children.length; i < l; i ++ ) {
  15297. projectObject( children[ i ], camera, groupOrder, sortObjects );
  15298. }
  15299. }
  15300. function renderObjects( renderList, scene, camera ) {
  15301. const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
  15302. for ( let i = 0, l = renderList.length; i < l; i ++ ) {
  15303. const renderItem = renderList[ i ];
  15304. const object = renderItem.object;
  15305. const geometry = renderItem.geometry;
  15306. const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
  15307. const group = renderItem.group;
  15308. if ( camera.isArrayCamera ) {
  15309. const cameras = camera.cameras;
  15310. for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
  15311. const camera2 = cameras[ j ];
  15312. if ( object.layers.test( camera2.layers ) ) {
  15313. state.viewport( _currentViewport.copy( camera2.viewport ) );
  15314. currentRenderState.setupLightsView( camera2 );
  15315. renderObject( object, scene, camera2, geometry, material, group );
  15316. }
  15317. }
  15318. } else {
  15319. renderObject( object, scene, camera, geometry, material, group );
  15320. }
  15321. }
  15322. }
  15323. function renderObject( object, scene, camera, geometry, material, group ) {
  15324. object.onBeforeRender( _this, scene, camera, geometry, material, group );
  15325. object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
  15326. object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
  15327. if ( object.isImmediateRenderObject ) {
  15328. const program = setProgram( camera, scene, material, object );
  15329. state.setMaterial( material );
  15330. bindingStates.reset();
  15331. renderObjectImmediate( object, program );
  15332. } else {
  15333. _this.renderBufferDirect( camera, scene, geometry, material, object, group );
  15334. }
  15335. object.onAfterRender( _this, scene, camera, geometry, material, group );
  15336. }
  15337. function initMaterial( material, scene, object ) {
  15338. if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
  15339. const materialProperties = properties.get( material );
  15340. const lights = currentRenderState.state.lights;
  15341. const shadowsArray = currentRenderState.state.shadowsArray;
  15342. const lightsStateVersion = lights.state.version;
  15343. const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
  15344. const programCacheKey = programCache.getProgramCacheKey( parameters );
  15345. let program = materialProperties.program;
  15346. let programChange = true;
  15347. if ( program === undefined ) {
  15348. // new material
  15349. material.addEventListener( 'dispose', onMaterialDispose );
  15350. } else if ( program.cacheKey !== programCacheKey ) {
  15351. // changed glsl or parameters
  15352. releaseMaterialProgramReference( material );
  15353. } else if ( materialProperties.lightsStateVersion !== lightsStateVersion ) {
  15354. programChange = false;
  15355. } else if ( parameters.shaderID !== undefined ) {
  15356. // same glsl and uniform list, envMap still needs the update here to avoid a frame-late effect
  15357. const environment = material.isMeshStandardMaterial ? scene.environment : null;
  15358. materialProperties.envMap = cubemaps.get( material.envMap || environment );
  15359. return;
  15360. } else {
  15361. // only rebuild uniform list
  15362. programChange = false;
  15363. }
  15364. if ( programChange ) {
  15365. parameters.uniforms = programCache.getUniforms( material );
  15366. material.onBeforeCompile( parameters, _this );
  15367. program = programCache.acquireProgram( parameters, programCacheKey );
  15368. materialProperties.program = program;
  15369. materialProperties.uniforms = parameters.uniforms;
  15370. materialProperties.outputEncoding = parameters.outputEncoding;
  15371. }
  15372. const uniforms = materialProperties.uniforms;
  15373. if ( ! material.isShaderMaterial &&
  15374. ! material.isRawShaderMaterial ||
  15375. material.clipping === true ) {
  15376. materialProperties.numClippingPlanes = clipping.numPlanes;
  15377. materialProperties.numIntersection = clipping.numIntersection;
  15378. uniforms.clippingPlanes = clipping.uniform;
  15379. }
  15380. materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
  15381. materialProperties.fog = scene.fog;
  15382. materialProperties.envMap = cubemaps.get( material.envMap || materialProperties.environment );
  15383. // store the light setup it was created for
  15384. materialProperties.needsLights = materialNeedsLights( material );
  15385. materialProperties.lightsStateVersion = lightsStateVersion;
  15386. if ( materialProperties.needsLights ) {
  15387. // wire up the material to this renderer's lighting state
  15388. uniforms.ambientLightColor.value = lights.state.ambient;
  15389. uniforms.lightProbe.value = lights.state.probe;
  15390. uniforms.directionalLights.value = lights.state.directional;
  15391. uniforms.directionalLightShadows.value = lights.state.directionalShadow;
  15392. uniforms.spotLights.value = lights.state.spot;
  15393. uniforms.spotLightShadows.value = lights.state.spotShadow;
  15394. uniforms.rectAreaLights.value = lights.state.rectArea;
  15395. uniforms.ltc_1.value = lights.state.rectAreaLTC1;
  15396. uniforms.ltc_2.value = lights.state.rectAreaLTC2;
  15397. uniforms.pointLights.value = lights.state.point;
  15398. uniforms.pointLightShadows.value = lights.state.pointShadow;
  15399. uniforms.hemisphereLights.value = lights.state.hemi;
  15400. uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
  15401. uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
  15402. uniforms.spotShadowMap.value = lights.state.spotShadowMap;
  15403. uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
  15404. uniforms.pointShadowMap.value = lights.state.pointShadowMap;
  15405. uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
  15406. // TODO (abelnation): add area lights shadow info to uniforms
  15407. }
  15408. const progUniforms = materialProperties.program.getUniforms();
  15409. const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
  15410. materialProperties.uniformsList = uniformsList;
  15411. }
  15412. function setProgram( camera, scene, material, object ) {
  15413. if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
  15414. textures.resetTextureUnits();
  15415. const fog = scene.fog;
  15416. const environment = material.isMeshStandardMaterial ? scene.environment : null;
  15417. const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
  15418. const envMap = cubemaps.get( material.envMap || environment );
  15419. const materialProperties = properties.get( material );
  15420. const lights = currentRenderState.state.lights;
  15421. if ( _clippingEnabled === true ) {
  15422. if ( _localClippingEnabled === true || camera !== _currentCamera ) {
  15423. const useCache =
  15424. camera === _currentCamera &&
  15425. material.id === _currentMaterialId;
  15426. // we might want to call this function with some ClippingGroup
  15427. // object instead of the material, once it becomes feasible
  15428. // (#8465, #8379)
  15429. clipping.setState( material, camera, useCache );
  15430. }
  15431. }
  15432. if ( material.version === materialProperties.__version ) {
  15433. if ( material.fog && materialProperties.fog !== fog ) {
  15434. initMaterial( material, scene, object );
  15435. } else if ( materialProperties.environment !== environment ) {
  15436. initMaterial( material, scene, object );
  15437. } else if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
  15438. initMaterial( material, scene, object );
  15439. } else if ( materialProperties.numClippingPlanes !== undefined &&
  15440. ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
  15441. materialProperties.numIntersection !== clipping.numIntersection ) ) {
  15442. initMaterial( material, scene, object );
  15443. } else if ( materialProperties.outputEncoding !== encoding ) {
  15444. initMaterial( material, scene, object );
  15445. } else if ( materialProperties.envMap !== envMap ) {
  15446. initMaterial( material, scene, object );
  15447. }
  15448. } else {
  15449. initMaterial( material, scene, object );
  15450. materialProperties.__version = material.version;
  15451. }
  15452. let refreshProgram = false;
  15453. let refreshMaterial = false;
  15454. let refreshLights = false;
  15455. const program = materialProperties.program,
  15456. p_uniforms = program.getUniforms(),
  15457. m_uniforms = materialProperties.uniforms;
  15458. if ( state.useProgram( program.program ) ) {
  15459. refreshProgram = true;
  15460. refreshMaterial = true;
  15461. refreshLights = true;
  15462. }
  15463. if ( material.id !== _currentMaterialId ) {
  15464. _currentMaterialId = material.id;
  15465. refreshMaterial = true;
  15466. }
  15467. if ( refreshProgram || _currentCamera !== camera ) {
  15468. p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
  15469. if ( capabilities.logarithmicDepthBuffer ) {
  15470. p_uniforms.setValue( _gl, 'logDepthBufFC',
  15471. 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
  15472. }
  15473. if ( _currentCamera !== camera ) {
  15474. _currentCamera = camera;
  15475. // lighting uniforms depend on the camera so enforce an update
  15476. // now, in case this material supports lights - or later, when
  15477. // the next material that does gets activated:
  15478. refreshMaterial = true; // set to true on material change
  15479. refreshLights = true; // remains set until update done
  15480. }
  15481. // load material specific uniforms
  15482. // (shader material also gets them for the sake of genericity)
  15483. if ( material.isShaderMaterial ||
  15484. material.isMeshPhongMaterial ||
  15485. material.isMeshToonMaterial ||
  15486. material.isMeshStandardMaterial ||
  15487. material.envMap ) {
  15488. const uCamPos = p_uniforms.map.cameraPosition;
  15489. if ( uCamPos !== undefined ) {
  15490. uCamPos.setValue( _gl,
  15491. _vector3.setFromMatrixPosition( camera.matrixWorld ) );
  15492. }
  15493. }
  15494. if ( material.isMeshPhongMaterial ||
  15495. material.isMeshToonMaterial ||
  15496. material.isMeshLambertMaterial ||
  15497. material.isMeshBasicMaterial ||
  15498. material.isMeshStandardMaterial ||
  15499. material.isShaderMaterial ) {
  15500. p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
  15501. }
  15502. if ( material.isMeshPhongMaterial ||
  15503. material.isMeshToonMaterial ||
  15504. material.isMeshLambertMaterial ||
  15505. material.isMeshBasicMaterial ||
  15506. material.isMeshStandardMaterial ||
  15507. material.isShaderMaterial ||
  15508. material.isShadowMaterial ||
  15509. material.skinning ) {
  15510. p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
  15511. }
  15512. }
  15513. // skinning uniforms must be set even if material didn't change
  15514. // auto-setting of texture unit for bone texture must go before other textures
  15515. // otherwise textures used for skinning can take over texture units reserved for other material textures
  15516. if ( material.skinning ) {
  15517. p_uniforms.setOptional( _gl, object, 'bindMatrix' );
  15518. p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
  15519. const skeleton = object.skeleton;
  15520. if ( skeleton ) {
  15521. const bones = skeleton.bones;
  15522. if ( capabilities.floatVertexTextures ) {
  15523. if ( skeleton.boneTexture === null ) {
  15524. // layout (1 matrix = 4 pixels)
  15525. // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
  15526. // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
  15527. // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
  15528. // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
  15529. // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
  15530. let size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
  15531. size = MathUtils.ceilPowerOfTwo( size );
  15532. size = Math.max( size, 4 );
  15533. const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
  15534. boneMatrices.set( skeleton.boneMatrices ); // copy current values
  15535. const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
  15536. skeleton.boneMatrices = boneMatrices;
  15537. skeleton.boneTexture = boneTexture;
  15538. skeleton.boneTextureSize = size;
  15539. }
  15540. p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
  15541. p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
  15542. } else {
  15543. p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
  15544. }
  15545. }
  15546. }
  15547. if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
  15548. materialProperties.receiveShadow = object.receiveShadow;
  15549. p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
  15550. }
  15551. if ( refreshMaterial ) {
  15552. p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
  15553. if ( materialProperties.needsLights ) {
  15554. // the current material requires lighting info
  15555. // note: all lighting uniforms are always set correctly
  15556. // they simply reference the renderer's state for their
  15557. // values
  15558. //
  15559. // use the current material's .needsUpdate flags to set
  15560. // the GL state when required
  15561. markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
  15562. }
  15563. // refresh uniforms common to several materials
  15564. if ( fog && material.fog ) {
  15565. materials.refreshFogUniforms( m_uniforms, fog );
  15566. }
  15567. materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height );
  15568. WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
  15569. }
  15570. if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
  15571. WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
  15572. material.uniformsNeedUpdate = false;
  15573. }
  15574. if ( material.isSpriteMaterial ) {
  15575. p_uniforms.setValue( _gl, 'center', object.center );
  15576. }
  15577. // common matrices
  15578. p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
  15579. p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
  15580. p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
  15581. return program;
  15582. }
  15583. // If uniforms are marked as clean, they don't need to be loaded to the GPU.
  15584. function markUniformsLightsNeedsUpdate( uniforms, value ) {
  15585. uniforms.ambientLightColor.needsUpdate = value;
  15586. uniforms.lightProbe.needsUpdate = value;
  15587. uniforms.directionalLights.needsUpdate = value;
  15588. uniforms.directionalLightShadows.needsUpdate = value;
  15589. uniforms.pointLights.needsUpdate = value;
  15590. uniforms.pointLightShadows.needsUpdate = value;
  15591. uniforms.spotLights.needsUpdate = value;
  15592. uniforms.spotLightShadows.needsUpdate = value;
  15593. uniforms.rectAreaLights.needsUpdate = value;
  15594. uniforms.hemisphereLights.needsUpdate = value;
  15595. }
  15596. function materialNeedsLights( material ) {
  15597. return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
  15598. material.isMeshStandardMaterial || material.isShadowMaterial ||
  15599. ( material.isShaderMaterial && material.lights === true );
  15600. }
  15601. //
  15602. this.setFramebuffer = function ( value ) {
  15603. if ( _framebuffer !== value && _currentRenderTarget === null ) _gl.bindFramebuffer( 36160, value );
  15604. _framebuffer = value;
  15605. };
  15606. this.getActiveCubeFace = function () {
  15607. return _currentActiveCubeFace;
  15608. };
  15609. this.getActiveMipmapLevel = function () {
  15610. return _currentActiveMipmapLevel;
  15611. };
  15612. this.getRenderList = function () {
  15613. return currentRenderList;
  15614. };
  15615. this.setRenderList = function ( renderList ) {
  15616. currentRenderList = renderList;
  15617. };
  15618. this.getRenderTarget = function () {
  15619. return _currentRenderTarget;
  15620. };
  15621. this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
  15622. _currentRenderTarget = renderTarget;
  15623. _currentActiveCubeFace = activeCubeFace;
  15624. _currentActiveMipmapLevel = activeMipmapLevel;
  15625. if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
  15626. textures.setupRenderTarget( renderTarget );
  15627. }
  15628. let framebuffer = _framebuffer;
  15629. let isCube = false;
  15630. if ( renderTarget ) {
  15631. const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
  15632. if ( renderTarget.isWebGLCubeRenderTarget ) {
  15633. framebuffer = __webglFramebuffer[ activeCubeFace ];
  15634. isCube = true;
  15635. } else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
  15636. framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
  15637. } else {
  15638. framebuffer = __webglFramebuffer;
  15639. }
  15640. _currentViewport.copy( renderTarget.viewport );
  15641. _currentScissor.copy( renderTarget.scissor );
  15642. _currentScissorTest = renderTarget.scissorTest;
  15643. } else {
  15644. _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
  15645. _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
  15646. _currentScissorTest = _scissorTest;
  15647. }
  15648. if ( _currentFramebuffer !== framebuffer ) {
  15649. _gl.bindFramebuffer( 36160, framebuffer );
  15650. _currentFramebuffer = framebuffer;
  15651. }
  15652. state.viewport( _currentViewport );
  15653. state.scissor( _currentScissor );
  15654. state.setScissorTest( _currentScissorTest );
  15655. if ( isCube ) {
  15656. const textureProperties = properties.get( renderTarget.texture );
  15657. _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
  15658. }
  15659. };
  15660. this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
  15661. if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
  15662. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
  15663. return;
  15664. }
  15665. let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
  15666. if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
  15667. framebuffer = framebuffer[ activeCubeFaceIndex ];
  15668. }
  15669. if ( framebuffer ) {
  15670. let restore = false;
  15671. if ( framebuffer !== _currentFramebuffer ) {
  15672. _gl.bindFramebuffer( 36160, framebuffer );
  15673. restore = true;
  15674. }
  15675. try {
  15676. const texture = renderTarget.texture;
  15677. const textureFormat = texture.format;
  15678. const textureType = texture.type;
  15679. if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) {
  15680. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
  15681. return;
  15682. }
  15683. if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // IE11, Edge and Chrome Mac < 52 (#9513)
  15684. ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
  15685. ! ( textureType === HalfFloatType && ( capabilities.isWebGL2 ? extensions.get( 'EXT_color_buffer_float' ) : extensions.get( 'EXT_color_buffer_half_float' ) ) ) ) {
  15686. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
  15687. return;
  15688. }
  15689. if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) {
  15690. // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
  15691. if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
  15692. _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
  15693. }
  15694. } else {
  15695. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
  15696. }
  15697. } finally {
  15698. if ( restore ) {
  15699. _gl.bindFramebuffer( 36160, _currentFramebuffer );
  15700. }
  15701. }
  15702. }
  15703. };
  15704. this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
  15705. const levelScale = Math.pow( 2, - level );
  15706. const width = Math.floor( texture.image.width * levelScale );
  15707. const height = Math.floor( texture.image.height * levelScale );
  15708. const glFormat = utils.convert( texture.format );
  15709. textures.setTexture2D( texture, 0 );
  15710. _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 );
  15711. state.unbindTexture();
  15712. };
  15713. this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
  15714. const width = srcTexture.image.width;
  15715. const height = srcTexture.image.height;
  15716. const glFormat = utils.convert( dstTexture.format );
  15717. const glType = utils.convert( dstTexture.type );
  15718. textures.setTexture2D( dstTexture, 0 );
  15719. // As another texture upload may have changed pixelStorei
  15720. // parameters, make sure they are correct for the dstTexture
  15721. _gl.pixelStorei( 37440, dstTexture.flipY );
  15722. _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha );
  15723. _gl.pixelStorei( 3317, dstTexture.unpackAlignment );
  15724. if ( srcTexture.isDataTexture ) {
  15725. _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
  15726. } else {
  15727. if ( srcTexture.isCompressedTexture ) {
  15728. _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
  15729. } else {
  15730. _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image );
  15731. }
  15732. }
  15733. // Generate mipmaps only when copying level 0
  15734. if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 );
  15735. state.unbindTexture();
  15736. };
  15737. this.initTexture = function ( texture ) {
  15738. textures.setTexture2D( texture, 0 );
  15739. state.unbindTexture();
  15740. };
  15741. this.resetState = function () {
  15742. state.reset();
  15743. bindingStates.reset();
  15744. };
  15745. if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
  15746. __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
  15747. }
  15748. }
  15749. function WebGL1Renderer( parameters ) {
  15750. WebGLRenderer.call( this, parameters );
  15751. }
  15752. WebGL1Renderer.prototype = Object.assign( Object.create( WebGLRenderer.prototype ), {
  15753. constructor: WebGL1Renderer,
  15754. isWebGL1Renderer: true
  15755. } );
  15756. class FogExp2 {
  15757. constructor( color, density ) {
  15758. Object.defineProperty( this, 'isFogExp2', { value: true } );
  15759. this.name = '';
  15760. this.color = new Color( color );
  15761. this.density = ( density !== undefined ) ? density : 0.00025;
  15762. }
  15763. clone() {
  15764. return new FogExp2( this.color, this.density );
  15765. }
  15766. toJSON( /* meta */ ) {
  15767. return {
  15768. type: 'FogExp2',
  15769. color: this.color.getHex(),
  15770. density: this.density
  15771. };
  15772. }
  15773. }
  15774. class Fog {
  15775. constructor( color, near, far ) {
  15776. Object.defineProperty( this, 'isFog', { value: true } );
  15777. this.name = '';
  15778. this.color = new Color( color );
  15779. this.near = ( near !== undefined ) ? near : 1;
  15780. this.far = ( far !== undefined ) ? far : 1000;
  15781. }
  15782. clone() {
  15783. return new Fog( this.color, this.near, this.far );
  15784. }
  15785. toJSON( /* meta */ ) {
  15786. return {
  15787. type: 'Fog',
  15788. color: this.color.getHex(),
  15789. near: this.near,
  15790. far: this.far
  15791. };
  15792. }
  15793. }
  15794. class Scene extends Object3D {
  15795. constructor() {
  15796. super();
  15797. Object.defineProperty( this, 'isScene', { value: true } );
  15798. this.type = 'Scene';
  15799. this.background = null;
  15800. this.environment = null;
  15801. this.fog = null;
  15802. this.overrideMaterial = null;
  15803. this.autoUpdate = true; // checked by the renderer
  15804. if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
  15805. __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
  15806. }
  15807. }
  15808. copy( source, recursive ) {
  15809. super.copy( source, recursive );
  15810. if ( source.background !== null ) this.background = source.background.clone();
  15811. if ( source.environment !== null ) this.environment = source.environment.clone();
  15812. if ( source.fog !== null ) this.fog = source.fog.clone();
  15813. if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
  15814. this.autoUpdate = source.autoUpdate;
  15815. this.matrixAutoUpdate = source.matrixAutoUpdate;
  15816. return this;
  15817. }
  15818. toJSON( meta ) {
  15819. const data = super.toJSON( meta );
  15820. if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
  15821. if ( this.environment !== null ) data.object.environment = this.environment.toJSON( meta );
  15822. if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
  15823. return data;
  15824. }
  15825. }
  15826. function InterleavedBuffer( array, stride ) {
  15827. this.array = array;
  15828. this.stride = stride;
  15829. this.count = array !== undefined ? array.length / stride : 0;
  15830. this.usage = StaticDrawUsage;
  15831. this.updateRange = { offset: 0, count: - 1 };
  15832. this.version = 0;
  15833. this.uuid = MathUtils.generateUUID();
  15834. }
  15835. Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {
  15836. set: function ( value ) {
  15837. if ( value === true ) this.version ++;
  15838. }
  15839. } );
  15840. Object.assign( InterleavedBuffer.prototype, {
  15841. isInterleavedBuffer: true,
  15842. onUploadCallback: function () {},
  15843. setUsage: function ( value ) {
  15844. this.usage = value;
  15845. return this;
  15846. },
  15847. copy: function ( source ) {
  15848. this.array = new source.array.constructor( source.array );
  15849. this.count = source.count;
  15850. this.stride = source.stride;
  15851. this.usage = source.usage;
  15852. return this;
  15853. },
  15854. copyAt: function ( index1, attribute, index2 ) {
  15855. index1 *= this.stride;
  15856. index2 *= attribute.stride;
  15857. for ( let i = 0, l = this.stride; i < l; i ++ ) {
  15858. this.array[ index1 + i ] = attribute.array[ index2 + i ];
  15859. }
  15860. return this;
  15861. },
  15862. set: function ( value, offset = 0 ) {
  15863. this.array.set( value, offset );
  15864. return this;
  15865. },
  15866. clone: function ( data ) {
  15867. if ( data.arrayBuffers === undefined ) {
  15868. data.arrayBuffers = {};
  15869. }
  15870. if ( this.array.buffer._uuid === undefined ) {
  15871. this.array.buffer._uuid = MathUtils.generateUUID();
  15872. }
  15873. if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
  15874. data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
  15875. }
  15876. const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
  15877. const ib = new InterleavedBuffer( array, this.stride );
  15878. ib.setUsage( this.usage );
  15879. return ib;
  15880. },
  15881. onUpload: function ( callback ) {
  15882. this.onUploadCallback = callback;
  15883. return this;
  15884. },
  15885. toJSON: function ( data ) {
  15886. if ( data.arrayBuffers === undefined ) {
  15887. data.arrayBuffers = {};
  15888. }
  15889. // generate UUID for array buffer if necessary
  15890. if ( this.array.buffer._uuid === undefined ) {
  15891. this.array.buffer._uuid = MathUtils.generateUUID();
  15892. }
  15893. if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
  15894. data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) );
  15895. }
  15896. //
  15897. return {
  15898. uuid: this.uuid,
  15899. buffer: this.array.buffer._uuid,
  15900. type: this.array.constructor.name,
  15901. stride: this.stride
  15902. };
  15903. }
  15904. } );
  15905. const _vector$6 = new Vector3();
  15906. function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
  15907. this.name = '';
  15908. this.data = interleavedBuffer;
  15909. this.itemSize = itemSize;
  15910. this.offset = offset;
  15911. this.normalized = normalized === true;
  15912. }
  15913. Object.defineProperties( InterleavedBufferAttribute.prototype, {
  15914. count: {
  15915. get: function () {
  15916. return this.data.count;
  15917. }
  15918. },
  15919. array: {
  15920. get: function () {
  15921. return this.data.array;
  15922. }
  15923. },
  15924. needsUpdate: {
  15925. set: function ( value ) {
  15926. this.data.needsUpdate = value;
  15927. }
  15928. }
  15929. } );
  15930. Object.assign( InterleavedBufferAttribute.prototype, {
  15931. isInterleavedBufferAttribute: true,
  15932. applyMatrix4: function ( m ) {
  15933. for ( let i = 0, l = this.data.count; i < l; i ++ ) {
  15934. _vector$6.x = this.getX( i );
  15935. _vector$6.y = this.getY( i );
  15936. _vector$6.z = this.getZ( i );
  15937. _vector$6.applyMatrix4( m );
  15938. this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
  15939. }
  15940. return this;
  15941. },
  15942. setX: function ( index, x ) {
  15943. this.data.array[ index * this.data.stride + this.offset ] = x;
  15944. return this;
  15945. },
  15946. setY: function ( index, y ) {
  15947. this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
  15948. return this;
  15949. },
  15950. setZ: function ( index, z ) {
  15951. this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
  15952. return this;
  15953. },
  15954. setW: function ( index, w ) {
  15955. this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
  15956. return this;
  15957. },
  15958. getX: function ( index ) {
  15959. return this.data.array[ index * this.data.stride + this.offset ];
  15960. },
  15961. getY: function ( index ) {
  15962. return this.data.array[ index * this.data.stride + this.offset + 1 ];
  15963. },
  15964. getZ: function ( index ) {
  15965. return this.data.array[ index * this.data.stride + this.offset + 2 ];
  15966. },
  15967. getW: function ( index ) {
  15968. return this.data.array[ index * this.data.stride + this.offset + 3 ];
  15969. },
  15970. setXY: function ( index, x, y ) {
  15971. index = index * this.data.stride + this.offset;
  15972. this.data.array[ index + 0 ] = x;
  15973. this.data.array[ index + 1 ] = y;
  15974. return this;
  15975. },
  15976. setXYZ: function ( index, x, y, z ) {
  15977. index = index * this.data.stride + this.offset;
  15978. this.data.array[ index + 0 ] = x;
  15979. this.data.array[ index + 1 ] = y;
  15980. this.data.array[ index + 2 ] = z;
  15981. return this;
  15982. },
  15983. setXYZW: function ( index, x, y, z, w ) {
  15984. index = index * this.data.stride + this.offset;
  15985. this.data.array[ index + 0 ] = x;
  15986. this.data.array[ index + 1 ] = y;
  15987. this.data.array[ index + 2 ] = z;
  15988. this.data.array[ index + 3 ] = w;
  15989. return this;
  15990. },
  15991. clone: function ( data ) {
  15992. if ( data === undefined ) {
  15993. console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' );
  15994. const array = [];
  15995. for ( let i = 0; i < this.count; i ++ ) {
  15996. const index = i * this.data.stride + this.offset;
  15997. for ( let j = 0; j < this.itemSize; j ++ ) {
  15998. array.push( this.data.array[ index + j ] );
  15999. }
  16000. }
  16001. return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
  16002. } else {
  16003. if ( data.interleavedBuffers === undefined ) {
  16004. data.interleavedBuffers = {};
  16005. }
  16006. if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
  16007. data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
  16008. }
  16009. return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
  16010. }
  16011. },
  16012. toJSON: function ( data ) {
  16013. if ( data === undefined ) {
  16014. console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' );
  16015. const array = [];
  16016. for ( let i = 0; i < this.count; i ++ ) {
  16017. const index = i * this.data.stride + this.offset;
  16018. for ( let j = 0; j < this.itemSize; j ++ ) {
  16019. array.push( this.data.array[ index + j ] );
  16020. }
  16021. }
  16022. // deinterleave data and save it as an ordinary buffer attribute for now
  16023. return {
  16024. itemSize: this.itemSize,
  16025. type: this.array.constructor.name,
  16026. array: array,
  16027. normalized: this.normalized
  16028. };
  16029. } else {
  16030. // save as true interlaved attribtue
  16031. if ( data.interleavedBuffers === undefined ) {
  16032. data.interleavedBuffers = {};
  16033. }
  16034. if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
  16035. data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
  16036. }
  16037. return {
  16038. isInterleavedBufferAttribute: true,
  16039. itemSize: this.itemSize,
  16040. data: this.data.uuid,
  16041. offset: this.offset,
  16042. normalized: this.normalized
  16043. };
  16044. }
  16045. }
  16046. } );
  16047. /**
  16048. * parameters = {
  16049. * color: <hex>,
  16050. * map: new THREE.Texture( <Image> ),
  16051. * alphaMap: new THREE.Texture( <Image> ),
  16052. * rotation: <float>,
  16053. * sizeAttenuation: <bool>
  16054. * }
  16055. */
  16056. function SpriteMaterial( parameters ) {
  16057. Material.call( this );
  16058. this.type = 'SpriteMaterial';
  16059. this.color = new Color( 0xffffff );
  16060. this.map = null;
  16061. this.alphaMap = null;
  16062. this.rotation = 0;
  16063. this.sizeAttenuation = true;
  16064. this.transparent = true;
  16065. this.setValues( parameters );
  16066. }
  16067. SpriteMaterial.prototype = Object.create( Material.prototype );
  16068. SpriteMaterial.prototype.constructor = SpriteMaterial;
  16069. SpriteMaterial.prototype.isSpriteMaterial = true;
  16070. SpriteMaterial.prototype.copy = function ( source ) {
  16071. Material.prototype.copy.call( this, source );
  16072. this.color.copy( source.color );
  16073. this.map = source.map;
  16074. this.alphaMap = source.alphaMap;
  16075. this.rotation = source.rotation;
  16076. this.sizeAttenuation = source.sizeAttenuation;
  16077. return this;
  16078. };
  16079. let _geometry;
  16080. const _intersectPoint = new Vector3();
  16081. const _worldScale = new Vector3();
  16082. const _mvPosition = new Vector3();
  16083. const _alignedPosition = new Vector2$1();
  16084. const _rotatedPosition = new Vector2$1();
  16085. const _viewWorldMatrix = new Matrix4();
  16086. const _vA$1 = new Vector3();
  16087. const _vB$1 = new Vector3();
  16088. const _vC$1 = new Vector3();
  16089. const _uvA$1 = new Vector2$1();
  16090. const _uvB$1 = new Vector2$1();
  16091. const _uvC$1 = new Vector2$1();
  16092. function Sprite( material ) {
  16093. Object3D.call( this );
  16094. this.type = 'Sprite';
  16095. if ( _geometry === undefined ) {
  16096. _geometry = new BufferGeometry();
  16097. const float32Array = new Float32Array( [
  16098. - 0.5, - 0.5, 0, 0, 0,
  16099. 0.5, - 0.5, 0, 1, 0,
  16100. 0.5, 0.5, 0, 1, 1,
  16101. - 0.5, 0.5, 0, 0, 1
  16102. ] );
  16103. const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
  16104. _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] );
  16105. _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
  16106. _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
  16107. }
  16108. this.geometry = _geometry;
  16109. this.material = ( material !== undefined ) ? material : new SpriteMaterial();
  16110. this.center = new Vector2$1( 0.5, 0.5 );
  16111. }
  16112. Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
  16113. constructor: Sprite,
  16114. isSprite: true,
  16115. raycast: function ( raycaster, intersects ) {
  16116. if ( raycaster.camera === null ) {
  16117. console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
  16118. }
  16119. _worldScale.setFromMatrixScale( this.matrixWorld );
  16120. _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
  16121. this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
  16122. _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
  16123. if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
  16124. _worldScale.multiplyScalar( - _mvPosition.z );
  16125. }
  16126. const rotation = this.material.rotation;
  16127. let sin, cos;
  16128. if ( rotation !== 0 ) {
  16129. cos = Math.cos( rotation );
  16130. sin = Math.sin( rotation );
  16131. }
  16132. const center = this.center;
  16133. transformVertex( _vA$1.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  16134. transformVertex( _vB$1.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  16135. transformVertex( _vC$1.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  16136. _uvA$1.set( 0, 0 );
  16137. _uvB$1.set( 1, 0 );
  16138. _uvC$1.set( 1, 1 );
  16139. // check first triangle
  16140. let intersect = raycaster.ray.intersectTriangle( _vA$1, _vB$1, _vC$1, false, _intersectPoint );
  16141. if ( intersect === null ) {
  16142. // check second triangle
  16143. transformVertex( _vB$1.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  16144. _uvB$1.set( 0, 1 );
  16145. intersect = raycaster.ray.intersectTriangle( _vA$1, _vC$1, _vB$1, false, _intersectPoint );
  16146. if ( intersect === null ) {
  16147. return;
  16148. }
  16149. }
  16150. const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
  16151. if ( distance < raycaster.near || distance > raycaster.far ) return;
  16152. intersects.push( {
  16153. distance: distance,
  16154. point: _intersectPoint.clone(),
  16155. uv: Triangle.getUV( _intersectPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2$1() ),
  16156. face: null,
  16157. object: this
  16158. } );
  16159. },
  16160. copy: function ( source ) {
  16161. Object3D.prototype.copy.call( this, source );
  16162. if ( source.center !== undefined ) this.center.copy( source.center );
  16163. this.material = source.material;
  16164. return this;
  16165. }
  16166. } );
  16167. function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
  16168. // compute position in camera space
  16169. _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
  16170. // to check if rotation is not zero
  16171. if ( sin !== undefined ) {
  16172. _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
  16173. _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
  16174. } else {
  16175. _rotatedPosition.copy( _alignedPosition );
  16176. }
  16177. vertexPosition.copy( mvPosition );
  16178. vertexPosition.x += _rotatedPosition.x;
  16179. vertexPosition.y += _rotatedPosition.y;
  16180. // transform to world space
  16181. vertexPosition.applyMatrix4( _viewWorldMatrix );
  16182. }
  16183. const _v1$4 = new Vector3();
  16184. const _v2$2 = new Vector3();
  16185. function LOD() {
  16186. Object3D.call( this );
  16187. this._currentLevel = 0;
  16188. this.type = 'LOD';
  16189. Object.defineProperties( this, {
  16190. levels: {
  16191. enumerable: true,
  16192. value: []
  16193. }
  16194. } );
  16195. this.autoUpdate = true;
  16196. }
  16197. LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
  16198. constructor: LOD,
  16199. isLOD: true,
  16200. copy: function ( source ) {
  16201. Object3D.prototype.copy.call( this, source, false );
  16202. const levels = source.levels;
  16203. for ( let i = 0, l = levels.length; i < l; i ++ ) {
  16204. const level = levels[ i ];
  16205. this.addLevel( level.object.clone(), level.distance );
  16206. }
  16207. this.autoUpdate = source.autoUpdate;
  16208. return this;
  16209. },
  16210. addLevel: function ( object, distance = 0 ) {
  16211. distance = Math.abs( distance );
  16212. const levels = this.levels;
  16213. let l;
  16214. for ( l = 0; l < levels.length; l ++ ) {
  16215. if ( distance < levels[ l ].distance ) {
  16216. break;
  16217. }
  16218. }
  16219. levels.splice( l, 0, { distance: distance, object: object } );
  16220. this.add( object );
  16221. return this;
  16222. },
  16223. getCurrentLevel: function () {
  16224. return this._currentLevel;
  16225. },
  16226. getObjectForDistance: function ( distance ) {
  16227. const levels = this.levels;
  16228. if ( levels.length > 0 ) {
  16229. let i, l;
  16230. for ( i = 1, l = levels.length; i < l; i ++ ) {
  16231. if ( distance < levels[ i ].distance ) {
  16232. break;
  16233. }
  16234. }
  16235. return levels[ i - 1 ].object;
  16236. }
  16237. return null;
  16238. },
  16239. raycast: function ( raycaster, intersects ) {
  16240. const levels = this.levels;
  16241. if ( levels.length > 0 ) {
  16242. _v1$4.setFromMatrixPosition( this.matrixWorld );
  16243. const distance = raycaster.ray.origin.distanceTo( _v1$4 );
  16244. this.getObjectForDistance( distance ).raycast( raycaster, intersects );
  16245. }
  16246. },
  16247. update: function ( camera ) {
  16248. const levels = this.levels;
  16249. if ( levels.length > 1 ) {
  16250. _v1$4.setFromMatrixPosition( camera.matrixWorld );
  16251. _v2$2.setFromMatrixPosition( this.matrixWorld );
  16252. const distance = _v1$4.distanceTo( _v2$2 ) / camera.zoom;
  16253. levels[ 0 ].object.visible = true;
  16254. let i, l;
  16255. for ( i = 1, l = levels.length; i < l; i ++ ) {
  16256. if ( distance >= levels[ i ].distance ) {
  16257. levels[ i - 1 ].object.visible = false;
  16258. levels[ i ].object.visible = true;
  16259. } else {
  16260. break;
  16261. }
  16262. }
  16263. this._currentLevel = i - 1;
  16264. for ( ; i < l; i ++ ) {
  16265. levels[ i ].object.visible = false;
  16266. }
  16267. }
  16268. },
  16269. toJSON: function ( meta ) {
  16270. const data = Object3D.prototype.toJSON.call( this, meta );
  16271. if ( this.autoUpdate === false ) data.object.autoUpdate = false;
  16272. data.object.levels = [];
  16273. const levels = this.levels;
  16274. for ( let i = 0, l = levels.length; i < l; i ++ ) {
  16275. const level = levels[ i ];
  16276. data.object.levels.push( {
  16277. object: level.object.uuid,
  16278. distance: level.distance
  16279. } );
  16280. }
  16281. return data;
  16282. }
  16283. } );
  16284. const _basePosition = new Vector3();
  16285. const _skinIndex = new Vector4();
  16286. const _skinWeight = new Vector4();
  16287. const _vector$7 = new Vector3();
  16288. const _matrix$1 = new Matrix4();
  16289. function SkinnedMesh( geometry, material ) {
  16290. if ( geometry && geometry.isGeometry ) {
  16291. console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
  16292. }
  16293. Mesh.call( this, geometry, material );
  16294. this.type = 'SkinnedMesh';
  16295. this.bindMode = 'attached';
  16296. this.bindMatrix = new Matrix4();
  16297. this.bindMatrixInverse = new Matrix4();
  16298. }
  16299. SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
  16300. constructor: SkinnedMesh,
  16301. isSkinnedMesh: true,
  16302. copy: function ( source ) {
  16303. Mesh.prototype.copy.call( this, source );
  16304. this.bindMode = source.bindMode;
  16305. this.bindMatrix.copy( source.bindMatrix );
  16306. this.bindMatrixInverse.copy( source.bindMatrixInverse );
  16307. this.skeleton = source.skeleton;
  16308. return this;
  16309. },
  16310. bind: function ( skeleton, bindMatrix ) {
  16311. this.skeleton = skeleton;
  16312. if ( bindMatrix === undefined ) {
  16313. this.updateMatrixWorld( true );
  16314. this.skeleton.calculateInverses();
  16315. bindMatrix = this.matrixWorld;
  16316. }
  16317. this.bindMatrix.copy( bindMatrix );
  16318. this.bindMatrixInverse.copy( bindMatrix ).invert();
  16319. },
  16320. pose: function () {
  16321. this.skeleton.pose();
  16322. },
  16323. normalizeSkinWeights: function () {
  16324. const vector = new Vector4();
  16325. const skinWeight = this.geometry.attributes.skinWeight;
  16326. for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
  16327. vector.x = skinWeight.getX( i );
  16328. vector.y = skinWeight.getY( i );
  16329. vector.z = skinWeight.getZ( i );
  16330. vector.w = skinWeight.getW( i );
  16331. const scale = 1.0 / vector.manhattanLength();
  16332. if ( scale !== Infinity ) {
  16333. vector.multiplyScalar( scale );
  16334. } else {
  16335. vector.set( 1, 0, 0, 0 ); // do something reasonable
  16336. }
  16337. skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
  16338. }
  16339. },
  16340. updateMatrixWorld: function ( force ) {
  16341. Mesh.prototype.updateMatrixWorld.call( this, force );
  16342. if ( this.bindMode === 'attached' ) {
  16343. this.bindMatrixInverse.copy( this.matrixWorld ).invert();
  16344. } else if ( this.bindMode === 'detached' ) {
  16345. this.bindMatrixInverse.copy( this.bindMatrix ).invert();
  16346. } else {
  16347. console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
  16348. }
  16349. },
  16350. boneTransform: function ( index, target ) {
  16351. const skeleton = this.skeleton;
  16352. const geometry = this.geometry;
  16353. _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
  16354. _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
  16355. _basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix );
  16356. target.set( 0, 0, 0 );
  16357. for ( let i = 0; i < 4; i ++ ) {
  16358. const weight = _skinWeight.getComponent( i );
  16359. if ( weight !== 0 ) {
  16360. const boneIndex = _skinIndex.getComponent( i );
  16361. _matrix$1.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
  16362. target.addScaledVector( _vector$7.copy( _basePosition ).applyMatrix4( _matrix$1 ), weight );
  16363. }
  16364. }
  16365. return target.applyMatrix4( this.bindMatrixInverse );
  16366. }
  16367. } );
  16368. function Bone() {
  16369. Object3D.call( this );
  16370. this.type = 'Bone';
  16371. }
  16372. Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
  16373. constructor: Bone,
  16374. isBone: true
  16375. } );
  16376. const _offsetMatrix = new Matrix4();
  16377. const _identityMatrix = new Matrix4();
  16378. function Skeleton( bones = [], boneInverses = [] ) {
  16379. this.uuid = MathUtils.generateUUID();
  16380. this.bones = bones.slice( 0 );
  16381. this.boneInverses = boneInverses;
  16382. this.boneMatrices = null;
  16383. this.boneTexture = null;
  16384. this.boneTextureSize = 0;
  16385. this.frame = - 1;
  16386. this.init();
  16387. }
  16388. Object.assign( Skeleton.prototype, {
  16389. init: function () {
  16390. const bones = this.bones;
  16391. const boneInverses = this.boneInverses;
  16392. this.boneMatrices = new Float32Array( bones.length * 16 );
  16393. // calculate inverse bone matrices if necessary
  16394. if ( boneInverses.length === 0 ) {
  16395. this.calculateInverses();
  16396. } else {
  16397. // handle special case
  16398. if ( bones.length !== boneInverses.length ) {
  16399. console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
  16400. this.boneInverses = [];
  16401. for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
  16402. this.boneInverses.push( new Matrix4() );
  16403. }
  16404. }
  16405. }
  16406. },
  16407. calculateInverses: function () {
  16408. this.boneInverses.length = 0;
  16409. for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
  16410. const inverse = new Matrix4();
  16411. if ( this.bones[ i ] ) {
  16412. inverse.copy( this.bones[ i ].matrixWorld ).invert();
  16413. }
  16414. this.boneInverses.push( inverse );
  16415. }
  16416. },
  16417. pose: function () {
  16418. // recover the bind-time world matrices
  16419. for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
  16420. const bone = this.bones[ i ];
  16421. if ( bone ) {
  16422. bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
  16423. }
  16424. }
  16425. // compute the local matrices, positions, rotations and scales
  16426. for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
  16427. const bone = this.bones[ i ];
  16428. if ( bone ) {
  16429. if ( bone.parent && bone.parent.isBone ) {
  16430. bone.matrix.copy( bone.parent.matrixWorld ).invert();
  16431. bone.matrix.multiply( bone.matrixWorld );
  16432. } else {
  16433. bone.matrix.copy( bone.matrixWorld );
  16434. }
  16435. bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
  16436. }
  16437. }
  16438. },
  16439. update: function () {
  16440. const bones = this.bones;
  16441. const boneInverses = this.boneInverses;
  16442. const boneMatrices = this.boneMatrices;
  16443. const boneTexture = this.boneTexture;
  16444. // flatten bone matrices to array
  16445. for ( let i = 0, il = bones.length; i < il; i ++ ) {
  16446. // compute the offset between the current and the original transform
  16447. const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix;
  16448. _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
  16449. _offsetMatrix.toArray( boneMatrices, i * 16 );
  16450. }
  16451. if ( boneTexture !== null ) {
  16452. boneTexture.needsUpdate = true;
  16453. }
  16454. },
  16455. clone: function () {
  16456. return new Skeleton( this.bones, this.boneInverses );
  16457. },
  16458. getBoneByName: function ( name ) {
  16459. for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
  16460. const bone = this.bones[ i ];
  16461. if ( bone.name === name ) {
  16462. return bone;
  16463. }
  16464. }
  16465. return undefined;
  16466. },
  16467. dispose: function ( ) {
  16468. if ( this.boneTexture !== null ) {
  16469. this.boneTexture.dispose();
  16470. this.boneTexture = null;
  16471. }
  16472. },
  16473. fromJSON: function ( json, bones ) {
  16474. this.uuid = json.uuid;
  16475. for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
  16476. const uuid = json.bones[ i ];
  16477. let bone = bones[ uuid ];
  16478. if ( bone === undefined ) {
  16479. console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
  16480. bone = new Bone();
  16481. }
  16482. this.bones.push( bone );
  16483. this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
  16484. }
  16485. this.init();
  16486. return this;
  16487. },
  16488. toJSON: function () {
  16489. const data = {
  16490. metadata: {
  16491. version: 4.5,
  16492. type: 'Skeleton',
  16493. generator: 'Skeleton.toJSON'
  16494. },
  16495. bones: [],
  16496. boneInverses: []
  16497. };
  16498. data.uuid = this.uuid;
  16499. const bones = this.bones;
  16500. const boneInverses = this.boneInverses;
  16501. for ( let i = 0, l = bones.length; i < l; i ++ ) {
  16502. const bone = bones[ i ];
  16503. data.bones.push( bone.uuid );
  16504. const boneInverse = boneInverses[ i ];
  16505. data.boneInverses.push( boneInverse.toArray() );
  16506. }
  16507. return data;
  16508. }
  16509. } );
  16510. const _instanceLocalMatrix = new Matrix4();
  16511. const _instanceWorldMatrix = new Matrix4();
  16512. const _instanceIntersects = [];
  16513. const _mesh = new Mesh();
  16514. function InstancedMesh( geometry, material, count ) {
  16515. Mesh.call( this, geometry, material );
  16516. this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
  16517. this.instanceColor = null;
  16518. this.count = count;
  16519. this.frustumCulled = false;
  16520. }
  16521. InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
  16522. constructor: InstancedMesh,
  16523. isInstancedMesh: true,
  16524. copy: function ( source ) {
  16525. Mesh.prototype.copy.call( this, source );
  16526. this.instanceMatrix.copy( source.instanceMatrix );
  16527. this.count = source.count;
  16528. return this;
  16529. },
  16530. getColorAt: function ( index, color ) {
  16531. color.fromArray( this.instanceColor.array, index * 3 );
  16532. },
  16533. getMatrixAt: function ( index, matrix ) {
  16534. matrix.fromArray( this.instanceMatrix.array, index * 16 );
  16535. },
  16536. raycast: function ( raycaster, intersects ) {
  16537. const matrixWorld = this.matrixWorld;
  16538. const raycastTimes = this.count;
  16539. _mesh.geometry = this.geometry;
  16540. _mesh.material = this.material;
  16541. if ( _mesh.material === undefined ) return;
  16542. for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
  16543. // calculate the world matrix for each instance
  16544. this.getMatrixAt( instanceId, _instanceLocalMatrix );
  16545. _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
  16546. // the mesh represents this single instance
  16547. _mesh.matrixWorld = _instanceWorldMatrix;
  16548. _mesh.raycast( raycaster, _instanceIntersects );
  16549. // process the result of raycast
  16550. for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
  16551. const intersect = _instanceIntersects[ i ];
  16552. intersect.instanceId = instanceId;
  16553. intersect.object = this;
  16554. intersects.push( intersect );
  16555. }
  16556. _instanceIntersects.length = 0;
  16557. }
  16558. },
  16559. setColorAt: function ( index, color ) {
  16560. if ( this.instanceColor === null ) {
  16561. this.instanceColor = new BufferAttribute( new Float32Array( this.count * 3 ), 3 );
  16562. }
  16563. color.toArray( this.instanceColor.array, index * 3 );
  16564. },
  16565. setMatrixAt: function ( index, matrix ) {
  16566. matrix.toArray( this.instanceMatrix.array, index * 16 );
  16567. },
  16568. updateMorphTargets: function () {
  16569. },
  16570. dispose: function () {
  16571. this.dispatchEvent( { type: 'dispose' } );
  16572. }
  16573. } );
  16574. /**
  16575. * parameters = {
  16576. * color: <hex>,
  16577. * opacity: <float>,
  16578. *
  16579. * lineWidth: <float>,
  16580. * linecap: "round",
  16581. * linejoin: "round"
  16582. * }
  16583. */
  16584. function LineBasicMaterial( parameters ) {
  16585. Material.call( this );
  16586. this.type = 'LineBasicMaterial';
  16587. this.color = new Color( 0xffffff );
  16588. this.lineWidth = 1;
  16589. this.linecap = 'round';
  16590. this.linejoin = 'round';
  16591. this.morphTargets = false;
  16592. this.setValues( parameters );
  16593. }
  16594. LineBasicMaterial.prototype = Object.create( Material.prototype );
  16595. LineBasicMaterial.prototype.constructor = LineBasicMaterial;
  16596. LineBasicMaterial.prototype.isLineBasicMaterial = true;
  16597. LineBasicMaterial.prototype.copy = function ( source ) {
  16598. Material.prototype.copy.call( this, source );
  16599. this.color.copy( source.color );
  16600. this.lineWidth = source.lineWidth;
  16601. this.linecap = source.linecap;
  16602. this.linejoin = source.linejoin;
  16603. this.morphTargets = source.morphTargets;
  16604. return this;
  16605. };
  16606. const _start = new Vector3();
  16607. const _end = new Vector3();
  16608. const _inverseMatrix$1 = new Matrix4();
  16609. const _ray$1 = new Ray();
  16610. const _sphere$2 = new Sphere();
  16611. function Line( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
  16612. Object3D.call( this );
  16613. this.type = 'Line';
  16614. this.geometry = geometry;
  16615. this.material = material;
  16616. this.updateMorphTargets();
  16617. }
  16618. Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
  16619. constructor: Line,
  16620. isLine: true,
  16621. copy: function ( source ) {
  16622. Object3D.prototype.copy.call( this, source );
  16623. this.material = source.material;
  16624. this.geometry = source.geometry;
  16625. return this;
  16626. },
  16627. computeLineDistances: function () {
  16628. const geometry = this.geometry;
  16629. if ( geometry.isBufferGeometry ) {
  16630. // we assume non-indexed geometry
  16631. if ( geometry.index === null ) {
  16632. const positionAttribute = geometry.attributes.position;
  16633. const lineDistances = [ 0 ];
  16634. for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
  16635. _start.fromBufferAttribute( positionAttribute, i - 1 );
  16636. _end.fromBufferAttribute( positionAttribute, i );
  16637. lineDistances[ i ] = lineDistances[ i - 1 ];
  16638. lineDistances[ i ] += _start.distanceTo( _end );
  16639. }
  16640. geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
  16641. } else {
  16642. console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
  16643. }
  16644. } else if ( geometry.isGeometry ) {
  16645. const vertices = geometry.vertices;
  16646. const lineDistances = geometry.lineDistances;
  16647. lineDistances[ 0 ] = 0;
  16648. for ( let i = 1, l = vertices.length; i < l; i ++ ) {
  16649. lineDistances[ i ] = lineDistances[ i - 1 ];
  16650. lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] );
  16651. }
  16652. }
  16653. return this;
  16654. },
  16655. raycast: function ( raycaster, intersects ) {
  16656. const geometry = this.geometry;
  16657. const matrixWorld = this.matrixWorld;
  16658. const threshold = raycaster.params.Line.threshold;
  16659. // Checking boundingSphere distance to ray
  16660. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  16661. _sphere$2.copy( geometry.boundingSphere );
  16662. _sphere$2.applyMatrix4( matrixWorld );
  16663. _sphere$2.radius += threshold;
  16664. if ( raycaster.ray.intersectsSphere( _sphere$2 ) === false ) return;
  16665. //
  16666. _inverseMatrix$1.copy( matrixWorld ).invert();
  16667. _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
  16668. const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
  16669. const localThresholdSq = localThreshold * localThreshold;
  16670. const vStart = new Vector3();
  16671. const vEnd = new Vector3();
  16672. const interSegment = new Vector3();
  16673. const interRay = new Vector3();
  16674. const step = this.isLineSegments ? 2 : 1;
  16675. if ( geometry.isBufferGeometry ) {
  16676. const index = geometry.index;
  16677. const attributes = geometry.attributes;
  16678. const positionAttribute = attributes.position;
  16679. if ( index !== null ) {
  16680. const indices = index.array;
  16681. for ( let i = 0, l = indices.length - 1; i < l; i += step ) {
  16682. const a = indices[ i ];
  16683. const b = indices[ i + 1 ];
  16684. vStart.fromBufferAttribute( positionAttribute, a );
  16685. vEnd.fromBufferAttribute( positionAttribute, b );
  16686. const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
  16687. if ( distSq > localThresholdSq ) continue;
  16688. interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
  16689. const distance = raycaster.ray.origin.distanceTo( interRay );
  16690. if ( distance < raycaster.near || distance > raycaster.far ) continue;
  16691. intersects.push( {
  16692. distance: distance,
  16693. // What do we want? intersection point on the ray or on the segment??
  16694. // point: raycaster.ray.at( distance ),
  16695. point: interSegment.clone().applyMatrix4( this.matrixWorld ),
  16696. index: i,
  16697. face: null,
  16698. faceIndex: null,
  16699. object: this
  16700. } );
  16701. }
  16702. } else {
  16703. for ( let i = 0, l = positionAttribute.count - 1; i < l; i += step ) {
  16704. vStart.fromBufferAttribute( positionAttribute, i );
  16705. vEnd.fromBufferAttribute( positionAttribute, i + 1 );
  16706. const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
  16707. if ( distSq > localThresholdSq ) continue;
  16708. interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
  16709. const distance = raycaster.ray.origin.distanceTo( interRay );
  16710. if ( distance < raycaster.near || distance > raycaster.far ) continue;
  16711. intersects.push( {
  16712. distance: distance,
  16713. // What do we want? intersection point on the ray or on the segment??
  16714. // point: raycaster.ray.at( distance ),
  16715. point: interSegment.clone().applyMatrix4( this.matrixWorld ),
  16716. index: i,
  16717. face: null,
  16718. faceIndex: null,
  16719. object: this
  16720. } );
  16721. }
  16722. }
  16723. } else if ( geometry.isGeometry ) {
  16724. const vertices = geometry.vertices;
  16725. const nbVertices = vertices.length;
  16726. for ( let i = 0; i < nbVertices - 1; i += step ) {
  16727. const distSq = _ray$1.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
  16728. if ( distSq > localThresholdSq ) continue;
  16729. interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
  16730. const distance = raycaster.ray.origin.distanceTo( interRay );
  16731. if ( distance < raycaster.near || distance > raycaster.far ) continue;
  16732. intersects.push( {
  16733. distance: distance,
  16734. // What do we want? intersection point on the ray or on the segment??
  16735. // point: raycaster.ray.at( distance ),
  16736. point: interSegment.clone().applyMatrix4( this.matrixWorld ),
  16737. index: i,
  16738. face: null,
  16739. faceIndex: null,
  16740. object: this
  16741. } );
  16742. }
  16743. }
  16744. },
  16745. updateMorphTargets: function () {
  16746. const geometry = this.geometry;
  16747. if ( geometry.isBufferGeometry ) {
  16748. const morphAttributes = geometry.morphAttributes;
  16749. const keys = Object.keys( morphAttributes );
  16750. if ( keys.length > 0 ) {
  16751. const morphAttribute = morphAttributes[ keys[ 0 ] ];
  16752. if ( morphAttribute !== undefined ) {
  16753. this.morphTargetInfluences = [];
  16754. this.morphTargetDictionary = {};
  16755. for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
  16756. const name = morphAttribute[ m ].name || String( m );
  16757. this.morphTargetInfluences.push( 0 );
  16758. this.morphTargetDictionary[ name ] = m;
  16759. }
  16760. }
  16761. }
  16762. } else {
  16763. const morphTargets = geometry.morphTargets;
  16764. if ( morphTargets !== undefined && morphTargets.length > 0 ) {
  16765. console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
  16766. }
  16767. }
  16768. }
  16769. } );
  16770. const _start$1 = new Vector3();
  16771. const _end$1 = new Vector3();
  16772. function LineSegments( geometry, material ) {
  16773. Line.call( this, geometry, material );
  16774. this.type = 'LineSegments';
  16775. }
  16776. LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
  16777. constructor: LineSegments,
  16778. isLineSegments: true,
  16779. computeLineDistances: function () {
  16780. const geometry = this.geometry;
  16781. if ( geometry.isBufferGeometry ) {
  16782. // we assume non-indexed geometry
  16783. if ( geometry.index === null ) {
  16784. const positionAttribute = geometry.attributes.position;
  16785. const lineDistances = [];
  16786. for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
  16787. _start$1.fromBufferAttribute( positionAttribute, i );
  16788. _end$1.fromBufferAttribute( positionAttribute, i + 1 );
  16789. lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
  16790. lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 );
  16791. }
  16792. geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
  16793. } else {
  16794. console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
  16795. }
  16796. } else if ( geometry.isGeometry ) {
  16797. const vertices = geometry.vertices;
  16798. const lineDistances = geometry.lineDistances;
  16799. for ( let i = 0, l = vertices.length; i < l; i += 2 ) {
  16800. _start$1.copy( vertices[ i ] );
  16801. _end$1.copy( vertices[ i + 1 ] );
  16802. lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
  16803. lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 );
  16804. }
  16805. }
  16806. return this;
  16807. }
  16808. } );
  16809. function LineLoop( geometry, material ) {
  16810. Line.call( this, geometry, material );
  16811. this.type = 'LineLoop';
  16812. }
  16813. LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
  16814. constructor: LineLoop,
  16815. isLineLoop: true,
  16816. } );
  16817. /**
  16818. * parameters = {
  16819. * color: <hex>,
  16820. * opacity: <float>,
  16821. * map: new THREE.Texture( <Image> ),
  16822. * alphaMap: new THREE.Texture( <Image> ),
  16823. *
  16824. * size: <float>,
  16825. * sizeAttenuation: <bool>
  16826. *
  16827. * morphTargets: <bool>
  16828. * }
  16829. */
  16830. function PointsMaterial( parameters ) {
  16831. Material.call( this );
  16832. this.type = 'PointsMaterial';
  16833. this.color = new Color( 0xffffff );
  16834. this.map = null;
  16835. this.alphaMap = null;
  16836. this.size = 1;
  16837. this.sizeAttenuation = true;
  16838. this.morphTargets = false;
  16839. this.setValues( parameters );
  16840. }
  16841. PointsMaterial.prototype = Object.create( Material.prototype );
  16842. PointsMaterial.prototype.constructor = PointsMaterial;
  16843. PointsMaterial.prototype.isPointsMaterial = true;
  16844. PointsMaterial.prototype.copy = function ( source ) {
  16845. Material.prototype.copy.call( this, source );
  16846. this.color.copy( source.color );
  16847. this.map = source.map;
  16848. this.alphaMap = source.alphaMap;
  16849. this.size = source.size;
  16850. this.sizeAttenuation = source.sizeAttenuation;
  16851. this.morphTargets = source.morphTargets;
  16852. return this;
  16853. };
  16854. const _inverseMatrix$2 = new Matrix4();
  16855. const _ray$2 = new Ray();
  16856. const _sphere$3 = new Sphere();
  16857. const _position$1 = new Vector3();
  16858. function Points( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
  16859. Object3D.call( this );
  16860. this.type = 'Points';
  16861. this.geometry = geometry;
  16862. this.material = material;
  16863. this.updateMorphTargets();
  16864. }
  16865. Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
  16866. constructor: Points,
  16867. isPoints: true,
  16868. copy: function ( source ) {
  16869. Object3D.prototype.copy.call( this, source );
  16870. this.material = source.material;
  16871. this.geometry = source.geometry;
  16872. return this;
  16873. },
  16874. raycast: function ( raycaster, intersects ) {
  16875. const geometry = this.geometry;
  16876. const matrixWorld = this.matrixWorld;
  16877. const threshold = raycaster.params.Points.threshold;
  16878. // Checking boundingSphere distance to ray
  16879. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  16880. _sphere$3.copy( geometry.boundingSphere );
  16881. _sphere$3.applyMatrix4( matrixWorld );
  16882. _sphere$3.radius += threshold;
  16883. if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
  16884. //
  16885. _inverseMatrix$2.copy( matrixWorld ).invert();
  16886. _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
  16887. const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
  16888. const localThresholdSq = localThreshold * localThreshold;
  16889. if ( geometry.isBufferGeometry ) {
  16890. const index = geometry.index;
  16891. const attributes = geometry.attributes;
  16892. const positionAttribute = attributes.position;
  16893. if ( index !== null ) {
  16894. const indices = index.array;
  16895. for ( let i = 0, il = indices.length; i < il; i ++ ) {
  16896. const a = indices[ i ];
  16897. _position$1.fromBufferAttribute( positionAttribute, a );
  16898. testPoint( _position$1, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
  16899. }
  16900. } else {
  16901. for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
  16902. _position$1.fromBufferAttribute( positionAttribute, i );
  16903. testPoint( _position$1, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
  16904. }
  16905. }
  16906. } else {
  16907. const vertices = geometry.vertices;
  16908. for ( let i = 0, l = vertices.length; i < l; i ++ ) {
  16909. testPoint( vertices[ i ], i, localThresholdSq, matrixWorld, raycaster, intersects, this );
  16910. }
  16911. }
  16912. },
  16913. updateMorphTargets: function () {
  16914. const geometry = this.geometry;
  16915. if ( geometry.isBufferGeometry ) {
  16916. const morphAttributes = geometry.morphAttributes;
  16917. const keys = Object.keys( morphAttributes );
  16918. if ( keys.length > 0 ) {
  16919. const morphAttribute = morphAttributes[ keys[ 0 ] ];
  16920. if ( morphAttribute !== undefined ) {
  16921. this.morphTargetInfluences = [];
  16922. this.morphTargetDictionary = {};
  16923. for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
  16924. const name = morphAttribute[ m ].name || String( m );
  16925. this.morphTargetInfluences.push( 0 );
  16926. this.morphTargetDictionary[ name ] = m;
  16927. }
  16928. }
  16929. }
  16930. } else {
  16931. const morphTargets = geometry.morphTargets;
  16932. if ( morphTargets !== undefined && morphTargets.length > 0 ) {
  16933. console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
  16934. }
  16935. }
  16936. }
  16937. } );
  16938. function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
  16939. const rayPointDistanceSq = _ray$2.distanceSqToPoint( point );
  16940. if ( rayPointDistanceSq < localThresholdSq ) {
  16941. const intersectPoint = new Vector3();
  16942. _ray$2.closestPointToPoint( point, intersectPoint );
  16943. intersectPoint.applyMatrix4( matrixWorld );
  16944. const distance = raycaster.ray.origin.distanceTo( intersectPoint );
  16945. if ( distance < raycaster.near || distance > raycaster.far ) return;
  16946. intersects.push( {
  16947. distance: distance,
  16948. distanceToRay: Math.sqrt( rayPointDistanceSq ),
  16949. point: intersectPoint,
  16950. index: index,
  16951. face: null,
  16952. object: object
  16953. } );
  16954. }
  16955. }
  16956. function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
  16957. Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
  16958. this.format = format !== undefined ? format : RGBFormat;
  16959. this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
  16960. this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
  16961. this.generateMipmaps = false;
  16962. const scope = this;
  16963. function updateVideo() {
  16964. scope.needsUpdate = true;
  16965. video.requestVideoFrameCallback( updateVideo );
  16966. }
  16967. if ( 'requestVideoFrameCallback' in video ) {
  16968. video.requestVideoFrameCallback( updateVideo );
  16969. }
  16970. }
  16971. VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), {
  16972. constructor: VideoTexture,
  16973. clone: function () {
  16974. return new this.constructor( this.image ).copy( this );
  16975. },
  16976. isVideoTexture: true,
  16977. update: function () {
  16978. const video = this.image;
  16979. const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
  16980. if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
  16981. this.needsUpdate = true;
  16982. }
  16983. }
  16984. } );
  16985. function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
  16986. Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
  16987. this.image = { width: width, height: height };
  16988. this.mipmaps = mipmaps;
  16989. // no flipping for cube textures
  16990. // (also flipping doesn't work for compressed textures )
  16991. this.flipY = false;
  16992. // can't generate mipmaps for compressed textures
  16993. // mips must be embedded in DDS files
  16994. this.generateMipmaps = false;
  16995. }
  16996. CompressedTexture.prototype = Object.create( Texture.prototype );
  16997. CompressedTexture.prototype.constructor = CompressedTexture;
  16998. CompressedTexture.prototype.isCompressedTexture = true;
  16999. function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
  17000. Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
  17001. this.needsUpdate = true;
  17002. }
  17003. CanvasTexture.prototype = Object.create( Texture.prototype );
  17004. CanvasTexture.prototype.constructor = CanvasTexture;
  17005. CanvasTexture.prototype.isCanvasTexture = true;
  17006. function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
  17007. format = format !== undefined ? format : DepthFormat;
  17008. if ( format !== DepthFormat && format !== DepthStencilFormat ) {
  17009. throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
  17010. }
  17011. if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
  17012. if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type$1;
  17013. Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
  17014. this.image = { width: width, height: height };
  17015. this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
  17016. this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
  17017. this.flipY = false;
  17018. this.generateMipmaps = false;
  17019. }
  17020. DepthTexture.prototype = Object.create( Texture.prototype );
  17021. DepthTexture.prototype.constructor = DepthTexture;
  17022. DepthTexture.prototype.isDepthTexture = true;
  17023. let _geometryId = 0; // Geometry uses even numbers as Id
  17024. const _m1$3 = new Matrix4();
  17025. const _obj$1 = new Object3D();
  17026. const _offset$1 = new Vector3();
  17027. function Geometry() {
  17028. Object.defineProperty( this, 'id', { value: _geometryId += 2 } );
  17029. this.uuid = MathUtils.generateUUID();
  17030. this.name = '';
  17031. this.type = 'Geometry';
  17032. this.vertices = [];
  17033. this.colors = [];
  17034. this.faces = [];
  17035. this.faceVertexUvs = [[]];
  17036. this.morphTargets = [];
  17037. this.morphNormals = [];
  17038. this.skinWeights = [];
  17039. this.skinIndices = [];
  17040. this.lineDistances = [];
  17041. this.boundingBox = null;
  17042. this.boundingSphere = null;
  17043. // update flags
  17044. this.elementsNeedUpdate = false;
  17045. this.verticesNeedUpdate = false;
  17046. this.uvsNeedUpdate = false;
  17047. this.normalsNeedUpdate = false;
  17048. this.colorsNeedUpdate = false;
  17049. this.lineDistancesNeedUpdate = false;
  17050. this.groupsNeedUpdate = false;
  17051. }
  17052. Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  17053. constructor: Geometry,
  17054. isGeometry: true,
  17055. applyMatrix4: function ( matrix ) {
  17056. const normalMatrix = new Matrix3().getNormalMatrix( matrix );
  17057. for ( let i = 0, il = this.vertices.length; i < il; i ++ ) {
  17058. const vertex = this.vertices[ i ];
  17059. vertex.applyMatrix4( matrix );
  17060. }
  17061. for ( let i = 0, il = this.faces.length; i < il; i ++ ) {
  17062. const face = this.faces[ i ];
  17063. face.normal.applyMatrix3( normalMatrix ).normalize();
  17064. for ( let j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
  17065. face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
  17066. }
  17067. }
  17068. if ( this.boundingBox !== null ) {
  17069. this.computeBoundingBox();
  17070. }
  17071. if ( this.boundingSphere !== null ) {
  17072. this.computeBoundingSphere();
  17073. }
  17074. this.verticesNeedUpdate = true;
  17075. this.normalsNeedUpdate = true;
  17076. return this;
  17077. },
  17078. rotateX: function ( angle ) {
  17079. // rotate geometry around world x-axis
  17080. _m1$3.makeRotationX( angle );
  17081. this.applyMatrix4( _m1$3 );
  17082. return this;
  17083. },
  17084. rotateY: function ( angle ) {
  17085. // rotate geometry around world y-axis
  17086. _m1$3.makeRotationY( angle );
  17087. this.applyMatrix4( _m1$3 );
  17088. return this;
  17089. },
  17090. rotateZ: function ( angle ) {
  17091. // rotate geometry around world z-axis
  17092. _m1$3.makeRotationZ( angle );
  17093. this.applyMatrix4( _m1$3 );
  17094. return this;
  17095. },
  17096. translate: function ( x, y, z ) {
  17097. // translate geometry
  17098. _m1$3.makeTranslation( x, y, z );
  17099. this.applyMatrix4( _m1$3 );
  17100. return this;
  17101. },
  17102. scale: function ( x, y, z ) {
  17103. // scale geometry
  17104. _m1$3.makeScale( x, y, z );
  17105. this.applyMatrix4( _m1$3 );
  17106. return this;
  17107. },
  17108. lookAt: function ( vector ) {
  17109. _obj$1.lookAt( vector );
  17110. _obj$1.updateMatrix();
  17111. this.applyMatrix4( _obj$1.matrix );
  17112. return this;
  17113. },
  17114. fromBufferGeometry: function ( geometry ) {
  17115. const scope = this;
  17116. const index = geometry.index !== null ? geometry.index : undefined;
  17117. const attributes = geometry.attributes;
  17118. if ( attributes.position === undefined ) {
  17119. console.error( 'THREE.Geometry.fromBufferGeometry(): Position attribute required for conversion.' );
  17120. return this;
  17121. }
  17122. const position = attributes.position;
  17123. const normal = attributes.normal;
  17124. const color = attributes.color;
  17125. const uv = attributes.uv;
  17126. const uv2 = attributes.uv2;
  17127. if ( uv2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
  17128. for ( let i = 0; i < position.count; i ++ ) {
  17129. scope.vertices.push( new Vector3().fromBufferAttribute( position, i ) );
  17130. if ( color !== undefined ) {
  17131. scope.colors.push( new Color().fromBufferAttribute( color, i ) );
  17132. }
  17133. }
  17134. function addFace( a, b, c, materialIndex ) {
  17135. const vertexColors = ( color === undefined ) ? [] : [
  17136. scope.colors[ a ].clone(),
  17137. scope.colors[ b ].clone(),
  17138. scope.colors[ c ].clone()
  17139. ];
  17140. const vertexNormals = ( normal === undefined ) ? [] : [
  17141. new Vector3().fromBufferAttribute( normal, a ),
  17142. new Vector3().fromBufferAttribute( normal, b ),
  17143. new Vector3().fromBufferAttribute( normal, c )
  17144. ];
  17145. const face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );
  17146. scope.faces.push( face );
  17147. if ( uv !== undefined ) {
  17148. scope.faceVertexUvs[ 0 ].push( [
  17149. new Vector2$1().fromBufferAttribute( uv, a ),
  17150. new Vector2$1().fromBufferAttribute( uv, b ),
  17151. new Vector2$1().fromBufferAttribute( uv, c )
  17152. ] );
  17153. }
  17154. if ( uv2 !== undefined ) {
  17155. scope.faceVertexUvs[ 1 ].push( [
  17156. new Vector2$1().fromBufferAttribute( uv2, a ),
  17157. new Vector2$1().fromBufferAttribute( uv2, b ),
  17158. new Vector2$1().fromBufferAttribute( uv2, c )
  17159. ] );
  17160. }
  17161. }
  17162. const groups = geometry.groups;
  17163. if ( groups.length > 0 ) {
  17164. for ( let i = 0; i < groups.length; i ++ ) {
  17165. const group = groups[ i ];
  17166. const start = group.start;
  17167. const count = group.count;
  17168. for ( let j = start, jl = start + count; j < jl; j += 3 ) {
  17169. if ( index !== undefined ) {
  17170. addFace( index.getX( j ), index.getX( j + 1 ), index.getX( j + 2 ), group.materialIndex );
  17171. } else {
  17172. addFace( j, j + 1, j + 2, group.materialIndex );
  17173. }
  17174. }
  17175. }
  17176. } else {
  17177. if ( index !== undefined ) {
  17178. for ( let i = 0; i < index.count; i += 3 ) {
  17179. addFace( index.getX( i ), index.getX( i + 1 ), index.getX( i + 2 ) );
  17180. }
  17181. } else {
  17182. for ( let i = 0; i < position.count; i += 3 ) {
  17183. addFace( i, i + 1, i + 2 );
  17184. }
  17185. }
  17186. }
  17187. this.computeFaceNormals();
  17188. if ( geometry.boundingBox !== null ) {
  17189. this.boundingBox = geometry.boundingBox.clone();
  17190. }
  17191. if ( geometry.boundingSphere !== null ) {
  17192. this.boundingSphere = geometry.boundingSphere.clone();
  17193. }
  17194. return this;
  17195. },
  17196. center: function () {
  17197. this.computeBoundingBox();
  17198. this.boundingBox.getCenter( _offset$1 ).negate();
  17199. this.translate( _offset$1.x, _offset$1.y, _offset$1.z );
  17200. return this;
  17201. },
  17202. normalize: function () {
  17203. this.computeBoundingSphere();
  17204. const center = this.boundingSphere.center;
  17205. const radius = this.boundingSphere.radius;
  17206. const s = radius === 0 ? 1 : 1.0 / radius;
  17207. const matrix = new Matrix4();
  17208. matrix.set(
  17209. s, 0, 0, - s * center.x,
  17210. 0, s, 0, - s * center.y,
  17211. 0, 0, s, - s * center.z,
  17212. 0, 0, 0, 1
  17213. );
  17214. this.applyMatrix4( matrix );
  17215. return this;
  17216. },
  17217. computeFaceNormals: function () {
  17218. const cb = new Vector3(), ab = new Vector3();
  17219. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17220. const face = this.faces[ f ];
  17221. const vA = this.vertices[ face.a ];
  17222. const vB = this.vertices[ face.b ];
  17223. const vC = this.vertices[ face.c ];
  17224. cb.subVectors( vC, vB );
  17225. ab.subVectors( vA, vB );
  17226. cb.cross( ab );
  17227. cb.normalize();
  17228. face.normal.copy( cb );
  17229. }
  17230. },
  17231. computeVertexNormals: function ( areaWeighted = true ) {
  17232. const vertices = new Array( this.vertices.length );
  17233. for ( let v = 0, vl = this.vertices.length; v < vl; v ++ ) {
  17234. vertices[ v ] = new Vector3();
  17235. }
  17236. if ( areaWeighted ) {
  17237. // vertex normals weighted by triangle areas
  17238. // http://www.iquilezles.org/www/articles/normals/normals.htm
  17239. const cb = new Vector3(), ab = new Vector3();
  17240. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17241. const face = this.faces[ f ];
  17242. const vA = this.vertices[ face.a ];
  17243. const vB = this.vertices[ face.b ];
  17244. const vC = this.vertices[ face.c ];
  17245. cb.subVectors( vC, vB );
  17246. ab.subVectors( vA, vB );
  17247. cb.cross( ab );
  17248. vertices[ face.a ].add( cb );
  17249. vertices[ face.b ].add( cb );
  17250. vertices[ face.c ].add( cb );
  17251. }
  17252. } else {
  17253. this.computeFaceNormals();
  17254. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17255. const face = this.faces[ f ];
  17256. vertices[ face.a ].add( face.normal );
  17257. vertices[ face.b ].add( face.normal );
  17258. vertices[ face.c ].add( face.normal );
  17259. }
  17260. }
  17261. for ( let v = 0, vl = this.vertices.length; v < vl; v ++ ) {
  17262. vertices[ v ].normalize();
  17263. }
  17264. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17265. const face = this.faces[ f ];
  17266. const vertexNormals = face.vertexNormals;
  17267. if ( vertexNormals.length === 3 ) {
  17268. vertexNormals[ 0 ].copy( vertices[ face.a ] );
  17269. vertexNormals[ 1 ].copy( vertices[ face.b ] );
  17270. vertexNormals[ 2 ].copy( vertices[ face.c ] );
  17271. } else {
  17272. vertexNormals[ 0 ] = vertices[ face.a ].clone();
  17273. vertexNormals[ 1 ] = vertices[ face.b ].clone();
  17274. vertexNormals[ 2 ] = vertices[ face.c ].clone();
  17275. }
  17276. }
  17277. if ( this.faces.length > 0 ) {
  17278. this.normalsNeedUpdate = true;
  17279. }
  17280. },
  17281. computeFlatVertexNormals: function () {
  17282. this.computeFaceNormals();
  17283. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17284. const face = this.faces[ f ];
  17285. const vertexNormals = face.vertexNormals;
  17286. if ( vertexNormals.length === 3 ) {
  17287. vertexNormals[ 0 ].copy( face.normal );
  17288. vertexNormals[ 1 ].copy( face.normal );
  17289. vertexNormals[ 2 ].copy( face.normal );
  17290. } else {
  17291. vertexNormals[ 0 ] = face.normal.clone();
  17292. vertexNormals[ 1 ] = face.normal.clone();
  17293. vertexNormals[ 2 ] = face.normal.clone();
  17294. }
  17295. }
  17296. if ( this.faces.length > 0 ) {
  17297. this.normalsNeedUpdate = true;
  17298. }
  17299. },
  17300. computeMorphNormals: function () {
  17301. // save original normals
  17302. // - create temp variables on first access
  17303. // otherwise just copy (for faster repeated calls)
  17304. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17305. const face = this.faces[ f ];
  17306. if ( ! face.__originalFaceNormal ) {
  17307. face.__originalFaceNormal = face.normal.clone();
  17308. } else {
  17309. face.__originalFaceNormal.copy( face.normal );
  17310. }
  17311. if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
  17312. for ( let i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
  17313. if ( ! face.__originalVertexNormals[ i ] ) {
  17314. face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
  17315. } else {
  17316. face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
  17317. }
  17318. }
  17319. }
  17320. // use temp geometry to compute face and vertex normals for each morph
  17321. const tmpGeo = new Geometry();
  17322. tmpGeo.faces = this.faces;
  17323. for ( let i = 0, il = this.morphTargets.length; i < il; i ++ ) {
  17324. // create on first access
  17325. if ( ! this.morphNormals[ i ] ) {
  17326. this.morphNormals[ i ] = {};
  17327. this.morphNormals[ i ].faceNormals = [];
  17328. this.morphNormals[ i ].vertexNormals = [];
  17329. const dstNormalsFace = this.morphNormals[ i ].faceNormals;
  17330. const dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
  17331. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17332. const faceNormal = new Vector3();
  17333. const vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
  17334. dstNormalsFace.push( faceNormal );
  17335. dstNormalsVertex.push( vertexNormals );
  17336. }
  17337. }
  17338. const morphNormals = this.morphNormals[ i ];
  17339. // set vertices to morph target
  17340. tmpGeo.vertices = this.morphTargets[ i ].vertices;
  17341. // compute morph normals
  17342. tmpGeo.computeFaceNormals();
  17343. tmpGeo.computeVertexNormals();
  17344. // store morph normals
  17345. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17346. const face = this.faces[ f ];
  17347. const faceNormal = morphNormals.faceNormals[ f ];
  17348. const vertexNormals = morphNormals.vertexNormals[ f ];
  17349. faceNormal.copy( face.normal );
  17350. vertexNormals.a.copy( face.vertexNormals[ 0 ] );
  17351. vertexNormals.b.copy( face.vertexNormals[ 1 ] );
  17352. vertexNormals.c.copy( face.vertexNormals[ 2 ] );
  17353. }
  17354. }
  17355. // restore original normals
  17356. for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
  17357. const face = this.faces[ f ];
  17358. face.normal = face.__originalFaceNormal;
  17359. face.vertexNormals = face.__originalVertexNormals;
  17360. }
  17361. },
  17362. computeBoundingBox: function () {
  17363. if ( this.boundingBox === null ) {
  17364. this.boundingBox = new Box3();
  17365. }
  17366. this.boundingBox.setFromPoints( this.vertices );
  17367. },
  17368. computeBoundingSphere: function () {
  17369. if ( this.boundingSphere === null ) {
  17370. this.boundingSphere = new Sphere();
  17371. }
  17372. this.boundingSphere.setFromPoints( this.vertices );
  17373. },
  17374. merge: function ( geometry, matrix, materialIndexOffset = 0 ) {
  17375. if ( ! ( geometry && geometry.isGeometry ) ) {
  17376. console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
  17377. return;
  17378. }
  17379. let normalMatrix;
  17380. const vertexOffset = this.vertices.length,
  17381. vertices1 = this.vertices,
  17382. vertices2 = geometry.vertices,
  17383. faces1 = this.faces,
  17384. faces2 = geometry.faces,
  17385. colors1 = this.colors,
  17386. colors2 = geometry.colors;
  17387. if ( matrix !== undefined ) {
  17388. normalMatrix = new Matrix3().getNormalMatrix( matrix );
  17389. }
  17390. // vertices
  17391. for ( let i = 0, il = vertices2.length; i < il; i ++ ) {
  17392. const vertex = vertices2[ i ];
  17393. const vertexCopy = vertex.clone();
  17394. if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
  17395. vertices1.push( vertexCopy );
  17396. }
  17397. // colors
  17398. for ( let i = 0, il = colors2.length; i < il; i ++ ) {
  17399. colors1.push( colors2[ i ].clone() );
  17400. }
  17401. // faces
  17402. for ( let i = 0, il = faces2.length; i < il; i ++ ) {
  17403. const face = faces2[ i ];
  17404. let normal, color;
  17405. const faceVertexNormals = face.vertexNormals,
  17406. faceVertexColors = face.vertexColors;
  17407. const faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
  17408. faceCopy.normal.copy( face.normal );
  17409. if ( normalMatrix !== undefined ) {
  17410. faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
  17411. }
  17412. for ( let j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
  17413. normal = faceVertexNormals[ j ].clone();
  17414. if ( normalMatrix !== undefined ) {
  17415. normal.applyMatrix3( normalMatrix ).normalize();
  17416. }
  17417. faceCopy.vertexNormals.push( normal );
  17418. }
  17419. faceCopy.color.copy( face.color );
  17420. for ( let j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
  17421. color = faceVertexColors[ j ];
  17422. faceCopy.vertexColors.push( color.clone() );
  17423. }
  17424. faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
  17425. faces1.push( faceCopy );
  17426. }
  17427. // uvs
  17428. for ( let i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
  17429. const faceVertexUvs2 = geometry.faceVertexUvs[ i ];
  17430. if ( this.faceVertexUvs[ i ] === undefined ) this.faceVertexUvs[ i ] = [];
  17431. for ( let j = 0, jl = faceVertexUvs2.length; j < jl; j ++ ) {
  17432. const uvs2 = faceVertexUvs2[ j ], uvsCopy = [];
  17433. for ( let k = 0, kl = uvs2.length; k < kl; k ++ ) {
  17434. uvsCopy.push( uvs2[ k ].clone() );
  17435. }
  17436. this.faceVertexUvs[ i ].push( uvsCopy );
  17437. }
  17438. }
  17439. },
  17440. mergeMesh: function ( mesh ) {
  17441. if ( ! ( mesh && mesh.isMesh ) ) {
  17442. console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
  17443. return;
  17444. }
  17445. if ( mesh.matrixAutoUpdate ) mesh.updateMatrix();
  17446. this.merge( mesh.geometry, mesh.matrix );
  17447. },
  17448. /*
  17449. * Checks for duplicate vertices with hashmap.
  17450. * Duplicated vertices are removed
  17451. * and faces' vertices are updated.
  17452. */
  17453. mergeVertices: function ( precisionPoints = 4 ) {
  17454. const verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
  17455. const unique = [], changes = [];
  17456. const precision = Math.pow( 10, precisionPoints );
  17457. for ( let i = 0, il = this.vertices.length; i < il; i ++ ) {
  17458. const v = this.vertices[ i ];
  17459. const key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
  17460. if ( verticesMap[ key ] === undefined ) {
  17461. verticesMap[ key ] = i;
  17462. unique.push( this.vertices[ i ] );
  17463. changes[ i ] = unique.length - 1;
  17464. } else {
  17465. //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
  17466. changes[ i ] = changes[ verticesMap[ key ] ];
  17467. }
  17468. }
  17469. // if faces are completely degenerate after merging vertices, we
  17470. // have to remove them from the geometry.
  17471. const faceIndicesToRemove = [];
  17472. for ( let i = 0, il = this.faces.length; i < il; i ++ ) {
  17473. const face = this.faces[ i ];
  17474. face.a = changes[ face.a ];
  17475. face.b = changes[ face.b ];
  17476. face.c = changes[ face.c ];
  17477. const indices = [ face.a, face.b, face.c ];
  17478. // if any duplicate vertices are found in a Face3
  17479. // we have to remove the face as nothing can be saved
  17480. for ( let n = 0; n < 3; n ++ ) {
  17481. if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {
  17482. faceIndicesToRemove.push( i );
  17483. break;
  17484. }
  17485. }
  17486. }
  17487. for ( let i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
  17488. const idx = faceIndicesToRemove[ i ];
  17489. this.faces.splice( idx, 1 );
  17490. for ( let j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
  17491. this.faceVertexUvs[ j ].splice( idx, 1 );
  17492. }
  17493. }
  17494. // Use unique set of vertices
  17495. const diff = this.vertices.length - unique.length;
  17496. this.vertices = unique;
  17497. return diff;
  17498. },
  17499. setFromPoints: function ( points ) {
  17500. this.vertices = [];
  17501. for ( let i = 0, l = points.length; i < l; i ++ ) {
  17502. const point = points[ i ];
  17503. this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
  17504. }
  17505. return this;
  17506. },
  17507. sortFacesByMaterialIndex: function () {
  17508. const faces = this.faces;
  17509. const length = faces.length;
  17510. // tag faces
  17511. for ( let i = 0; i < length; i ++ ) {
  17512. faces[ i ]._id = i;
  17513. }
  17514. // sort faces
  17515. function materialIndexSort( a, b ) {
  17516. return a.materialIndex - b.materialIndex;
  17517. }
  17518. faces.sort( materialIndexSort );
  17519. // sort uvs
  17520. const uvs1 = this.faceVertexUvs[ 0 ];
  17521. const uvs2 = this.faceVertexUvs[ 1 ];
  17522. let newUvs1, newUvs2;
  17523. if ( uvs1 && uvs1.length === length ) newUvs1 = [];
  17524. if ( uvs2 && uvs2.length === length ) newUvs2 = [];
  17525. for ( let i = 0; i < length; i ++ ) {
  17526. const id = faces[ i ]._id;
  17527. if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
  17528. if ( newUvs2 ) newUvs2.push( uvs2[ id ] );
  17529. }
  17530. if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
  17531. if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;
  17532. },
  17533. toJSON: function () {
  17534. const data = {
  17535. metadata: {
  17536. version: 4.5,
  17537. type: 'Geometry',
  17538. generator: 'Geometry.toJSON'
  17539. }
  17540. };
  17541. // standard Geometry serialization
  17542. data.uuid = this.uuid;
  17543. data.type = this.type;
  17544. if ( this.name !== '' ) data.name = this.name;
  17545. if ( this.parameters !== undefined ) {
  17546. const parameters = this.parameters;
  17547. for ( const key in parameters ) {
  17548. if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
  17549. }
  17550. return data;
  17551. }
  17552. const vertices = [];
  17553. for ( let i = 0; i < this.vertices.length; i ++ ) {
  17554. const vertex = this.vertices[ i ];
  17555. vertices.push( vertex.x, vertex.y, vertex.z );
  17556. }
  17557. const faces = [];
  17558. const normals = [];
  17559. const normalsHash = {};
  17560. const colors = [];
  17561. const colorsHash = {};
  17562. const uvs = [];
  17563. const uvsHash = {};
  17564. for ( let i = 0; i < this.faces.length; i ++ ) {
  17565. const face = this.faces[ i ];
  17566. const hasMaterial = true;
  17567. const hasFaceUv = false; // deprecated
  17568. const hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
  17569. const hasFaceNormal = face.normal.length() > 0;
  17570. const hasFaceVertexNormal = face.vertexNormals.length > 0;
  17571. const hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
  17572. const hasFaceVertexColor = face.vertexColors.length > 0;
  17573. let faceType = 0;
  17574. faceType = setBit( faceType, 0, 0 ); // isQuad
  17575. faceType = setBit( faceType, 1, hasMaterial );
  17576. faceType = setBit( faceType, 2, hasFaceUv );
  17577. faceType = setBit( faceType, 3, hasFaceVertexUv );
  17578. faceType = setBit( faceType, 4, hasFaceNormal );
  17579. faceType = setBit( faceType, 5, hasFaceVertexNormal );
  17580. faceType = setBit( faceType, 6, hasFaceColor );
  17581. faceType = setBit( faceType, 7, hasFaceVertexColor );
  17582. faces.push( faceType );
  17583. faces.push( face.a, face.b, face.c );
  17584. faces.push( face.materialIndex );
  17585. if ( hasFaceVertexUv ) {
  17586. const faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
  17587. faces.push(
  17588. getUvIndex( faceVertexUvs[ 0 ] ),
  17589. getUvIndex( faceVertexUvs[ 1 ] ),
  17590. getUvIndex( faceVertexUvs[ 2 ] )
  17591. );
  17592. }
  17593. if ( hasFaceNormal ) {
  17594. faces.push( getNormalIndex( face.normal ) );
  17595. }
  17596. if ( hasFaceVertexNormal ) {
  17597. const vertexNormals = face.vertexNormals;
  17598. faces.push(
  17599. getNormalIndex( vertexNormals[ 0 ] ),
  17600. getNormalIndex( vertexNormals[ 1 ] ),
  17601. getNormalIndex( vertexNormals[ 2 ] )
  17602. );
  17603. }
  17604. if ( hasFaceColor ) {
  17605. faces.push( getColorIndex( face.color ) );
  17606. }
  17607. if ( hasFaceVertexColor ) {
  17608. const vertexColors = face.vertexColors;
  17609. faces.push(
  17610. getColorIndex( vertexColors[ 0 ] ),
  17611. getColorIndex( vertexColors[ 1 ] ),
  17612. getColorIndex( vertexColors[ 2 ] )
  17613. );
  17614. }
  17615. }
  17616. function setBit( value, position, enabled ) {
  17617. return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );
  17618. }
  17619. function getNormalIndex( normal ) {
  17620. const hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
  17621. if ( normalsHash[ hash ] !== undefined ) {
  17622. return normalsHash[ hash ];
  17623. }
  17624. normalsHash[ hash ] = normals.length / 3;
  17625. normals.push( normal.x, normal.y, normal.z );
  17626. return normalsHash[ hash ];
  17627. }
  17628. function getColorIndex( color ) {
  17629. const hash = color.r.toString() + color.g.toString() + color.b.toString();
  17630. if ( colorsHash[ hash ] !== undefined ) {
  17631. return colorsHash[ hash ];
  17632. }
  17633. colorsHash[ hash ] = colors.length;
  17634. colors.push( color.getHex() );
  17635. return colorsHash[ hash ];
  17636. }
  17637. function getUvIndex( uv ) {
  17638. const hash = uv.x.toString() + uv.y.toString();
  17639. if ( uvsHash[ hash ] !== undefined ) {
  17640. return uvsHash[ hash ];
  17641. }
  17642. uvsHash[ hash ] = uvs.length / 2;
  17643. uvs.push( uv.x, uv.y );
  17644. return uvsHash[ hash ];
  17645. }
  17646. data.data = {};
  17647. data.data.vertices = vertices;
  17648. data.data.normals = normals;
  17649. if ( colors.length > 0 ) data.data.colors = colors;
  17650. if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
  17651. data.data.faces = faces;
  17652. return data;
  17653. },
  17654. clone: function () {
  17655. /*
  17656. // Handle primitives
  17657. const parameters = this.parameters;
  17658. if ( parameters !== undefined ) {
  17659. const values = [];
  17660. for ( const key in parameters ) {
  17661. values.push( parameters[ key ] );
  17662. }
  17663. const geometry = Object.create( this.constructor.prototype );
  17664. this.constructor.apply( geometry, values );
  17665. return geometry;
  17666. }
  17667. return new this.constructor().copy( this );
  17668. */
  17669. return new Geometry().copy( this );
  17670. },
  17671. copy: function ( source ) {
  17672. // reset
  17673. this.vertices = [];
  17674. this.colors = [];
  17675. this.faces = [];
  17676. this.faceVertexUvs = [[]];
  17677. this.morphTargets = [];
  17678. this.morphNormals = [];
  17679. this.skinWeights = [];
  17680. this.skinIndices = [];
  17681. this.lineDistances = [];
  17682. this.boundingBox = null;
  17683. this.boundingSphere = null;
  17684. // name
  17685. this.name = source.name;
  17686. // vertices
  17687. const vertices = source.vertices;
  17688. for ( let i = 0, il = vertices.length; i < il; i ++ ) {
  17689. this.vertices.push( vertices[ i ].clone() );
  17690. }
  17691. // colors
  17692. const colors = source.colors;
  17693. for ( let i = 0, il = colors.length; i < il; i ++ ) {
  17694. this.colors.push( colors[ i ].clone() );
  17695. }
  17696. // faces
  17697. const faces = source.faces;
  17698. for ( let i = 0, il = faces.length; i < il; i ++ ) {
  17699. this.faces.push( faces[ i ].clone() );
  17700. }
  17701. // face vertex uvs
  17702. for ( let i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {
  17703. const faceVertexUvs = source.faceVertexUvs[ i ];
  17704. if ( this.faceVertexUvs[ i ] === undefined ) {
  17705. this.faceVertexUvs[ i ] = [];
  17706. }
  17707. for ( let j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {
  17708. const uvs = faceVertexUvs[ j ], uvsCopy = [];
  17709. for ( let k = 0, kl = uvs.length; k < kl; k ++ ) {
  17710. const uv = uvs[ k ];
  17711. uvsCopy.push( uv.clone() );
  17712. }
  17713. this.faceVertexUvs[ i ].push( uvsCopy );
  17714. }
  17715. }
  17716. // morph targets
  17717. const morphTargets = source.morphTargets;
  17718. for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
  17719. const morphTarget = {};
  17720. morphTarget.name = morphTargets[ i ].name;
  17721. // vertices
  17722. if ( morphTargets[ i ].vertices !== undefined ) {
  17723. morphTarget.vertices = [];
  17724. for ( let j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {
  17725. morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );
  17726. }
  17727. }
  17728. // normals
  17729. if ( morphTargets[ i ].normals !== undefined ) {
  17730. morphTarget.normals = [];
  17731. for ( let j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {
  17732. morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );
  17733. }
  17734. }
  17735. this.morphTargets.push( morphTarget );
  17736. }
  17737. // morph normals
  17738. const morphNormals = source.morphNormals;
  17739. for ( let i = 0, il = morphNormals.length; i < il; i ++ ) {
  17740. const morphNormal = {};
  17741. // vertex normals
  17742. if ( morphNormals[ i ].vertexNormals !== undefined ) {
  17743. morphNormal.vertexNormals = [];
  17744. for ( let j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {
  17745. const srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
  17746. const destVertexNormal = {};
  17747. destVertexNormal.a = srcVertexNormal.a.clone();
  17748. destVertexNormal.b = srcVertexNormal.b.clone();
  17749. destVertexNormal.c = srcVertexNormal.c.clone();
  17750. morphNormal.vertexNormals.push( destVertexNormal );
  17751. }
  17752. }
  17753. // face normals
  17754. if ( morphNormals[ i ].faceNormals !== undefined ) {
  17755. morphNormal.faceNormals = [];
  17756. for ( let j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {
  17757. morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );
  17758. }
  17759. }
  17760. this.morphNormals.push( morphNormal );
  17761. }
  17762. // skin weights
  17763. const skinWeights = source.skinWeights;
  17764. for ( let i = 0, il = skinWeights.length; i < il; i ++ ) {
  17765. this.skinWeights.push( skinWeights[ i ].clone() );
  17766. }
  17767. // skin indices
  17768. const skinIndices = source.skinIndices;
  17769. for ( let i = 0, il = skinIndices.length; i < il; i ++ ) {
  17770. this.skinIndices.push( skinIndices[ i ].clone() );
  17771. }
  17772. // line distances
  17773. const lineDistances = source.lineDistances;
  17774. for ( let i = 0, il = lineDistances.length; i < il; i ++ ) {
  17775. this.lineDistances.push( lineDistances[ i ] );
  17776. }
  17777. // bounding box
  17778. const boundingBox = source.boundingBox;
  17779. if ( boundingBox !== null ) {
  17780. this.boundingBox = boundingBox.clone();
  17781. }
  17782. // bounding sphere
  17783. const boundingSphere = source.boundingSphere;
  17784. if ( boundingSphere !== null ) {
  17785. this.boundingSphere = boundingSphere.clone();
  17786. }
  17787. // update flags
  17788. this.elementsNeedUpdate = source.elementsNeedUpdate;
  17789. this.verticesNeedUpdate = source.verticesNeedUpdate;
  17790. this.uvsNeedUpdate = source.uvsNeedUpdate;
  17791. this.normalsNeedUpdate = source.normalsNeedUpdate;
  17792. this.colorsNeedUpdate = source.colorsNeedUpdate;
  17793. this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
  17794. this.groupsNeedUpdate = source.groupsNeedUpdate;
  17795. return this;
  17796. },
  17797. dispose: function () {
  17798. this.dispatchEvent( { type: 'dispose' } );
  17799. }
  17800. } );
  17801. class BoxGeometry extends Geometry {
  17802. constructor( width, height, depth, widthSegments, heightSegments, depthSegments ) {
  17803. super();
  17804. this.type = 'BoxGeometry';
  17805. this.parameters = {
  17806. width: width,
  17807. height: height,
  17808. depth: depth,
  17809. widthSegments: widthSegments,
  17810. heightSegments: heightSegments,
  17811. depthSegments: depthSegments
  17812. };
  17813. this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
  17814. this.mergeVertices();
  17815. }
  17816. }
  17817. class CircleBufferGeometry extends BufferGeometry {
  17818. constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) {
  17819. super();
  17820. this.type = 'CircleBufferGeometry';
  17821. this.parameters = {
  17822. radius: radius,
  17823. segments: segments,
  17824. thetaStart: thetaStart,
  17825. thetaLength: thetaLength
  17826. };
  17827. segments = Math.max( 3, segments );
  17828. // buffers
  17829. const indices = [];
  17830. const vertices = [];
  17831. const normals = [];
  17832. const uvs = [];
  17833. // helper variables
  17834. const vertex = new Vector3();
  17835. const uv = new Vector2$1();
  17836. // center point
  17837. vertices.push( 0, 0, 0 );
  17838. normals.push( 0, 0, 1 );
  17839. uvs.push( 0.5, 0.5 );
  17840. for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
  17841. const segment = thetaStart + s / segments * thetaLength;
  17842. // vertex
  17843. vertex.x = radius * Math.cos( segment );
  17844. vertex.y = radius * Math.sin( segment );
  17845. vertices.push( vertex.x, vertex.y, vertex.z );
  17846. // normal
  17847. normals.push( 0, 0, 1 );
  17848. // uvs
  17849. uv.x = ( vertices[ i ] / radius + 1 ) / 2;
  17850. uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
  17851. uvs.push( uv.x, uv.y );
  17852. }
  17853. // indices
  17854. for ( let i = 1; i <= segments; i ++ ) {
  17855. indices.push( i, i + 1, 0 );
  17856. }
  17857. // build geometry
  17858. this.setIndex( indices );
  17859. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  17860. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  17861. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  17862. }
  17863. }
  17864. class CircleGeometry extends Geometry {
  17865. constructor( radius, segments, thetaStart, thetaLength ) {
  17866. super();
  17867. this.type = 'CircleGeometry';
  17868. this.parameters = {
  17869. radius: radius,
  17870. segments: segments,
  17871. thetaStart: thetaStart,
  17872. thetaLength: thetaLength
  17873. };
  17874. this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
  17875. this.mergeVertices();
  17876. }
  17877. }
  17878. class CylinderBufferGeometry extends BufferGeometry {
  17879. constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
  17880. super();
  17881. this.type = 'CylinderBufferGeometry';
  17882. this.parameters = {
  17883. radiusTop: radiusTop,
  17884. radiusBottom: radiusBottom,
  17885. height: height,
  17886. radialSegments: radialSegments,
  17887. heightSegments: heightSegments,
  17888. openEnded: openEnded,
  17889. thetaStart: thetaStart,
  17890. thetaLength: thetaLength
  17891. };
  17892. const scope = this;
  17893. radialSegments = Math.floor( radialSegments );
  17894. heightSegments = Math.floor( heightSegments );
  17895. // buffers
  17896. const indices = [];
  17897. const vertices = [];
  17898. const normals = [];
  17899. const uvs = [];
  17900. // helper variables
  17901. let index = 0;
  17902. const indexArray = [];
  17903. const halfHeight = height / 2;
  17904. let groupStart = 0;
  17905. // generate geometry
  17906. generateTorso();
  17907. if ( openEnded === false ) {
  17908. if ( radiusTop > 0 ) generateCap( true );
  17909. if ( radiusBottom > 0 ) generateCap( false );
  17910. }
  17911. // build geometry
  17912. this.setIndex( indices );
  17913. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  17914. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  17915. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  17916. function generateTorso() {
  17917. const normal = new Vector3();
  17918. const vertex = new Vector3();
  17919. let groupCount = 0;
  17920. // this will be used to calculate the normal
  17921. const slope = ( radiusBottom - radiusTop ) / height;
  17922. // generate vertices, normals and uvs
  17923. for ( let y = 0; y <= heightSegments; y ++ ) {
  17924. const indexRow = [];
  17925. const v = y / heightSegments;
  17926. // calculate the radius of the current row
  17927. const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
  17928. for ( let x = 0; x <= radialSegments; x ++ ) {
  17929. const u = x / radialSegments;
  17930. const theta = u * thetaLength + thetaStart;
  17931. const sinTheta = Math.sin( theta );
  17932. const cosTheta = Math.cos( theta );
  17933. // vertex
  17934. vertex.x = radius * sinTheta;
  17935. vertex.y = - v * height + halfHeight;
  17936. vertex.z = radius * cosTheta;
  17937. vertices.push( vertex.x, vertex.y, vertex.z );
  17938. // normal
  17939. normal.set( sinTheta, slope, cosTheta ).normalize();
  17940. normals.push( normal.x, normal.y, normal.z );
  17941. // uv
  17942. uvs.push( u, 1 - v );
  17943. // save index of vertex in respective row
  17944. indexRow.push( index ++ );
  17945. }
  17946. // now save vertices of the row in our index array
  17947. indexArray.push( indexRow );
  17948. }
  17949. // generate indices
  17950. for ( let x = 0; x < radialSegments; x ++ ) {
  17951. for ( let y = 0; y < heightSegments; y ++ ) {
  17952. // we use the index array to access the correct indices
  17953. const a = indexArray[ y ][ x ];
  17954. const b = indexArray[ y + 1 ][ x ];
  17955. const c = indexArray[ y + 1 ][ x + 1 ];
  17956. const d = indexArray[ y ][ x + 1 ];
  17957. // faces
  17958. indices.push( a, b, d );
  17959. indices.push( b, c, d );
  17960. // update group counter
  17961. groupCount += 6;
  17962. }
  17963. }
  17964. // add a group to the geometry. this will ensure multi material support
  17965. scope.addGroup( groupStart, groupCount, 0 );
  17966. // calculate new start value for groups
  17967. groupStart += groupCount;
  17968. }
  17969. function generateCap( top ) {
  17970. // save the index of the first center vertex
  17971. const centerIndexStart = index;
  17972. const uv = new Vector2$1();
  17973. const vertex = new Vector3();
  17974. let groupCount = 0;
  17975. const radius = ( top === true ) ? radiusTop : radiusBottom;
  17976. const sign = ( top === true ) ? 1 : - 1;
  17977. // first we generate the center vertex data of the cap.
  17978. // because the geometry needs one set of uvs per face,
  17979. // we must generate a center vertex per face/segment
  17980. for ( let x = 1; x <= radialSegments; x ++ ) {
  17981. // vertex
  17982. vertices.push( 0, halfHeight * sign, 0 );
  17983. // normal
  17984. normals.push( 0, sign, 0 );
  17985. // uv
  17986. uvs.push( 0.5, 0.5 );
  17987. // increase index
  17988. index ++;
  17989. }
  17990. // save the index of the last center vertex
  17991. const centerIndexEnd = index;
  17992. // now we generate the surrounding vertices, normals and uvs
  17993. for ( let x = 0; x <= radialSegments; x ++ ) {
  17994. const u = x / radialSegments;
  17995. const theta = u * thetaLength + thetaStart;
  17996. const cosTheta = Math.cos( theta );
  17997. const sinTheta = Math.sin( theta );
  17998. // vertex
  17999. vertex.x = radius * sinTheta;
  18000. vertex.y = halfHeight * sign;
  18001. vertex.z = radius * cosTheta;
  18002. vertices.push( vertex.x, vertex.y, vertex.z );
  18003. // normal
  18004. normals.push( 0, sign, 0 );
  18005. // uv
  18006. uv.x = ( cosTheta * 0.5 ) + 0.5;
  18007. uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
  18008. uvs.push( uv.x, uv.y );
  18009. // increase index
  18010. index ++;
  18011. }
  18012. // generate indices
  18013. for ( let x = 0; x < radialSegments; x ++ ) {
  18014. const c = centerIndexStart + x;
  18015. const i = centerIndexEnd + x;
  18016. if ( top === true ) {
  18017. // face top
  18018. indices.push( i, i + 1, c );
  18019. } else {
  18020. // face bottom
  18021. indices.push( i + 1, i, c );
  18022. }
  18023. groupCount += 3;
  18024. }
  18025. // add a group to the geometry. this will ensure multi material support
  18026. scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
  18027. // calculate new start value for groups
  18028. groupStart += groupCount;
  18029. }
  18030. }
  18031. }
  18032. class CylinderGeometry extends Geometry {
  18033. constructor( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
  18034. super();
  18035. this.type = 'CylinderGeometry';
  18036. this.parameters = {
  18037. radiusTop: radiusTop,
  18038. radiusBottom: radiusBottom,
  18039. height: height,
  18040. radialSegments: radialSegments,
  18041. heightSegments: heightSegments,
  18042. openEnded: openEnded,
  18043. thetaStart: thetaStart,
  18044. thetaLength: thetaLength
  18045. };
  18046. this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
  18047. this.mergeVertices();
  18048. }
  18049. }
  18050. class ConeGeometry extends CylinderGeometry {
  18051. constructor( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
  18052. super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
  18053. this.type = 'ConeGeometry';
  18054. this.parameters = {
  18055. radius: radius,
  18056. height: height,
  18057. radialSegments: radialSegments,
  18058. heightSegments: heightSegments,
  18059. openEnded: openEnded,
  18060. thetaStart: thetaStart,
  18061. thetaLength: thetaLength
  18062. };
  18063. }
  18064. }
  18065. class ConeBufferGeometry extends CylinderBufferGeometry {
  18066. constructor( radius = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
  18067. super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
  18068. this.type = 'ConeBufferGeometry';
  18069. this.parameters = {
  18070. radius: radius,
  18071. height: height,
  18072. radialSegments: radialSegments,
  18073. heightSegments: heightSegments,
  18074. openEnded: openEnded,
  18075. thetaStart: thetaStart,
  18076. thetaLength: thetaLength
  18077. };
  18078. }
  18079. }
  18080. class PolyhedronBufferGeometry extends BufferGeometry {
  18081. constructor( vertices, indices, radius = 1, detail = 0 ) {
  18082. super();
  18083. this.type = 'PolyhedronBufferGeometry';
  18084. this.parameters = {
  18085. vertices: vertices,
  18086. indices: indices,
  18087. radius: radius,
  18088. detail: detail
  18089. };
  18090. // default buffer data
  18091. const vertexBuffer = [];
  18092. const uvBuffer = [];
  18093. // the subdivision creates the vertex buffer data
  18094. subdivide( detail );
  18095. // all vertices should lie on a conceptual sphere with a given radius
  18096. applyRadius( radius );
  18097. // finally, create the uv data
  18098. generateUVs();
  18099. // build non-indexed geometry
  18100. this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
  18101. this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
  18102. this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
  18103. if ( detail === 0 ) {
  18104. this.computeVertexNormals(); // flat normals
  18105. } else {
  18106. this.normalizeNormals(); // smooth normals
  18107. }
  18108. // helper functions
  18109. function subdivide( detail ) {
  18110. const a = new Vector3();
  18111. const b = new Vector3();
  18112. const c = new Vector3();
  18113. // iterate over all faces and apply a subdivison with the given detail value
  18114. for ( let i = 0; i < indices.length; i += 3 ) {
  18115. // get the vertices of the face
  18116. getVertexByIndex( indices[ i + 0 ], a );
  18117. getVertexByIndex( indices[ i + 1 ], b );
  18118. getVertexByIndex( indices[ i + 2 ], c );
  18119. // perform subdivision
  18120. subdivideFace( a, b, c, detail );
  18121. }
  18122. }
  18123. function subdivideFace( a, b, c, detail ) {
  18124. const cols = detail + 1;
  18125. // we use this multidimensional array as a data structure for creating the subdivision
  18126. const v = [];
  18127. // construct all of the vertices for this subdivision
  18128. for ( let i = 0; i <= cols; i ++ ) {
  18129. v[ i ] = [];
  18130. const aj = a.clone().lerp( c, i / cols );
  18131. const bj = b.clone().lerp( c, i / cols );
  18132. const rows = cols - i;
  18133. for ( let j = 0; j <= rows; j ++ ) {
  18134. if ( j === 0 && i === cols ) {
  18135. v[ i ][ j ] = aj;
  18136. } else {
  18137. v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
  18138. }
  18139. }
  18140. }
  18141. // construct all of the faces
  18142. for ( let i = 0; i < cols; i ++ ) {
  18143. for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
  18144. const k = Math.floor( j / 2 );
  18145. if ( j % 2 === 0 ) {
  18146. pushVertex( v[ i ][ k + 1 ] );
  18147. pushVertex( v[ i + 1 ][ k ] );
  18148. pushVertex( v[ i ][ k ] );
  18149. } else {
  18150. pushVertex( v[ i ][ k + 1 ] );
  18151. pushVertex( v[ i + 1 ][ k + 1 ] );
  18152. pushVertex( v[ i + 1 ][ k ] );
  18153. }
  18154. }
  18155. }
  18156. }
  18157. function applyRadius( radius ) {
  18158. const vertex = new Vector3();
  18159. // iterate over the entire buffer and apply the radius to each vertex
  18160. for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
  18161. vertex.x = vertexBuffer[ i + 0 ];
  18162. vertex.y = vertexBuffer[ i + 1 ];
  18163. vertex.z = vertexBuffer[ i + 2 ];
  18164. vertex.normalize().multiplyScalar( radius );
  18165. vertexBuffer[ i + 0 ] = vertex.x;
  18166. vertexBuffer[ i + 1 ] = vertex.y;
  18167. vertexBuffer[ i + 2 ] = vertex.z;
  18168. }
  18169. }
  18170. function generateUVs() {
  18171. const vertex = new Vector3();
  18172. for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
  18173. vertex.x = vertexBuffer[ i + 0 ];
  18174. vertex.y = vertexBuffer[ i + 1 ];
  18175. vertex.z = vertexBuffer[ i + 2 ];
  18176. const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
  18177. const v = inclination( vertex ) / Math.PI + 0.5;
  18178. uvBuffer.push( u, 1 - v );
  18179. }
  18180. correctUVs();
  18181. correctSeam();
  18182. }
  18183. function correctSeam() {
  18184. // handle case when face straddles the seam, see #3269
  18185. for ( let i = 0; i < uvBuffer.length; i += 6 ) {
  18186. // uv data of a single face
  18187. const x0 = uvBuffer[ i + 0 ];
  18188. const x1 = uvBuffer[ i + 2 ];
  18189. const x2 = uvBuffer[ i + 4 ];
  18190. const max = Math.max( x0, x1, x2 );
  18191. const min = Math.min( x0, x1, x2 );
  18192. // 0.9 is somewhat arbitrary
  18193. if ( max > 0.9 && min < 0.1 ) {
  18194. if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
  18195. if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
  18196. if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
  18197. }
  18198. }
  18199. }
  18200. function pushVertex( vertex ) {
  18201. vertexBuffer.push( vertex.x, vertex.y, vertex.z );
  18202. }
  18203. function getVertexByIndex( index, vertex ) {
  18204. const stride = index * 3;
  18205. vertex.x = vertices[ stride + 0 ];
  18206. vertex.y = vertices[ stride + 1 ];
  18207. vertex.z = vertices[ stride + 2 ];
  18208. }
  18209. function correctUVs() {
  18210. const a = new Vector3();
  18211. const b = new Vector3();
  18212. const c = new Vector3();
  18213. const centroid = new Vector3();
  18214. const uvA = new Vector2$1();
  18215. const uvB = new Vector2$1();
  18216. const uvC = new Vector2$1();
  18217. for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
  18218. a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
  18219. b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
  18220. c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
  18221. uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
  18222. uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
  18223. uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
  18224. centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
  18225. const azi = azimuth( centroid );
  18226. correctUV( uvA, j + 0, a, azi );
  18227. correctUV( uvB, j + 2, b, azi );
  18228. correctUV( uvC, j + 4, c, azi );
  18229. }
  18230. }
  18231. function correctUV( uv, stride, vector, azimuth ) {
  18232. if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
  18233. uvBuffer[ stride ] = uv.x - 1;
  18234. }
  18235. if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
  18236. uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
  18237. }
  18238. }
  18239. // Angle around the Y axis, counter-clockwise when looking from above.
  18240. function azimuth( vector ) {
  18241. return Math.atan2( vector.z, - vector.x );
  18242. }
  18243. // Angle above the XZ plane.
  18244. function inclination( vector ) {
  18245. return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
  18246. }
  18247. }
  18248. }
  18249. class DodecahedronBufferGeometry extends PolyhedronBufferGeometry {
  18250. constructor( radius = 1, detail = 0 ) {
  18251. const t = ( 1 + Math.sqrt( 5 ) ) / 2;
  18252. const r = 1 / t;
  18253. const vertices = [
  18254. // (±1, ±1, ±1)
  18255. - 1, - 1, - 1, - 1, - 1, 1,
  18256. - 1, 1, - 1, - 1, 1, 1,
  18257. 1, - 1, - 1, 1, - 1, 1,
  18258. 1, 1, - 1, 1, 1, 1,
  18259. // (0, ±1/φ, ±φ)
  18260. 0, - r, - t, 0, - r, t,
  18261. 0, r, - t, 0, r, t,
  18262. // (±1/φ, ±φ, 0)
  18263. - r, - t, 0, - r, t, 0,
  18264. r, - t, 0, r, t, 0,
  18265. // (±φ, 0, ±1/φ)
  18266. - t, 0, - r, t, 0, - r,
  18267. - t, 0, r, t, 0, r
  18268. ];
  18269. const indices = [
  18270. 3, 11, 7, 3, 7, 15, 3, 15, 13,
  18271. 7, 19, 17, 7, 17, 6, 7, 6, 15,
  18272. 17, 4, 8, 17, 8, 10, 17, 10, 6,
  18273. 8, 0, 16, 8, 16, 2, 8, 2, 10,
  18274. 0, 12, 1, 0, 1, 18, 0, 18, 16,
  18275. 6, 10, 2, 6, 2, 13, 6, 13, 15,
  18276. 2, 16, 18, 2, 18, 3, 2, 3, 13,
  18277. 18, 1, 9, 18, 9, 11, 18, 11, 3,
  18278. 4, 14, 12, 4, 12, 0, 4, 0, 8,
  18279. 11, 9, 5, 11, 5, 19, 11, 19, 7,
  18280. 19, 5, 14, 19, 14, 4, 19, 4, 17,
  18281. 1, 12, 14, 1, 14, 5, 1, 5, 9
  18282. ];
  18283. super( vertices, indices, radius, detail );
  18284. this.type = 'DodecahedronBufferGeometry';
  18285. this.parameters = {
  18286. radius: radius,
  18287. detail: detail
  18288. };
  18289. }
  18290. }
  18291. class DodecahedronGeometry extends Geometry {
  18292. constructor( radius, detail ) {
  18293. super();
  18294. this.type = 'DodecahedronGeometry';
  18295. this.parameters = {
  18296. radius: radius,
  18297. detail: detail
  18298. };
  18299. this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
  18300. this.mergeVertices();
  18301. }
  18302. }
  18303. const _v0$2 = new Vector3();
  18304. const _v1$5 = new Vector3();
  18305. const _normal$1 = new Vector3();
  18306. const _triangle = new Triangle();
  18307. class EdgesGeometry extends BufferGeometry {
  18308. constructor( geometry, thresholdAngle ) {
  18309. super();
  18310. this.type = 'EdgesGeometry';
  18311. this.parameters = {
  18312. thresholdAngle: thresholdAngle
  18313. };
  18314. thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
  18315. if ( geometry.isGeometry ) {
  18316. geometry = new BufferGeometry().fromGeometry( geometry );
  18317. }
  18318. const precisionPoints = 4;
  18319. const precision = Math.pow( 10, precisionPoints );
  18320. const thresholdDot = Math.cos( MathUtils.DEG2RAD * thresholdAngle );
  18321. const indexAttr = geometry.getIndex();
  18322. const positionAttr = geometry.getAttribute( 'position' );
  18323. const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
  18324. const indexArr = [ 0, 0, 0 ];
  18325. const vertKeys = [ 'a', 'b', 'c' ];
  18326. const hashes = new Array( 3 );
  18327. const edgeData = {};
  18328. const vertices = [];
  18329. for ( let i = 0; i < indexCount; i += 3 ) {
  18330. if ( indexAttr ) {
  18331. indexArr[ 0 ] = indexAttr.getX( i );
  18332. indexArr[ 1 ] = indexAttr.getX( i + 1 );
  18333. indexArr[ 2 ] = indexAttr.getX( i + 2 );
  18334. } else {
  18335. indexArr[ 0 ] = i;
  18336. indexArr[ 1 ] = i + 1;
  18337. indexArr[ 2 ] = i + 2;
  18338. }
  18339. const { a, b, c } = _triangle;
  18340. a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
  18341. b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
  18342. c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
  18343. _triangle.getNormal( _normal$1 );
  18344. // create hashes for the edge from the vertices
  18345. hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;
  18346. hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;
  18347. hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;
  18348. // skip degenerate triangles
  18349. if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {
  18350. continue;
  18351. }
  18352. // iterate over every edge
  18353. for ( let j = 0; j < 3; j ++ ) {
  18354. // get the first and next vertex making up the edge
  18355. const jNext = ( j + 1 ) % 3;
  18356. const vecHash0 = hashes[ j ];
  18357. const vecHash1 = hashes[ jNext ];
  18358. const v0 = _triangle[ vertKeys[ j ] ];
  18359. const v1 = _triangle[ vertKeys[ jNext ] ];
  18360. const hash = `${ vecHash0 }_${ vecHash1 }`;
  18361. const reverseHash = `${ vecHash1 }_${ vecHash0 }`;
  18362. if ( reverseHash in edgeData && edgeData[ reverseHash ] ) {
  18363. // if we found a sibling edge add it into the vertex array if
  18364. // it meets the angle threshold and delete the edge from the map.
  18365. if ( _normal$1.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {
  18366. vertices.push( v0.x, v0.y, v0.z );
  18367. vertices.push( v1.x, v1.y, v1.z );
  18368. }
  18369. edgeData[ reverseHash ] = null;
  18370. } else if ( ! ( hash in edgeData ) ) {
  18371. // if we've already got an edge here then skip adding a new one
  18372. edgeData[ hash ] = {
  18373. index0: indexArr[ j ],
  18374. index1: indexArr[ jNext ],
  18375. normal: _normal$1.clone(),
  18376. };
  18377. }
  18378. }
  18379. }
  18380. // iterate over all remaining, unmatched edges and add them to the vertex array
  18381. for ( const key in edgeData ) {
  18382. if ( edgeData[ key ] ) {
  18383. const { index0, index1 } = edgeData[ key ];
  18384. _v0$2.fromBufferAttribute( positionAttr, index0 );
  18385. _v1$5.fromBufferAttribute( positionAttr, index1 );
  18386. vertices.push( _v0$2.x, _v0$2.y, _v0$2.z );
  18387. vertices.push( _v1$5.x, _v1$5.y, _v1$5.z );
  18388. }
  18389. }
  18390. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  18391. }
  18392. }
  18393. /**
  18394. * Port from https://github.com/mapbox/earcut (v2.2.2)
  18395. */
  18396. const Earcut = {
  18397. triangulate: function ( data, holeIndices, dim ) {
  18398. dim = dim || 2;
  18399. const hasHoles = holeIndices && holeIndices.length;
  18400. const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
  18401. let outerNode = linkedList( data, 0, outerLen, dim, true );
  18402. const triangles = [];
  18403. if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
  18404. let minX, minY, maxX, maxY, x, y, invSize;
  18405. if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
  18406. // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  18407. if ( data.length > 80 * dim ) {
  18408. minX = maxX = data[ 0 ];
  18409. minY = maxY = data[ 1 ];
  18410. for ( let i = dim; i < outerLen; i += dim ) {
  18411. x = data[ i ];
  18412. y = data[ i + 1 ];
  18413. if ( x < minX ) minX = x;
  18414. if ( y < minY ) minY = y;
  18415. if ( x > maxX ) maxX = x;
  18416. if ( y > maxY ) maxY = y;
  18417. }
  18418. // minX, minY and invSize are later used to transform coords into integers for z-order calculation
  18419. invSize = Math.max( maxX - minX, maxY - minY );
  18420. invSize = invSize !== 0 ? 1 / invSize : 0;
  18421. }
  18422. earcutLinked( outerNode, triangles, dim, minX, minY, invSize );
  18423. return triangles;
  18424. }
  18425. };
  18426. // create a circular doubly linked list from polygon points in the specified winding order
  18427. function linkedList( data, start, end, dim, clockwise ) {
  18428. let i, last;
  18429. if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
  18430. for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
  18431. } else {
  18432. for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
  18433. }
  18434. if ( last && equals( last, last.next ) ) {
  18435. removeNode( last );
  18436. last = last.next;
  18437. }
  18438. return last;
  18439. }
  18440. // eliminate colinear or duplicate points
  18441. function filterPoints( start, end ) {
  18442. if ( ! start ) return start;
  18443. if ( ! end ) end = start;
  18444. let p = start,
  18445. again;
  18446. do {
  18447. again = false;
  18448. if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
  18449. removeNode( p );
  18450. p = end = p.prev;
  18451. if ( p === p.next ) break;
  18452. again = true;
  18453. } else {
  18454. p = p.next;
  18455. }
  18456. } while ( again || p !== end );
  18457. return end;
  18458. }
  18459. // main ear slicing loop which triangulates a polygon (given as a linked list)
  18460. function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
  18461. if ( ! ear ) return;
  18462. // interlink polygon nodes in z-order
  18463. if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
  18464. let stop = ear,
  18465. prev, next;
  18466. // iterate through ears, slicing them one by one
  18467. while ( ear.prev !== ear.next ) {
  18468. prev = ear.prev;
  18469. next = ear.next;
  18470. if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
  18471. // cut off the triangle
  18472. triangles.push( prev.i / dim );
  18473. triangles.push( ear.i / dim );
  18474. triangles.push( next.i / dim );
  18475. removeNode( ear );
  18476. // skipping the next vertex leads to less sliver triangles
  18477. ear = next.next;
  18478. stop = next.next;
  18479. continue;
  18480. }
  18481. ear = next;
  18482. // if we looped through the whole remaining polygon and can't find any more ears
  18483. if ( ear === stop ) {
  18484. // try filtering points and slicing again
  18485. if ( ! pass ) {
  18486. earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
  18487. // if this didn't work, try curing all small self-intersections locally
  18488. } else if ( pass === 1 ) {
  18489. ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
  18490. earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
  18491. // as a last resort, try splitting the remaining polygon into two
  18492. } else if ( pass === 2 ) {
  18493. splitEarcut( ear, triangles, dim, minX, minY, invSize );
  18494. }
  18495. break;
  18496. }
  18497. }
  18498. }
  18499. // check whether a polygon node forms a valid ear with adjacent nodes
  18500. function isEar( ear ) {
  18501. const a = ear.prev,
  18502. b = ear,
  18503. c = ear.next;
  18504. if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
  18505. // now make sure we don't have other points inside the potential ear
  18506. let p = ear.next.next;
  18507. while ( p !== ear.prev ) {
  18508. if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
  18509. area( p.prev, p, p.next ) >= 0 ) return false;
  18510. p = p.next;
  18511. }
  18512. return true;
  18513. }
  18514. function isEarHashed( ear, minX, minY, invSize ) {
  18515. const a = ear.prev,
  18516. b = ear,
  18517. c = ear.next;
  18518. if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
  18519. // triangle bbox; min & max are calculated like this for speed
  18520. const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
  18521. minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
  18522. maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
  18523. maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
  18524. // z-order range for the current triangle bbox;
  18525. const minZ = zOrder( minTX, minTY, minX, minY, invSize ),
  18526. maxZ = zOrder( maxTX, maxTY, minX, minY, invSize );
  18527. let p = ear.prevZ,
  18528. n = ear.nextZ;
  18529. // look for points inside the triangle in both directions
  18530. while ( p && p.z >= minZ && n && n.z <= maxZ ) {
  18531. if ( p !== ear.prev && p !== ear.next &&
  18532. pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
  18533. area( p.prev, p, p.next ) >= 0 ) return false;
  18534. p = p.prevZ;
  18535. if ( n !== ear.prev && n !== ear.next &&
  18536. pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
  18537. area( n.prev, n, n.next ) >= 0 ) return false;
  18538. n = n.nextZ;
  18539. }
  18540. // look for remaining points in decreasing z-order
  18541. while ( p && p.z >= minZ ) {
  18542. if ( p !== ear.prev && p !== ear.next &&
  18543. pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
  18544. area( p.prev, p, p.next ) >= 0 ) return false;
  18545. p = p.prevZ;
  18546. }
  18547. // look for remaining points in increasing z-order
  18548. while ( n && n.z <= maxZ ) {
  18549. if ( n !== ear.prev && n !== ear.next &&
  18550. pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
  18551. area( n.prev, n, n.next ) >= 0 ) return false;
  18552. n = n.nextZ;
  18553. }
  18554. return true;
  18555. }
  18556. // go through all polygon nodes and cure small local self-intersections
  18557. function cureLocalIntersections( start, triangles, dim ) {
  18558. let p = start;
  18559. do {
  18560. const a = p.prev,
  18561. b = p.next.next;
  18562. if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
  18563. triangles.push( a.i / dim );
  18564. triangles.push( p.i / dim );
  18565. triangles.push( b.i / dim );
  18566. // remove two nodes involved
  18567. removeNode( p );
  18568. removeNode( p.next );
  18569. p = start = b;
  18570. }
  18571. p = p.next;
  18572. } while ( p !== start );
  18573. return filterPoints( p );
  18574. }
  18575. // try splitting polygon into two and triangulate them independently
  18576. function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
  18577. // look for a valid diagonal that divides the polygon into two
  18578. let a = start;
  18579. do {
  18580. let b = a.next.next;
  18581. while ( b !== a.prev ) {
  18582. if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
  18583. // split the polygon in two by the diagonal
  18584. let c = splitPolygon( a, b );
  18585. // filter colinear points around the cuts
  18586. a = filterPoints( a, a.next );
  18587. c = filterPoints( c, c.next );
  18588. // run earcut on each half
  18589. earcutLinked( a, triangles, dim, minX, minY, invSize );
  18590. earcutLinked( c, triangles, dim, minX, minY, invSize );
  18591. return;
  18592. }
  18593. b = b.next;
  18594. }
  18595. a = a.next;
  18596. } while ( a !== start );
  18597. }
  18598. // link every hole into the outer loop, producing a single-ring polygon without holes
  18599. function eliminateHoles( data, holeIndices, outerNode, dim ) {
  18600. const queue = [];
  18601. let i, len, start, end, list;
  18602. for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
  18603. start = holeIndices[ i ] * dim;
  18604. end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
  18605. list = linkedList( data, start, end, dim, false );
  18606. if ( list === list.next ) list.steiner = true;
  18607. queue.push( getLeftmost( list ) );
  18608. }
  18609. queue.sort( compareX );
  18610. // process holes from left to right
  18611. for ( i = 0; i < queue.length; i ++ ) {
  18612. eliminateHole( queue[ i ], outerNode );
  18613. outerNode = filterPoints( outerNode, outerNode.next );
  18614. }
  18615. return outerNode;
  18616. }
  18617. function compareX( a, b ) {
  18618. return a.x - b.x;
  18619. }
  18620. // find a bridge between vertices that connects hole with an outer ring and and link it
  18621. function eliminateHole( hole, outerNode ) {
  18622. outerNode = findHoleBridge( hole, outerNode );
  18623. if ( outerNode ) {
  18624. const b = splitPolygon( outerNode, hole );
  18625. // filter collinear points around the cuts
  18626. filterPoints( outerNode, outerNode.next );
  18627. filterPoints( b, b.next );
  18628. }
  18629. }
  18630. // David Eberly's algorithm for finding a bridge between hole and outer polygon
  18631. function findHoleBridge( hole, outerNode ) {
  18632. let p = outerNode;
  18633. const hx = hole.x;
  18634. const hy = hole.y;
  18635. let qx = - Infinity, m;
  18636. // find a segment intersected by a ray from the hole's leftmost point to the left;
  18637. // segment's endpoint with lesser x will be potential connection point
  18638. do {
  18639. if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
  18640. const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
  18641. if ( x <= hx && x > qx ) {
  18642. qx = x;
  18643. if ( x === hx ) {
  18644. if ( hy === p.y ) return p;
  18645. if ( hy === p.next.y ) return p.next;
  18646. }
  18647. m = p.x < p.next.x ? p : p.next;
  18648. }
  18649. }
  18650. p = p.next;
  18651. } while ( p !== outerNode );
  18652. if ( ! m ) return null;
  18653. if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint
  18654. // look for points inside the triangle of hole point, segment intersection and endpoint;
  18655. // if there are no points found, we have a valid connection;
  18656. // otherwise choose the point of the minimum angle with the ray as connection point
  18657. const stop = m,
  18658. mx = m.x,
  18659. my = m.y;
  18660. let tanMin = Infinity, tan;
  18661. p = m;
  18662. do {
  18663. if ( hx >= p.x && p.x >= mx && hx !== p.x &&
  18664. pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
  18665. tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
  18666. if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
  18667. m = p;
  18668. tanMin = tan;
  18669. }
  18670. }
  18671. p = p.next;
  18672. } while ( p !== stop );
  18673. return m;
  18674. }
  18675. // whether sector in vertex m contains sector in vertex p in the same coordinates
  18676. function sectorContainsSector( m, p ) {
  18677. return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
  18678. }
  18679. // interlink polygon nodes in z-order
  18680. function indexCurve( start, minX, minY, invSize ) {
  18681. let p = start;
  18682. do {
  18683. if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
  18684. p.prevZ = p.prev;
  18685. p.nextZ = p.next;
  18686. p = p.next;
  18687. } while ( p !== start );
  18688. p.prevZ.nextZ = null;
  18689. p.prevZ = null;
  18690. sortLinked( p );
  18691. }
  18692. // Simon Tatham's linked list merge sort algorithm
  18693. // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
  18694. function sortLinked( list ) {
  18695. let i, p, q, e, tail, numMerges, pSize, qSize,
  18696. inSize = 1;
  18697. do {
  18698. p = list;
  18699. list = null;
  18700. tail = null;
  18701. numMerges = 0;
  18702. while ( p ) {
  18703. numMerges ++;
  18704. q = p;
  18705. pSize = 0;
  18706. for ( i = 0; i < inSize; i ++ ) {
  18707. pSize ++;
  18708. q = q.nextZ;
  18709. if ( ! q ) break;
  18710. }
  18711. qSize = inSize;
  18712. while ( pSize > 0 || ( qSize > 0 && q ) ) {
  18713. if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
  18714. e = p;
  18715. p = p.nextZ;
  18716. pSize --;
  18717. } else {
  18718. e = q;
  18719. q = q.nextZ;
  18720. qSize --;
  18721. }
  18722. if ( tail ) tail.nextZ = e;
  18723. else list = e;
  18724. e.prevZ = tail;
  18725. tail = e;
  18726. }
  18727. p = q;
  18728. }
  18729. tail.nextZ = null;
  18730. inSize *= 2;
  18731. } while ( numMerges > 1 );
  18732. return list;
  18733. }
  18734. // z-order of a point given coords and inverse of the longer side of data bbox
  18735. function zOrder( x, y, minX, minY, invSize ) {
  18736. // coords are transformed into non-negative 15-bit integer range
  18737. x = 32767 * ( x - minX ) * invSize;
  18738. y = 32767 * ( y - minY ) * invSize;
  18739. x = ( x | ( x << 8 ) ) & 0x00FF00FF;
  18740. x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
  18741. x = ( x | ( x << 2 ) ) & 0x33333333;
  18742. x = ( x | ( x << 1 ) ) & 0x55555555;
  18743. y = ( y | ( y << 8 ) ) & 0x00FF00FF;
  18744. y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
  18745. y = ( y | ( y << 2 ) ) & 0x33333333;
  18746. y = ( y | ( y << 1 ) ) & 0x55555555;
  18747. return x | ( y << 1 );
  18748. }
  18749. // find the leftmost node of a polygon ring
  18750. function getLeftmost( start ) {
  18751. let p = start,
  18752. leftmost = start;
  18753. do {
  18754. if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
  18755. p = p.next;
  18756. } while ( p !== start );
  18757. return leftmost;
  18758. }
  18759. // check if a point lies within a convex triangle
  18760. function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
  18761. return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
  18762. ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
  18763. ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
  18764. }
  18765. // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
  18766. function isValidDiagonal( a, b ) {
  18767. return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
  18768. ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
  18769. ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
  18770. equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
  18771. }
  18772. // signed area of a triangle
  18773. function area( p, q, r ) {
  18774. return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
  18775. }
  18776. // check if two points are equal
  18777. function equals( p1, p2 ) {
  18778. return p1.x === p2.x && p1.y === p2.y;
  18779. }
  18780. // check if two segments intersect
  18781. function intersects( p1, q1, p2, q2 ) {
  18782. const o1 = sign( area( p1, q1, p2 ) );
  18783. const o2 = sign( area( p1, q1, q2 ) );
  18784. const o3 = sign( area( p2, q2, p1 ) );
  18785. const o4 = sign( area( p2, q2, q1 ) );
  18786. if ( o1 !== o2 && o3 !== o4 ) return true; // general case
  18787. if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
  18788. if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
  18789. if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
  18790. if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
  18791. return false;
  18792. }
  18793. // for collinear points p, q, r, check if point q lies on segment pr
  18794. function onSegment( p, q, r ) {
  18795. return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
  18796. }
  18797. function sign( num ) {
  18798. return num > 0 ? 1 : num < 0 ? - 1 : 0;
  18799. }
  18800. // check if a polygon diagonal intersects any polygon segments
  18801. function intersectsPolygon( a, b ) {
  18802. let p = a;
  18803. do {
  18804. if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
  18805. intersects( p, p.next, a, b ) ) return true;
  18806. p = p.next;
  18807. } while ( p !== a );
  18808. return false;
  18809. }
  18810. // check if a polygon diagonal is locally inside the polygon
  18811. function locallyInside( a, b ) {
  18812. return area( a.prev, a, a.next ) < 0 ?
  18813. area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
  18814. area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
  18815. }
  18816. // check if the middle point of a polygon diagonal is inside the polygon
  18817. function middleInside( a, b ) {
  18818. let p = a,
  18819. inside = false;
  18820. const px = ( a.x + b.x ) / 2,
  18821. py = ( a.y + b.y ) / 2;
  18822. do {
  18823. if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
  18824. ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
  18825. inside = ! inside;
  18826. p = p.next;
  18827. } while ( p !== a );
  18828. return inside;
  18829. }
  18830. // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
  18831. // if one belongs to the outer ring and another to a hole, it merges it into a single ring
  18832. function splitPolygon( a, b ) {
  18833. const a2 = new Node( a.i, a.x, a.y ),
  18834. b2 = new Node( b.i, b.x, b.y ),
  18835. an = a.next,
  18836. bp = b.prev;
  18837. a.next = b;
  18838. b.prev = a;
  18839. a2.next = an;
  18840. an.prev = a2;
  18841. b2.next = a2;
  18842. a2.prev = b2;
  18843. bp.next = b2;
  18844. b2.prev = bp;
  18845. return b2;
  18846. }
  18847. // create a node and optionally link it with previous one (in a circular doubly linked list)
  18848. function insertNode( i, x, y, last ) {
  18849. const p = new Node( i, x, y );
  18850. if ( ! last ) {
  18851. p.prev = p;
  18852. p.next = p;
  18853. } else {
  18854. p.next = last.next;
  18855. p.prev = last;
  18856. last.next.prev = p;
  18857. last.next = p;
  18858. }
  18859. return p;
  18860. }
  18861. function removeNode( p ) {
  18862. p.next.prev = p.prev;
  18863. p.prev.next = p.next;
  18864. if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
  18865. if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
  18866. }
  18867. function Node( i, x, y ) {
  18868. // vertex index in coordinates array
  18869. this.i = i;
  18870. // vertex coordinates
  18871. this.x = x;
  18872. this.y = y;
  18873. // previous and next vertex nodes in a polygon ring
  18874. this.prev = null;
  18875. this.next = null;
  18876. // z-order curve value
  18877. this.z = null;
  18878. // previous and next nodes in z-order
  18879. this.prevZ = null;
  18880. this.nextZ = null;
  18881. // indicates whether this is a steiner point
  18882. this.steiner = false;
  18883. }
  18884. function signedArea( data, start, end, dim ) {
  18885. let sum = 0;
  18886. for ( let i = start, j = end - dim; i < end; i += dim ) {
  18887. sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
  18888. j = i;
  18889. }
  18890. return sum;
  18891. }
  18892. const ShapeUtils = {
  18893. // calculate area of the contour polygon
  18894. area: function ( contour ) {
  18895. const n = contour.length;
  18896. let a = 0.0;
  18897. for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
  18898. a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
  18899. }
  18900. return a * 0.5;
  18901. },
  18902. isClockWise: function ( pts ) {
  18903. return ShapeUtils.area( pts ) < 0;
  18904. },
  18905. triangulateShape: function ( contour, holes ) {
  18906. const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
  18907. const holeIndices = []; // array of hole indices
  18908. const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
  18909. removeDupEndPts( contour );
  18910. addContour( vertices, contour );
  18911. //
  18912. let holeIndex = contour.length;
  18913. holes.forEach( removeDupEndPts );
  18914. for ( let i = 0; i < holes.length; i ++ ) {
  18915. holeIndices.push( holeIndex );
  18916. holeIndex += holes[ i ].length;
  18917. addContour( vertices, holes[ i ] );
  18918. }
  18919. //
  18920. const triangles = Earcut.triangulate( vertices, holeIndices );
  18921. //
  18922. for ( let i = 0; i < triangles.length; i += 3 ) {
  18923. faces.push( triangles.slice( i, i + 3 ) );
  18924. }
  18925. return faces;
  18926. }
  18927. };
  18928. function removeDupEndPts( points ) {
  18929. const l = points.length;
  18930. if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
  18931. points.pop();
  18932. }
  18933. }
  18934. function addContour( vertices, contour ) {
  18935. for ( let i = 0; i < contour.length; i ++ ) {
  18936. vertices.push( contour[ i ].x );
  18937. vertices.push( contour[ i ].y );
  18938. }
  18939. }
  18940. /**
  18941. * Creates extruded geometry from a path shape.
  18942. *
  18943. * parameters = {
  18944. *
  18945. * curveSegments: <int>, // number of points on the curves
  18946. * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
  18947. * depth: <float>, // Depth to extrude the shape
  18948. *
  18949. * bevelEnabled: <bool>, // turn on bevel
  18950. * bevelThickness: <float>, // how deep into the original shape bevel goes
  18951. * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
  18952. * bevelOffset: <float>, // how far from shape outline does bevel start
  18953. * bevelSegments: <int>, // number of bevel layers
  18954. *
  18955. * extrudePath: <THREE.Curve> // curve to extrude shape along
  18956. *
  18957. * UVGenerator: <Object> // object that provides UV generator functions
  18958. *
  18959. * }
  18960. */
  18961. class ExtrudeBufferGeometry extends BufferGeometry {
  18962. constructor( shapes, options ) {
  18963. super();
  18964. this.type = 'ExtrudeBufferGeometry';
  18965. this.parameters = {
  18966. shapes: shapes,
  18967. options: options
  18968. };
  18969. shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
  18970. const scope = this;
  18971. const verticesArray = [];
  18972. const uvArray = [];
  18973. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  18974. const shape = shapes[ i ];
  18975. addShape( shape );
  18976. }
  18977. // build geometry
  18978. this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
  18979. this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
  18980. this.computeVertexNormals();
  18981. // functions
  18982. function addShape( shape ) {
  18983. const placeholder = [];
  18984. // options
  18985. const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
  18986. const steps = options.steps !== undefined ? options.steps : 1;
  18987. let depth = options.depth !== undefined ? options.depth : 100;
  18988. let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
  18989. let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
  18990. let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
  18991. let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
  18992. let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
  18993. const extrudePath = options.extrudePath;
  18994. const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
  18995. // deprecated options
  18996. if ( options.amount !== undefined ) {
  18997. console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
  18998. depth = options.amount;
  18999. }
  19000. //
  19001. let extrudePts, extrudeByPath = false;
  19002. let splineTube, binormal, normal, position2;
  19003. if ( extrudePath ) {
  19004. extrudePts = extrudePath.getSpacedPoints( steps );
  19005. extrudeByPath = true;
  19006. bevelEnabled = false; // bevels not supported for path extrusion
  19007. // SETUP TNB variables
  19008. // TODO1 - have a .isClosed in spline?
  19009. splineTube = extrudePath.computeFrenetFrames( steps, false );
  19010. // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
  19011. binormal = new Vector3();
  19012. normal = new Vector3();
  19013. position2 = new Vector3();
  19014. }
  19015. // Safeguards if bevels are not enabled
  19016. if ( ! bevelEnabled ) {
  19017. bevelSegments = 0;
  19018. bevelThickness = 0;
  19019. bevelSize = 0;
  19020. bevelOffset = 0;
  19021. }
  19022. // Variables initialization
  19023. const shapePoints = shape.extractPoints( curveSegments );
  19024. let vertices = shapePoints.shape;
  19025. const holes = shapePoints.holes;
  19026. const reverse = ! ShapeUtils.isClockWise( vertices );
  19027. if ( reverse ) {
  19028. vertices = vertices.reverse();
  19029. // Maybe we should also check if holes are in the opposite direction, just to be safe ...
  19030. for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
  19031. const ahole = holes[ h ];
  19032. if ( ShapeUtils.isClockWise( ahole ) ) {
  19033. holes[ h ] = ahole.reverse();
  19034. }
  19035. }
  19036. }
  19037. const faces = ShapeUtils.triangulateShape( vertices, holes );
  19038. /* Vertices */
  19039. const contour = vertices; // vertices has all points but contour has only points of circumference
  19040. for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
  19041. const ahole = holes[ h ];
  19042. vertices = vertices.concat( ahole );
  19043. }
  19044. function scalePt2( pt, vec, size ) {
  19045. if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
  19046. return vec.clone().multiplyScalar( size ).add( pt );
  19047. }
  19048. const vlen = vertices.length, flen = faces.length;
  19049. // Find directions for point movement
  19050. function getBevelVec( inPt, inPrev, inNext ) {
  19051. // computes for inPt the corresponding point inPt' on a new contour
  19052. // shifted by 1 unit (length of normalized vector) to the left
  19053. // if we walk along contour clockwise, this new contour is outside the old one
  19054. //
  19055. // inPt' is the intersection of the two lines parallel to the two
  19056. // adjacent edges of inPt at a distance of 1 unit on the left side.
  19057. let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
  19058. // good reading for geometry algorithms (here: line-line intersection)
  19059. // http://geomalgorithms.com/a05-_intersect-1.html
  19060. const v_prev_x = inPt.x - inPrev.x,
  19061. v_prev_y = inPt.y - inPrev.y;
  19062. const v_next_x = inNext.x - inPt.x,
  19063. v_next_y = inNext.y - inPt.y;
  19064. const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
  19065. // check for collinear edges
  19066. const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
  19067. if ( Math.abs( collinear0 ) > Number.EPSILON ) {
  19068. // not collinear
  19069. // length of vectors for normalizing
  19070. const v_prev_len = Math.sqrt( v_prev_lensq );
  19071. const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
  19072. // shift adjacent points by unit vectors to the left
  19073. const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
  19074. const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
  19075. const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
  19076. const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
  19077. // scaling factor for v_prev to intersection point
  19078. const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
  19079. ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
  19080. ( v_prev_x * v_next_y - v_prev_y * v_next_x );
  19081. // vector from inPt to intersection point
  19082. v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
  19083. v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
  19084. // Don't normalize!, otherwise sharp corners become ugly
  19085. // but prevent crazy spikes
  19086. const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
  19087. if ( v_trans_lensq <= 2 ) {
  19088. return new Vector2$1( v_trans_x, v_trans_y );
  19089. } else {
  19090. shrink_by = Math.sqrt( v_trans_lensq / 2 );
  19091. }
  19092. } else {
  19093. // handle special case of collinear edges
  19094. let direction_eq = false; // assumes: opposite
  19095. if ( v_prev_x > Number.EPSILON ) {
  19096. if ( v_next_x > Number.EPSILON ) {
  19097. direction_eq = true;
  19098. }
  19099. } else {
  19100. if ( v_prev_x < - Number.EPSILON ) {
  19101. if ( v_next_x < - Number.EPSILON ) {
  19102. direction_eq = true;
  19103. }
  19104. } else {
  19105. if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
  19106. direction_eq = true;
  19107. }
  19108. }
  19109. }
  19110. if ( direction_eq ) {
  19111. // console.log("Warning: lines are a straight sequence");
  19112. v_trans_x = - v_prev_y;
  19113. v_trans_y = v_prev_x;
  19114. shrink_by = Math.sqrt( v_prev_lensq );
  19115. } else {
  19116. // console.log("Warning: lines are a straight spike");
  19117. v_trans_x = v_prev_x;
  19118. v_trans_y = v_prev_y;
  19119. shrink_by = Math.sqrt( v_prev_lensq / 2 );
  19120. }
  19121. }
  19122. return new Vector2$1( v_trans_x / shrink_by, v_trans_y / shrink_by );
  19123. }
  19124. const contourMovements = [];
  19125. for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
  19126. if ( j === il ) j = 0;
  19127. if ( k === il ) k = 0;
  19128. // (j)---(i)---(k)
  19129. // console.log('i,j,k', i, j , k)
  19130. contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
  19131. }
  19132. const holesMovements = [];
  19133. let oneHoleMovements, verticesMovements = contourMovements.concat();
  19134. for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
  19135. const ahole = holes[ h ];
  19136. oneHoleMovements = [];
  19137. for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
  19138. if ( j === il ) j = 0;
  19139. if ( k === il ) k = 0;
  19140. // (j)---(i)---(k)
  19141. oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
  19142. }
  19143. holesMovements.push( oneHoleMovements );
  19144. verticesMovements = verticesMovements.concat( oneHoleMovements );
  19145. }
  19146. // Loop bevelSegments, 1 for the front, 1 for the back
  19147. for ( let b = 0; b < bevelSegments; b ++ ) {
  19148. //for ( b = bevelSegments; b > 0; b -- ) {
  19149. const t = b / bevelSegments;
  19150. const z = bevelThickness * Math.cos( t * Math.PI / 2 );
  19151. const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
  19152. // contract shape
  19153. for ( let i = 0, il = contour.length; i < il; i ++ ) {
  19154. const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
  19155. v( vert.x, vert.y, - z );
  19156. }
  19157. // expand holes
  19158. for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
  19159. const ahole = holes[ h ];
  19160. oneHoleMovements = holesMovements[ h ];
  19161. for ( let i = 0, il = ahole.length; i < il; i ++ ) {
  19162. const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
  19163. v( vert.x, vert.y, - z );
  19164. }
  19165. }
  19166. }
  19167. const bs = bevelSize + bevelOffset;
  19168. // Back facing vertices
  19169. for ( let i = 0; i < vlen; i ++ ) {
  19170. const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
  19171. if ( ! extrudeByPath ) {
  19172. v( vert.x, vert.y, 0 );
  19173. } else {
  19174. // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
  19175. normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
  19176. binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
  19177. position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
  19178. v( position2.x, position2.y, position2.z );
  19179. }
  19180. }
  19181. // Add stepped vertices...
  19182. // Including front facing vertices
  19183. for ( let s = 1; s <= steps; s ++ ) {
  19184. for ( let i = 0; i < vlen; i ++ ) {
  19185. const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
  19186. if ( ! extrudeByPath ) {
  19187. v( vert.x, vert.y, depth / steps * s );
  19188. } else {
  19189. // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
  19190. normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
  19191. binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
  19192. position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
  19193. v( position2.x, position2.y, position2.z );
  19194. }
  19195. }
  19196. }
  19197. // Add bevel segments planes
  19198. //for ( b = 1; b <= bevelSegments; b ++ ) {
  19199. for ( let b = bevelSegments - 1; b >= 0; b -- ) {
  19200. const t = b / bevelSegments;
  19201. const z = bevelThickness * Math.cos( t * Math.PI / 2 );
  19202. const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
  19203. // contract shape
  19204. for ( let i = 0, il = contour.length; i < il; i ++ ) {
  19205. const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
  19206. v( vert.x, vert.y, depth + z );
  19207. }
  19208. // expand holes
  19209. for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
  19210. const ahole = holes[ h ];
  19211. oneHoleMovements = holesMovements[ h ];
  19212. for ( let i = 0, il = ahole.length; i < il; i ++ ) {
  19213. const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
  19214. if ( ! extrudeByPath ) {
  19215. v( vert.x, vert.y, depth + z );
  19216. } else {
  19217. v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
  19218. }
  19219. }
  19220. }
  19221. }
  19222. /* Faces */
  19223. // Top and bottom faces
  19224. buildLidFaces();
  19225. // Sides faces
  19226. buildSideFaces();
  19227. ///// Internal functions
  19228. function buildLidFaces() {
  19229. const start = verticesArray.length / 3;
  19230. if ( bevelEnabled ) {
  19231. let layer = 0; // steps + 1
  19232. let offset = vlen * layer;
  19233. // Bottom faces
  19234. for ( let i = 0; i < flen; i ++ ) {
  19235. const face = faces[ i ];
  19236. f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
  19237. }
  19238. layer = steps + bevelSegments * 2;
  19239. offset = vlen * layer;
  19240. // Top faces
  19241. for ( let i = 0; i < flen; i ++ ) {
  19242. const face = faces[ i ];
  19243. f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
  19244. }
  19245. } else {
  19246. // Bottom faces
  19247. for ( let i = 0; i < flen; i ++ ) {
  19248. const face = faces[ i ];
  19249. f3( face[ 2 ], face[ 1 ], face[ 0 ] );
  19250. }
  19251. // Top faces
  19252. for ( let i = 0; i < flen; i ++ ) {
  19253. const face = faces[ i ];
  19254. f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
  19255. }
  19256. }
  19257. scope.addGroup( start, verticesArray.length / 3 - start, 0 );
  19258. }
  19259. // Create faces for the z-sides of the shape
  19260. function buildSideFaces() {
  19261. const start = verticesArray.length / 3;
  19262. let layeroffset = 0;
  19263. sidewalls( contour, layeroffset );
  19264. layeroffset += contour.length;
  19265. for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
  19266. const ahole = holes[ h ];
  19267. sidewalls( ahole, layeroffset );
  19268. //, true
  19269. layeroffset += ahole.length;
  19270. }
  19271. scope.addGroup( start, verticesArray.length / 3 - start, 1 );
  19272. }
  19273. function sidewalls( contour, layeroffset ) {
  19274. let i = contour.length;
  19275. while ( -- i >= 0 ) {
  19276. const j = i;
  19277. let k = i - 1;
  19278. if ( k < 0 ) k = contour.length - 1;
  19279. //console.log('b', i,j, i-1, k,vertices.length);
  19280. for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
  19281. const slen1 = vlen * s;
  19282. const slen2 = vlen * ( s + 1 );
  19283. const a = layeroffset + j + slen1,
  19284. b = layeroffset + k + slen1,
  19285. c = layeroffset + k + slen2,
  19286. d = layeroffset + j + slen2;
  19287. f4( a, b, c, d );
  19288. }
  19289. }
  19290. }
  19291. function v( x, y, z ) {
  19292. placeholder.push( x );
  19293. placeholder.push( y );
  19294. placeholder.push( z );
  19295. }
  19296. function f3( a, b, c ) {
  19297. addVertex( a );
  19298. addVertex( b );
  19299. addVertex( c );
  19300. const nextIndex = verticesArray.length / 3;
  19301. const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
  19302. addUV( uvs[ 0 ] );
  19303. addUV( uvs[ 1 ] );
  19304. addUV( uvs[ 2 ] );
  19305. }
  19306. function f4( a, b, c, d ) {
  19307. addVertex( a );
  19308. addVertex( b );
  19309. addVertex( d );
  19310. addVertex( b );
  19311. addVertex( c );
  19312. addVertex( d );
  19313. const nextIndex = verticesArray.length / 3;
  19314. const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
  19315. addUV( uvs[ 0 ] );
  19316. addUV( uvs[ 1 ] );
  19317. addUV( uvs[ 3 ] );
  19318. addUV( uvs[ 1 ] );
  19319. addUV( uvs[ 2 ] );
  19320. addUV( uvs[ 3 ] );
  19321. }
  19322. function addVertex( index ) {
  19323. verticesArray.push( placeholder[ index * 3 + 0 ] );
  19324. verticesArray.push( placeholder[ index * 3 + 1 ] );
  19325. verticesArray.push( placeholder[ index * 3 + 2 ] );
  19326. }
  19327. function addUV( vector2 ) {
  19328. uvArray.push( vector2.x );
  19329. uvArray.push( vector2.y );
  19330. }
  19331. }
  19332. }
  19333. toJSON() {
  19334. const data = BufferGeometry.prototype.toJSON.call( this );
  19335. const shapes = this.parameters.shapes;
  19336. const options = this.parameters.options;
  19337. return toJSON( shapes, options, data );
  19338. }
  19339. }
  19340. const WorldUVGenerator = {
  19341. generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
  19342. const a_x = vertices[ indexA * 3 ];
  19343. const a_y = vertices[ indexA * 3 + 1 ];
  19344. const b_x = vertices[ indexB * 3 ];
  19345. const b_y = vertices[ indexB * 3 + 1 ];
  19346. const c_x = vertices[ indexC * 3 ];
  19347. const c_y = vertices[ indexC * 3 + 1 ];
  19348. return [
  19349. new Vector2$1( a_x, a_y ),
  19350. new Vector2$1( b_x, b_y ),
  19351. new Vector2$1( c_x, c_y )
  19352. ];
  19353. },
  19354. generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
  19355. const a_x = vertices[ indexA * 3 ];
  19356. const a_y = vertices[ indexA * 3 + 1 ];
  19357. const a_z = vertices[ indexA * 3 + 2 ];
  19358. const b_x = vertices[ indexB * 3 ];
  19359. const b_y = vertices[ indexB * 3 + 1 ];
  19360. const b_z = vertices[ indexB * 3 + 2 ];
  19361. const c_x = vertices[ indexC * 3 ];
  19362. const c_y = vertices[ indexC * 3 + 1 ];
  19363. const c_z = vertices[ indexC * 3 + 2 ];
  19364. const d_x = vertices[ indexD * 3 ];
  19365. const d_y = vertices[ indexD * 3 + 1 ];
  19366. const d_z = vertices[ indexD * 3 + 2 ];
  19367. if ( Math.abs( a_y - b_y ) < 0.01 ) {
  19368. return [
  19369. new Vector2$1( a_x, 1 - a_z ),
  19370. new Vector2$1( b_x, 1 - b_z ),
  19371. new Vector2$1( c_x, 1 - c_z ),
  19372. new Vector2$1( d_x, 1 - d_z )
  19373. ];
  19374. } else {
  19375. return [
  19376. new Vector2$1( a_y, 1 - a_z ),
  19377. new Vector2$1( b_y, 1 - b_z ),
  19378. new Vector2$1( c_y, 1 - c_z ),
  19379. new Vector2$1( d_y, 1 - d_z )
  19380. ];
  19381. }
  19382. }
  19383. };
  19384. function toJSON( shapes, options, data ) {
  19385. data.shapes = [];
  19386. if ( Array.isArray( shapes ) ) {
  19387. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  19388. const shape = shapes[ i ];
  19389. data.shapes.push( shape.uuid );
  19390. }
  19391. } else {
  19392. data.shapes.push( shapes.uuid );
  19393. }
  19394. if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
  19395. return data;
  19396. }
  19397. /**
  19398. * Creates extruded geometry from a path shape.
  19399. *
  19400. * parameters = {
  19401. *
  19402. * curveSegments: <int>, // number of points on the curves
  19403. * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
  19404. * depth: <float>, // Depth to extrude the shape
  19405. *
  19406. * bevelEnabled: <bool>, // turn on bevel
  19407. * bevelThickness: <float>, // how deep into the original shape bevel goes
  19408. * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
  19409. * bevelOffset: <float>, // how far from shape outline does bevel start
  19410. * bevelSegments: <int>, // number of bevel layers
  19411. *
  19412. * extrudePath: <THREE.Curve> // curve to extrude shape along
  19413. *
  19414. * UVGenerator: <Object> // object that provides UV generator functions
  19415. *
  19416. * }
  19417. */
  19418. class ExtrudeGeometry extends Geometry {
  19419. constructor( shapes, options ) {
  19420. super();
  19421. this.type = 'ExtrudeGeometry';
  19422. this.parameters = {
  19423. shapes: shapes,
  19424. options: options
  19425. };
  19426. this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );
  19427. this.mergeVertices();
  19428. }
  19429. toJSON() {
  19430. const data = super.toJSON();
  19431. const shapes = this.parameters.shapes;
  19432. const options = this.parameters.options;
  19433. return toJSON$1( shapes, options, data );
  19434. }
  19435. }
  19436. function toJSON$1( shapes, options, data ) {
  19437. data.shapes = [];
  19438. if ( Array.isArray( shapes ) ) {
  19439. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  19440. const shape = shapes[ i ];
  19441. data.shapes.push( shape.uuid );
  19442. }
  19443. } else {
  19444. data.shapes.push( shapes.uuid );
  19445. }
  19446. if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
  19447. return data;
  19448. }
  19449. class IcosahedronBufferGeometry extends PolyhedronBufferGeometry {
  19450. constructor( radius = 1, detail = 0 ) {
  19451. const t = ( 1 + Math.sqrt( 5 ) ) / 2;
  19452. const vertices = [
  19453. - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
  19454. 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
  19455. t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
  19456. ];
  19457. const indices = [
  19458. 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
  19459. 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
  19460. 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
  19461. 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
  19462. ];
  19463. super( vertices, indices, radius, detail );
  19464. this.type = 'IcosahedronBufferGeometry';
  19465. this.parameters = {
  19466. radius: radius,
  19467. detail: detail
  19468. };
  19469. }
  19470. }
  19471. class IcosahedronGeometry extends Geometry {
  19472. constructor( radius, detail ) {
  19473. super();
  19474. this.type = 'IcosahedronGeometry';
  19475. this.parameters = {
  19476. radius: radius,
  19477. detail: detail
  19478. };
  19479. this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
  19480. this.mergeVertices();
  19481. }
  19482. }
  19483. class LatheBufferGeometry extends BufferGeometry {
  19484. constructor( points, segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {
  19485. super();
  19486. this.type = 'LatheBufferGeometry';
  19487. this.parameters = {
  19488. points: points,
  19489. segments: segments,
  19490. phiStart: phiStart,
  19491. phiLength: phiLength
  19492. };
  19493. segments = Math.floor( segments );
  19494. // clamp phiLength so it's in range of [ 0, 2PI ]
  19495. phiLength = MathUtils.clamp( phiLength, 0, Math.PI * 2 );
  19496. // buffers
  19497. const indices = [];
  19498. const vertices = [];
  19499. const uvs = [];
  19500. // helper variables
  19501. const inverseSegments = 1.0 / segments;
  19502. const vertex = new Vector3();
  19503. const uv = new Vector2$1();
  19504. // generate vertices and uvs
  19505. for ( let i = 0; i <= segments; i ++ ) {
  19506. const phi = phiStart + i * inverseSegments * phiLength;
  19507. const sin = Math.sin( phi );
  19508. const cos = Math.cos( phi );
  19509. for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
  19510. // vertex
  19511. vertex.x = points[ j ].x * sin;
  19512. vertex.y = points[ j ].y;
  19513. vertex.z = points[ j ].x * cos;
  19514. vertices.push( vertex.x, vertex.y, vertex.z );
  19515. // uv
  19516. uv.x = i / segments;
  19517. uv.y = j / ( points.length - 1 );
  19518. uvs.push( uv.x, uv.y );
  19519. }
  19520. }
  19521. // indices
  19522. for ( let i = 0; i < segments; i ++ ) {
  19523. for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
  19524. const base = j + i * points.length;
  19525. const a = base;
  19526. const b = base + points.length;
  19527. const c = base + points.length + 1;
  19528. const d = base + 1;
  19529. // faces
  19530. indices.push( a, b, d );
  19531. indices.push( b, c, d );
  19532. }
  19533. }
  19534. // build geometry
  19535. this.setIndex( indices );
  19536. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  19537. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  19538. // generate normals
  19539. this.computeVertexNormals();
  19540. // if the geometry is closed, we need to average the normals along the seam.
  19541. // because the corresponding vertices are identical (but still have different UVs).
  19542. if ( phiLength === Math.PI * 2 ) {
  19543. const normals = this.attributes.normal.array;
  19544. const n1 = new Vector3();
  19545. const n2 = new Vector3();
  19546. const n = new Vector3();
  19547. // this is the buffer offset for the last line of vertices
  19548. const base = segments * points.length * 3;
  19549. for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) {
  19550. // select the normal of the vertex in the first line
  19551. n1.x = normals[ j + 0 ];
  19552. n1.y = normals[ j + 1 ];
  19553. n1.z = normals[ j + 2 ];
  19554. // select the normal of the vertex in the last line
  19555. n2.x = normals[ base + j + 0 ];
  19556. n2.y = normals[ base + j + 1 ];
  19557. n2.z = normals[ base + j + 2 ];
  19558. // average normals
  19559. n.addVectors( n1, n2 ).normalize();
  19560. // assign the new values to both normals
  19561. normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
  19562. normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
  19563. normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
  19564. }
  19565. }
  19566. }
  19567. }
  19568. class LatheGeometry extends Geometry {
  19569. constructor( points, segments, phiStart, phiLength ) {
  19570. super();
  19571. this.type = 'LatheGeometry';
  19572. this.parameters = {
  19573. points: points,
  19574. segments: segments,
  19575. phiStart: phiStart,
  19576. phiLength: phiLength
  19577. };
  19578. this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
  19579. this.mergeVertices();
  19580. }
  19581. }
  19582. class OctahedronBufferGeometry extends PolyhedronBufferGeometry {
  19583. constructor( radius = 1, detail = 0 ) {
  19584. const vertices = [
  19585. 1, 0, 0, - 1, 0, 0, 0, 1, 0,
  19586. 0, - 1, 0, 0, 0, 1, 0, 0, - 1
  19587. ];
  19588. const indices = [
  19589. 0, 2, 4, 0, 4, 3, 0, 3, 5,
  19590. 0, 5, 2, 1, 2, 5, 1, 5, 3,
  19591. 1, 3, 4, 1, 4, 2
  19592. ];
  19593. super( vertices, indices, radius, detail );
  19594. this.type = 'OctahedronBufferGeometry';
  19595. this.parameters = {
  19596. radius: radius,
  19597. detail: detail
  19598. };
  19599. }
  19600. }
  19601. class OctahedronGeometry extends Geometry {
  19602. constructor( radius, detail ) {
  19603. super();
  19604. this.type = 'OctahedronGeometry';
  19605. this.parameters = {
  19606. radius: radius,
  19607. detail: detail
  19608. };
  19609. this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
  19610. this.mergeVertices();
  19611. }
  19612. }
  19613. /**
  19614. * Parametric Surfaces Geometry
  19615. * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
  19616. */
  19617. function ParametricBufferGeometry( func, slices, stacks ) {
  19618. BufferGeometry.call( this );
  19619. this.type = 'ParametricBufferGeometry';
  19620. this.parameters = {
  19621. func: func,
  19622. slices: slices,
  19623. stacks: stacks
  19624. };
  19625. // buffers
  19626. const indices = [];
  19627. const vertices = [];
  19628. const normals = [];
  19629. const uvs = [];
  19630. const EPS = 0.00001;
  19631. const normal = new Vector3();
  19632. const p0 = new Vector3(), p1 = new Vector3();
  19633. const pu = new Vector3(), pv = new Vector3();
  19634. if ( func.length < 3 ) {
  19635. console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
  19636. }
  19637. // generate vertices, normals and uvs
  19638. const sliceCount = slices + 1;
  19639. for ( let i = 0; i <= stacks; i ++ ) {
  19640. const v = i / stacks;
  19641. for ( let j = 0; j <= slices; j ++ ) {
  19642. const u = j / slices;
  19643. // vertex
  19644. func( u, v, p0 );
  19645. vertices.push( p0.x, p0.y, p0.z );
  19646. // normal
  19647. // approximate tangent vectors via finite differences
  19648. if ( u - EPS >= 0 ) {
  19649. func( u - EPS, v, p1 );
  19650. pu.subVectors( p0, p1 );
  19651. } else {
  19652. func( u + EPS, v, p1 );
  19653. pu.subVectors( p1, p0 );
  19654. }
  19655. if ( v - EPS >= 0 ) {
  19656. func( u, v - EPS, p1 );
  19657. pv.subVectors( p0, p1 );
  19658. } else {
  19659. func( u, v + EPS, p1 );
  19660. pv.subVectors( p1, p0 );
  19661. }
  19662. // cross product of tangent vectors returns surface normal
  19663. normal.crossVectors( pu, pv ).normalize();
  19664. normals.push( normal.x, normal.y, normal.z );
  19665. // uv
  19666. uvs.push( u, v );
  19667. }
  19668. }
  19669. // generate indices
  19670. for ( let i = 0; i < stacks; i ++ ) {
  19671. for ( let j = 0; j < slices; j ++ ) {
  19672. const a = i * sliceCount + j;
  19673. const b = i * sliceCount + j + 1;
  19674. const c = ( i + 1 ) * sliceCount + j + 1;
  19675. const d = ( i + 1 ) * sliceCount + j;
  19676. // faces one and two
  19677. indices.push( a, b, d );
  19678. indices.push( b, c, d );
  19679. }
  19680. }
  19681. // build geometry
  19682. this.setIndex( indices );
  19683. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  19684. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  19685. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  19686. }
  19687. ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
  19688. ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
  19689. /**
  19690. * Parametric Surfaces Geometry
  19691. * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
  19692. */
  19693. function ParametricGeometry( func, slices, stacks ) {
  19694. Geometry.call( this );
  19695. this.type = 'ParametricGeometry';
  19696. this.parameters = {
  19697. func: func,
  19698. slices: slices,
  19699. stacks: stacks
  19700. };
  19701. this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
  19702. this.mergeVertices();
  19703. }
  19704. ParametricGeometry.prototype = Object.create( Geometry.prototype );
  19705. ParametricGeometry.prototype.constructor = ParametricGeometry;
  19706. class PlaneGeometry extends Geometry {
  19707. constructor( width, height, widthSegments, heightSegments ) {
  19708. super();
  19709. this.type = 'PlaneGeometry';
  19710. this.parameters = {
  19711. width: width,
  19712. height: height,
  19713. widthSegments: widthSegments,
  19714. heightSegments: heightSegments
  19715. };
  19716. this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
  19717. this.mergeVertices();
  19718. }
  19719. }
  19720. class PolyhedronGeometry extends Geometry {
  19721. constructor( vertices, indices, radius, detail ) {
  19722. super();
  19723. this.type = 'PolyhedronGeometry';
  19724. this.parameters = {
  19725. vertices: vertices,
  19726. indices: indices,
  19727. radius: radius,
  19728. detail: detail
  19729. };
  19730. this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
  19731. this.mergeVertices();
  19732. }
  19733. }
  19734. class RingBufferGeometry extends BufferGeometry {
  19735. constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 8, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {
  19736. super();
  19737. this.type = 'RingBufferGeometry';
  19738. this.parameters = {
  19739. innerRadius: innerRadius,
  19740. outerRadius: outerRadius,
  19741. thetaSegments: thetaSegments,
  19742. phiSegments: phiSegments,
  19743. thetaStart: thetaStart,
  19744. thetaLength: thetaLength
  19745. };
  19746. thetaSegments = Math.max( 3, thetaSegments );
  19747. phiSegments = Math.max( 1, phiSegments );
  19748. // buffers
  19749. const indices = [];
  19750. const vertices = [];
  19751. const normals = [];
  19752. const uvs = [];
  19753. // some helper variables
  19754. let radius = innerRadius;
  19755. const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
  19756. const vertex = new Vector3();
  19757. const uv = new Vector2$1();
  19758. // generate vertices, normals and uvs
  19759. for ( let j = 0; j <= phiSegments; j ++ ) {
  19760. for ( let i = 0; i <= thetaSegments; i ++ ) {
  19761. // values are generate from the inside of the ring to the outside
  19762. const segment = thetaStart + i / thetaSegments * thetaLength;
  19763. // vertex
  19764. vertex.x = radius * Math.cos( segment );
  19765. vertex.y = radius * Math.sin( segment );
  19766. vertices.push( vertex.x, vertex.y, vertex.z );
  19767. // normal
  19768. normals.push( 0, 0, 1 );
  19769. // uv
  19770. uv.x = ( vertex.x / outerRadius + 1 ) / 2;
  19771. uv.y = ( vertex.y / outerRadius + 1 ) / 2;
  19772. uvs.push( uv.x, uv.y );
  19773. }
  19774. // increase the radius for next row of vertices
  19775. radius += radiusStep;
  19776. }
  19777. // indices
  19778. for ( let j = 0; j < phiSegments; j ++ ) {
  19779. const thetaSegmentLevel = j * ( thetaSegments + 1 );
  19780. for ( let i = 0; i < thetaSegments; i ++ ) {
  19781. const segment = i + thetaSegmentLevel;
  19782. const a = segment;
  19783. const b = segment + thetaSegments + 1;
  19784. const c = segment + thetaSegments + 2;
  19785. const d = segment + 1;
  19786. // faces
  19787. indices.push( a, b, d );
  19788. indices.push( b, c, d );
  19789. }
  19790. }
  19791. // build geometry
  19792. this.setIndex( indices );
  19793. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  19794. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  19795. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  19796. }
  19797. }
  19798. class RingGeometry extends Geometry {
  19799. constructor( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
  19800. super();
  19801. this.type = 'RingGeometry';
  19802. this.parameters = {
  19803. innerRadius: innerRadius,
  19804. outerRadius: outerRadius,
  19805. thetaSegments: thetaSegments,
  19806. phiSegments: phiSegments,
  19807. thetaStart: thetaStart,
  19808. thetaLength: thetaLength
  19809. };
  19810. this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
  19811. this.mergeVertices();
  19812. }
  19813. }
  19814. class ShapeBufferGeometry extends BufferGeometry {
  19815. constructor( shapes, curveSegments = 12 ) {
  19816. super();
  19817. this.type = 'ShapeBufferGeometry';
  19818. this.parameters = {
  19819. shapes: shapes,
  19820. curveSegments: curveSegments
  19821. };
  19822. // buffers
  19823. const indices = [];
  19824. const vertices = [];
  19825. const normals = [];
  19826. const uvs = [];
  19827. // helper variables
  19828. let groupStart = 0;
  19829. let groupCount = 0;
  19830. // allow single and array values for "shapes" parameter
  19831. if ( Array.isArray( shapes ) === false ) {
  19832. addShape( shapes );
  19833. } else {
  19834. for ( let i = 0; i < shapes.length; i ++ ) {
  19835. addShape( shapes[ i ] );
  19836. this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
  19837. groupStart += groupCount;
  19838. groupCount = 0;
  19839. }
  19840. }
  19841. // build geometry
  19842. this.setIndex( indices );
  19843. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  19844. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  19845. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  19846. // helper functions
  19847. function addShape( shape ) {
  19848. const indexOffset = vertices.length / 3;
  19849. const points = shape.extractPoints( curveSegments );
  19850. let shapeVertices = points.shape;
  19851. const shapeHoles = points.holes;
  19852. // check direction of vertices
  19853. if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
  19854. shapeVertices = shapeVertices.reverse();
  19855. }
  19856. for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
  19857. const shapeHole = shapeHoles[ i ];
  19858. if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
  19859. shapeHoles[ i ] = shapeHole.reverse();
  19860. }
  19861. }
  19862. const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
  19863. // join vertices of inner and outer paths to a single array
  19864. for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
  19865. const shapeHole = shapeHoles[ i ];
  19866. shapeVertices = shapeVertices.concat( shapeHole );
  19867. }
  19868. // vertices, normals, uvs
  19869. for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
  19870. const vertex = shapeVertices[ i ];
  19871. vertices.push( vertex.x, vertex.y, 0 );
  19872. normals.push( 0, 0, 1 );
  19873. uvs.push( vertex.x, vertex.y ); // world uvs
  19874. }
  19875. // incides
  19876. for ( let i = 0, l = faces.length; i < l; i ++ ) {
  19877. const face = faces[ i ];
  19878. const a = face[ 0 ] + indexOffset;
  19879. const b = face[ 1 ] + indexOffset;
  19880. const c = face[ 2 ] + indexOffset;
  19881. indices.push( a, b, c );
  19882. groupCount += 3;
  19883. }
  19884. }
  19885. }
  19886. toJSON() {
  19887. const data = BufferGeometry.prototype.toJSON.call( this );
  19888. const shapes = this.parameters.shapes;
  19889. return toJSON$2( shapes, data );
  19890. }
  19891. }
  19892. function toJSON$2( shapes, data ) {
  19893. data.shapes = [];
  19894. if ( Array.isArray( shapes ) ) {
  19895. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  19896. const shape = shapes[ i ];
  19897. data.shapes.push( shape.uuid );
  19898. }
  19899. } else {
  19900. data.shapes.push( shapes.uuid );
  19901. }
  19902. return data;
  19903. }
  19904. class ShapeGeometry extends Geometry {
  19905. constructor( shapes, curveSegments ) {
  19906. super();
  19907. this.type = 'ShapeGeometry';
  19908. if ( typeof curveSegments === 'object' ) {
  19909. console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
  19910. curveSegments = curveSegments.curveSegments;
  19911. }
  19912. this.parameters = {
  19913. shapes: shapes,
  19914. curveSegments: curveSegments
  19915. };
  19916. this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
  19917. this.mergeVertices();
  19918. }
  19919. toJSON() {
  19920. const data = Geometry.prototype.toJSON.call( this );
  19921. const shapes = this.parameters.shapes;
  19922. return toJSON$3( shapes, data );
  19923. }
  19924. }
  19925. function toJSON$3( shapes, data ) {
  19926. data.shapes = [];
  19927. if ( Array.isArray( shapes ) ) {
  19928. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  19929. const shape = shapes[ i ];
  19930. data.shapes.push( shape.uuid );
  19931. }
  19932. } else {
  19933. data.shapes.push( shapes.uuid );
  19934. }
  19935. return data;
  19936. }
  19937. class SphereBufferGeometry extends BufferGeometry {
  19938. constructor( radius = 1, widthSegments = 8, heightSegments = 6, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
  19939. super();
  19940. this.type = 'SphereBufferGeometry';
  19941. this.parameters = {
  19942. radius: radius,
  19943. widthSegments: widthSegments,
  19944. heightSegments: heightSegments,
  19945. phiStart: phiStart,
  19946. phiLength: phiLength,
  19947. thetaStart: thetaStart,
  19948. thetaLength: thetaLength
  19949. };
  19950. widthSegments = Math.max( 3, Math.floor( widthSegments ) );
  19951. heightSegments = Math.max( 2, Math.floor( heightSegments ) );
  19952. const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
  19953. let index = 0;
  19954. const grid = [];
  19955. const vertex = new Vector3();
  19956. const normal = new Vector3();
  19957. // buffers
  19958. const indices = [];
  19959. const vertices = [];
  19960. const normals = [];
  19961. const uvs = [];
  19962. // generate vertices, normals and uvs
  19963. for ( let iy = 0; iy <= heightSegments; iy ++ ) {
  19964. const verticesRow = [];
  19965. const v = iy / heightSegments;
  19966. // special case for the poles
  19967. let uOffset = 0;
  19968. if ( iy == 0 && thetaStart == 0 ) {
  19969. uOffset = 0.5 / widthSegments;
  19970. } else if ( iy == heightSegments && thetaEnd == Math.PI ) {
  19971. uOffset = - 0.5 / widthSegments;
  19972. }
  19973. for ( let ix = 0; ix <= widthSegments; ix ++ ) {
  19974. const u = ix / widthSegments;
  19975. // vertex
  19976. vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
  19977. vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
  19978. vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
  19979. vertices.push( vertex.x, vertex.y, vertex.z );
  19980. // normal
  19981. normal.copy( vertex ).normalize();
  19982. normals.push( normal.x, normal.y, normal.z );
  19983. // uv
  19984. uvs.push( u + uOffset, 1 - v );
  19985. verticesRow.push( index ++ );
  19986. }
  19987. grid.push( verticesRow );
  19988. }
  19989. // indices
  19990. for ( let iy = 0; iy < heightSegments; iy ++ ) {
  19991. for ( let ix = 0; ix < widthSegments; ix ++ ) {
  19992. const a = grid[ iy ][ ix + 1 ];
  19993. const b = grid[ iy ][ ix ];
  19994. const c = grid[ iy + 1 ][ ix ];
  19995. const d = grid[ iy + 1 ][ ix + 1 ];
  19996. if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
  19997. if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
  19998. }
  19999. }
  20000. // build geometry
  20001. this.setIndex( indices );
  20002. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  20003. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  20004. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  20005. }
  20006. }
  20007. class SphereGeometry extends Geometry {
  20008. constructor( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
  20009. super();
  20010. this.type = 'SphereGeometry';
  20011. this.parameters = {
  20012. radius: radius,
  20013. widthSegments: widthSegments,
  20014. heightSegments: heightSegments,
  20015. phiStart: phiStart,
  20016. phiLength: phiLength,
  20017. thetaStart: thetaStart,
  20018. thetaLength: thetaLength
  20019. };
  20020. this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
  20021. this.mergeVertices();
  20022. }
  20023. }
  20024. class TetrahedronBufferGeometry extends PolyhedronBufferGeometry {
  20025. constructor( radius = 1, detail = 0 ) {
  20026. const vertices = [
  20027. 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
  20028. ];
  20029. const indices = [
  20030. 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
  20031. ];
  20032. super( vertices, indices, radius, detail );
  20033. this.type = 'TetrahedronBufferGeometry';
  20034. this.parameters = {
  20035. radius: radius,
  20036. detail: detail
  20037. };
  20038. }
  20039. }
  20040. class TetrahedronGeometry extends Geometry {
  20041. constructor( radius, detail ) {
  20042. super();
  20043. this.type = 'TetrahedronGeometry';
  20044. this.parameters = {
  20045. radius: radius,
  20046. detail: detail
  20047. };
  20048. this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
  20049. this.mergeVertices();
  20050. }
  20051. }
  20052. /**
  20053. * Text = 3D Text
  20054. *
  20055. * parameters = {
  20056. * font: <THREE.Font>, // font
  20057. *
  20058. * size: <float>, // size of the text
  20059. * height: <float>, // thickness to extrude text
  20060. * curveSegments: <int>, // number of points on the curves
  20061. *
  20062. * bevelEnabled: <bool>, // turn on bevel
  20063. * bevelThickness: <float>, // how deep into text bevel goes
  20064. * bevelSize: <float>, // how far from text outline (including bevelOffset) is bevel
  20065. * bevelOffset: <float> // how far from text outline does bevel start
  20066. * }
  20067. */
  20068. class TextBufferGeometry extends ExtrudeBufferGeometry {
  20069. constructor( text, parameters = {} ) {
  20070. const font = parameters.font;
  20071. if ( ! ( font && font.isFont ) ) {
  20072. console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
  20073. return new BufferGeometry();
  20074. }
  20075. const shapes = font.generateShapes( text, parameters.size );
  20076. // translate parameters to ExtrudeGeometry API
  20077. parameters.depth = parameters.height !== undefined ? parameters.height : 50;
  20078. // defaults
  20079. if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
  20080. if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
  20081. if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
  20082. super( shapes, parameters );
  20083. this.type = 'TextBufferGeometry';
  20084. }
  20085. }
  20086. /**
  20087. * Text = 3D Text
  20088. *
  20089. * parameters = {
  20090. * font: <THREE.Font>, // font
  20091. *
  20092. * size: <float>, // size of the text
  20093. * height: <float>, // thickness to extrude text
  20094. * curveSegments: <int>, // number of points on the curves
  20095. *
  20096. * bevelEnabled: <bool>, // turn on bevel
  20097. * bevelThickness: <float>, // how deep into text bevel goes
  20098. * bevelSize: <float>, // how far from text outline (including bevelOffset) is bevel
  20099. * bevelOffset: <float> // how far from text outline does bevel start
  20100. * }
  20101. */
  20102. class TextGeometry extends Geometry {
  20103. constructor( text, parameters ) {
  20104. super();
  20105. this.type = 'TextGeometry';
  20106. this.parameters = {
  20107. text: text,
  20108. parameters: parameters
  20109. };
  20110. this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
  20111. this.mergeVertices();
  20112. }
  20113. }
  20114. class TorusBufferGeometry extends BufferGeometry {
  20115. constructor( radius = 1, tube = 0.4, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2 ) {
  20116. super();
  20117. this.type = 'TorusBufferGeometry';
  20118. this.parameters = {
  20119. radius: radius,
  20120. tube: tube,
  20121. radialSegments: radialSegments,
  20122. tubularSegments: tubularSegments,
  20123. arc: arc
  20124. };
  20125. radialSegments = Math.floor( radialSegments );
  20126. tubularSegments = Math.floor( tubularSegments );
  20127. // buffers
  20128. const indices = [];
  20129. const vertices = [];
  20130. const normals = [];
  20131. const uvs = [];
  20132. // helper variables
  20133. const center = new Vector3();
  20134. const vertex = new Vector3();
  20135. const normal = new Vector3();
  20136. // generate vertices, normals and uvs
  20137. for ( let j = 0; j <= radialSegments; j ++ ) {
  20138. for ( let i = 0; i <= tubularSegments; i ++ ) {
  20139. const u = i / tubularSegments * arc;
  20140. const v = j / radialSegments * Math.PI * 2;
  20141. // vertex
  20142. vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
  20143. vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
  20144. vertex.z = tube * Math.sin( v );
  20145. vertices.push( vertex.x, vertex.y, vertex.z );
  20146. // normal
  20147. center.x = radius * Math.cos( u );
  20148. center.y = radius * Math.sin( u );
  20149. normal.subVectors( vertex, center ).normalize();
  20150. normals.push( normal.x, normal.y, normal.z );
  20151. // uv
  20152. uvs.push( i / tubularSegments );
  20153. uvs.push( j / radialSegments );
  20154. }
  20155. }
  20156. // generate indices
  20157. for ( let j = 1; j <= radialSegments; j ++ ) {
  20158. for ( let i = 1; i <= tubularSegments; i ++ ) {
  20159. // indices
  20160. const a = ( tubularSegments + 1 ) * j + i - 1;
  20161. const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
  20162. const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
  20163. const d = ( tubularSegments + 1 ) * j + i;
  20164. // faces
  20165. indices.push( a, b, d );
  20166. indices.push( b, c, d );
  20167. }
  20168. }
  20169. // build geometry
  20170. this.setIndex( indices );
  20171. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  20172. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  20173. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  20174. }
  20175. }
  20176. class TorusGeometry extends Geometry {
  20177. constructor( radius, tube, radialSegments, tubularSegments, arc ) {
  20178. super();
  20179. this.type = 'TorusGeometry';
  20180. this.parameters = {
  20181. radius: radius,
  20182. tube: tube,
  20183. radialSegments: radialSegments,
  20184. tubularSegments: tubularSegments,
  20185. arc: arc
  20186. };
  20187. this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
  20188. this.mergeVertices();
  20189. }
  20190. }
  20191. class TorusKnotBufferGeometry extends BufferGeometry {
  20192. constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {
  20193. super();
  20194. this.type = 'TorusKnotBufferGeometry';
  20195. this.parameters = {
  20196. radius: radius,
  20197. tube: tube,
  20198. tubularSegments: tubularSegments,
  20199. radialSegments: radialSegments,
  20200. p: p,
  20201. q: q
  20202. };
  20203. tubularSegments = Math.floor( tubularSegments );
  20204. radialSegments = Math.floor( radialSegments );
  20205. // buffers
  20206. const indices = [];
  20207. const vertices = [];
  20208. const normals = [];
  20209. const uvs = [];
  20210. // helper variables
  20211. const vertex = new Vector3();
  20212. const normal = new Vector3();
  20213. const P1 = new Vector3();
  20214. const P2 = new Vector3();
  20215. const B = new Vector3();
  20216. const T = new Vector3();
  20217. const N = new Vector3();
  20218. // generate vertices, normals and uvs
  20219. for ( let i = 0; i <= tubularSegments; ++ i ) {
  20220. // the radian "u" is used to calculate the position on the torus curve of the current tubular segement
  20221. const u = i / tubularSegments * p * Math.PI * 2;
  20222. // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
  20223. // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
  20224. calculatePositionOnCurve( u, p, q, radius, P1 );
  20225. calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
  20226. // calculate orthonormal basis
  20227. T.subVectors( P2, P1 );
  20228. N.addVectors( P2, P1 );
  20229. B.crossVectors( T, N );
  20230. N.crossVectors( B, T );
  20231. // normalize B, N. T can be ignored, we don't use it
  20232. B.normalize();
  20233. N.normalize();
  20234. for ( let j = 0; j <= radialSegments; ++ j ) {
  20235. // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
  20236. // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
  20237. const v = j / radialSegments * Math.PI * 2;
  20238. const cx = - tube * Math.cos( v );
  20239. const cy = tube * Math.sin( v );
  20240. // now calculate the final vertex position.
  20241. // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
  20242. vertex.x = P1.x + ( cx * N.x + cy * B.x );
  20243. vertex.y = P1.y + ( cx * N.y + cy * B.y );
  20244. vertex.z = P1.z + ( cx * N.z + cy * B.z );
  20245. vertices.push( vertex.x, vertex.y, vertex.z );
  20246. // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
  20247. normal.subVectors( vertex, P1 ).normalize();
  20248. normals.push( normal.x, normal.y, normal.z );
  20249. // uv
  20250. uvs.push( i / tubularSegments );
  20251. uvs.push( j / radialSegments );
  20252. }
  20253. }
  20254. // generate indices
  20255. for ( let j = 1; j <= tubularSegments; j ++ ) {
  20256. for ( let i = 1; i <= radialSegments; i ++ ) {
  20257. // indices
  20258. const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
  20259. const b = ( radialSegments + 1 ) * j + ( i - 1 );
  20260. const c = ( radialSegments + 1 ) * j + i;
  20261. const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
  20262. // faces
  20263. indices.push( a, b, d );
  20264. indices.push( b, c, d );
  20265. }
  20266. }
  20267. // build geometry
  20268. this.setIndex( indices );
  20269. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  20270. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  20271. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  20272. // this function calculates the current position on the torus curve
  20273. function calculatePositionOnCurve( u, p, q, radius, position ) {
  20274. const cu = Math.cos( u );
  20275. const su = Math.sin( u );
  20276. const quOverP = q / p * u;
  20277. const cs = Math.cos( quOverP );
  20278. position.x = radius * ( 2 + cs ) * 0.5 * cu;
  20279. position.y = radius * ( 2 + cs ) * su * 0.5;
  20280. position.z = radius * Math.sin( quOverP ) * 0.5;
  20281. }
  20282. }
  20283. }
  20284. class TorusKnotGeometry extends Geometry {
  20285. constructor( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
  20286. super();
  20287. this.type = 'TorusKnotGeometry';
  20288. this.parameters = {
  20289. radius: radius,
  20290. tube: tube,
  20291. tubularSegments: tubularSegments,
  20292. radialSegments: radialSegments,
  20293. p: p,
  20294. q: q
  20295. };
  20296. if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
  20297. this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
  20298. this.mergeVertices();
  20299. }
  20300. }
  20301. class TubeBufferGeometry extends BufferGeometry {
  20302. constructor( path, tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {
  20303. super();
  20304. this.type = 'TubeBufferGeometry';
  20305. this.parameters = {
  20306. path: path,
  20307. tubularSegments: tubularSegments,
  20308. radius: radius,
  20309. radialSegments: radialSegments,
  20310. closed: closed
  20311. };
  20312. const frames = path.computeFrenetFrames( tubularSegments, closed );
  20313. // expose internals
  20314. this.tangents = frames.tangents;
  20315. this.normals = frames.normals;
  20316. this.binormals = frames.binormals;
  20317. // helper variables
  20318. const vertex = new Vector3();
  20319. const normal = new Vector3();
  20320. const uv = new Vector2$1();
  20321. let P = new Vector3();
  20322. // buffer
  20323. const vertices = [];
  20324. const normals = [];
  20325. const uvs = [];
  20326. const indices = [];
  20327. // create buffer data
  20328. generateBufferData();
  20329. // build geometry
  20330. this.setIndex( indices );
  20331. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  20332. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  20333. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  20334. // functions
  20335. function generateBufferData() {
  20336. for ( let i = 0; i < tubularSegments; i ++ ) {
  20337. generateSegment( i );
  20338. }
  20339. // if the geometry is not closed, generate the last row of vertices and normals
  20340. // at the regular position on the given path
  20341. //
  20342. // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
  20343. generateSegment( ( closed === false ) ? tubularSegments : 0 );
  20344. // uvs are generated in a separate function.
  20345. // this makes it easy compute correct values for closed geometries
  20346. generateUVs();
  20347. // finally create faces
  20348. generateIndices();
  20349. }
  20350. function generateSegment( i ) {
  20351. // we use getPointAt to sample evenly distributed points from the given path
  20352. P = path.getPointAt( i / tubularSegments, P );
  20353. // retrieve corresponding normal and binormal
  20354. const N = frames.normals[ i ];
  20355. const B = frames.binormals[ i ];
  20356. // generate normals and vertices for the current segment
  20357. for ( let j = 0; j <= radialSegments; j ++ ) {
  20358. const v = j / radialSegments * Math.PI * 2;
  20359. const sin = Math.sin( v );
  20360. const cos = - Math.cos( v );
  20361. // normal
  20362. normal.x = ( cos * N.x + sin * B.x );
  20363. normal.y = ( cos * N.y + sin * B.y );
  20364. normal.z = ( cos * N.z + sin * B.z );
  20365. normal.normalize();
  20366. normals.push( normal.x, normal.y, normal.z );
  20367. // vertex
  20368. vertex.x = P.x + radius * normal.x;
  20369. vertex.y = P.y + radius * normal.y;
  20370. vertex.z = P.z + radius * normal.z;
  20371. vertices.push( vertex.x, vertex.y, vertex.z );
  20372. }
  20373. }
  20374. function generateIndices() {
  20375. for ( let j = 1; j <= tubularSegments; j ++ ) {
  20376. for ( let i = 1; i <= radialSegments; i ++ ) {
  20377. const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
  20378. const b = ( radialSegments + 1 ) * j + ( i - 1 );
  20379. const c = ( radialSegments + 1 ) * j + i;
  20380. const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
  20381. // faces
  20382. indices.push( a, b, d );
  20383. indices.push( b, c, d );
  20384. }
  20385. }
  20386. }
  20387. function generateUVs() {
  20388. for ( let i = 0; i <= tubularSegments; i ++ ) {
  20389. for ( let j = 0; j <= radialSegments; j ++ ) {
  20390. uv.x = i / tubularSegments;
  20391. uv.y = j / radialSegments;
  20392. uvs.push( uv.x, uv.y );
  20393. }
  20394. }
  20395. }
  20396. }
  20397. toJSON() {
  20398. const data = BufferGeometry.prototype.toJSON.call( this );
  20399. data.path = this.parameters.path.toJSON();
  20400. return data;
  20401. }
  20402. }
  20403. class TubeGeometry extends Geometry {
  20404. constructor( path, tubularSegments, radius, radialSegments, closed, taper ) {
  20405. super();
  20406. this.type = 'TubeGeometry';
  20407. this.parameters = {
  20408. path: path,
  20409. tubularSegments: tubularSegments,
  20410. radius: radius,
  20411. radialSegments: radialSegments,
  20412. closed: closed
  20413. };
  20414. if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
  20415. const bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
  20416. // expose internals
  20417. this.tangents = bufferGeometry.tangents;
  20418. this.normals = bufferGeometry.normals;
  20419. this.binormals = bufferGeometry.binormals;
  20420. // create geometry
  20421. this.fromBufferGeometry( bufferGeometry );
  20422. this.mergeVertices();
  20423. }
  20424. }
  20425. class WireframeGeometry extends BufferGeometry {
  20426. constructor( geometry ) {
  20427. super();
  20428. this.type = 'WireframeGeometry';
  20429. // buffer
  20430. const vertices = [];
  20431. // helper variables
  20432. const edge = [ 0, 0 ], edges = {};
  20433. const keys = [ 'a', 'b', 'c' ];
  20434. // different logic for Geometry and BufferGeometry
  20435. if ( geometry && geometry.isGeometry ) {
  20436. // create a data structure that contains all edges without duplicates
  20437. const faces = geometry.faces;
  20438. for ( let i = 0, l = faces.length; i < l; i ++ ) {
  20439. const face = faces[ i ];
  20440. for ( let j = 0; j < 3; j ++ ) {
  20441. const edge1 = face[ keys[ j ] ];
  20442. const edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
  20443. edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
  20444. edge[ 1 ] = Math.max( edge1, edge2 );
  20445. const key = edge[ 0 ] + ',' + edge[ 1 ];
  20446. if ( edges[ key ] === undefined ) {
  20447. edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
  20448. }
  20449. }
  20450. }
  20451. // generate vertices
  20452. for ( const key in edges ) {
  20453. const e = edges[ key ];
  20454. let vertex = geometry.vertices[ e.index1 ];
  20455. vertices.push( vertex.x, vertex.y, vertex.z );
  20456. vertex = geometry.vertices[ e.index2 ];
  20457. vertices.push( vertex.x, vertex.y, vertex.z );
  20458. }
  20459. } else if ( geometry && geometry.isBufferGeometry ) {
  20460. const vertex = new Vector3();
  20461. if ( geometry.index !== null ) {
  20462. // indexed BufferGeometry
  20463. const position = geometry.attributes.position;
  20464. const indices = geometry.index;
  20465. let groups = geometry.groups;
  20466. if ( groups.length === 0 ) {
  20467. groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
  20468. }
  20469. // create a data structure that contains all eges without duplicates
  20470. for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
  20471. const group = groups[ o ];
  20472. const start = group.start;
  20473. const count = group.count;
  20474. for ( let i = start, l = ( start + count ); i < l; i += 3 ) {
  20475. for ( let j = 0; j < 3; j ++ ) {
  20476. const edge1 = indices.getX( i + j );
  20477. const edge2 = indices.getX( i + ( j + 1 ) % 3 );
  20478. edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
  20479. edge[ 1 ] = Math.max( edge1, edge2 );
  20480. const key = edge[ 0 ] + ',' + edge[ 1 ];
  20481. if ( edges[ key ] === undefined ) {
  20482. edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
  20483. }
  20484. }
  20485. }
  20486. }
  20487. // generate vertices
  20488. for ( const key in edges ) {
  20489. const e = edges[ key ];
  20490. vertex.fromBufferAttribute( position, e.index1 );
  20491. vertices.push( vertex.x, vertex.y, vertex.z );
  20492. vertex.fromBufferAttribute( position, e.index2 );
  20493. vertices.push( vertex.x, vertex.y, vertex.z );
  20494. }
  20495. } else {
  20496. // non-indexed BufferGeometry
  20497. const position = geometry.attributes.position;
  20498. for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
  20499. for ( let j = 0; j < 3; j ++ ) {
  20500. // three edges per triangle, an edge is represented as (index1, index2)
  20501. // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
  20502. const index1 = 3 * i + j;
  20503. vertex.fromBufferAttribute( position, index1 );
  20504. vertices.push( vertex.x, vertex.y, vertex.z );
  20505. const index2 = 3 * i + ( ( j + 1 ) % 3 );
  20506. vertex.fromBufferAttribute( position, index2 );
  20507. vertices.push( vertex.x, vertex.y, vertex.z );
  20508. }
  20509. }
  20510. }
  20511. }
  20512. // build geometry
  20513. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  20514. }
  20515. }
  20516. var Geometries = /*#__PURE__*/Object.freeze({
  20517. __proto__: null,
  20518. BoxGeometry: BoxGeometry,
  20519. BoxBufferGeometry: BoxBufferGeometry,
  20520. CircleGeometry: CircleGeometry,
  20521. CircleBufferGeometry: CircleBufferGeometry,
  20522. ConeGeometry: ConeGeometry,
  20523. ConeBufferGeometry: ConeBufferGeometry,
  20524. CylinderGeometry: CylinderGeometry,
  20525. CylinderBufferGeometry: CylinderBufferGeometry,
  20526. DodecahedronGeometry: DodecahedronGeometry,
  20527. DodecahedronBufferGeometry: DodecahedronBufferGeometry,
  20528. EdgesGeometry: EdgesGeometry,
  20529. ExtrudeGeometry: ExtrudeGeometry,
  20530. ExtrudeBufferGeometry: ExtrudeBufferGeometry,
  20531. IcosahedronGeometry: IcosahedronGeometry,
  20532. IcosahedronBufferGeometry: IcosahedronBufferGeometry,
  20533. LatheGeometry: LatheGeometry,
  20534. LatheBufferGeometry: LatheBufferGeometry,
  20535. OctahedronGeometry: OctahedronGeometry,
  20536. OctahedronBufferGeometry: OctahedronBufferGeometry,
  20537. ParametricGeometry: ParametricGeometry,
  20538. ParametricBufferGeometry: ParametricBufferGeometry,
  20539. PlaneGeometry: PlaneGeometry,
  20540. PlaneBufferGeometry: PlaneBufferGeometry,
  20541. PolyhedronGeometry: PolyhedronGeometry,
  20542. PolyhedronBufferGeometry: PolyhedronBufferGeometry,
  20543. RingGeometry: RingGeometry,
  20544. RingBufferGeometry: RingBufferGeometry,
  20545. ShapeGeometry: ShapeGeometry,
  20546. ShapeBufferGeometry: ShapeBufferGeometry,
  20547. SphereGeometry: SphereGeometry,
  20548. SphereBufferGeometry: SphereBufferGeometry,
  20549. TetrahedronGeometry: TetrahedronGeometry,
  20550. TetrahedronBufferGeometry: TetrahedronBufferGeometry,
  20551. TextGeometry: TextGeometry,
  20552. TextBufferGeometry: TextBufferGeometry,
  20553. TorusGeometry: TorusGeometry,
  20554. TorusBufferGeometry: TorusBufferGeometry,
  20555. TorusKnotGeometry: TorusKnotGeometry,
  20556. TorusKnotBufferGeometry: TorusKnotBufferGeometry,
  20557. TubeGeometry: TubeGeometry,
  20558. TubeBufferGeometry: TubeBufferGeometry,
  20559. WireframeGeometry: WireframeGeometry
  20560. });
  20561. /**
  20562. * parameters = {
  20563. * color: <THREE.Color>
  20564. * }
  20565. */
  20566. function ShadowMaterial( parameters ) {
  20567. Material.call( this );
  20568. this.type = 'ShadowMaterial';
  20569. this.color = new Color( 0x000000 );
  20570. this.transparent = true;
  20571. this.setValues( parameters );
  20572. }
  20573. ShadowMaterial.prototype = Object.create( Material.prototype );
  20574. ShadowMaterial.prototype.constructor = ShadowMaterial;
  20575. ShadowMaterial.prototype.isShadowMaterial = true;
  20576. ShadowMaterial.prototype.copy = function ( source ) {
  20577. Material.prototype.copy.call( this, source );
  20578. this.color.copy( source.color );
  20579. return this;
  20580. };
  20581. function RawShaderMaterial( parameters ) {
  20582. ShaderMaterial.call( this, parameters );
  20583. this.type = 'RawShaderMaterial';
  20584. }
  20585. RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
  20586. RawShaderMaterial.prototype.constructor = RawShaderMaterial;
  20587. RawShaderMaterial.prototype.isRawShaderMaterial = true;
  20588. /**
  20589. * parameters = {
  20590. * color: <hex>,
  20591. * roughness: <float>,
  20592. * metalness: <float>,
  20593. * opacity: <float>,
  20594. *
  20595. * map: new THREE.Texture( <Image> ),
  20596. *
  20597. * lightMap: new THREE.Texture( <Image> ),
  20598. * lightMapIntensity: <float>
  20599. *
  20600. * aoMap: new THREE.Texture( <Image> ),
  20601. * aoMapIntensity: <float>
  20602. *
  20603. * emissive: <hex>,
  20604. * emissiveIntensity: <float>
  20605. * emissiveMap: new THREE.Texture( <Image> ),
  20606. *
  20607. * bumpMap: new THREE.Texture( <Image> ),
  20608. * bumpScale: <float>,
  20609. *
  20610. * normalMap: new THREE.Texture( <Image> ),
  20611. * normalMapType: THREE.TangentSpaceNormalMap,
  20612. * normalScale: <Vector2>,
  20613. *
  20614. * displacementMap: new THREE.Texture( <Image> ),
  20615. * displacementScale: <float>,
  20616. * displacementBias: <float>,
  20617. *
  20618. * roughnessMap: new THREE.Texture( <Image> ),
  20619. *
  20620. * metalnessMap: new THREE.Texture( <Image> ),
  20621. *
  20622. * alphaMap: new THREE.Texture( <Image> ),
  20623. *
  20624. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  20625. * envMapIntensity: <float>
  20626. *
  20627. * refractionRatio: <float>,
  20628. *
  20629. * wireframe: <boolean>,
  20630. * wireframelineWidth: <float>,
  20631. *
  20632. * skinning: <bool>,
  20633. * morphTargets: <bool>,
  20634. * morphNormals: <bool>
  20635. * }
  20636. */
  20637. function MeshStandardMaterial( parameters ) {
  20638. Material.call( this );
  20639. this.defines = { 'STANDARD': '' };
  20640. this.type = 'MeshStandardMaterial';
  20641. this.color = new Color( 0xffffff ); // diffuse
  20642. this.roughness = 1.0;
  20643. this.metalness = 0.0;
  20644. this.map = null;
  20645. this.lightMap = null;
  20646. this.lightMapIntensity = 1.0;
  20647. this.aoMap = null;
  20648. this.aoMapIntensity = 1.0;
  20649. this.emissive = new Color( 0x000000 );
  20650. this.emissiveIntensity = 1.0;
  20651. this.emissiveMap = null;
  20652. this.bumpMap = null;
  20653. this.bumpScale = 1;
  20654. this.normalMap = null;
  20655. this.normalMapType = TangentSpaceNormalMap;
  20656. this.normalScale = new Vector2$1( 1, 1 );
  20657. this.displacementMap = null;
  20658. this.displacementScale = 1;
  20659. this.displacementBias = 0;
  20660. this.roughnessMap = null;
  20661. this.metalnessMap = null;
  20662. this.alphaMap = null;
  20663. this.envMap = null;
  20664. this.envMapIntensity = 1.0;
  20665. this.refractionRatio = 0.98;
  20666. this.wireframe = false;
  20667. this.wireframelineWidth = 1;
  20668. this.wireframeLinecap = 'round';
  20669. this.wireframeLinejoin = 'round';
  20670. this.skinning = false;
  20671. this.morphTargets = false;
  20672. this.morphNormals = false;
  20673. this.vertexTangents = false;
  20674. this.setValues( parameters );
  20675. }
  20676. MeshStandardMaterial.prototype = Object.create( Material.prototype );
  20677. MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
  20678. MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
  20679. MeshStandardMaterial.prototype.copy = function ( source ) {
  20680. Material.prototype.copy.call( this, source );
  20681. this.defines = { 'STANDARD': '' };
  20682. this.color.copy( source.color );
  20683. this.roughness = source.roughness;
  20684. this.metalness = source.metalness;
  20685. this.map = source.map;
  20686. this.lightMap = source.lightMap;
  20687. this.lightMapIntensity = source.lightMapIntensity;
  20688. this.aoMap = source.aoMap;
  20689. this.aoMapIntensity = source.aoMapIntensity;
  20690. this.emissive.copy( source.emissive );
  20691. this.emissiveMap = source.emissiveMap;
  20692. this.emissiveIntensity = source.emissiveIntensity;
  20693. this.bumpMap = source.bumpMap;
  20694. this.bumpScale = source.bumpScale;
  20695. this.normalMap = source.normalMap;
  20696. this.normalMapType = source.normalMapType;
  20697. this.normalScale.copy( source.normalScale );
  20698. this.displacementMap = source.displacementMap;
  20699. this.displacementScale = source.displacementScale;
  20700. this.displacementBias = source.displacementBias;
  20701. this.roughnessMap = source.roughnessMap;
  20702. this.metalnessMap = source.metalnessMap;
  20703. this.alphaMap = source.alphaMap;
  20704. this.envMap = source.envMap;
  20705. this.envMapIntensity = source.envMapIntensity;
  20706. this.refractionRatio = source.refractionRatio;
  20707. this.wireframe = source.wireframe;
  20708. this.wireframelineWidth = source.wireframelineWidth;
  20709. this.wireframeLinecap = source.wireframeLinecap;
  20710. this.wireframeLinejoin = source.wireframeLinejoin;
  20711. this.skinning = source.skinning;
  20712. this.morphTargets = source.morphTargets;
  20713. this.morphNormals = source.morphNormals;
  20714. this.vertexTangents = source.vertexTangents;
  20715. return this;
  20716. };
  20717. /**
  20718. * parameters = {
  20719. * clearcoat: <float>,
  20720. * clearcoatMap: new THREE.Texture( <Image> ),
  20721. * clearcoatRoughness: <float>,
  20722. * clearcoatRoughnessMap: new THREE.Texture( <Image> ),
  20723. * clearcoatNormalScale: <Vector2>,
  20724. * clearcoatNormalMap: new THREE.Texture( <Image> ),
  20725. *
  20726. * reflectivity: <float>,
  20727. * ior: <float>,
  20728. *
  20729. * sheen: <Color>,
  20730. *
  20731. * transmission: <float>,
  20732. * transmissionMap: new THREE.Texture( <Image> )
  20733. * }
  20734. */
  20735. function MeshPhysicalMaterial( parameters ) {
  20736. MeshStandardMaterial.call( this );
  20737. this.defines = {
  20738. 'STANDARD': '',
  20739. 'PHYSICAL': ''
  20740. };
  20741. this.type = 'MeshPhysicalMaterial';
  20742. this.clearcoat = 0.0;
  20743. this.clearcoatMap = null;
  20744. this.clearcoatRoughness = 0.0;
  20745. this.clearcoatRoughnessMap = null;
  20746. this.clearcoatNormalScale = new Vector2$1( 1, 1 );
  20747. this.clearcoatNormalMap = null;
  20748. this.reflectivity = 0.5; // maps to F0 = 0.04
  20749. Object.defineProperty( this, 'ior', {
  20750. get: function () {
  20751. return ( 1 + 0.4 * this.reflectivity ) / ( 1 - 0.4 * this.reflectivity );
  20752. },
  20753. set: function ( ior ) {
  20754. this.reflectivity = MathUtils.clamp( 2.5 * ( ior - 1 ) / ( ior + 1 ), 0, 1 );
  20755. }
  20756. } );
  20757. this.sheen = null; // null will disable sheen bsdf
  20758. this.transmission = 0.0;
  20759. this.transmissionMap = null;
  20760. this.setValues( parameters );
  20761. }
  20762. MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
  20763. MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
  20764. MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
  20765. MeshPhysicalMaterial.prototype.copy = function ( source ) {
  20766. MeshStandardMaterial.prototype.copy.call( this, source );
  20767. this.defines = {
  20768. 'STANDARD': '',
  20769. 'PHYSICAL': ''
  20770. };
  20771. this.clearcoat = source.clearcoat;
  20772. this.clearcoatMap = source.clearcoatMap;
  20773. this.clearcoatRoughness = source.clearcoatRoughness;
  20774. this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
  20775. this.clearcoatNormalMap = source.clearcoatNormalMap;
  20776. this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
  20777. this.reflectivity = source.reflectivity;
  20778. if ( source.sheen ) {
  20779. this.sheen = ( this.sheen || new Color() ).copy( source.sheen );
  20780. } else {
  20781. this.sheen = null;
  20782. }
  20783. this.transmission = source.transmission;
  20784. this.transmissionMap = source.transmissionMap;
  20785. return this;
  20786. };
  20787. /**
  20788. * parameters = {
  20789. * color: <hex>,
  20790. * specular: <hex>,
  20791. * shininess: <float>,
  20792. * opacity: <float>,
  20793. *
  20794. * map: new THREE.Texture( <Image> ),
  20795. *
  20796. * lightMap: new THREE.Texture( <Image> ),
  20797. * lightMapIntensity: <float>
  20798. *
  20799. * aoMap: new THREE.Texture( <Image> ),
  20800. * aoMapIntensity: <float>
  20801. *
  20802. * emissive: <hex>,
  20803. * emissiveIntensity: <float>
  20804. * emissiveMap: new THREE.Texture( <Image> ),
  20805. *
  20806. * bumpMap: new THREE.Texture( <Image> ),
  20807. * bumpScale: <float>,
  20808. *
  20809. * normalMap: new THREE.Texture( <Image> ),
  20810. * normalMapType: THREE.TangentSpaceNormalMap,
  20811. * normalScale: <Vector2>,
  20812. *
  20813. * displacementMap: new THREE.Texture( <Image> ),
  20814. * displacementScale: <float>,
  20815. * displacementBias: <float>,
  20816. *
  20817. * specularMap: new THREE.Texture( <Image> ),
  20818. *
  20819. * alphaMap: new THREE.Texture( <Image> ),
  20820. *
  20821. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  20822. * combine: THREE.MultiplyOperation,
  20823. * reflectivity: <float>,
  20824. * refractionRatio: <float>,
  20825. *
  20826. * wireframe: <boolean>,
  20827. * wireframelineWidth: <float>,
  20828. *
  20829. * skinning: <bool>,
  20830. * morphTargets: <bool>,
  20831. * morphNormals: <bool>
  20832. * }
  20833. */
  20834. function MeshPhongMaterial( parameters ) {
  20835. Material.call( this );
  20836. this.type = 'MeshPhongMaterial';
  20837. this.color = new Color( 0xffffff ); // diffuse
  20838. this.specular = new Color( 0x111111 );
  20839. this.shininess = 30;
  20840. this.map = null;
  20841. this.lightMap = null;
  20842. this.lightMapIntensity = 1.0;
  20843. this.aoMap = null;
  20844. this.aoMapIntensity = 1.0;
  20845. this.emissive = new Color( 0x000000 );
  20846. this.emissiveIntensity = 1.0;
  20847. this.emissiveMap = null;
  20848. this.bumpMap = null;
  20849. this.bumpScale = 1;
  20850. this.normalMap = null;
  20851. this.normalMapType = TangentSpaceNormalMap;
  20852. this.normalScale = new Vector2$1( 1, 1 );
  20853. this.displacementMap = null;
  20854. this.displacementScale = 1;
  20855. this.displacementBias = 0;
  20856. this.specularMap = null;
  20857. this.alphaMap = null;
  20858. this.envMap = null;
  20859. this.combine = MultiplyOperation;
  20860. this.reflectivity = 1;
  20861. this.refractionRatio = 0.98;
  20862. this.wireframe = false;
  20863. this.wireframelineWidth = 1;
  20864. this.wireframeLinecap = 'round';
  20865. this.wireframeLinejoin = 'round';
  20866. this.skinning = false;
  20867. this.morphTargets = false;
  20868. this.morphNormals = false;
  20869. this.setValues( parameters );
  20870. }
  20871. MeshPhongMaterial.prototype = Object.create( Material.prototype );
  20872. MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
  20873. MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
  20874. MeshPhongMaterial.prototype.copy = function ( source ) {
  20875. Material.prototype.copy.call( this, source );
  20876. this.color.copy( source.color );
  20877. this.specular.copy( source.specular );
  20878. this.shininess = source.shininess;
  20879. this.map = source.map;
  20880. this.lightMap = source.lightMap;
  20881. this.lightMapIntensity = source.lightMapIntensity;
  20882. this.aoMap = source.aoMap;
  20883. this.aoMapIntensity = source.aoMapIntensity;
  20884. this.emissive.copy( source.emissive );
  20885. this.emissiveMap = source.emissiveMap;
  20886. this.emissiveIntensity = source.emissiveIntensity;
  20887. this.bumpMap = source.bumpMap;
  20888. this.bumpScale = source.bumpScale;
  20889. this.normalMap = source.normalMap;
  20890. this.normalMapType = source.normalMapType;
  20891. this.normalScale.copy( source.normalScale );
  20892. this.displacementMap = source.displacementMap;
  20893. this.displacementScale = source.displacementScale;
  20894. this.displacementBias = source.displacementBias;
  20895. this.specularMap = source.specularMap;
  20896. this.alphaMap = source.alphaMap;
  20897. this.envMap = source.envMap;
  20898. this.combine = source.combine;
  20899. this.reflectivity = source.reflectivity;
  20900. this.refractionRatio = source.refractionRatio;
  20901. this.wireframe = source.wireframe;
  20902. this.wireframelineWidth = source.wireframelineWidth;
  20903. this.wireframeLinecap = source.wireframeLinecap;
  20904. this.wireframeLinejoin = source.wireframeLinejoin;
  20905. this.skinning = source.skinning;
  20906. this.morphTargets = source.morphTargets;
  20907. this.morphNormals = source.morphNormals;
  20908. return this;
  20909. };
  20910. /**
  20911. * parameters = {
  20912. * color: <hex>,
  20913. *
  20914. * map: new THREE.Texture( <Image> ),
  20915. * gradientMap: new THREE.Texture( <Image> ),
  20916. *
  20917. * lightMap: new THREE.Texture( <Image> ),
  20918. * lightMapIntensity: <float>
  20919. *
  20920. * aoMap: new THREE.Texture( <Image> ),
  20921. * aoMapIntensity: <float>
  20922. *
  20923. * emissive: <hex>,
  20924. * emissiveIntensity: <float>
  20925. * emissiveMap: new THREE.Texture( <Image> ),
  20926. *
  20927. * bumpMap: new THREE.Texture( <Image> ),
  20928. * bumpScale: <float>,
  20929. *
  20930. * normalMap: new THREE.Texture( <Image> ),
  20931. * normalMapType: THREE.TangentSpaceNormalMap,
  20932. * normalScale: <Vector2>,
  20933. *
  20934. * displacementMap: new THREE.Texture( <Image> ),
  20935. * displacementScale: <float>,
  20936. * displacementBias: <float>,
  20937. *
  20938. * alphaMap: new THREE.Texture( <Image> ),
  20939. *
  20940. * wireframe: <boolean>,
  20941. * wireframelineWidth: <float>,
  20942. *
  20943. * skinning: <bool>,
  20944. * morphTargets: <bool>,
  20945. * morphNormals: <bool>
  20946. * }
  20947. */
  20948. function MeshToonMaterial( parameters ) {
  20949. Material.call( this );
  20950. this.defines = { 'TOON': '' };
  20951. this.type = 'MeshToonMaterial';
  20952. this.color = new Color( 0xffffff );
  20953. this.map = null;
  20954. this.gradientMap = null;
  20955. this.lightMap = null;
  20956. this.lightMapIntensity = 1.0;
  20957. this.aoMap = null;
  20958. this.aoMapIntensity = 1.0;
  20959. this.emissive = new Color( 0x000000 );
  20960. this.emissiveIntensity = 1.0;
  20961. this.emissiveMap = null;
  20962. this.bumpMap = null;
  20963. this.bumpScale = 1;
  20964. this.normalMap = null;
  20965. this.normalMapType = TangentSpaceNormalMap;
  20966. this.normalScale = new Vector2$1( 1, 1 );
  20967. this.displacementMap = null;
  20968. this.displacementScale = 1;
  20969. this.displacementBias = 0;
  20970. this.alphaMap = null;
  20971. this.wireframe = false;
  20972. this.wireframelineWidth = 1;
  20973. this.wireframeLinecap = 'round';
  20974. this.wireframeLinejoin = 'round';
  20975. this.skinning = false;
  20976. this.morphTargets = false;
  20977. this.morphNormals = false;
  20978. this.setValues( parameters );
  20979. }
  20980. MeshToonMaterial.prototype = Object.create( Material.prototype );
  20981. MeshToonMaterial.prototype.constructor = MeshToonMaterial;
  20982. MeshToonMaterial.prototype.isMeshToonMaterial = true;
  20983. MeshToonMaterial.prototype.copy = function ( source ) {
  20984. Material.prototype.copy.call( this, source );
  20985. this.color.copy( source.color );
  20986. this.map = source.map;
  20987. this.gradientMap = source.gradientMap;
  20988. this.lightMap = source.lightMap;
  20989. this.lightMapIntensity = source.lightMapIntensity;
  20990. this.aoMap = source.aoMap;
  20991. this.aoMapIntensity = source.aoMapIntensity;
  20992. this.emissive.copy( source.emissive );
  20993. this.emissiveMap = source.emissiveMap;
  20994. this.emissiveIntensity = source.emissiveIntensity;
  20995. this.bumpMap = source.bumpMap;
  20996. this.bumpScale = source.bumpScale;
  20997. this.normalMap = source.normalMap;
  20998. this.normalMapType = source.normalMapType;
  20999. this.normalScale.copy( source.normalScale );
  21000. this.displacementMap = source.displacementMap;
  21001. this.displacementScale = source.displacementScale;
  21002. this.displacementBias = source.displacementBias;
  21003. this.alphaMap = source.alphaMap;
  21004. this.wireframe = source.wireframe;
  21005. this.wireframelineWidth = source.wireframelineWidth;
  21006. this.wireframeLinecap = source.wireframeLinecap;
  21007. this.wireframeLinejoin = source.wireframeLinejoin;
  21008. this.skinning = source.skinning;
  21009. this.morphTargets = source.morphTargets;
  21010. this.morphNormals = source.morphNormals;
  21011. return this;
  21012. };
  21013. /**
  21014. * parameters = {
  21015. * opacity: <float>,
  21016. *
  21017. * bumpMap: new THREE.Texture( <Image> ),
  21018. * bumpScale: <float>,
  21019. *
  21020. * normalMap: new THREE.Texture( <Image> ),
  21021. * normalMapType: THREE.TangentSpaceNormalMap,
  21022. * normalScale: <Vector2>,
  21023. *
  21024. * displacementMap: new THREE.Texture( <Image> ),
  21025. * displacementScale: <float>,
  21026. * displacementBias: <float>,
  21027. *
  21028. * wireframe: <boolean>,
  21029. * wireframelineWidth: <float>
  21030. *
  21031. * skinning: <bool>,
  21032. * morphTargets: <bool>,
  21033. * morphNormals: <bool>
  21034. * }
  21035. */
  21036. function MeshNormalMaterial( parameters ) {
  21037. Material.call( this );
  21038. this.type = 'MeshNormalMaterial';
  21039. this.bumpMap = null;
  21040. this.bumpScale = 1;
  21041. this.normalMap = null;
  21042. this.normalMapType = TangentSpaceNormalMap;
  21043. this.normalScale = new Vector2$1( 1, 1 );
  21044. this.displacementMap = null;
  21045. this.displacementScale = 1;
  21046. this.displacementBias = 0;
  21047. this.wireframe = false;
  21048. this.wireframelineWidth = 1;
  21049. this.fog = false;
  21050. this.skinning = false;
  21051. this.morphTargets = false;
  21052. this.morphNormals = false;
  21053. this.setValues( parameters );
  21054. }
  21055. MeshNormalMaterial.prototype = Object.create( Material.prototype );
  21056. MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
  21057. MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
  21058. MeshNormalMaterial.prototype.copy = function ( source ) {
  21059. Material.prototype.copy.call( this, source );
  21060. this.bumpMap = source.bumpMap;
  21061. this.bumpScale = source.bumpScale;
  21062. this.normalMap = source.normalMap;
  21063. this.normalMapType = source.normalMapType;
  21064. this.normalScale.copy( source.normalScale );
  21065. this.displacementMap = source.displacementMap;
  21066. this.displacementScale = source.displacementScale;
  21067. this.displacementBias = source.displacementBias;
  21068. this.wireframe = source.wireframe;
  21069. this.wireframelineWidth = source.wireframelineWidth;
  21070. this.skinning = source.skinning;
  21071. this.morphTargets = source.morphTargets;
  21072. this.morphNormals = source.morphNormals;
  21073. return this;
  21074. };
  21075. /**
  21076. * parameters = {
  21077. * color: <hex>,
  21078. * opacity: <float>,
  21079. *
  21080. * map: new THREE.Texture( <Image> ),
  21081. *
  21082. * lightMap: new THREE.Texture( <Image> ),
  21083. * lightMapIntensity: <float>
  21084. *
  21085. * aoMap: new THREE.Texture( <Image> ),
  21086. * aoMapIntensity: <float>
  21087. *
  21088. * emissive: <hex>,
  21089. * emissiveIntensity: <float>
  21090. * emissiveMap: new THREE.Texture( <Image> ),
  21091. *
  21092. * specularMap: new THREE.Texture( <Image> ),
  21093. *
  21094. * alphaMap: new THREE.Texture( <Image> ),
  21095. *
  21096. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  21097. * combine: THREE.Multiply,
  21098. * reflectivity: <float>,
  21099. * refractionRatio: <float>,
  21100. *
  21101. * wireframe: <boolean>,
  21102. * wireframelineWidth: <float>,
  21103. *
  21104. * skinning: <bool>,
  21105. * morphTargets: <bool>,
  21106. * morphNormals: <bool>
  21107. * }
  21108. */
  21109. function MeshLambertMaterial( parameters ) {
  21110. Material.call( this );
  21111. this.type = 'MeshLambertMaterial';
  21112. this.color = new Color( 0xffffff ); // diffuse
  21113. this.map = null;
  21114. this.lightMap = null;
  21115. this.lightMapIntensity = 1.0;
  21116. this.aoMap = null;
  21117. this.aoMapIntensity = 1.0;
  21118. this.emissive = new Color( 0x000000 );
  21119. this.emissiveIntensity = 1.0;
  21120. this.emissiveMap = null;
  21121. this.specularMap = null;
  21122. this.alphaMap = null;
  21123. this.envMap = null;
  21124. this.combine = MultiplyOperation;
  21125. this.reflectivity = 1;
  21126. this.refractionRatio = 0.98;
  21127. this.wireframe = false;
  21128. this.wireframelineWidth = 1;
  21129. this.wireframeLinecap = 'round';
  21130. this.wireframeLinejoin = 'round';
  21131. this.skinning = false;
  21132. this.morphTargets = false;
  21133. this.morphNormals = false;
  21134. this.setValues( parameters );
  21135. }
  21136. MeshLambertMaterial.prototype = Object.create( Material.prototype );
  21137. MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
  21138. MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
  21139. MeshLambertMaterial.prototype.copy = function ( source ) {
  21140. Material.prototype.copy.call( this, source );
  21141. this.color.copy( source.color );
  21142. this.map = source.map;
  21143. this.lightMap = source.lightMap;
  21144. this.lightMapIntensity = source.lightMapIntensity;
  21145. this.aoMap = source.aoMap;
  21146. this.aoMapIntensity = source.aoMapIntensity;
  21147. this.emissive.copy( source.emissive );
  21148. this.emissiveMap = source.emissiveMap;
  21149. this.emissiveIntensity = source.emissiveIntensity;
  21150. this.specularMap = source.specularMap;
  21151. this.alphaMap = source.alphaMap;
  21152. this.envMap = source.envMap;
  21153. this.combine = source.combine;
  21154. this.reflectivity = source.reflectivity;
  21155. this.refractionRatio = source.refractionRatio;
  21156. this.wireframe = source.wireframe;
  21157. this.wireframelineWidth = source.wireframelineWidth;
  21158. this.wireframeLinecap = source.wireframeLinecap;
  21159. this.wireframeLinejoin = source.wireframeLinejoin;
  21160. this.skinning = source.skinning;
  21161. this.morphTargets = source.morphTargets;
  21162. this.morphNormals = source.morphNormals;
  21163. return this;
  21164. };
  21165. /**
  21166. * parameters = {
  21167. * color: <hex>,
  21168. * opacity: <float>,
  21169. *
  21170. * matcap: new THREE.Texture( <Image> ),
  21171. *
  21172. * map: new THREE.Texture( <Image> ),
  21173. *
  21174. * bumpMap: new THREE.Texture( <Image> ),
  21175. * bumpScale: <float>,
  21176. *
  21177. * normalMap: new THREE.Texture( <Image> ),
  21178. * normalMapType: THREE.TangentSpaceNormalMap,
  21179. * normalScale: <Vector2>,
  21180. *
  21181. * displacementMap: new THREE.Texture( <Image> ),
  21182. * displacementScale: <float>,
  21183. * displacementBias: <float>,
  21184. *
  21185. * alphaMap: new THREE.Texture( <Image> ),
  21186. *
  21187. * skinning: <bool>,
  21188. * morphTargets: <bool>,
  21189. * morphNormals: <bool>
  21190. * }
  21191. */
  21192. function MeshMatcapMaterial( parameters ) {
  21193. Material.call( this );
  21194. this.defines = { 'MATCAP': '' };
  21195. this.type = 'MeshMatcapMaterial';
  21196. this.color = new Color( 0xffffff ); // diffuse
  21197. this.matcap = null;
  21198. this.map = null;
  21199. this.bumpMap = null;
  21200. this.bumpScale = 1;
  21201. this.normalMap = null;
  21202. this.normalMapType = TangentSpaceNormalMap;
  21203. this.normalScale = new Vector2$1( 1, 1 );
  21204. this.displacementMap = null;
  21205. this.displacementScale = 1;
  21206. this.displacementBias = 0;
  21207. this.alphaMap = null;
  21208. this.skinning = false;
  21209. this.morphTargets = false;
  21210. this.morphNormals = false;
  21211. this.setValues( parameters );
  21212. }
  21213. MeshMatcapMaterial.prototype = Object.create( Material.prototype );
  21214. MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial;
  21215. MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true;
  21216. MeshMatcapMaterial.prototype.copy = function ( source ) {
  21217. Material.prototype.copy.call( this, source );
  21218. this.defines = { 'MATCAP': '' };
  21219. this.color.copy( source.color );
  21220. this.matcap = source.matcap;
  21221. this.map = source.map;
  21222. this.bumpMap = source.bumpMap;
  21223. this.bumpScale = source.bumpScale;
  21224. this.normalMap = source.normalMap;
  21225. this.normalMapType = source.normalMapType;
  21226. this.normalScale.copy( source.normalScale );
  21227. this.displacementMap = source.displacementMap;
  21228. this.displacementScale = source.displacementScale;
  21229. this.displacementBias = source.displacementBias;
  21230. this.alphaMap = source.alphaMap;
  21231. this.skinning = source.skinning;
  21232. this.morphTargets = source.morphTargets;
  21233. this.morphNormals = source.morphNormals;
  21234. return this;
  21235. };
  21236. /**
  21237. * parameters = {
  21238. * color: <hex>,
  21239. * opacity: <float>,
  21240. *
  21241. * lineWidth: <float>,
  21242. *
  21243. * scale: <float>,
  21244. * dashSize: <float>,
  21245. * gapSize: <float>
  21246. * }
  21247. */
  21248. function LineDashedMaterial( parameters ) {
  21249. LineBasicMaterial.call( this );
  21250. this.type = 'LineDashedMaterial';
  21251. this.scale = 1;
  21252. this.dashSize = 3;
  21253. this.gapSize = 1;
  21254. this.setValues( parameters );
  21255. }
  21256. LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );
  21257. LineDashedMaterial.prototype.constructor = LineDashedMaterial;
  21258. LineDashedMaterial.prototype.isLineDashedMaterial = true;
  21259. LineDashedMaterial.prototype.copy = function ( source ) {
  21260. LineBasicMaterial.prototype.copy.call( this, source );
  21261. this.scale = source.scale;
  21262. this.dashSize = source.dashSize;
  21263. this.gapSize = source.gapSize;
  21264. return this;
  21265. };
  21266. var Materials = /*#__PURE__*/Object.freeze({
  21267. __proto__: null,
  21268. ShadowMaterial: ShadowMaterial,
  21269. SpriteMaterial: SpriteMaterial,
  21270. RawShaderMaterial: RawShaderMaterial,
  21271. ShaderMaterial: ShaderMaterial,
  21272. PointsMaterial: PointsMaterial,
  21273. MeshPhysicalMaterial: MeshPhysicalMaterial,
  21274. MeshStandardMaterial: MeshStandardMaterial,
  21275. MeshPhongMaterial: MeshPhongMaterial,
  21276. MeshToonMaterial: MeshToonMaterial,
  21277. MeshNormalMaterial: MeshNormalMaterial,
  21278. MeshLambertMaterial: MeshLambertMaterial,
  21279. MeshDepthMaterial: MeshDepthMaterial,
  21280. MeshDistanceMaterial: MeshDistanceMaterial,
  21281. MeshBasicMaterial: MeshBasicMaterial,
  21282. MeshMatcapMaterial: MeshMatcapMaterial,
  21283. LineDashedMaterial: LineDashedMaterial,
  21284. LineBasicMaterial: LineBasicMaterial,
  21285. Material: Material
  21286. });
  21287. const AnimationUtils = {
  21288. // same as Array.prototype.slice, but also works on typed arrays
  21289. arraySlice: function ( array, from, to ) {
  21290. if ( AnimationUtils.isTypedArray( array ) ) {
  21291. // in ios9 array.subarray(from, undefined) will return empty array
  21292. // but array.subarray(from) or array.subarray(from, len) is correct
  21293. return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
  21294. }
  21295. return array.slice( from, to );
  21296. },
  21297. // converts an array to a specific type
  21298. convertArray: function ( array, type, forceClone ) {
  21299. if ( ! array || // let 'undefined' and 'null' pass
  21300. ! forceClone && array.constructor === type ) return array;
  21301. if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
  21302. return new type( array ); // create typed array
  21303. }
  21304. return Array.prototype.slice.call( array ); // create Array
  21305. },
  21306. isTypedArray: function ( object ) {
  21307. return ArrayBuffer.isView( object ) &&
  21308. ! ( object instanceof DataView );
  21309. },
  21310. // returns an array by which times and values can be sorted
  21311. getKeyframeOrder: function ( times ) {
  21312. function compareTime( i, j ) {
  21313. return times[ i ] - times[ j ];
  21314. }
  21315. const n = times.length;
  21316. const result = new Array( n );
  21317. for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
  21318. result.sort( compareTime );
  21319. return result;
  21320. },
  21321. // uses the array previously returned by 'getKeyframeOrder' to sort data
  21322. sortedArray: function ( values, stride, order ) {
  21323. const nValues = values.length;
  21324. const result = new values.constructor( nValues );
  21325. for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
  21326. const srcOffset = order[ i ] * stride;
  21327. for ( let j = 0; j !== stride; ++ j ) {
  21328. result[ dstOffset ++ ] = values[ srcOffset + j ];
  21329. }
  21330. }
  21331. return result;
  21332. },
  21333. // function for parsing AOS keyframe formats
  21334. flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
  21335. let i = 1, key = jsonKeys[ 0 ];
  21336. while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
  21337. key = jsonKeys[ i ++ ];
  21338. }
  21339. if ( key === undefined ) return; // no data
  21340. let value = key[ valuePropertyName ];
  21341. if ( value === undefined ) return; // no data
  21342. if ( Array.isArray( value ) ) {
  21343. do {
  21344. value = key[ valuePropertyName ];
  21345. if ( value !== undefined ) {
  21346. times.push( key.time );
  21347. values.push.apply( values, value ); // push all elements
  21348. }
  21349. key = jsonKeys[ i ++ ];
  21350. } while ( key !== undefined );
  21351. } else if ( value.toArray !== undefined ) {
  21352. // ...assume THREE.Math-ish
  21353. do {
  21354. value = key[ valuePropertyName ];
  21355. if ( value !== undefined ) {
  21356. times.push( key.time );
  21357. value.toArray( values, values.length );
  21358. }
  21359. key = jsonKeys[ i ++ ];
  21360. } while ( key !== undefined );
  21361. } else {
  21362. // otherwise push as-is
  21363. do {
  21364. value = key[ valuePropertyName ];
  21365. if ( value !== undefined ) {
  21366. times.push( key.time );
  21367. values.push( value );
  21368. }
  21369. key = jsonKeys[ i ++ ];
  21370. } while ( key !== undefined );
  21371. }
  21372. },
  21373. subclip: function ( sourceClip, name, startFrame, endFrame, fps = 30 ) {
  21374. const clip = sourceClip.clone();
  21375. clip.name = name;
  21376. const tracks = [];
  21377. for ( let i = 0; i < clip.tracks.length; ++ i ) {
  21378. const track = clip.tracks[ i ];
  21379. const valueSize = track.getValueSize();
  21380. const times = [];
  21381. const values = [];
  21382. for ( let j = 0; j < track.times.length; ++ j ) {
  21383. const frame = track.times[ j ] * fps;
  21384. if ( frame < startFrame || frame >= endFrame ) continue;
  21385. times.push( track.times[ j ] );
  21386. for ( let k = 0; k < valueSize; ++ k ) {
  21387. values.push( track.values[ j * valueSize + k ] );
  21388. }
  21389. }
  21390. if ( times.length === 0 ) continue;
  21391. track.times = AnimationUtils.convertArray( times, track.times.constructor );
  21392. track.values = AnimationUtils.convertArray( values, track.values.constructor );
  21393. tracks.push( track );
  21394. }
  21395. clip.tracks = tracks;
  21396. // find minimum .times value across all tracks in the trimmed clip
  21397. let minStartTime = Infinity;
  21398. for ( let i = 0; i < clip.tracks.length; ++ i ) {
  21399. if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
  21400. minStartTime = clip.tracks[ i ].times[ 0 ];
  21401. }
  21402. }
  21403. // shift all tracks such that clip begins at t=0
  21404. for ( let i = 0; i < clip.tracks.length; ++ i ) {
  21405. clip.tracks[ i ].shift( - 1 * minStartTime );
  21406. }
  21407. clip.resetDuration();
  21408. return clip;
  21409. },
  21410. makeClipAdditive: function ( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
  21411. if ( fps <= 0 ) fps = 30;
  21412. const numTracks = referenceClip.tracks.length;
  21413. const referenceTime = referenceFrame / fps;
  21414. // Make each track's values relative to the values at the reference frame
  21415. for ( let i = 0; i < numTracks; ++ i ) {
  21416. const referenceTrack = referenceClip.tracks[ i ];
  21417. const referenceTrackType = referenceTrack.ValueTypeName;
  21418. // Skip this track if it's non-numeric
  21419. if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
  21420. // Find the track in the target clip whose name and type matches the reference track
  21421. const targetTrack = targetClip.tracks.find( function ( track ) {
  21422. return track.name === referenceTrack.name
  21423. && track.ValueTypeName === referenceTrackType;
  21424. } );
  21425. if ( targetTrack === undefined ) continue;
  21426. let referenceOffset = 0;
  21427. const referenceValueSize = referenceTrack.getValueSize();
  21428. if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
  21429. referenceOffset = referenceValueSize / 3;
  21430. }
  21431. let targetOffset = 0;
  21432. const targetValueSize = targetTrack.getValueSize();
  21433. if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
  21434. targetOffset = targetValueSize / 3;
  21435. }
  21436. const lastIndex = referenceTrack.times.length - 1;
  21437. let referenceValue;
  21438. // Find the value to subtract out of the track
  21439. if ( referenceTime <= referenceTrack.times[ 0 ] ) {
  21440. // Reference frame is earlier than the first keyframe, so just use the first keyframe
  21441. const startIndex = referenceOffset;
  21442. const endIndex = referenceValueSize - referenceOffset;
  21443. referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
  21444. } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
  21445. // Reference frame is after the last keyframe, so just use the last keyframe
  21446. const startIndex = lastIndex * referenceValueSize + referenceOffset;
  21447. const endIndex = startIndex + referenceValueSize - referenceOffset;
  21448. referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
  21449. } else {
  21450. // Interpolate to the reference value
  21451. const interpolant = referenceTrack.createInterpolant();
  21452. const startIndex = referenceOffset;
  21453. const endIndex = referenceValueSize - referenceOffset;
  21454. interpolant.evaluate( referenceTime );
  21455. referenceValue = AnimationUtils.arraySlice( interpolant.resultBuffer, startIndex, endIndex );
  21456. }
  21457. // Conjugate the quaternion
  21458. if ( referenceTrackType === 'quaternion' ) {
  21459. const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
  21460. referenceQuat.toArray( referenceValue );
  21461. }
  21462. // Subtract the reference value from all of the track values
  21463. const numTimes = targetTrack.times.length;
  21464. for ( let j = 0; j < numTimes; ++ j ) {
  21465. const valueStart = j * targetValueSize + targetOffset;
  21466. if ( referenceTrackType === 'quaternion' ) {
  21467. // Multiply the conjugate for quaternion track types
  21468. Quaternion.multiplyQuaternionsFlat(
  21469. targetTrack.values,
  21470. valueStart,
  21471. referenceValue,
  21472. 0,
  21473. targetTrack.values,
  21474. valueStart
  21475. );
  21476. } else {
  21477. const valueEnd = targetValueSize - targetOffset * 2;
  21478. // Subtract each value for all other numeric track types
  21479. for ( let k = 0; k < valueEnd; ++ k ) {
  21480. targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
  21481. }
  21482. }
  21483. }
  21484. }
  21485. targetClip.blendMode = AdditiveAnimationBlendMode;
  21486. return targetClip;
  21487. }
  21488. };
  21489. /**
  21490. * Abstract base class of interpolants over parametric samples.
  21491. *
  21492. * The parameter domain is one dimensional, typically the time or a path
  21493. * along a curve defined by the data.
  21494. *
  21495. * The sample values can have any dimensionality and derived classes may
  21496. * apply special interpretations to the data.
  21497. *
  21498. * This class provides the interval seek in a Template Method, deferring
  21499. * the actual interpolation to derived classes.
  21500. *
  21501. * Time complexity is O(1) for linear access crossing at most two points
  21502. * and O(log N) for random access, where N is the number of positions.
  21503. *
  21504. * References:
  21505. *
  21506. * http://www.oodesign.com/template-method-pattern.html
  21507. *
  21508. */
  21509. function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
  21510. this.parameterPositions = parameterPositions;
  21511. this._cachedIndex = 0;
  21512. this.resultBuffer = resultBuffer !== undefined ?
  21513. resultBuffer : new sampleValues.constructor( sampleSize );
  21514. this.sampleValues = sampleValues;
  21515. this.valueSize = sampleSize;
  21516. }
  21517. Object.assign( Interpolant.prototype, {
  21518. evaluate: function ( t ) {
  21519. const pp = this.parameterPositions;
  21520. let i1 = this._cachedIndex,
  21521. t1 = pp[ i1 ],
  21522. t0 = pp[ i1 - 1 ];
  21523. validate_interval: {
  21524. seek: {
  21525. let right;
  21526. linear_scan: {
  21527. //- See http://jsperf.com/comparison-to-undefined/3
  21528. //- slower code:
  21529. //-
  21530. //- if ( t >= t1 || t1 === undefined ) {
  21531. forward_scan: if ( ! ( t < t1 ) ) {
  21532. for ( let giveUpAt = i1 + 2; ; ) {
  21533. if ( t1 === undefined ) {
  21534. if ( t < t0 ) break forward_scan;
  21535. // after end
  21536. i1 = pp.length;
  21537. this._cachedIndex = i1;
  21538. return this.afterEnd_( i1 - 1, t, t0 );
  21539. }
  21540. if ( i1 === giveUpAt ) break; // this loop
  21541. t0 = t1;
  21542. t1 = pp[ ++ i1 ];
  21543. if ( t < t1 ) {
  21544. // we have arrived at the sought interval
  21545. break seek;
  21546. }
  21547. }
  21548. // prepare binary search on the right side of the index
  21549. right = pp.length;
  21550. break linear_scan;
  21551. }
  21552. //- slower code:
  21553. //- if ( t < t0 || t0 === undefined ) {
  21554. if ( ! ( t >= t0 ) ) {
  21555. // looping?
  21556. const t1global = pp[ 1 ];
  21557. if ( t < t1global ) {
  21558. i1 = 2; // + 1, using the scan for the details
  21559. t0 = t1global;
  21560. }
  21561. // linear reverse scan
  21562. for ( let giveUpAt = i1 - 2; ; ) {
  21563. if ( t0 === undefined ) {
  21564. // before start
  21565. this._cachedIndex = 0;
  21566. return this.beforeStart_( 0, t, t1 );
  21567. }
  21568. if ( i1 === giveUpAt ) break; // this loop
  21569. t1 = t0;
  21570. t0 = pp[ -- i1 - 1 ];
  21571. if ( t >= t0 ) {
  21572. // we have arrived at the sought interval
  21573. break seek;
  21574. }
  21575. }
  21576. // prepare binary search on the left side of the index
  21577. right = i1;
  21578. i1 = 0;
  21579. break linear_scan;
  21580. }
  21581. // the interval is valid
  21582. break validate_interval;
  21583. } // linear scan
  21584. // binary search
  21585. while ( i1 < right ) {
  21586. const mid = ( i1 + right ) >>> 1;
  21587. if ( t < pp[ mid ] ) {
  21588. right = mid;
  21589. } else {
  21590. i1 = mid + 1;
  21591. }
  21592. }
  21593. t1 = pp[ i1 ];
  21594. t0 = pp[ i1 - 1 ];
  21595. // check boundary cases, again
  21596. if ( t0 === undefined ) {
  21597. this._cachedIndex = 0;
  21598. return this.beforeStart_( 0, t, t1 );
  21599. }
  21600. if ( t1 === undefined ) {
  21601. i1 = pp.length;
  21602. this._cachedIndex = i1;
  21603. return this.afterEnd_( i1 - 1, t0, t );
  21604. }
  21605. } // seek
  21606. this._cachedIndex = i1;
  21607. this.intervalChanged_( i1, t0, t1 );
  21608. } // validate_interval
  21609. return this.interpolate_( i1, t0, t, t1 );
  21610. },
  21611. settings: null, // optional, subclass-specific settings structure
  21612. // Note: The indirection allows central control of many interpolants.
  21613. // --- Protected interface
  21614. DefaultSettings_: {},
  21615. getSettings_: function () {
  21616. return this.settings || this.DefaultSettings_;
  21617. },
  21618. copySampleValue_: function ( index ) {
  21619. // copies a sample value to the result buffer
  21620. const result = this.resultBuffer,
  21621. values = this.sampleValues,
  21622. stride = this.valueSize,
  21623. offset = index * stride;
  21624. for ( let i = 0; i !== stride; ++ i ) {
  21625. result[ i ] = values[ offset + i ];
  21626. }
  21627. return result;
  21628. },
  21629. // Template methods for derived classes:
  21630. interpolate_: function ( /* i1, t0, t, t1 */ ) {
  21631. throw new Error( 'call to abstract method' );
  21632. // implementations shall return this.resultBuffer
  21633. },
  21634. intervalChanged_: function ( /* i1, t0, t1 */ ) {
  21635. // empty
  21636. }
  21637. } );
  21638. // DECLARE ALIAS AFTER assign prototype
  21639. Object.assign( Interpolant.prototype, {
  21640. //( 0, t, t0 ), returns this.resultBuffer
  21641. beforeStart_: Interpolant.prototype.copySampleValue_,
  21642. //( N-1, tN-1, t ), returns this.resultBuffer
  21643. afterEnd_: Interpolant.prototype.copySampleValue_,
  21644. } );
  21645. /**
  21646. * Fast and simple cubic spline interpolant.
  21647. *
  21648. * It was derived from a Hermitian construction setting the first derivative
  21649. * at each sample position to the linear slope between neighboring positions
  21650. * over their parameter interval.
  21651. */
  21652. function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
  21653. Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
  21654. this._weightPrev = - 0;
  21655. this._offsetPrev = - 0;
  21656. this._weightNext = - 0;
  21657. this._offsetNext = - 0;
  21658. }
  21659. CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
  21660. constructor: CubicInterpolant,
  21661. DefaultSettings_: {
  21662. endingStart: ZeroCurvatureEnding,
  21663. endingEnd: ZeroCurvatureEnding
  21664. },
  21665. intervalChanged_: function ( i1, t0, t1 ) {
  21666. const pp = this.parameterPositions;
  21667. let iPrev = i1 - 2,
  21668. iNext = i1 + 1,
  21669. tPrev = pp[ iPrev ],
  21670. tNext = pp[ iNext ];
  21671. if ( tPrev === undefined ) {
  21672. switch ( this.getSettings_().endingStart ) {
  21673. case ZeroSlopeEnding:
  21674. // f'(t0) = 0
  21675. iPrev = i1;
  21676. tPrev = 2 * t0 - t1;
  21677. break;
  21678. case WrapAroundEnding:
  21679. // use the other end of the curve
  21680. iPrev = pp.length - 2;
  21681. tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
  21682. break;
  21683. default: // ZeroCurvatureEnding
  21684. // f''(t0) = 0 a.k.a. Natural Spline
  21685. iPrev = i1;
  21686. tPrev = t1;
  21687. }
  21688. }
  21689. if ( tNext === undefined ) {
  21690. switch ( this.getSettings_().endingEnd ) {
  21691. case ZeroSlopeEnding:
  21692. // f'(tN) = 0
  21693. iNext = i1;
  21694. tNext = 2 * t1 - t0;
  21695. break;
  21696. case WrapAroundEnding:
  21697. // use the other end of the curve
  21698. iNext = 1;
  21699. tNext = t1 + pp[ 1 ] - pp[ 0 ];
  21700. break;
  21701. default: // ZeroCurvatureEnding
  21702. // f''(tN) = 0, a.k.a. Natural Spline
  21703. iNext = i1 - 1;
  21704. tNext = t0;
  21705. }
  21706. }
  21707. const halfDt = ( t1 - t0 ) * 0.5,
  21708. stride = this.valueSize;
  21709. this._weightPrev = halfDt / ( t0 - tPrev );
  21710. this._weightNext = halfDt / ( tNext - t1 );
  21711. this._offsetPrev = iPrev * stride;
  21712. this._offsetNext = iNext * stride;
  21713. },
  21714. interpolate_: function ( i1, t0, t, t1 ) {
  21715. const result = this.resultBuffer,
  21716. values = this.sampleValues,
  21717. stride = this.valueSize,
  21718. o1 = i1 * stride, o0 = o1 - stride,
  21719. oP = this._offsetPrev, oN = this._offsetNext,
  21720. wP = this._weightPrev, wN = this._weightNext,
  21721. p = ( t - t0 ) / ( t1 - t0 ),
  21722. pp = p * p,
  21723. ppp = pp * p;
  21724. // evaluate polynomials
  21725. const sP = - wP * ppp + 2 * wP * pp - wP * p;
  21726. const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
  21727. const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
  21728. const sN = wN * ppp - wN * pp;
  21729. // combine data linearly
  21730. for ( let i = 0; i !== stride; ++ i ) {
  21731. result[ i ] =
  21732. sP * values[ oP + i ] +
  21733. s0 * values[ o0 + i ] +
  21734. s1 * values[ o1 + i ] +
  21735. sN * values[ oN + i ];
  21736. }
  21737. return result;
  21738. }
  21739. } );
  21740. function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
  21741. Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
  21742. }
  21743. LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
  21744. constructor: LinearInterpolant,
  21745. interpolate_: function ( i1, t0, t, t1 ) {
  21746. const result = this.resultBuffer,
  21747. values = this.sampleValues,
  21748. stride = this.valueSize,
  21749. offset1 = i1 * stride,
  21750. offset0 = offset1 - stride,
  21751. weight1 = ( t - t0 ) / ( t1 - t0 ),
  21752. weight0 = 1 - weight1;
  21753. for ( let i = 0; i !== stride; ++ i ) {
  21754. result[ i ] =
  21755. values[ offset0 + i ] * weight0 +
  21756. values[ offset1 + i ] * weight1;
  21757. }
  21758. return result;
  21759. }
  21760. } );
  21761. /**
  21762. *
  21763. * Interpolant that evaluates to the sample value at the position preceeding
  21764. * the parameter.
  21765. */
  21766. function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
  21767. Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
  21768. }
  21769. DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
  21770. constructor: DiscreteInterpolant,
  21771. interpolate_: function ( i1 /*, t0, t, t1 */ ) {
  21772. return this.copySampleValue_( i1 - 1 );
  21773. }
  21774. } );
  21775. function KeyframeTrack( name, times, values, interpolation ) {
  21776. if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
  21777. if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
  21778. this.name = name;
  21779. this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
  21780. this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
  21781. this.setInterpolation( interpolation || this.DefaultInterpolation );
  21782. }
  21783. // Static methods
  21784. Object.assign( KeyframeTrack, {
  21785. // Serialization (in static context, because of constructor invocation
  21786. // and automatic invocation of .toJSON):
  21787. toJSON: function ( track ) {
  21788. const trackType = track.constructor;
  21789. let json;
  21790. // derived classes can define a static toJSON method
  21791. if ( trackType.toJSON !== undefined ) {
  21792. json = trackType.toJSON( track );
  21793. } else {
  21794. // by default, we assume the data can be serialized as-is
  21795. json = {
  21796. 'name': track.name,
  21797. 'times': AnimationUtils.convertArray( track.times, Array ),
  21798. 'values': AnimationUtils.convertArray( track.values, Array )
  21799. };
  21800. const interpolation = track.getInterpolation();
  21801. if ( interpolation !== track.DefaultInterpolation ) {
  21802. json.interpolation = interpolation;
  21803. }
  21804. }
  21805. json.type = track.ValueTypeName; // mandatory
  21806. return json;
  21807. }
  21808. } );
  21809. Object.assign( KeyframeTrack.prototype, {
  21810. constructor: KeyframeTrack,
  21811. TimeBufferType: Float32Array,
  21812. ValueBufferType: Float32Array,
  21813. DefaultInterpolation: InterpolateLinear,
  21814. InterpolantFactoryMethodDiscrete: function ( result ) {
  21815. return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
  21816. },
  21817. InterpolantFactoryMethodLinear: function ( result ) {
  21818. return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
  21819. },
  21820. InterpolantFactoryMethodSmooth: function ( result ) {
  21821. return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
  21822. },
  21823. setInterpolation: function ( interpolation ) {
  21824. let factoryMethod;
  21825. switch ( interpolation ) {
  21826. case InterpolateDiscrete:
  21827. factoryMethod = this.InterpolantFactoryMethodDiscrete;
  21828. break;
  21829. case InterpolateLinear:
  21830. factoryMethod = this.InterpolantFactoryMethodLinear;
  21831. break;
  21832. case InterpolateSmooth:
  21833. factoryMethod = this.InterpolantFactoryMethodSmooth;
  21834. break;
  21835. }
  21836. if ( factoryMethod === undefined ) {
  21837. const message = 'unsupported interpolation for ' +
  21838. this.ValueTypeName + ' keyframe track named ' + this.name;
  21839. if ( this.createInterpolant === undefined ) {
  21840. // fall back to default, unless the default itself is messed up
  21841. if ( interpolation !== this.DefaultInterpolation ) {
  21842. this.setInterpolation( this.DefaultInterpolation );
  21843. } else {
  21844. throw new Error( message ); // fatal, in this case
  21845. }
  21846. }
  21847. console.warn( 'THREE.KeyframeTrack:', message );
  21848. return this;
  21849. }
  21850. this.createInterpolant = factoryMethod;
  21851. return this;
  21852. },
  21853. getInterpolation: function () {
  21854. switch ( this.createInterpolant ) {
  21855. case this.InterpolantFactoryMethodDiscrete:
  21856. return InterpolateDiscrete;
  21857. case this.InterpolantFactoryMethodLinear:
  21858. return InterpolateLinear;
  21859. case this.InterpolantFactoryMethodSmooth:
  21860. return InterpolateSmooth;
  21861. }
  21862. },
  21863. getValueSize: function () {
  21864. return this.values.length / this.times.length;
  21865. },
  21866. // move all keyframes either forwards or backwards in time
  21867. shift: function ( timeOffset ) {
  21868. if ( timeOffset !== 0.0 ) {
  21869. const times = this.times;
  21870. for ( let i = 0, n = times.length; i !== n; ++ i ) {
  21871. times[ i ] += timeOffset;
  21872. }
  21873. }
  21874. return this;
  21875. },
  21876. // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
  21877. scale: function ( timeScale ) {
  21878. if ( timeScale !== 1.0 ) {
  21879. const times = this.times;
  21880. for ( let i = 0, n = times.length; i !== n; ++ i ) {
  21881. times[ i ] *= timeScale;
  21882. }
  21883. }
  21884. return this;
  21885. },
  21886. // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
  21887. // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
  21888. trim: function ( startTime, endTime ) {
  21889. const times = this.times,
  21890. nKeys = times.length;
  21891. let from = 0,
  21892. to = nKeys - 1;
  21893. while ( from !== nKeys && times[ from ] < startTime ) {
  21894. ++ from;
  21895. }
  21896. while ( to !== - 1 && times[ to ] > endTime ) {
  21897. -- to;
  21898. }
  21899. ++ to; // inclusive -> exclusive bound
  21900. if ( from !== 0 || to !== nKeys ) {
  21901. // empty tracks are forbidden, so keep at least one keyframe
  21902. if ( from >= to ) {
  21903. to = Math.max( to, 1 );
  21904. from = to - 1;
  21905. }
  21906. const stride = this.getValueSize();
  21907. this.times = AnimationUtils.arraySlice( times, from, to );
  21908. this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
  21909. }
  21910. return this;
  21911. },
  21912. // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
  21913. validate: function () {
  21914. let valid = true;
  21915. const valueSize = this.getValueSize();
  21916. if ( valueSize - Math.floor( valueSize ) !== 0 ) {
  21917. console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
  21918. valid = false;
  21919. }
  21920. const times = this.times,
  21921. values = this.values,
  21922. nKeys = times.length;
  21923. if ( nKeys === 0 ) {
  21924. console.error( 'THREE.KeyframeTrack: Track is empty.', this );
  21925. valid = false;
  21926. }
  21927. let prevTime = null;
  21928. for ( let i = 0; i !== nKeys; i ++ ) {
  21929. const currTime = times[ i ];
  21930. if ( typeof currTime === 'number' && isNaN( currTime ) ) {
  21931. console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
  21932. valid = false;
  21933. break;
  21934. }
  21935. if ( prevTime !== null && prevTime > currTime ) {
  21936. console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
  21937. valid = false;
  21938. break;
  21939. }
  21940. prevTime = currTime;
  21941. }
  21942. if ( values !== undefined ) {
  21943. if ( AnimationUtils.isTypedArray( values ) ) {
  21944. for ( let i = 0, n = values.length; i !== n; ++ i ) {
  21945. const value = values[ i ];
  21946. if ( isNaN( value ) ) {
  21947. console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
  21948. valid = false;
  21949. break;
  21950. }
  21951. }
  21952. }
  21953. }
  21954. return valid;
  21955. },
  21956. // removes equivalent sequential keys as common in morph target sequences
  21957. // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
  21958. optimize: function () {
  21959. // times or values may be shared with other tracks, so overwriting is unsafe
  21960. const times = AnimationUtils.arraySlice( this.times ),
  21961. values = AnimationUtils.arraySlice( this.values ),
  21962. stride = this.getValueSize(),
  21963. smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
  21964. lastIndex = times.length - 1;
  21965. let writeIndex = 1;
  21966. for ( let i = 1; i < lastIndex; ++ i ) {
  21967. let keep = false;
  21968. const time = times[ i ];
  21969. const timeNext = times[ i + 1 ];
  21970. // remove adjacent keyframes scheduled at the same time
  21971. if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
  21972. if ( ! smoothInterpolation ) {
  21973. // remove unnecessary keyframes same as their neighbors
  21974. const offset = i * stride,
  21975. offsetP = offset - stride,
  21976. offsetN = offset + stride;
  21977. for ( let j = 0; j !== stride; ++ j ) {
  21978. const value = values[ offset + j ];
  21979. if ( value !== values[ offsetP + j ] ||
  21980. value !== values[ offsetN + j ] ) {
  21981. keep = true;
  21982. break;
  21983. }
  21984. }
  21985. } else {
  21986. keep = true;
  21987. }
  21988. }
  21989. // in-place compaction
  21990. if ( keep ) {
  21991. if ( i !== writeIndex ) {
  21992. times[ writeIndex ] = times[ i ];
  21993. const readOffset = i * stride,
  21994. writeOffset = writeIndex * stride;
  21995. for ( let j = 0; j !== stride; ++ j ) {
  21996. values[ writeOffset + j ] = values[ readOffset + j ];
  21997. }
  21998. }
  21999. ++ writeIndex;
  22000. }
  22001. }
  22002. // flush last keyframe (compaction looks ahead)
  22003. if ( lastIndex > 0 ) {
  22004. times[ writeIndex ] = times[ lastIndex ];
  22005. for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
  22006. values[ writeOffset + j ] = values[ readOffset + j ];
  22007. }
  22008. ++ writeIndex;
  22009. }
  22010. if ( writeIndex !== times.length ) {
  22011. this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
  22012. this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
  22013. } else {
  22014. this.times = times;
  22015. this.values = values;
  22016. }
  22017. return this;
  22018. },
  22019. clone: function () {
  22020. const times = AnimationUtils.arraySlice( this.times, 0 );
  22021. const values = AnimationUtils.arraySlice( this.values, 0 );
  22022. const TypedKeyframeTrack = this.constructor;
  22023. const track = new TypedKeyframeTrack( this.name, times, values );
  22024. // Interpolant argument to constructor is not saved, so copy the factory method directly.
  22025. track.createInterpolant = this.createInterpolant;
  22026. return track;
  22027. }
  22028. } );
  22029. /**
  22030. * A Track of Boolean keyframe values.
  22031. */
  22032. function BooleanKeyframeTrack( name, times, values ) {
  22033. KeyframeTrack.call( this, name, times, values );
  22034. }
  22035. BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
  22036. constructor: BooleanKeyframeTrack,
  22037. ValueTypeName: 'bool',
  22038. ValueBufferType: Array,
  22039. DefaultInterpolation: InterpolateDiscrete,
  22040. InterpolantFactoryMethodLinear: undefined,
  22041. InterpolantFactoryMethodSmooth: undefined
  22042. // Note: Actually this track could have a optimized / compressed
  22043. // representation of a single value and a custom interpolant that
  22044. // computes "firstValue ^ isOdd( index )".
  22045. } );
  22046. /**
  22047. * A Track of keyframe values that represent color.
  22048. */
  22049. function ColorKeyframeTrack( name, times, values, interpolation ) {
  22050. KeyframeTrack.call( this, name, times, values, interpolation );
  22051. }
  22052. ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
  22053. constructor: ColorKeyframeTrack,
  22054. ValueTypeName: 'color'
  22055. // ValueBufferType is inherited
  22056. // DefaultInterpolation is inherited
  22057. // Note: Very basic implementation and nothing special yet.
  22058. // However, this is the place for color space parameterization.
  22059. } );
  22060. /**
  22061. * A Track of numeric keyframe values.
  22062. */
  22063. function NumberKeyframeTrack( name, times, values, interpolation ) {
  22064. KeyframeTrack.call( this, name, times, values, interpolation );
  22065. }
  22066. NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
  22067. constructor: NumberKeyframeTrack,
  22068. ValueTypeName: 'number'
  22069. // ValueBufferType is inherited
  22070. // DefaultInterpolation is inherited
  22071. } );
  22072. /**
  22073. * Spherical linear unit quaternion interpolant.
  22074. */
  22075. function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
  22076. Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
  22077. }
  22078. QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
  22079. constructor: QuaternionLinearInterpolant,
  22080. interpolate_: function ( i1, t0, t, t1 ) {
  22081. const result = this.resultBuffer,
  22082. values = this.sampleValues,
  22083. stride = this.valueSize,
  22084. alpha = ( t - t0 ) / ( t1 - t0 );
  22085. let offset = i1 * stride;
  22086. for ( let end = offset + stride; offset !== end; offset += 4 ) {
  22087. Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
  22088. }
  22089. return result;
  22090. }
  22091. } );
  22092. /**
  22093. * A Track of quaternion keyframe values.
  22094. */
  22095. function QuaternionKeyframeTrack( name, times, values, interpolation ) {
  22096. KeyframeTrack.call( this, name, times, values, interpolation );
  22097. }
  22098. QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
  22099. constructor: QuaternionKeyframeTrack,
  22100. ValueTypeName: 'quaternion',
  22101. // ValueBufferType is inherited
  22102. DefaultInterpolation: InterpolateLinear,
  22103. InterpolantFactoryMethodLinear: function ( result ) {
  22104. return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
  22105. },
  22106. InterpolantFactoryMethodSmooth: undefined // not yet implemented
  22107. } );
  22108. /**
  22109. * A Track that interpolates Strings
  22110. */
  22111. function StringKeyframeTrack( name, times, values, interpolation ) {
  22112. KeyframeTrack.call( this, name, times, values, interpolation );
  22113. }
  22114. StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
  22115. constructor: StringKeyframeTrack,
  22116. ValueTypeName: 'string',
  22117. ValueBufferType: Array,
  22118. DefaultInterpolation: InterpolateDiscrete,
  22119. InterpolantFactoryMethodLinear: undefined,
  22120. InterpolantFactoryMethodSmooth: undefined
  22121. } );
  22122. /**
  22123. * A Track of vectored keyframe values.
  22124. */
  22125. function VectorKeyframeTrack( name, times, values, interpolation ) {
  22126. KeyframeTrack.call( this, name, times, values, interpolation );
  22127. }
  22128. VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
  22129. constructor: VectorKeyframeTrack,
  22130. ValueTypeName: 'vector'
  22131. // ValueBufferType is inherited
  22132. // DefaultInterpolation is inherited
  22133. } );
  22134. function AnimationClip( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
  22135. this.name = name;
  22136. this.tracks = tracks;
  22137. this.duration = duration;
  22138. this.blendMode = blendMode;
  22139. this.uuid = MathUtils.generateUUID();
  22140. // this means it should figure out its duration by scanning the tracks
  22141. if ( this.duration < 0 ) {
  22142. this.resetDuration();
  22143. }
  22144. }
  22145. function getTrackTypeForValueTypeName( typeName ) {
  22146. switch ( typeName.toLowerCase() ) {
  22147. case 'scalar':
  22148. case 'double':
  22149. case 'float':
  22150. case 'number':
  22151. case 'integer':
  22152. return NumberKeyframeTrack;
  22153. case 'vector':
  22154. case 'vector2':
  22155. case 'vector3':
  22156. case 'vector4':
  22157. return VectorKeyframeTrack;
  22158. case 'color':
  22159. return ColorKeyframeTrack;
  22160. case 'quaternion':
  22161. return QuaternionKeyframeTrack;
  22162. case 'bool':
  22163. case 'boolean':
  22164. return BooleanKeyframeTrack;
  22165. case 'string':
  22166. return StringKeyframeTrack;
  22167. }
  22168. throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
  22169. }
  22170. function parseKeyframeTrack( json ) {
  22171. if ( json.type === undefined ) {
  22172. throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
  22173. }
  22174. const trackType = getTrackTypeForValueTypeName( json.type );
  22175. if ( json.times === undefined ) {
  22176. const times = [], values = [];
  22177. AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
  22178. json.times = times;
  22179. json.values = values;
  22180. }
  22181. // derived classes can define a static parse method
  22182. if ( trackType.parse !== undefined ) {
  22183. return trackType.parse( json );
  22184. } else {
  22185. // by default, we assume a constructor compatible with the base
  22186. return new trackType( json.name, json.times, json.values, json.interpolation );
  22187. }
  22188. }
  22189. Object.assign( AnimationClip, {
  22190. parse: function ( json ) {
  22191. const tracks = [],
  22192. jsonTracks = json.tracks,
  22193. frameTime = 1.0 / ( json.fps || 1.0 );
  22194. for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
  22195. tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
  22196. }
  22197. const clip = new AnimationClip( json.name, json.duration, tracks, json.blendMode );
  22198. clip.uuid = json.uuid;
  22199. return clip;
  22200. },
  22201. toJSON: function ( clip ) {
  22202. const tracks = [],
  22203. clipTracks = clip.tracks;
  22204. const json = {
  22205. 'name': clip.name,
  22206. 'duration': clip.duration,
  22207. 'tracks': tracks,
  22208. 'uuid': clip.uuid,
  22209. 'blendMode': clip.blendMode
  22210. };
  22211. for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
  22212. tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
  22213. }
  22214. return json;
  22215. },
  22216. CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
  22217. const numMorphTargets = morphTargetSequence.length;
  22218. const tracks = [];
  22219. for ( let i = 0; i < numMorphTargets; i ++ ) {
  22220. let times = [];
  22221. let values = [];
  22222. times.push(
  22223. ( i + numMorphTargets - 1 ) % numMorphTargets,
  22224. i,
  22225. ( i + 1 ) % numMorphTargets );
  22226. values.push( 0, 1, 0 );
  22227. const order = AnimationUtils.getKeyframeOrder( times );
  22228. times = AnimationUtils.sortedArray( times, 1, order );
  22229. values = AnimationUtils.sortedArray( values, 1, order );
  22230. // if there is a key at the first frame, duplicate it as the
  22231. // last frame as well for perfect loop.
  22232. if ( ! noLoop && times[ 0 ] === 0 ) {
  22233. times.push( numMorphTargets );
  22234. values.push( values[ 0 ] );
  22235. }
  22236. tracks.push(
  22237. new NumberKeyframeTrack(
  22238. '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
  22239. times, values
  22240. ).scale( 1.0 / fps ) );
  22241. }
  22242. return new AnimationClip( name, - 1, tracks );
  22243. },
  22244. findByName: function ( objectOrClipArray, name ) {
  22245. let clipArray = objectOrClipArray;
  22246. if ( ! Array.isArray( objectOrClipArray ) ) {
  22247. const o = objectOrClipArray;
  22248. clipArray = o.geometry && o.geometry.animations || o.animations;
  22249. }
  22250. for ( let i = 0; i < clipArray.length; i ++ ) {
  22251. if ( clipArray[ i ].name === name ) {
  22252. return clipArray[ i ];
  22253. }
  22254. }
  22255. return null;
  22256. },
  22257. CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
  22258. const animationToMorphTargets = {};
  22259. // tested with https://regex101.com/ on trick sequences
  22260. // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
  22261. const pattern = /^([\w-]*?)([\d]+)$/;
  22262. // sort morph target names into animation groups based
  22263. // patterns like Walk_001, Walk_002, Run_001, Run_002
  22264. for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
  22265. const morphTarget = morphTargets[ i ];
  22266. const parts = morphTarget.name.match( pattern );
  22267. if ( parts && parts.length > 1 ) {
  22268. const name = parts[ 1 ];
  22269. let animationMorphTargets = animationToMorphTargets[ name ];
  22270. if ( ! animationMorphTargets ) {
  22271. animationToMorphTargets[ name ] = animationMorphTargets = [];
  22272. }
  22273. animationMorphTargets.push( morphTarget );
  22274. }
  22275. }
  22276. const clips = [];
  22277. for ( const name in animationToMorphTargets ) {
  22278. clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
  22279. }
  22280. return clips;
  22281. },
  22282. // parse the animation.hierarchy format
  22283. parseAnimation: function ( animation, bones ) {
  22284. if ( ! animation ) {
  22285. console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
  22286. return null;
  22287. }
  22288. const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
  22289. // only return track if there are actually keys.
  22290. if ( animationKeys.length !== 0 ) {
  22291. const times = [];
  22292. const values = [];
  22293. AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
  22294. // empty keys are filtered out, so check again
  22295. if ( times.length !== 0 ) {
  22296. destTracks.push( new trackType( trackName, times, values ) );
  22297. }
  22298. }
  22299. };
  22300. const tracks = [];
  22301. const clipName = animation.name || 'default';
  22302. const fps = animation.fps || 30;
  22303. const blendMode = animation.blendMode;
  22304. // automatic length determination in AnimationClip.
  22305. let duration = animation.length || - 1;
  22306. const hierarchyTracks = animation.hierarchy || [];
  22307. for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
  22308. const animationKeys = hierarchyTracks[ h ].keys;
  22309. // skip empty tracks
  22310. if ( ! animationKeys || animationKeys.length === 0 ) continue;
  22311. // process morph targets
  22312. if ( animationKeys[ 0 ].morphTargets ) {
  22313. // figure out all morph targets used in this track
  22314. const morphTargetNames = {};
  22315. let k;
  22316. for ( k = 0; k < animationKeys.length; k ++ ) {
  22317. if ( animationKeys[ k ].morphTargets ) {
  22318. for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
  22319. morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
  22320. }
  22321. }
  22322. }
  22323. // create a track for each morph target with all zero
  22324. // morphTargetInfluences except for the keys in which
  22325. // the morphTarget is named.
  22326. for ( const morphTargetName in morphTargetNames ) {
  22327. const times = [];
  22328. const values = [];
  22329. for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
  22330. const animationKey = animationKeys[ k ];
  22331. times.push( animationKey.time );
  22332. values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
  22333. }
  22334. tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
  22335. }
  22336. duration = morphTargetNames.length * ( fps || 1.0 );
  22337. } else {
  22338. // ...assume skeletal animation
  22339. const boneName = '.bones[' + bones[ h ].name + ']';
  22340. addNonemptyTrack(
  22341. VectorKeyframeTrack, boneName + '.position',
  22342. animationKeys, 'pos', tracks );
  22343. addNonemptyTrack(
  22344. QuaternionKeyframeTrack, boneName + '.quaternion',
  22345. animationKeys, 'rot', tracks );
  22346. addNonemptyTrack(
  22347. VectorKeyframeTrack, boneName + '.scale',
  22348. animationKeys, 'scl', tracks );
  22349. }
  22350. }
  22351. if ( tracks.length === 0 ) {
  22352. return null;
  22353. }
  22354. const clip = new AnimationClip( clipName, duration, tracks, blendMode );
  22355. return clip;
  22356. }
  22357. } );
  22358. Object.assign( AnimationClip.prototype, {
  22359. resetDuration: function () {
  22360. const tracks = this.tracks;
  22361. let duration = 0;
  22362. for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
  22363. const track = this.tracks[ i ];
  22364. duration = Math.max( duration, track.times[ track.times.length - 1 ] );
  22365. }
  22366. this.duration = duration;
  22367. return this;
  22368. },
  22369. trim: function () {
  22370. for ( let i = 0; i < this.tracks.length; i ++ ) {
  22371. this.tracks[ i ].trim( 0, this.duration );
  22372. }
  22373. return this;
  22374. },
  22375. validate: function () {
  22376. let valid = true;
  22377. for ( let i = 0; i < this.tracks.length; i ++ ) {
  22378. valid = valid && this.tracks[ i ].validate();
  22379. }
  22380. return valid;
  22381. },
  22382. optimize: function () {
  22383. for ( let i = 0; i < this.tracks.length; i ++ ) {
  22384. this.tracks[ i ].optimize();
  22385. }
  22386. return this;
  22387. },
  22388. clone: function () {
  22389. const tracks = [];
  22390. for ( let i = 0; i < this.tracks.length; i ++ ) {
  22391. tracks.push( this.tracks[ i ].clone() );
  22392. }
  22393. return new AnimationClip( this.name, this.duration, tracks, this.blendMode );
  22394. },
  22395. toJSON: function () {
  22396. return AnimationClip.toJSON( this );
  22397. }
  22398. } );
  22399. const Cache = {
  22400. enabled: false,
  22401. files: {},
  22402. add: function ( key, file ) {
  22403. if ( this.enabled === false ) return;
  22404. // console.log( 'THREE.Cache', 'Adding key:', key );
  22405. this.files[ key ] = file;
  22406. },
  22407. get: function ( key ) {
  22408. if ( this.enabled === false ) return;
  22409. // console.log( 'THREE.Cache', 'Checking key:', key );
  22410. return this.files[ key ];
  22411. },
  22412. remove: function ( key ) {
  22413. delete this.files[ key ];
  22414. },
  22415. clear: function () {
  22416. this.files = {};
  22417. }
  22418. };
  22419. function LoadingManager( onLoad, onProgress, onError ) {
  22420. const scope = this;
  22421. let isLoading = false;
  22422. let itemsLoaded = 0;
  22423. let itemsTotal = 0;
  22424. let urlModifier = undefined;
  22425. const handlers = [];
  22426. // Refer to #5689 for the reason why we don't set .onStart
  22427. // in the constructor
  22428. this.onStart = undefined;
  22429. this.onLoad = onLoad;
  22430. this.onProgress = onProgress;
  22431. this.onError = onError;
  22432. this.itemStart = function ( url ) {
  22433. itemsTotal ++;
  22434. if ( isLoading === false ) {
  22435. if ( scope.onStart !== undefined ) {
  22436. scope.onStart( url, itemsLoaded, itemsTotal );
  22437. }
  22438. }
  22439. isLoading = true;
  22440. };
  22441. this.itemEnd = function ( url ) {
  22442. itemsLoaded ++;
  22443. if ( scope.onProgress !== undefined ) {
  22444. scope.onProgress( url, itemsLoaded, itemsTotal );
  22445. }
  22446. if ( itemsLoaded === itemsTotal ) {
  22447. isLoading = false;
  22448. if ( scope.onLoad !== undefined ) {
  22449. scope.onLoad();
  22450. }
  22451. }
  22452. };
  22453. this.itemError = function ( url ) {
  22454. if ( scope.onError !== undefined ) {
  22455. scope.onError( url );
  22456. }
  22457. };
  22458. this.resolveURL = function ( url ) {
  22459. if ( urlModifier ) {
  22460. return urlModifier( url );
  22461. }
  22462. return url;
  22463. };
  22464. this.setURLModifier = function ( transform ) {
  22465. urlModifier = transform;
  22466. return this;
  22467. };
  22468. this.addHandler = function ( regex, loader ) {
  22469. handlers.push( regex, loader );
  22470. return this;
  22471. };
  22472. this.removeHandler = function ( regex ) {
  22473. const index = handlers.indexOf( regex );
  22474. if ( index !== - 1 ) {
  22475. handlers.splice( index, 2 );
  22476. }
  22477. return this;
  22478. };
  22479. this.getHandler = function ( file ) {
  22480. for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
  22481. const regex = handlers[ i ];
  22482. const loader = handlers[ i + 1 ];
  22483. if ( regex.global ) regex.lastIndex = 0; // see #17920
  22484. if ( regex.test( file ) ) {
  22485. return loader;
  22486. }
  22487. }
  22488. return null;
  22489. };
  22490. }
  22491. const DefaultLoadingManager = new LoadingManager();
  22492. function Loader( manager ) {
  22493. this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
  22494. this.crossOrigin = 'anonymous';
  22495. this.withCredentials = false;
  22496. this.path = '';
  22497. this.resourcePath = '';
  22498. this.requestHeader = {};
  22499. }
  22500. Object.assign( Loader.prototype, {
  22501. load: function ( /* url, onLoad, onProgress, onError */ ) {},
  22502. loadAsync: function ( url, onProgress ) {
  22503. const scope = this;
  22504. return new Promise( function ( resolve, reject ) {
  22505. scope.load( url, resolve, onProgress, reject );
  22506. } );
  22507. },
  22508. parse: function ( /* data */ ) {},
  22509. setCrossOrigin: function ( crossOrigin ) {
  22510. this.crossOrigin = crossOrigin;
  22511. return this;
  22512. },
  22513. setWithCredentials: function ( value ) {
  22514. this.withCredentials = value;
  22515. return this;
  22516. },
  22517. setPath: function ( path ) {
  22518. this.path = path;
  22519. return this;
  22520. },
  22521. setResourcePath: function ( resourcePath ) {
  22522. this.resourcePath = resourcePath;
  22523. return this;
  22524. },
  22525. setRequestHeader: function ( requestHeader ) {
  22526. this.requestHeader = requestHeader;
  22527. return this;
  22528. }
  22529. } );
  22530. const loading = {};
  22531. function FileLoader( manager ) {
  22532. Loader.call( this, manager );
  22533. }
  22534. FileLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22535. constructor: FileLoader,
  22536. load: function ( url, onLoad, onProgress, onError ) {
  22537. if ( url === undefined ) url = '';
  22538. if ( this.path !== undefined ) url = this.path + url;
  22539. url = this.manager.resolveURL( url );
  22540. const scope = this;
  22541. const cached = Cache.get( url );
  22542. if ( cached !== undefined ) {
  22543. scope.manager.itemStart( url );
  22544. setTimeout( function () {
  22545. if ( onLoad ) onLoad( cached );
  22546. scope.manager.itemEnd( url );
  22547. }, 0 );
  22548. return cached;
  22549. }
  22550. // Check if request is duplicate
  22551. if ( loading[ url ] !== undefined ) {
  22552. loading[ url ].push( {
  22553. onLoad: onLoad,
  22554. onProgress: onProgress,
  22555. onError: onError
  22556. } );
  22557. return;
  22558. }
  22559. // Check for data: URI
  22560. const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
  22561. const dataUriRegexResult = url.match( dataUriRegex );
  22562. let request;
  22563. // Safari can not handle Data URIs through XMLHttpRequest so process manually
  22564. if ( dataUriRegexResult ) {
  22565. const mimeType = dataUriRegexResult[ 1 ];
  22566. const isBase64 = !! dataUriRegexResult[ 2 ];
  22567. let data = dataUriRegexResult[ 3 ];
  22568. data = decodeURIComponent( data );
  22569. if ( isBase64 ) data = atob( data );
  22570. try {
  22571. let response;
  22572. const responseType = ( this.responseType || '' ).toLowerCase();
  22573. switch ( responseType ) {
  22574. case 'arraybuffer':
  22575. case 'blob':
  22576. const view = new Uint8Array( data.length );
  22577. for ( let i = 0; i < data.length; i ++ ) {
  22578. view[ i ] = data.charCodeAt( i );
  22579. }
  22580. if ( responseType === 'blob' ) {
  22581. response = new Blob( [ view.buffer ], { type: mimeType } );
  22582. } else {
  22583. response = view.buffer;
  22584. }
  22585. break;
  22586. case 'document':
  22587. const parser = new DOMParser();
  22588. response = parser.parseFromString( data, mimeType );
  22589. break;
  22590. case 'json':
  22591. response = JSON.parse( data );
  22592. break;
  22593. default: // 'text' or other
  22594. response = data;
  22595. break;
  22596. }
  22597. // Wait for next browser tick like standard XMLHttpRequest event dispatching does
  22598. setTimeout( function () {
  22599. if ( onLoad ) onLoad( response );
  22600. scope.manager.itemEnd( url );
  22601. }, 0 );
  22602. } catch ( error ) {
  22603. // Wait for next browser tick like standard XMLHttpRequest event dispatching does
  22604. setTimeout( function () {
  22605. if ( onError ) onError( error );
  22606. scope.manager.itemError( url );
  22607. scope.manager.itemEnd( url );
  22608. }, 0 );
  22609. }
  22610. } else {
  22611. // Initialise array for duplicate requests
  22612. loading[ url ] = [];
  22613. loading[ url ].push( {
  22614. onLoad: onLoad,
  22615. onProgress: onProgress,
  22616. onError: onError
  22617. } );
  22618. request = new XMLHttpRequest();
  22619. request.open( 'GET', url, true );
  22620. request.addEventListener( 'load', function ( event ) {
  22621. const response = this.response;
  22622. const callbacks = loading[ url ];
  22623. delete loading[ url ];
  22624. if ( this.status === 200 || this.status === 0 ) {
  22625. // Some browsers return HTTP Status 0 when using non-http protocol
  22626. // e.g. 'file://' or 'data://'. Handle as success.
  22627. if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
  22628. // Add to cache only on HTTP success, so that we do not cache
  22629. // error response bodies as proper responses to requests.
  22630. Cache.add( url, response );
  22631. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  22632. const callback = callbacks[ i ];
  22633. if ( callback.onLoad ) callback.onLoad( response, event.total); //xzw add event.total
  22634. }
  22635. scope.manager.itemEnd( url );
  22636. } else {
  22637. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  22638. const callback = callbacks[ i ];
  22639. if ( callback.onError ) callback.onError( event );
  22640. }
  22641. scope.manager.itemError( url );
  22642. scope.manager.itemEnd( url );
  22643. }
  22644. }, false );
  22645. request.addEventListener( 'progress', function ( event ) {
  22646. const callbacks = loading[ url ];
  22647. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  22648. const callback = callbacks[ i ];
  22649. if ( callback.onProgress ) callback.onProgress( event );
  22650. }
  22651. }, false );
  22652. request.addEventListener( 'error', function ( event ) {
  22653. const callbacks = loading[ url ];
  22654. delete loading[ url ];
  22655. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  22656. const callback = callbacks[ i ];
  22657. if ( callback.onError ) callback.onError( event );
  22658. }
  22659. scope.manager.itemError( url );
  22660. scope.manager.itemEnd( url );
  22661. }, false );
  22662. request.addEventListener( 'abort', function ( event ) {
  22663. const callbacks = loading[ url ];
  22664. delete loading[ url ];
  22665. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  22666. const callback = callbacks[ i ];
  22667. if ( callback.onError ) callback.onError( event );
  22668. }
  22669. scope.manager.itemError( url );
  22670. scope.manager.itemEnd( url );
  22671. }, false );
  22672. if ( this.responseType !== undefined ) request.responseType = this.responseType;
  22673. if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
  22674. if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
  22675. for ( const header in this.requestHeader ) {
  22676. request.setRequestHeader( header, this.requestHeader[ header ] );
  22677. }
  22678. request.send( null );
  22679. }
  22680. scope.manager.itemStart( url );
  22681. return request;
  22682. },
  22683. setResponseType: function ( value ) {
  22684. this.responseType = value;
  22685. return this;
  22686. },
  22687. setMimeType: function ( value ) {
  22688. this.mimeType = value;
  22689. return this;
  22690. }
  22691. } );
  22692. function AnimationLoader( manager ) {
  22693. Loader.call( this, manager );
  22694. }
  22695. AnimationLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22696. constructor: AnimationLoader,
  22697. load: function ( url, onLoad, onProgress, onError ) {
  22698. const scope = this;
  22699. const loader = new FileLoader( scope.manager );
  22700. loader.setPath( scope.path );
  22701. loader.setRequestHeader( scope.requestHeader );
  22702. loader.setWithCredentials( scope.withCredentials );
  22703. loader.load( url, function ( text ) {
  22704. try {
  22705. onLoad( scope.parse( JSON.parse( text ) ) );
  22706. } catch ( e ) {
  22707. if ( onError ) {
  22708. onError( e );
  22709. } else {
  22710. console.error( e );
  22711. }
  22712. scope.manager.itemError( url );
  22713. }
  22714. }, onProgress, onError );
  22715. },
  22716. parse: function ( json ) {
  22717. const animations = [];
  22718. for ( let i = 0; i < json.length; i ++ ) {
  22719. const clip = AnimationClip.parse( json[ i ] );
  22720. animations.push( clip );
  22721. }
  22722. return animations;
  22723. }
  22724. } );
  22725. /**
  22726. * Abstract Base class to block based textures loader (dds, pvr, ...)
  22727. *
  22728. * Sub classes have to implement the parse() method which will be used in load().
  22729. */
  22730. function CompressedTextureLoader( manager ) {
  22731. Loader.call( this, manager );
  22732. }
  22733. CompressedTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22734. constructor: CompressedTextureLoader,
  22735. load: function ( url, onLoad, onProgress, onError ) {
  22736. const scope = this;
  22737. const images = [];
  22738. const texture = new CompressedTexture();
  22739. const loader = new FileLoader( this.manager );
  22740. loader.setPath( this.path );
  22741. loader.setResponseType( 'arraybuffer' );
  22742. loader.setRequestHeader( this.requestHeader );
  22743. loader.setWithCredentials( scope.withCredentials );
  22744. let loaded = 0;
  22745. function loadTexture( i ) {
  22746. loader.load( url[ i ], function ( buffer ) {
  22747. const texDatas = scope.parse( buffer, true );
  22748. images[ i ] = {
  22749. width: texDatas.width,
  22750. height: texDatas.height,
  22751. format: texDatas.format,
  22752. mipmaps: texDatas.mipmaps
  22753. };
  22754. loaded += 1;
  22755. if ( loaded === 6 ) {
  22756. if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
  22757. texture.image = images;
  22758. texture.format = texDatas.format;
  22759. texture.needsUpdate = true;
  22760. if ( onLoad ) onLoad( texture );
  22761. }
  22762. }, onProgress, onError );
  22763. }
  22764. if ( Array.isArray( url ) ) {
  22765. for ( let i = 0, il = url.length; i < il; ++ i ) {
  22766. loadTexture( i );
  22767. }
  22768. } else {
  22769. // compressed cubemap texture stored in a single DDS file
  22770. loader.load( url, function ( buffer ) {
  22771. const texDatas = scope.parse( buffer, true );
  22772. if ( texDatas.isCubemap ) {
  22773. const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
  22774. for ( let f = 0; f < faces; f ++ ) {
  22775. images[ f ] = { mipmaps: [] };
  22776. for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
  22777. images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
  22778. images[ f ].format = texDatas.format;
  22779. images[ f ].width = texDatas.width;
  22780. images[ f ].height = texDatas.height;
  22781. }
  22782. }
  22783. texture.image = images;
  22784. } else {
  22785. texture.image.width = texDatas.width;
  22786. texture.image.height = texDatas.height;
  22787. texture.mipmaps = texDatas.mipmaps;
  22788. }
  22789. if ( texDatas.mipmapCount === 1 ) {
  22790. texture.minFilter = LinearFilter;
  22791. }
  22792. texture.format = texDatas.format;
  22793. texture.needsUpdate = true;
  22794. if ( onLoad ) onLoad( texture );
  22795. }, onProgress, onError );
  22796. }
  22797. return texture;
  22798. }
  22799. } );
  22800. function ImageLoader( manager ) {
  22801. Loader.call( this, manager );
  22802. }
  22803. ImageLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22804. constructor: ImageLoader,
  22805. load: function ( url, onLoad, onProgress, onError ) {
  22806. if ( this.path !== undefined ) url = this.path + url;
  22807. url = this.manager.resolveURL( url );
  22808. const scope = this;
  22809. const cached = Cache.get( url );
  22810. if ( cached !== undefined ) {
  22811. scope.manager.itemStart( url );
  22812. setTimeout( function () {
  22813. if ( onLoad ) onLoad( cached );
  22814. scope.manager.itemEnd( url );
  22815. }, 0 );
  22816. return cached;
  22817. }
  22818. const image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
  22819. function onImageLoad() {
  22820. image.removeEventListener( 'load', onImageLoad, false );
  22821. image.removeEventListener( 'error', onImageError, false );
  22822. Cache.add( url, this );
  22823. if ( onLoad ) onLoad( this );
  22824. scope.manager.itemEnd( url );
  22825. }
  22826. function onImageError( event ) {
  22827. image.removeEventListener( 'load', onImageLoad, false );
  22828. image.removeEventListener( 'error', onImageError, false );
  22829. if ( onError ) onError( event );
  22830. scope.manager.itemError( url );
  22831. scope.manager.itemEnd( url );
  22832. }
  22833. image.addEventListener( 'load', onImageLoad, false );
  22834. image.addEventListener( 'error', onImageError, false );
  22835. if ( url.substr( 0, 5 ) !== 'data:' ) {
  22836. if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
  22837. }
  22838. scope.manager.itemStart( url );
  22839. image.src = url;
  22840. return image;
  22841. }
  22842. } );
  22843. function CubeTextureLoader( manager ) {
  22844. Loader.call( this, manager );
  22845. }
  22846. CubeTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22847. constructor: CubeTextureLoader,
  22848. load: function ( urls, onLoad, onProgress, onError ) {
  22849. const texture = new CubeTexture();
  22850. const loader = new ImageLoader( this.manager );
  22851. loader.setCrossOrigin( this.crossOrigin );
  22852. loader.setPath( this.path );
  22853. let loaded = 0;
  22854. function loadTexture( i ) {
  22855. loader.load( urls[ i ], function ( image ) {
  22856. texture.images[ i ] = image;
  22857. loaded ++;
  22858. if ( loaded === 6 ) {
  22859. texture.needsUpdate = true;
  22860. if ( onLoad ) onLoad( texture );
  22861. }
  22862. }, undefined, onError );
  22863. }
  22864. for ( let i = 0; i < urls.length; ++ i ) {
  22865. loadTexture( i );
  22866. }
  22867. return texture;
  22868. }
  22869. } );
  22870. /**
  22871. * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
  22872. *
  22873. * Sub classes have to implement the parse() method which will be used in load().
  22874. */
  22875. function DataTextureLoader( manager ) {
  22876. Loader.call( this, manager );
  22877. }
  22878. DataTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22879. constructor: DataTextureLoader,
  22880. load: function ( url, onLoad, onProgress, onError ) {
  22881. const scope = this;
  22882. const texture = new DataTexture();
  22883. const loader = new FileLoader( this.manager );
  22884. loader.setResponseType( 'arraybuffer' );
  22885. loader.setRequestHeader( this.requestHeader );
  22886. loader.setPath( this.path );
  22887. loader.setWithCredentials( scope.withCredentials );
  22888. loader.load( url, function ( buffer ) {
  22889. const texData = scope.parse( buffer );
  22890. if ( ! texData ) return;
  22891. if ( texData.image !== undefined ) {
  22892. texture.image = texData.image;
  22893. } else if ( texData.data !== undefined ) {
  22894. texture.image.width = texData.width;
  22895. texture.image.height = texData.height;
  22896. texture.image.data = texData.data;
  22897. }
  22898. texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
  22899. texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
  22900. texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
  22901. texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
  22902. texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
  22903. if ( texData.format !== undefined ) {
  22904. texture.format = texData.format;
  22905. }
  22906. if ( texData.type !== undefined ) {
  22907. texture.type = texData.type;
  22908. }
  22909. if ( texData.mipmaps !== undefined ) {
  22910. texture.mipmaps = texData.mipmaps;
  22911. texture.minFilter = LinearMipmapLinearFilter; // presumably...
  22912. }
  22913. if ( texData.mipmapCount === 1 ) {
  22914. texture.minFilter = LinearFilter;
  22915. }
  22916. texture.needsUpdate = true;
  22917. if ( onLoad ) onLoad( texture, texData );
  22918. }, onProgress, onError );
  22919. return texture;
  22920. }
  22921. } );
  22922. function TextureLoader( manager ) {
  22923. Loader.call( this, manager );
  22924. }
  22925. TextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  22926. constructor: TextureLoader,
  22927. load: function ( url, onLoad, onProgress, onError ) {
  22928. const texture = new Texture();
  22929. const loader = new ImageLoader( this.manager );
  22930. loader.setCrossOrigin( this.crossOrigin );
  22931. loader.setPath( this.path );
  22932. loader.load( url, function ( image ) {
  22933. texture.image = image;
  22934. // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
  22935. const isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
  22936. texture.format = isJPEG ? RGBFormat : RGBAFormat;
  22937. texture.needsUpdate = true;
  22938. if ( onLoad !== undefined ) {
  22939. onLoad( texture );
  22940. }
  22941. }, onProgress, onError );
  22942. return texture;
  22943. }
  22944. } );
  22945. /**
  22946. * Extensible curve object.
  22947. *
  22948. * Some common of curve methods:
  22949. * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
  22950. * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
  22951. * .getPoints(), .getSpacedPoints()
  22952. * .getLength()
  22953. * .updateArcLengths()
  22954. *
  22955. * This following curves inherit from THREE.Curve:
  22956. *
  22957. * -- 2D curves --
  22958. * THREE.ArcCurve
  22959. * THREE.CubicBezierCurve
  22960. * THREE.EllipseCurve
  22961. * THREE.LineCurve
  22962. * THREE.QuadraticBezierCurve
  22963. * THREE.SplineCurve
  22964. *
  22965. * -- 3D curves --
  22966. * THREE.CatmullRomCurve3
  22967. * THREE.CubicBezierCurve3
  22968. * THREE.LineCurve3
  22969. * THREE.QuadraticBezierCurve3
  22970. *
  22971. * A series of curves can be represented as a THREE.CurvePath.
  22972. *
  22973. **/
  22974. function Curve() {
  22975. this.type = 'Curve';
  22976. this.arcLengthDivisions = 200;
  22977. }
  22978. Object.assign( Curve.prototype, {
  22979. // Virtual base class method to overwrite and implement in subclasses
  22980. // - t [0 .. 1]
  22981. getPoint: function ( /* t, optionalTarget */ ) {
  22982. console.warn( 'THREE.Curve: .getPoint() not implemented.' );
  22983. return null;
  22984. },
  22985. // Get point at relative position in curve according to arc length
  22986. // - u [0 .. 1]
  22987. getPointAt: function ( u, optionalTarget ) {
  22988. const t = this.getUtoTmapping( u );
  22989. return this.getPoint( t, optionalTarget );
  22990. },
  22991. // Get sequence of points using getPoint( t )
  22992. getPoints: function ( divisions = 5 ) {
  22993. const points = [];
  22994. for ( let d = 0; d <= divisions; d ++ ) {
  22995. points.push( this.getPoint( d / divisions ) );
  22996. }
  22997. return points;
  22998. },
  22999. // Get sequence of points using getPointAt( u )
  23000. getSpacedPoints: function ( divisions = 5 ) {
  23001. const points = [];
  23002. for ( let d = 0; d <= divisions; d ++ ) {
  23003. points.push( this.getPointAt( d / divisions ) );
  23004. }
  23005. return points;
  23006. },
  23007. // Get total curve arc length
  23008. getLength: function () {
  23009. const lengths = this.getLengths();
  23010. return lengths[ lengths.length - 1 ];
  23011. },
  23012. // Get list of cumulative segment lengths
  23013. getLengths: function ( divisions ) {
  23014. if ( divisions === undefined ) divisions = this.arcLengthDivisions;
  23015. if ( this.cacheArcLengths &&
  23016. ( this.cacheArcLengths.length === divisions + 1 ) &&
  23017. ! this.needsUpdate ) {
  23018. return this.cacheArcLengths;
  23019. }
  23020. this.needsUpdate = false;
  23021. const cache = [];
  23022. let current, last = this.getPoint( 0 );
  23023. let sum = 0;
  23024. cache.push( 0 );
  23025. for ( let p = 1; p <= divisions; p ++ ) {
  23026. current = this.getPoint( p / divisions );
  23027. sum += current.distanceTo( last );
  23028. cache.push( sum );
  23029. last = current;
  23030. }
  23031. this.cacheArcLengths = cache;
  23032. return cache; // { sums: cache, sum: sum }; Sum is in the last element.
  23033. },
  23034. updateArcLengths: function () {
  23035. this.needsUpdate = true;
  23036. this.getLengths();
  23037. },
  23038. // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
  23039. getUtoTmapping: function ( u, distance ) {
  23040. const arcLengths = this.getLengths();
  23041. let i = 0;
  23042. const il = arcLengths.length;
  23043. let targetArcLength; // The targeted u distance value to get
  23044. if ( distance ) {
  23045. targetArcLength = distance;
  23046. } else {
  23047. targetArcLength = u * arcLengths[ il - 1 ];
  23048. }
  23049. // binary search for the index with largest value smaller than target u distance
  23050. let low = 0, high = il - 1, comparison;
  23051. while ( low <= high ) {
  23052. i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
  23053. comparison = arcLengths[ i ] - targetArcLength;
  23054. if ( comparison < 0 ) {
  23055. low = i + 1;
  23056. } else if ( comparison > 0 ) {
  23057. high = i - 1;
  23058. } else {
  23059. high = i;
  23060. break;
  23061. // DONE
  23062. }
  23063. }
  23064. i = high;
  23065. if ( arcLengths[ i ] === targetArcLength ) {
  23066. return i / ( il - 1 );
  23067. }
  23068. // we could get finer grain at lengths, or use simple interpolation between two points
  23069. const lengthBefore = arcLengths[ i ];
  23070. const lengthAfter = arcLengths[ i + 1 ];
  23071. const segmentLength = lengthAfter - lengthBefore;
  23072. // determine where we are between the 'before' and 'after' points
  23073. const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
  23074. // add that fractional amount to t
  23075. const t = ( i + segmentFraction ) / ( il - 1 );
  23076. return t;
  23077. },
  23078. // Returns a unit vector tangent at t
  23079. // In case any sub curve does not implement its tangent derivation,
  23080. // 2 points a small delta apart will be used to find its gradient
  23081. // which seems to give a reasonable approximation
  23082. getTangent: function ( t, optionalTarget ) {
  23083. const delta = 0.0001;
  23084. let t1 = t - delta;
  23085. let t2 = t + delta;
  23086. // Capping in case of danger
  23087. if ( t1 < 0 ) t1 = 0;
  23088. if ( t2 > 1 ) t2 = 1;
  23089. const pt1 = this.getPoint( t1 );
  23090. const pt2 = this.getPoint( t2 );
  23091. const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2$1() : new Vector3() );
  23092. tangent.copy( pt2 ).sub( pt1 ).normalize();
  23093. return tangent;
  23094. },
  23095. getTangentAt: function ( u, optionalTarget ) {
  23096. const t = this.getUtoTmapping( u );
  23097. return this.getTangent( t, optionalTarget );
  23098. },
  23099. computeFrenetFrames: function ( segments, closed ) {
  23100. // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
  23101. const normal = new Vector3();
  23102. const tangents = [];
  23103. const normals = [];
  23104. const binormals = [];
  23105. const vec = new Vector3();
  23106. const mat = new Matrix4();
  23107. // compute the tangent vectors for each segment on the curve
  23108. for ( let i = 0; i <= segments; i ++ ) {
  23109. const u = i / segments;
  23110. tangents[ i ] = this.getTangentAt( u, new Vector3() );
  23111. tangents[ i ].normalize();
  23112. }
  23113. // select an initial normal vector perpendicular to the first tangent vector,
  23114. // and in the direction of the minimum tangent xyz component
  23115. normals[ 0 ] = new Vector3();
  23116. binormals[ 0 ] = new Vector3();
  23117. let min = Number.MAX_VALUE;
  23118. const tx = Math.abs( tangents[ 0 ].x );
  23119. const ty = Math.abs( tangents[ 0 ].y );
  23120. const tz = Math.abs( tangents[ 0 ].z );
  23121. if ( tx <= min ) {
  23122. min = tx;
  23123. normal.set( 1, 0, 0 );
  23124. }
  23125. if ( ty <= min ) {
  23126. min = ty;
  23127. normal.set( 0, 1, 0 );
  23128. }
  23129. if ( tz <= min ) {
  23130. normal.set( 0, 0, 1 );
  23131. }
  23132. vec.crossVectors( tangents[ 0 ], normal ).normalize();
  23133. normals[ 0 ].crossVectors( tangents[ 0 ], vec );
  23134. binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
  23135. // compute the slowly-varying normal and binormal vectors for each segment on the curve
  23136. for ( let i = 1; i <= segments; i ++ ) {
  23137. normals[ i ] = normals[ i - 1 ].clone();
  23138. binormals[ i ] = binormals[ i - 1 ].clone();
  23139. vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
  23140. if ( vec.length() > Number.EPSILON ) {
  23141. vec.normalize();
  23142. const theta = Math.acos( MathUtils.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
  23143. normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
  23144. }
  23145. binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
  23146. }
  23147. // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
  23148. if ( closed === true ) {
  23149. let theta = Math.acos( MathUtils.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
  23150. theta /= segments;
  23151. if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
  23152. theta = - theta;
  23153. }
  23154. for ( let i = 1; i <= segments; i ++ ) {
  23155. // twist a little...
  23156. normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
  23157. binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
  23158. }
  23159. }
  23160. return {
  23161. tangents: tangents,
  23162. normals: normals,
  23163. binormals: binormals
  23164. };
  23165. },
  23166. clone: function () {
  23167. return new this.constructor().copy( this );
  23168. },
  23169. copy: function ( source ) {
  23170. this.arcLengthDivisions = source.arcLengthDivisions;
  23171. return this;
  23172. },
  23173. toJSON: function () {
  23174. const data = {
  23175. metadata: {
  23176. version: 4.5,
  23177. type: 'Curve',
  23178. generator: 'Curve.toJSON'
  23179. }
  23180. };
  23181. data.arcLengthDivisions = this.arcLengthDivisions;
  23182. data.type = this.type;
  23183. return data;
  23184. },
  23185. fromJSON: function ( json ) {
  23186. this.arcLengthDivisions = json.arcLengthDivisions;
  23187. return this;
  23188. }
  23189. } );
  23190. function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
  23191. Curve.call( this );
  23192. this.type = 'EllipseCurve';
  23193. this.aX = aX || 0;
  23194. this.aY = aY || 0;
  23195. this.xRadius = xRadius || 1;
  23196. this.yRadius = yRadius || 1;
  23197. this.aStartAngle = aStartAngle || 0;
  23198. this.aEndAngle = aEndAngle || 2 * Math.PI;
  23199. this.aClockwise = aClockwise || false;
  23200. this.aRotation = aRotation || 0;
  23201. }
  23202. EllipseCurve.prototype = Object.create( Curve.prototype );
  23203. EllipseCurve.prototype.constructor = EllipseCurve;
  23204. EllipseCurve.prototype.isEllipseCurve = true;
  23205. EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) {
  23206. const point = optionalTarget || new Vector2$1();
  23207. const twoPi = Math.PI * 2;
  23208. let deltaAngle = this.aEndAngle - this.aStartAngle;
  23209. const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
  23210. // ensures that deltaAngle is 0 .. 2 PI
  23211. while ( deltaAngle < 0 ) deltaAngle += twoPi;
  23212. while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
  23213. if ( deltaAngle < Number.EPSILON ) {
  23214. if ( samePoints ) {
  23215. deltaAngle = 0;
  23216. } else {
  23217. deltaAngle = twoPi;
  23218. }
  23219. }
  23220. if ( this.aClockwise === true && ! samePoints ) {
  23221. if ( deltaAngle === twoPi ) {
  23222. deltaAngle = - twoPi;
  23223. } else {
  23224. deltaAngle = deltaAngle - twoPi;
  23225. }
  23226. }
  23227. const angle = this.aStartAngle + t * deltaAngle;
  23228. let x = this.aX + this.xRadius * Math.cos( angle );
  23229. let y = this.aY + this.yRadius * Math.sin( angle );
  23230. if ( this.aRotation !== 0 ) {
  23231. const cos = Math.cos( this.aRotation );
  23232. const sin = Math.sin( this.aRotation );
  23233. const tx = x - this.aX;
  23234. const ty = y - this.aY;
  23235. // Rotate the point about the center of the ellipse.
  23236. x = tx * cos - ty * sin + this.aX;
  23237. y = tx * sin + ty * cos + this.aY;
  23238. }
  23239. return point.set( x, y );
  23240. };
  23241. EllipseCurve.prototype.copy = function ( source ) {
  23242. Curve.prototype.copy.call( this, source );
  23243. this.aX = source.aX;
  23244. this.aY = source.aY;
  23245. this.xRadius = source.xRadius;
  23246. this.yRadius = source.yRadius;
  23247. this.aStartAngle = source.aStartAngle;
  23248. this.aEndAngle = source.aEndAngle;
  23249. this.aClockwise = source.aClockwise;
  23250. this.aRotation = source.aRotation;
  23251. return this;
  23252. };
  23253. EllipseCurve.prototype.toJSON = function () {
  23254. const data = Curve.prototype.toJSON.call( this );
  23255. data.aX = this.aX;
  23256. data.aY = this.aY;
  23257. data.xRadius = this.xRadius;
  23258. data.yRadius = this.yRadius;
  23259. data.aStartAngle = this.aStartAngle;
  23260. data.aEndAngle = this.aEndAngle;
  23261. data.aClockwise = this.aClockwise;
  23262. data.aRotation = this.aRotation;
  23263. return data;
  23264. };
  23265. EllipseCurve.prototype.fromJSON = function ( json ) {
  23266. Curve.prototype.fromJSON.call( this, json );
  23267. this.aX = json.aX;
  23268. this.aY = json.aY;
  23269. this.xRadius = json.xRadius;
  23270. this.yRadius = json.yRadius;
  23271. this.aStartAngle = json.aStartAngle;
  23272. this.aEndAngle = json.aEndAngle;
  23273. this.aClockwise = json.aClockwise;
  23274. this.aRotation = json.aRotation;
  23275. return this;
  23276. };
  23277. function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
  23278. EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
  23279. this.type = 'ArcCurve';
  23280. }
  23281. ArcCurve.prototype = Object.create( EllipseCurve.prototype );
  23282. ArcCurve.prototype.constructor = ArcCurve;
  23283. ArcCurve.prototype.isArcCurve = true;
  23284. /**
  23285. * Centripetal CatmullRom Curve - which is useful for avoiding
  23286. * cusps and self-intersections in non-uniform catmull rom curves.
  23287. * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
  23288. *
  23289. * curve.type accepts centripetal(default), chordal and catmullrom
  23290. * curve.tension is used for catmullrom which defaults to 0.5
  23291. */
  23292. /*
  23293. Based on an optimized c++ solution in
  23294. - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
  23295. - http://ideone.com/NoEbVM
  23296. This CubicPoly class could be used for reusing some variables and calculations,
  23297. but for three.js curve use, it could be possible inlined and flatten into a single function call
  23298. which can be placed in CurveUtils.
  23299. */
  23300. function CubicPoly() {
  23301. let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
  23302. /*
  23303. * Compute coefficients for a cubic polynomial
  23304. * p(s) = c0 + c1*s + c2*s^2 + c3*s^3
  23305. * such that
  23306. * p(0) = x0, p(1) = x1
  23307. * and
  23308. * p'(0) = t0, p'(1) = t1.
  23309. */
  23310. function init( x0, x1, t0, t1 ) {
  23311. c0 = x0;
  23312. c1 = t0;
  23313. c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
  23314. c3 = 2 * x0 - 2 * x1 + t0 + t1;
  23315. }
  23316. return {
  23317. initCatmullRom: function ( x0, x1, x2, x3, tension ) {
  23318. init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
  23319. },
  23320. initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
  23321. // compute tangents when parameterized in [t1,t2]
  23322. let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
  23323. let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
  23324. // rescale tangents for parametrization in [0,1]
  23325. t1 *= dt1;
  23326. t2 *= dt1;
  23327. init( x1, x2, t1, t2 );
  23328. },
  23329. calc: function ( t ) {
  23330. const t2 = t * t;
  23331. const t3 = t2 * t;
  23332. return c0 + c1 * t + c2 * t2 + c3 * t3;
  23333. }
  23334. };
  23335. }
  23336. //
  23337. const tmp = new Vector3();
  23338. const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();
  23339. function CatmullRomCurve3( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
  23340. Curve.call( this );
  23341. this.type = 'CatmullRomCurve3';
  23342. this.points = points;
  23343. this.closed = closed;
  23344. this.curveType = curveType;
  23345. this.tension = tension;
  23346. }
  23347. CatmullRomCurve3.prototype = Object.create( Curve.prototype );
  23348. CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
  23349. CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
  23350. CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
  23351. const point = optionalTarget;
  23352. const points = this.points;
  23353. const l = points.length;
  23354. const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
  23355. let intPoint = Math.floor( p );
  23356. let weight = p - intPoint;
  23357. if ( this.closed ) {
  23358. intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
  23359. } else if ( weight === 0 && intPoint === l - 1 ) {
  23360. intPoint = l - 2;
  23361. weight = 1;
  23362. }
  23363. let p0, p3; // 4 points (p1 & p2 defined below)
  23364. if ( this.closed || intPoint > 0 ) {
  23365. p0 = points[ ( intPoint - 1 ) % l ];
  23366. } else {
  23367. // extrapolate first point
  23368. tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
  23369. p0 = tmp;
  23370. }
  23371. const p1 = points[ intPoint % l ];
  23372. const p2 = points[ ( intPoint + 1 ) % l ];
  23373. if ( this.closed || intPoint + 2 < l ) {
  23374. p3 = points[ ( intPoint + 2 ) % l ];
  23375. } else {
  23376. // extrapolate last point
  23377. tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
  23378. p3 = tmp;
  23379. }
  23380. if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
  23381. // init Centripetal / Chordal Catmull-Rom
  23382. const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
  23383. let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
  23384. let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
  23385. let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
  23386. // safety check for repeated points
  23387. if ( dt1 < 1e-4 ) dt1 = 1.0;
  23388. if ( dt0 < 1e-4 ) dt0 = dt1;
  23389. if ( dt2 < 1e-4 ) dt2 = dt1;
  23390. px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
  23391. py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
  23392. pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
  23393. } else if ( this.curveType === 'catmullrom' ) {
  23394. px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
  23395. py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
  23396. pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
  23397. }
  23398. point.set(
  23399. px.calc( weight ),
  23400. py.calc( weight ),
  23401. pz.calc( weight )
  23402. );
  23403. return point;
  23404. };
  23405. CatmullRomCurve3.prototype.copy = function ( source ) {
  23406. Curve.prototype.copy.call( this, source );
  23407. this.points = [];
  23408. for ( let i = 0, l = source.points.length; i < l; i ++ ) {
  23409. const point = source.points[ i ];
  23410. this.points.push( point.clone() );
  23411. }
  23412. this.closed = source.closed;
  23413. this.curveType = source.curveType;
  23414. this.tension = source.tension;
  23415. return this;
  23416. };
  23417. CatmullRomCurve3.prototype.toJSON = function () {
  23418. const data = Curve.prototype.toJSON.call( this );
  23419. data.points = [];
  23420. for ( let i = 0, l = this.points.length; i < l; i ++ ) {
  23421. const point = this.points[ i ];
  23422. data.points.push( point.toArray() );
  23423. }
  23424. data.closed = this.closed;
  23425. data.curveType = this.curveType;
  23426. data.tension = this.tension;
  23427. return data;
  23428. };
  23429. CatmullRomCurve3.prototype.fromJSON = function ( json ) {
  23430. Curve.prototype.fromJSON.call( this, json );
  23431. this.points = [];
  23432. for ( let i = 0, l = json.points.length; i < l; i ++ ) {
  23433. const point = json.points[ i ];
  23434. this.points.push( new Vector3().fromArray( point ) );
  23435. }
  23436. this.closed = json.closed;
  23437. this.curveType = json.curveType;
  23438. this.tension = json.tension;
  23439. return this;
  23440. };
  23441. /**
  23442. * Bezier Curves formulas obtained from
  23443. * http://en.wikipedia.org/wiki/Bézier_curve
  23444. */
  23445. function CatmullRom( t, p0, p1, p2, p3 ) {
  23446. const v0 = ( p2 - p0 ) * 0.5;
  23447. const v1 = ( p3 - p1 ) * 0.5;
  23448. const t2 = t * t;
  23449. const t3 = t * t2;
  23450. return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
  23451. }
  23452. //
  23453. function QuadraticBezierP0( t, p ) {
  23454. const k = 1 - t;
  23455. return k * k * p;
  23456. }
  23457. function QuadraticBezierP1( t, p ) {
  23458. return 2 * ( 1 - t ) * t * p;
  23459. }
  23460. function QuadraticBezierP2( t, p ) {
  23461. return t * t * p;
  23462. }
  23463. function QuadraticBezier( t, p0, p1, p2 ) {
  23464. return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
  23465. QuadraticBezierP2( t, p2 );
  23466. }
  23467. //
  23468. function CubicBezierP0( t, p ) {
  23469. const k = 1 - t;
  23470. return k * k * k * p;
  23471. }
  23472. function CubicBezierP1( t, p ) {
  23473. const k = 1 - t;
  23474. return 3 * k * k * t * p;
  23475. }
  23476. function CubicBezierP2( t, p ) {
  23477. return 3 * ( 1 - t ) * t * t * p;
  23478. }
  23479. function CubicBezierP3( t, p ) {
  23480. return t * t * t * p;
  23481. }
  23482. function CubicBezier( t, p0, p1, p2, p3 ) {
  23483. return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
  23484. CubicBezierP3( t, p3 );
  23485. }
  23486. function CubicBezierCurve( v0 = new Vector2$1(), v1 = new Vector2$1(), v2 = new Vector2$1(), v3 = new Vector2$1() ) {
  23487. Curve.call( this );
  23488. this.type = 'CubicBezierCurve';
  23489. this.v0 = v0;
  23490. this.v1 = v1;
  23491. this.v2 = v2;
  23492. this.v3 = v3;
  23493. }
  23494. CubicBezierCurve.prototype = Object.create( Curve.prototype );
  23495. CubicBezierCurve.prototype.constructor = CubicBezierCurve;
  23496. CubicBezierCurve.prototype.isCubicBezierCurve = true;
  23497. CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2$1() ) {
  23498. const point = optionalTarget;
  23499. const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
  23500. point.set(
  23501. CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
  23502. CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
  23503. );
  23504. return point;
  23505. };
  23506. CubicBezierCurve.prototype.copy = function ( source ) {
  23507. Curve.prototype.copy.call( this, source );
  23508. this.v0.copy( source.v0 );
  23509. this.v1.copy( source.v1 );
  23510. this.v2.copy( source.v2 );
  23511. this.v3.copy( source.v3 );
  23512. return this;
  23513. };
  23514. CubicBezierCurve.prototype.toJSON = function () {
  23515. const data = Curve.prototype.toJSON.call( this );
  23516. data.v0 = this.v0.toArray();
  23517. data.v1 = this.v1.toArray();
  23518. data.v2 = this.v2.toArray();
  23519. data.v3 = this.v3.toArray();
  23520. return data;
  23521. };
  23522. CubicBezierCurve.prototype.fromJSON = function ( json ) {
  23523. Curve.prototype.fromJSON.call( this, json );
  23524. this.v0.fromArray( json.v0 );
  23525. this.v1.fromArray( json.v1 );
  23526. this.v2.fromArray( json.v2 );
  23527. this.v3.fromArray( json.v3 );
  23528. return this;
  23529. };
  23530. function CubicBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
  23531. Curve.call( this );
  23532. this.type = 'CubicBezierCurve3';
  23533. this.v0 = v0;
  23534. this.v1 = v1;
  23535. this.v2 = v2;
  23536. this.v3 = v3;
  23537. }
  23538. CubicBezierCurve3.prototype = Object.create( Curve.prototype );
  23539. CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
  23540. CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
  23541. CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
  23542. const point = optionalTarget;
  23543. const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
  23544. point.set(
  23545. CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
  23546. CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
  23547. CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
  23548. );
  23549. return point;
  23550. };
  23551. CubicBezierCurve3.prototype.copy = function ( source ) {
  23552. Curve.prototype.copy.call( this, source );
  23553. this.v0.copy( source.v0 );
  23554. this.v1.copy( source.v1 );
  23555. this.v2.copy( source.v2 );
  23556. this.v3.copy( source.v3 );
  23557. return this;
  23558. };
  23559. CubicBezierCurve3.prototype.toJSON = function () {
  23560. const data = Curve.prototype.toJSON.call( this );
  23561. data.v0 = this.v0.toArray();
  23562. data.v1 = this.v1.toArray();
  23563. data.v2 = this.v2.toArray();
  23564. data.v3 = this.v3.toArray();
  23565. return data;
  23566. };
  23567. CubicBezierCurve3.prototype.fromJSON = function ( json ) {
  23568. Curve.prototype.fromJSON.call( this, json );
  23569. this.v0.fromArray( json.v0 );
  23570. this.v1.fromArray( json.v1 );
  23571. this.v2.fromArray( json.v2 );
  23572. this.v3.fromArray( json.v3 );
  23573. return this;
  23574. };
  23575. function LineCurve( v1 = new Vector2$1(), v2 = new Vector2$1() ) {
  23576. Curve.call( this );
  23577. this.type = 'LineCurve';
  23578. this.v1 = v1;
  23579. this.v2 = v2;
  23580. }
  23581. LineCurve.prototype = Object.create( Curve.prototype );
  23582. LineCurve.prototype.constructor = LineCurve;
  23583. LineCurve.prototype.isLineCurve = true;
  23584. LineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2$1() ) {
  23585. const point = optionalTarget;
  23586. if ( t === 1 ) {
  23587. point.copy( this.v2 );
  23588. } else {
  23589. point.copy( this.v2 ).sub( this.v1 );
  23590. point.multiplyScalar( t ).add( this.v1 );
  23591. }
  23592. return point;
  23593. };
  23594. // Line curve is linear, so we can overwrite default getPointAt
  23595. LineCurve.prototype.getPointAt = function ( u, optionalTarget ) {
  23596. return this.getPoint( u, optionalTarget );
  23597. };
  23598. LineCurve.prototype.getTangent = function ( t, optionalTarget ) {
  23599. const tangent = optionalTarget || new Vector2$1();
  23600. tangent.copy( this.v2 ).sub( this.v1 ).normalize();
  23601. return tangent;
  23602. };
  23603. LineCurve.prototype.copy = function ( source ) {
  23604. Curve.prototype.copy.call( this, source );
  23605. this.v1.copy( source.v1 );
  23606. this.v2.copy( source.v2 );
  23607. return this;
  23608. };
  23609. LineCurve.prototype.toJSON = function () {
  23610. const data = Curve.prototype.toJSON.call( this );
  23611. data.v1 = this.v1.toArray();
  23612. data.v2 = this.v2.toArray();
  23613. return data;
  23614. };
  23615. LineCurve.prototype.fromJSON = function ( json ) {
  23616. Curve.prototype.fromJSON.call( this, json );
  23617. this.v1.fromArray( json.v1 );
  23618. this.v2.fromArray( json.v2 );
  23619. return this;
  23620. };
  23621. function LineCurve3( v1 = new Vector3(), v2 = new Vector3() ) {
  23622. Curve.call( this );
  23623. this.type = 'LineCurve3';
  23624. this.v1 = v1;
  23625. this.v2 = v2;
  23626. }
  23627. LineCurve3.prototype = Object.create( Curve.prototype );
  23628. LineCurve3.prototype.constructor = LineCurve3;
  23629. LineCurve3.prototype.isLineCurve3 = true;
  23630. LineCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
  23631. const point = optionalTarget;
  23632. if ( t === 1 ) {
  23633. point.copy( this.v2 );
  23634. } else {
  23635. point.copy( this.v2 ).sub( this.v1 );
  23636. point.multiplyScalar( t ).add( this.v1 );
  23637. }
  23638. return point;
  23639. };
  23640. // Line curve is linear, so we can overwrite default getPointAt
  23641. LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) {
  23642. return this.getPoint( u, optionalTarget );
  23643. };
  23644. LineCurve3.prototype.copy = function ( source ) {
  23645. Curve.prototype.copy.call( this, source );
  23646. this.v1.copy( source.v1 );
  23647. this.v2.copy( source.v2 );
  23648. return this;
  23649. };
  23650. LineCurve3.prototype.toJSON = function () {
  23651. const data = Curve.prototype.toJSON.call( this );
  23652. data.v1 = this.v1.toArray();
  23653. data.v2 = this.v2.toArray();
  23654. return data;
  23655. };
  23656. LineCurve3.prototype.fromJSON = function ( json ) {
  23657. Curve.prototype.fromJSON.call( this, json );
  23658. this.v1.fromArray( json.v1 );
  23659. this.v2.fromArray( json.v2 );
  23660. return this;
  23661. };
  23662. function QuadraticBezierCurve( v0 = new Vector2$1(), v1 = new Vector2$1(), v2 = new Vector2$1() ) {
  23663. Curve.call( this );
  23664. this.type = 'QuadraticBezierCurve';
  23665. this.v0 = v0;
  23666. this.v1 = v1;
  23667. this.v2 = v2;
  23668. }
  23669. QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
  23670. QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
  23671. QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
  23672. QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2$1() ) {
  23673. const point = optionalTarget;
  23674. const v0 = this.v0, v1 = this.v1, v2 = this.v2;
  23675. point.set(
  23676. QuadraticBezier( t, v0.x, v1.x, v2.x ),
  23677. QuadraticBezier( t, v0.y, v1.y, v2.y )
  23678. );
  23679. return point;
  23680. };
  23681. QuadraticBezierCurve.prototype.copy = function ( source ) {
  23682. Curve.prototype.copy.call( this, source );
  23683. this.v0.copy( source.v0 );
  23684. this.v1.copy( source.v1 );
  23685. this.v2.copy( source.v2 );
  23686. return this;
  23687. };
  23688. QuadraticBezierCurve.prototype.toJSON = function () {
  23689. const data = Curve.prototype.toJSON.call( this );
  23690. data.v0 = this.v0.toArray();
  23691. data.v1 = this.v1.toArray();
  23692. data.v2 = this.v2.toArray();
  23693. return data;
  23694. };
  23695. QuadraticBezierCurve.prototype.fromJSON = function ( json ) {
  23696. Curve.prototype.fromJSON.call( this, json );
  23697. this.v0.fromArray( json.v0 );
  23698. this.v1.fromArray( json.v1 );
  23699. this.v2.fromArray( json.v2 );
  23700. return this;
  23701. };
  23702. function QuadraticBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
  23703. Curve.call( this );
  23704. this.type = 'QuadraticBezierCurve3';
  23705. this.v0 = v0;
  23706. this.v1 = v1;
  23707. this.v2 = v2;
  23708. }
  23709. QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
  23710. QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
  23711. QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
  23712. QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
  23713. const point = optionalTarget;
  23714. const v0 = this.v0, v1 = this.v1, v2 = this.v2;
  23715. point.set(
  23716. QuadraticBezier( t, v0.x, v1.x, v2.x ),
  23717. QuadraticBezier( t, v0.y, v1.y, v2.y ),
  23718. QuadraticBezier( t, v0.z, v1.z, v2.z )
  23719. );
  23720. return point;
  23721. };
  23722. QuadraticBezierCurve3.prototype.copy = function ( source ) {
  23723. Curve.prototype.copy.call( this, source );
  23724. this.v0.copy( source.v0 );
  23725. this.v1.copy( source.v1 );
  23726. this.v2.copy( source.v2 );
  23727. return this;
  23728. };
  23729. QuadraticBezierCurve3.prototype.toJSON = function () {
  23730. const data = Curve.prototype.toJSON.call( this );
  23731. data.v0 = this.v0.toArray();
  23732. data.v1 = this.v1.toArray();
  23733. data.v2 = this.v2.toArray();
  23734. return data;
  23735. };
  23736. QuadraticBezierCurve3.prototype.fromJSON = function ( json ) {
  23737. Curve.prototype.fromJSON.call( this, json );
  23738. this.v0.fromArray( json.v0 );
  23739. this.v1.fromArray( json.v1 );
  23740. this.v2.fromArray( json.v2 );
  23741. return this;
  23742. };
  23743. function SplineCurve( points = [] ) {
  23744. Curve.call( this );
  23745. this.type = 'SplineCurve';
  23746. this.points = points;
  23747. }
  23748. SplineCurve.prototype = Object.create( Curve.prototype );
  23749. SplineCurve.prototype.constructor = SplineCurve;
  23750. SplineCurve.prototype.isSplineCurve = true;
  23751. SplineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2$1() ) {
  23752. const point = optionalTarget;
  23753. const points = this.points;
  23754. const p = ( points.length - 1 ) * t;
  23755. const intPoint = Math.floor( p );
  23756. const weight = p - intPoint;
  23757. const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
  23758. const p1 = points[ intPoint ];
  23759. const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
  23760. const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
  23761. point.set(
  23762. CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
  23763. CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
  23764. );
  23765. return point;
  23766. };
  23767. SplineCurve.prototype.copy = function ( source ) {
  23768. Curve.prototype.copy.call( this, source );
  23769. this.points = [];
  23770. for ( let i = 0, l = source.points.length; i < l; i ++ ) {
  23771. const point = source.points[ i ];
  23772. this.points.push( point.clone() );
  23773. }
  23774. return this;
  23775. };
  23776. SplineCurve.prototype.toJSON = function () {
  23777. const data = Curve.prototype.toJSON.call( this );
  23778. data.points = [];
  23779. for ( let i = 0, l = this.points.length; i < l; i ++ ) {
  23780. const point = this.points[ i ];
  23781. data.points.push( point.toArray() );
  23782. }
  23783. return data;
  23784. };
  23785. SplineCurve.prototype.fromJSON = function ( json ) {
  23786. Curve.prototype.fromJSON.call( this, json );
  23787. this.points = [];
  23788. for ( let i = 0, l = json.points.length; i < l; i ++ ) {
  23789. const point = json.points[ i ];
  23790. this.points.push( new Vector2$1().fromArray( point ) );
  23791. }
  23792. return this;
  23793. };
  23794. var Curves = /*#__PURE__*/Object.freeze({
  23795. __proto__: null,
  23796. ArcCurve: ArcCurve,
  23797. CatmullRomCurve3: CatmullRomCurve3,
  23798. CubicBezierCurve: CubicBezierCurve,
  23799. CubicBezierCurve3: CubicBezierCurve3,
  23800. EllipseCurve: EllipseCurve,
  23801. LineCurve: LineCurve,
  23802. LineCurve3: LineCurve3,
  23803. QuadraticBezierCurve: QuadraticBezierCurve,
  23804. QuadraticBezierCurve3: QuadraticBezierCurve3,
  23805. SplineCurve: SplineCurve
  23806. });
  23807. /**************************************************************
  23808. * Curved Path - a curve path is simply a array of connected
  23809. * curves, but retains the api of a curve
  23810. **************************************************************/
  23811. function CurvePath() {
  23812. Curve.call( this );
  23813. this.type = 'CurvePath';
  23814. this.curves = [];
  23815. this.autoClose = false; // Automatically closes the path
  23816. }
  23817. CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
  23818. constructor: CurvePath,
  23819. add: function ( curve ) {
  23820. this.curves.push( curve );
  23821. },
  23822. closePath: function () {
  23823. // Add a line curve if start and end of lines are not connected
  23824. const startPoint = this.curves[ 0 ].getPoint( 0 );
  23825. const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
  23826. if ( ! startPoint.equals( endPoint ) ) {
  23827. this.curves.push( new LineCurve( endPoint, startPoint ) );
  23828. }
  23829. },
  23830. // To get accurate point with reference to
  23831. // entire path distance at time t,
  23832. // following has to be done:
  23833. // 1. Length of each sub path have to be known
  23834. // 2. Locate and identify type of curve
  23835. // 3. Get t for the curve
  23836. // 4. Return curve.getPointAt(t')
  23837. getPoint: function ( t ) {
  23838. const d = t * this.getLength();
  23839. const curveLengths = this.getCurveLengths();
  23840. let i = 0;
  23841. // To think about boundaries points.
  23842. while ( i < curveLengths.length ) {
  23843. if ( curveLengths[ i ] >= d ) {
  23844. const diff = curveLengths[ i ] - d;
  23845. const curve = this.curves[ i ];
  23846. const segmentLength = curve.getLength();
  23847. const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
  23848. return curve.getPointAt( u );
  23849. }
  23850. i ++;
  23851. }
  23852. return null;
  23853. // loop where sum != 0, sum > d , sum+1 <d
  23854. },
  23855. // We cannot use the default THREE.Curve getPoint() with getLength() because in
  23856. // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
  23857. // getPoint() depends on getLength
  23858. getLength: function () {
  23859. const lens = this.getCurveLengths();
  23860. return lens[ lens.length - 1 ];
  23861. },
  23862. // cacheLengths must be recalculated.
  23863. updateArcLengths: function () {
  23864. this.needsUpdate = true;
  23865. this.cacheLengths = null;
  23866. this.getCurveLengths();
  23867. },
  23868. // Compute lengths and cache them
  23869. // We cannot overwrite getLengths() because UtoT mapping uses it.
  23870. getCurveLengths: function () {
  23871. // We use cache values if curves and cache array are same length
  23872. if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
  23873. return this.cacheLengths;
  23874. }
  23875. // Get length of sub-curve
  23876. // Push sums into cached array
  23877. const lengths = [];
  23878. let sums = 0;
  23879. for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
  23880. sums += this.curves[ i ].getLength();
  23881. lengths.push( sums );
  23882. }
  23883. this.cacheLengths = lengths;
  23884. return lengths;
  23885. },
  23886. getSpacedPoints: function ( divisions = 40 ) {
  23887. const points = [];
  23888. for ( let i = 0; i <= divisions; i ++ ) {
  23889. points.push( this.getPoint( i / divisions ) );
  23890. }
  23891. if ( this.autoClose ) {
  23892. points.push( points[ 0 ] );
  23893. }
  23894. return points;
  23895. },
  23896. getPoints: function ( divisions = 12 ) {
  23897. const points = [];
  23898. let last;
  23899. for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
  23900. const curve = curves[ i ];
  23901. const resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
  23902. : ( curve && ( curve.isLineCurve || curve.isLineCurve3 ) ) ? 1
  23903. : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
  23904. : divisions;
  23905. const pts = curve.getPoints( resolution );
  23906. for ( let j = 0; j < pts.length; j ++ ) {
  23907. const point = pts[ j ];
  23908. if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
  23909. points.push( point );
  23910. last = point;
  23911. }
  23912. }
  23913. if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
  23914. points.push( points[ 0 ] );
  23915. }
  23916. return points;
  23917. },
  23918. copy: function ( source ) {
  23919. Curve.prototype.copy.call( this, source );
  23920. this.curves = [];
  23921. for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
  23922. const curve = source.curves[ i ];
  23923. this.curves.push( curve.clone() );
  23924. }
  23925. this.autoClose = source.autoClose;
  23926. return this;
  23927. },
  23928. toJSON: function () {
  23929. const data = Curve.prototype.toJSON.call( this );
  23930. data.autoClose = this.autoClose;
  23931. data.curves = [];
  23932. for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
  23933. const curve = this.curves[ i ];
  23934. data.curves.push( curve.toJSON() );
  23935. }
  23936. return data;
  23937. },
  23938. fromJSON: function ( json ) {
  23939. Curve.prototype.fromJSON.call( this, json );
  23940. this.autoClose = json.autoClose;
  23941. this.curves = [];
  23942. for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
  23943. const curve = json.curves[ i ];
  23944. this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
  23945. }
  23946. return this;
  23947. }
  23948. } );
  23949. function Path( points ) {
  23950. CurvePath.call( this );
  23951. this.type = 'Path';
  23952. this.currentPoint = new Vector2$1();
  23953. if ( points ) {
  23954. this.setFromPoints( points );
  23955. }
  23956. }
  23957. Path.prototype = Object.assign( Object.create( CurvePath.prototype ), {
  23958. constructor: Path,
  23959. setFromPoints: function ( points ) {
  23960. this.moveTo( points[ 0 ].x, points[ 0 ].y );
  23961. for ( let i = 1, l = points.length; i < l; i ++ ) {
  23962. this.lineTo( points[ i ].x, points[ i ].y );
  23963. }
  23964. return this;
  23965. },
  23966. moveTo: function ( x, y ) {
  23967. this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
  23968. return this;
  23969. },
  23970. lineTo: function ( x, y ) {
  23971. const curve = new LineCurve( this.currentPoint.clone(), new Vector2$1( x, y ) );
  23972. this.curves.push( curve );
  23973. this.currentPoint.set( x, y );
  23974. return this;
  23975. },
  23976. quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
  23977. const curve = new QuadraticBezierCurve(
  23978. this.currentPoint.clone(),
  23979. new Vector2$1( aCPx, aCPy ),
  23980. new Vector2$1( aX, aY )
  23981. );
  23982. this.curves.push( curve );
  23983. this.currentPoint.set( aX, aY );
  23984. return this;
  23985. },
  23986. bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
  23987. const curve = new CubicBezierCurve(
  23988. this.currentPoint.clone(),
  23989. new Vector2$1( aCP1x, aCP1y ),
  23990. new Vector2$1( aCP2x, aCP2y ),
  23991. new Vector2$1( aX, aY )
  23992. );
  23993. this.curves.push( curve );
  23994. this.currentPoint.set( aX, aY );
  23995. return this;
  23996. },
  23997. splineThru: function ( pts /*Array of Vector*/ ) {
  23998. const npts = [ this.currentPoint.clone() ].concat( pts );
  23999. const curve = new SplineCurve( npts );
  24000. this.curves.push( curve );
  24001. this.currentPoint.copy( pts[ pts.length - 1 ] );
  24002. return this;
  24003. },
  24004. arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
  24005. const x0 = this.currentPoint.x;
  24006. const y0 = this.currentPoint.y;
  24007. this.absarc( aX + x0, aY + y0, aRadius,
  24008. aStartAngle, aEndAngle, aClockwise );
  24009. return this;
  24010. },
  24011. absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
  24012. this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
  24013. return this;
  24014. },
  24015. ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
  24016. const x0 = this.currentPoint.x;
  24017. const y0 = this.currentPoint.y;
  24018. this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
  24019. return this;
  24020. },
  24021. absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
  24022. const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
  24023. if ( this.curves.length > 0 ) {
  24024. // if a previous curve is present, attempt to join
  24025. const firstPoint = curve.getPoint( 0 );
  24026. if ( ! firstPoint.equals( this.currentPoint ) ) {
  24027. this.lineTo( firstPoint.x, firstPoint.y );
  24028. }
  24029. }
  24030. this.curves.push( curve );
  24031. const lastPoint = curve.getPoint( 1 );
  24032. this.currentPoint.copy( lastPoint );
  24033. return this;
  24034. },
  24035. copy: function ( source ) {
  24036. CurvePath.prototype.copy.call( this, source );
  24037. this.currentPoint.copy( source.currentPoint );
  24038. return this;
  24039. },
  24040. toJSON: function () {
  24041. const data = CurvePath.prototype.toJSON.call( this );
  24042. data.currentPoint = this.currentPoint.toArray();
  24043. return data;
  24044. },
  24045. fromJSON: function ( json ) {
  24046. CurvePath.prototype.fromJSON.call( this, json );
  24047. this.currentPoint.fromArray( json.currentPoint );
  24048. return this;
  24049. }
  24050. } );
  24051. function Shape( points ) {
  24052. Path.call( this, points );
  24053. this.uuid = MathUtils.generateUUID();
  24054. this.type = 'Shape';
  24055. this.holes = [];
  24056. }
  24057. Shape.prototype = Object.assign( Object.create( Path.prototype ), {
  24058. constructor: Shape,
  24059. getPointsHoles: function ( divisions ) {
  24060. const holesPts = [];
  24061. for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
  24062. holesPts[ i ] = this.holes[ i ].getPoints( divisions );
  24063. }
  24064. return holesPts;
  24065. },
  24066. // get points of shape and holes (keypoints based on segments parameter)
  24067. extractPoints: function ( divisions ) {
  24068. return {
  24069. shape: this.getPoints( divisions ),
  24070. holes: this.getPointsHoles( divisions )
  24071. };
  24072. },
  24073. copy: function ( source ) {
  24074. Path.prototype.copy.call( this, source );
  24075. this.holes = [];
  24076. for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
  24077. const hole = source.holes[ i ];
  24078. this.holes.push( hole.clone() );
  24079. }
  24080. return this;
  24081. },
  24082. toJSON: function () {
  24083. const data = Path.prototype.toJSON.call( this );
  24084. data.uuid = this.uuid;
  24085. data.holes = [];
  24086. for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
  24087. const hole = this.holes[ i ];
  24088. data.holes.push( hole.toJSON() );
  24089. }
  24090. return data;
  24091. },
  24092. fromJSON: function ( json ) {
  24093. Path.prototype.fromJSON.call( this, json );
  24094. this.uuid = json.uuid;
  24095. this.holes = [];
  24096. for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
  24097. const hole = json.holes[ i ];
  24098. this.holes.push( new Path().fromJSON( hole ) );
  24099. }
  24100. return this;
  24101. }
  24102. } );
  24103. function Light( color, intensity = 1 ) {
  24104. Object3D.call( this );
  24105. this.type = 'Light';
  24106. this.color = new Color( color );
  24107. this.intensity = intensity;
  24108. }
  24109. Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
  24110. constructor: Light,
  24111. isLight: true,
  24112. copy: function ( source ) {
  24113. Object3D.prototype.copy.call( this, source );
  24114. this.color.copy( source.color );
  24115. this.intensity = source.intensity;
  24116. return this;
  24117. },
  24118. toJSON: function ( meta ) {
  24119. const data = Object3D.prototype.toJSON.call( this, meta );
  24120. data.object.color = this.color.getHex();
  24121. data.object.intensity = this.intensity;
  24122. if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
  24123. if ( this.distance !== undefined ) data.object.distance = this.distance;
  24124. if ( this.angle !== undefined ) data.object.angle = this.angle;
  24125. if ( this.decay !== undefined ) data.object.decay = this.decay;
  24126. if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
  24127. if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
  24128. return data;
  24129. }
  24130. } );
  24131. function HemisphereLight( skyColor, groundColor, intensity ) {
  24132. Light.call( this, skyColor, intensity );
  24133. this.type = 'HemisphereLight';
  24134. this.position.copy( Object3D.DefaultUp );
  24135. this.updateMatrix();
  24136. this.groundColor = new Color( groundColor );
  24137. }
  24138. HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
  24139. constructor: HemisphereLight,
  24140. isHemisphereLight: true,
  24141. copy: function ( source ) {
  24142. Light.prototype.copy.call( this, source );
  24143. this.groundColor.copy( source.groundColor );
  24144. return this;
  24145. }
  24146. } );
  24147. function LightShadow( camera ) {
  24148. this.camera = camera;
  24149. this.bias = 0;
  24150. this.normalBias = 0;
  24151. this.radius = 1;
  24152. this.mapSize = new Vector2$1( 512, 512 );
  24153. this.map = null;
  24154. this.mapPass = null;
  24155. this.matrix = new Matrix4();
  24156. this.autoUpdate = true;
  24157. this.needsUpdate = false;
  24158. this._frustum = new Frustum();
  24159. this._frameExtents = new Vector2$1( 1, 1 );
  24160. this._viewportCount = 1;
  24161. this._viewports = [
  24162. new Vector4( 0, 0, 1, 1 )
  24163. ];
  24164. }
  24165. Object.assign( LightShadow.prototype, {
  24166. _projScreenMatrix: new Matrix4(),
  24167. _lightPositionWorld: new Vector3(),
  24168. _lookTarget: new Vector3(),
  24169. getViewportCount: function () {
  24170. return this._viewportCount;
  24171. },
  24172. getFrustum: function () {
  24173. return this._frustum;
  24174. },
  24175. updateMatrices: function ( light ) {
  24176. const shadowCamera = this.camera,
  24177. shadowMatrix = this.matrix,
  24178. projScreenMatrix = this._projScreenMatrix,
  24179. lookTarget = this._lookTarget,
  24180. lightPositionWorld = this._lightPositionWorld;
  24181. lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
  24182. shadowCamera.position.copy( lightPositionWorld );
  24183. lookTarget.setFromMatrixPosition( light.target.matrixWorld );
  24184. shadowCamera.lookAt( lookTarget );
  24185. shadowCamera.updateMatrixWorld();
  24186. projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
  24187. this._frustum.setFromProjectionMatrix( projScreenMatrix );
  24188. shadowMatrix.set(
  24189. 0.5, 0.0, 0.0, 0.5,
  24190. 0.0, 0.5, 0.0, 0.5,
  24191. 0.0, 0.0, 0.5, 0.5,
  24192. 0.0, 0.0, 0.0, 1.0
  24193. );
  24194. shadowMatrix.multiply( shadowCamera.projectionMatrix );
  24195. shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
  24196. },
  24197. getViewport: function ( viewportIndex ) {
  24198. return this._viewports[ viewportIndex ];
  24199. },
  24200. getFrameExtents: function () {
  24201. return this._frameExtents;
  24202. },
  24203. copy: function ( source ) {
  24204. this.camera = source.camera.clone();
  24205. this.bias = source.bias;
  24206. this.radius = source.radius;
  24207. this.mapSize.copy( source.mapSize );
  24208. return this;
  24209. },
  24210. clone: function () {
  24211. return new this.constructor().copy( this );
  24212. },
  24213. toJSON: function () {
  24214. const object = {};
  24215. if ( this.bias !== 0 ) object.bias = this.bias;
  24216. if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
  24217. if ( this.radius !== 1 ) object.radius = this.radius;
  24218. if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
  24219. object.camera = this.camera.toJSON( false ).object;
  24220. delete object.camera.matrix;
  24221. return object;
  24222. }
  24223. } );
  24224. function SpotLightShadow() {
  24225. LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
  24226. this.focus = 1;
  24227. }
  24228. SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
  24229. constructor: SpotLightShadow,
  24230. isSpotLightShadow: true,
  24231. updateMatrices: function ( light ) {
  24232. const camera = this.camera;
  24233. const fov = MathUtils.RAD2DEG * 2 * light.angle * this.focus;
  24234. const aspect = this.mapSize.width / this.mapSize.height;
  24235. const far = light.distance || camera.far;
  24236. if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
  24237. camera.fov = fov;
  24238. camera.aspect = aspect;
  24239. camera.far = far;
  24240. camera.updateProjectionMatrix();
  24241. }
  24242. LightShadow.prototype.updateMatrices.call( this, light );
  24243. }
  24244. } );
  24245. function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
  24246. Light.call( this, color, intensity );
  24247. this.type = 'SpotLight';
  24248. this.position.copy( Object3D.DefaultUp );
  24249. this.updateMatrix();
  24250. this.target = new Object3D();
  24251. Object.defineProperty( this, 'power', {
  24252. get: function () {
  24253. // intensity = power per solid angle.
  24254. // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  24255. return this.intensity * Math.PI;
  24256. },
  24257. set: function ( power ) {
  24258. // intensity = power per solid angle.
  24259. // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  24260. this.intensity = power / Math.PI;
  24261. }
  24262. } );
  24263. this.distance = ( distance !== undefined ) ? distance : 0;
  24264. this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
  24265. this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
  24266. this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
  24267. this.shadow = new SpotLightShadow();
  24268. }
  24269. SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
  24270. constructor: SpotLight,
  24271. isSpotLight: true,
  24272. copy: function ( source ) {
  24273. Light.prototype.copy.call( this, source );
  24274. this.distance = source.distance;
  24275. this.angle = source.angle;
  24276. this.penumbra = source.penumbra;
  24277. this.decay = source.decay;
  24278. this.target = source.target.clone();
  24279. this.shadow = source.shadow.clone();
  24280. return this;
  24281. }
  24282. } );
  24283. function PointLightShadow() {
  24284. LightShadow.call( this, new PerspectiveCamera( 90, 1, 0.5, 500 ) );
  24285. this._frameExtents = new Vector2$1( 4, 2 );
  24286. this._viewportCount = 6;
  24287. this._viewports = [
  24288. // These viewports map a cube-map onto a 2D texture with the
  24289. // following orientation:
  24290. //
  24291. // xzXZ
  24292. // y Y
  24293. //
  24294. // X - Positive x direction
  24295. // x - Negative x direction
  24296. // Y - Positive y direction
  24297. // y - Negative y direction
  24298. // Z - Positive z direction
  24299. // z - Negative z direction
  24300. // positive X
  24301. new Vector4( 2, 1, 1, 1 ),
  24302. // negative X
  24303. new Vector4( 0, 1, 1, 1 ),
  24304. // positive Z
  24305. new Vector4( 3, 1, 1, 1 ),
  24306. // negative Z
  24307. new Vector4( 1, 1, 1, 1 ),
  24308. // positive Y
  24309. new Vector4( 3, 0, 1, 1 ),
  24310. // negative Y
  24311. new Vector4( 1, 0, 1, 1 )
  24312. ];
  24313. this._cubeDirections = [
  24314. new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
  24315. new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
  24316. ];
  24317. this._cubeUps = [
  24318. new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
  24319. new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
  24320. ];
  24321. }
  24322. PointLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
  24323. constructor: PointLightShadow,
  24324. isPointLightShadow: true,
  24325. updateMatrices: function ( light, viewportIndex = 0 ) {
  24326. const camera = this.camera,
  24327. shadowMatrix = this.matrix,
  24328. lightPositionWorld = this._lightPositionWorld,
  24329. lookTarget = this._lookTarget,
  24330. projScreenMatrix = this._projScreenMatrix;
  24331. lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
  24332. camera.position.copy( lightPositionWorld );
  24333. lookTarget.copy( camera.position );
  24334. lookTarget.add( this._cubeDirections[ viewportIndex ] );
  24335. camera.up.copy( this._cubeUps[ viewportIndex ] );
  24336. camera.lookAt( lookTarget );
  24337. camera.updateMatrixWorld();
  24338. shadowMatrix.makeTranslation( - lightPositionWorld.x, - lightPositionWorld.y, - lightPositionWorld.z );
  24339. projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
  24340. this._frustum.setFromProjectionMatrix( projScreenMatrix );
  24341. }
  24342. } );
  24343. function PointLight( color, intensity, distance, decay ) {
  24344. Light.call( this, color, intensity );
  24345. this.type = 'PointLight';
  24346. Object.defineProperty( this, 'power', {
  24347. get: function () {
  24348. // intensity = power per solid angle.
  24349. // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  24350. return this.intensity * 4 * Math.PI;
  24351. },
  24352. set: function ( power ) {
  24353. // intensity = power per solid angle.
  24354. // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  24355. this.intensity = power / ( 4 * Math.PI );
  24356. }
  24357. } );
  24358. this.distance = ( distance !== undefined ) ? distance : 0;
  24359. this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
  24360. this.shadow = new PointLightShadow();
  24361. }
  24362. PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
  24363. constructor: PointLight,
  24364. isPointLight: true,
  24365. copy: function ( source ) {
  24366. Light.prototype.copy.call( this, source );
  24367. this.distance = source.distance;
  24368. this.decay = source.decay;
  24369. this.shadow = source.shadow.clone();
  24370. return this;
  24371. }
  24372. } );
  24373. function OrthographicCamera( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
  24374. Camera.call( this );
  24375. this.type = 'OrthographicCamera';
  24376. this.zoom = 1;
  24377. this.view = null;
  24378. this.left = left;
  24379. this.right = right;
  24380. this.top = top;
  24381. this.bottom = bottom;
  24382. this.near = near;
  24383. this.far = far;
  24384. this.updateProjectionMatrix();
  24385. }
  24386. OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
  24387. constructor: OrthographicCamera,
  24388. isOrthographicCamera: true,
  24389. copy: function ( source, recursive ) {
  24390. Camera.prototype.copy.call( this, source, recursive );
  24391. this.left = source.left;
  24392. this.right = source.right;
  24393. this.top = source.top;
  24394. this.bottom = source.bottom;
  24395. this.near = source.near;
  24396. this.far = source.far;
  24397. this.zoom = source.zoom;
  24398. this.view = source.view === null ? null : Object.assign( {}, source.view );
  24399. return this;
  24400. },
  24401. setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
  24402. if ( this.view === null ) {
  24403. this.view = {
  24404. enabled: true,
  24405. fullWidth: 1,
  24406. fullHeight: 1,
  24407. offsetX: 0,
  24408. offsetY: 0,
  24409. width: 1,
  24410. height: 1
  24411. };
  24412. }
  24413. this.view.enabled = true;
  24414. this.view.fullWidth = fullWidth;
  24415. this.view.fullHeight = fullHeight;
  24416. this.view.offsetX = x;
  24417. this.view.offsetY = y;
  24418. this.view.width = width;
  24419. this.view.height = height;
  24420. this.updateProjectionMatrix();
  24421. },
  24422. clearViewOffset: function () {
  24423. if ( this.view !== null ) {
  24424. this.view.enabled = false;
  24425. }
  24426. this.updateProjectionMatrix();
  24427. },
  24428. updateProjectionMatrix: function () {
  24429. const dx = ( this.right - this.left ) / ( 2 * this.zoom );
  24430. const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
  24431. const cx = ( this.right + this.left ) / 2;
  24432. const cy = ( this.top + this.bottom ) / 2;
  24433. let left = cx - dx;
  24434. let right = cx + dx;
  24435. let top = cy + dy;
  24436. let bottom = cy - dy;
  24437. if ( this.view !== null && this.view.enabled ) {
  24438. const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
  24439. const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
  24440. left += scaleW * this.view.offsetX;
  24441. right = left + scaleW * this.view.width;
  24442. top -= scaleH * this.view.offsetY;
  24443. bottom = top - scaleH * this.view.height;
  24444. }
  24445. this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
  24446. this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
  24447. },
  24448. toJSON: function ( meta ) {
  24449. const data = Object3D.prototype.toJSON.call( this, meta );
  24450. data.object.zoom = this.zoom;
  24451. data.object.left = this.left;
  24452. data.object.right = this.right;
  24453. data.object.top = this.top;
  24454. data.object.bottom = this.bottom;
  24455. data.object.near = this.near;
  24456. data.object.far = this.far;
  24457. if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
  24458. return data;
  24459. }
  24460. } );
  24461. function DirectionalLightShadow() {
  24462. LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
  24463. }
  24464. DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
  24465. constructor: DirectionalLightShadow,
  24466. isDirectionalLightShadow: true,
  24467. updateMatrices: function ( light ) {
  24468. LightShadow.prototype.updateMatrices.call( this, light );
  24469. }
  24470. } );
  24471. function DirectionalLight( color, intensity ) {
  24472. Light.call( this, color, intensity );
  24473. this.type = 'DirectionalLight';
  24474. this.position.copy( Object3D.DefaultUp );
  24475. this.updateMatrix();
  24476. this.target = new Object3D();
  24477. this.shadow = new DirectionalLightShadow();
  24478. }
  24479. DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
  24480. constructor: DirectionalLight,
  24481. isDirectionalLight: true,
  24482. copy: function ( source ) {
  24483. Light.prototype.copy.call( this, source );
  24484. this.target = source.target.clone();
  24485. this.shadow = source.shadow.clone();
  24486. return this;
  24487. }
  24488. } );
  24489. function AmbientLight( color, intensity ) {
  24490. Light.call( this, color, intensity );
  24491. this.type = 'AmbientLight';
  24492. }
  24493. AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
  24494. constructor: AmbientLight,
  24495. isAmbientLight: true
  24496. } );
  24497. function RectAreaLight( color, intensity, width, height ) {
  24498. Light.call( this, color, intensity );
  24499. this.type = 'RectAreaLight';
  24500. this.width = ( width !== undefined ) ? width : 10;
  24501. this.height = ( height !== undefined ) ? height : 10;
  24502. }
  24503. RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
  24504. constructor: RectAreaLight,
  24505. isRectAreaLight: true,
  24506. copy: function ( source ) {
  24507. Light.prototype.copy.call( this, source );
  24508. this.width = source.width;
  24509. this.height = source.height;
  24510. return this;
  24511. },
  24512. toJSON: function ( meta ) {
  24513. const data = Light.prototype.toJSON.call( this, meta );
  24514. data.object.width = this.width;
  24515. data.object.height = this.height;
  24516. return data;
  24517. }
  24518. } );
  24519. /**
  24520. * Primary reference:
  24521. * https://graphics.stanford.edu/papers/envmap/envmap.pdf
  24522. *
  24523. * Secondary reference:
  24524. * https://www.ppsloan.org/publications/StupidSH36.pdf
  24525. */
  24526. // 3-band SH defined by 9 coefficients
  24527. class SphericalHarmonics3 {
  24528. constructor() {
  24529. Object.defineProperty( this, 'isSphericalHarmonics3', { value: true } );
  24530. this.coefficients = [];
  24531. for ( let i = 0; i < 9; i ++ ) {
  24532. this.coefficients.push( new Vector3() );
  24533. }
  24534. }
  24535. set( coefficients ) {
  24536. for ( let i = 0; i < 9; i ++ ) {
  24537. this.coefficients[ i ].copy( coefficients[ i ] );
  24538. }
  24539. return this;
  24540. }
  24541. zero() {
  24542. for ( let i = 0; i < 9; i ++ ) {
  24543. this.coefficients[ i ].set( 0, 0, 0 );
  24544. }
  24545. return this;
  24546. }
  24547. // get the radiance in the direction of the normal
  24548. // target is a Vector3
  24549. getAt( normal, target ) {
  24550. // normal is assumed to be unit length
  24551. const x = normal.x, y = normal.y, z = normal.z;
  24552. const coeff = this.coefficients;
  24553. // band 0
  24554. target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
  24555. // band 1
  24556. target.addScaledVector( coeff[ 1 ], 0.488603 * y );
  24557. target.addScaledVector( coeff[ 2 ], 0.488603 * z );
  24558. target.addScaledVector( coeff[ 3 ], 0.488603 * x );
  24559. // band 2
  24560. target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
  24561. target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
  24562. target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
  24563. target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
  24564. target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
  24565. return target;
  24566. }
  24567. // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
  24568. // target is a Vector3
  24569. // https://graphics.stanford.edu/papers/envmap/envmap.pdf
  24570. getIrradianceAt( normal, target ) {
  24571. // normal is assumed to be unit length
  24572. const x = normal.x, y = normal.y, z = normal.z;
  24573. const coeff = this.coefficients;
  24574. // band 0
  24575. target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
  24576. // band 1
  24577. target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
  24578. target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
  24579. target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
  24580. // band 2
  24581. target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
  24582. target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
  24583. target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
  24584. target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
  24585. target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
  24586. return target;
  24587. }
  24588. add( sh ) {
  24589. for ( let i = 0; i < 9; i ++ ) {
  24590. this.coefficients[ i ].add( sh.coefficients[ i ] );
  24591. }
  24592. return this;
  24593. }
  24594. addScaledSH( sh, s ) {
  24595. for ( let i = 0; i < 9; i ++ ) {
  24596. this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
  24597. }
  24598. return this;
  24599. }
  24600. scale( s ) {
  24601. for ( let i = 0; i < 9; i ++ ) {
  24602. this.coefficients[ i ].multiplyScalar( s );
  24603. }
  24604. return this;
  24605. }
  24606. lerp( sh, alpha ) {
  24607. for ( let i = 0; i < 9; i ++ ) {
  24608. this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
  24609. }
  24610. return this;
  24611. }
  24612. equals( sh ) {
  24613. for ( let i = 0; i < 9; i ++ ) {
  24614. if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
  24615. return false;
  24616. }
  24617. }
  24618. return true;
  24619. }
  24620. copy( sh ) {
  24621. return this.set( sh.coefficients );
  24622. }
  24623. clone() {
  24624. return new this.constructor().copy( this );
  24625. }
  24626. fromArray( array, offset = 0 ) {
  24627. const coefficients = this.coefficients;
  24628. for ( let i = 0; i < 9; i ++ ) {
  24629. coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
  24630. }
  24631. return this;
  24632. }
  24633. toArray( array = [], offset = 0 ) {
  24634. const coefficients = this.coefficients;
  24635. for ( let i = 0; i < 9; i ++ ) {
  24636. coefficients[ i ].toArray( array, offset + ( i * 3 ) );
  24637. }
  24638. return array;
  24639. }
  24640. // evaluate the basis functions
  24641. // shBasis is an Array[ 9 ]
  24642. static getBasisAt( normal, shBasis ) {
  24643. // normal is assumed to be unit length
  24644. const x = normal.x, y = normal.y, z = normal.z;
  24645. // band 0
  24646. shBasis[ 0 ] = 0.282095;
  24647. // band 1
  24648. shBasis[ 1 ] = 0.488603 * y;
  24649. shBasis[ 2 ] = 0.488603 * z;
  24650. shBasis[ 3 ] = 0.488603 * x;
  24651. // band 2
  24652. shBasis[ 4 ] = 1.092548 * x * y;
  24653. shBasis[ 5 ] = 1.092548 * y * z;
  24654. shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
  24655. shBasis[ 7 ] = 1.092548 * x * z;
  24656. shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
  24657. }
  24658. }
  24659. function LightProbe( sh, intensity ) {
  24660. Light.call( this, undefined, intensity );
  24661. this.type = 'LightProbe';
  24662. this.sh = ( sh !== undefined ) ? sh : new SphericalHarmonics3();
  24663. }
  24664. LightProbe.prototype = Object.assign( Object.create( Light.prototype ), {
  24665. constructor: LightProbe,
  24666. isLightProbe: true,
  24667. copy: function ( source ) {
  24668. Light.prototype.copy.call( this, source );
  24669. this.sh.copy( source.sh );
  24670. return this;
  24671. },
  24672. fromJSON: function ( json ) {
  24673. this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
  24674. this.sh.fromArray( json.sh );
  24675. return this;
  24676. },
  24677. toJSON: function ( meta ) {
  24678. const data = Light.prototype.toJSON.call( this, meta );
  24679. data.object.sh = this.sh.toArray();
  24680. return data;
  24681. }
  24682. } );
  24683. function MaterialLoader( manager ) {
  24684. Loader.call( this, manager );
  24685. this.textures = {};
  24686. }
  24687. MaterialLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  24688. constructor: MaterialLoader,
  24689. load: function ( url, onLoad, onProgress, onError ) {
  24690. const scope = this;
  24691. const loader = new FileLoader( scope.manager );
  24692. loader.setPath( scope.path );
  24693. loader.setRequestHeader( scope.requestHeader );
  24694. loader.setWithCredentials( scope.withCredentials );
  24695. loader.load( url, function ( text ) {
  24696. try {
  24697. onLoad( scope.parse( JSON.parse( text ) ) );
  24698. } catch ( e ) {
  24699. if ( onError ) {
  24700. onError( e );
  24701. } else {
  24702. console.error( e );
  24703. }
  24704. scope.manager.itemError( url );
  24705. }
  24706. }, onProgress, onError );
  24707. },
  24708. parse: function ( json ) {
  24709. const textures = this.textures;
  24710. function getTexture( name ) {
  24711. if ( textures[ name ] === undefined ) {
  24712. console.warn( 'THREE.MaterialLoader: Undefined texture', name );
  24713. }
  24714. return textures[ name ];
  24715. }
  24716. const material = new Materials[ json.type ]();
  24717. if ( json.uuid !== undefined ) material.uuid = json.uuid;
  24718. if ( json.name !== undefined ) material.name = json.name;
  24719. if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
  24720. if ( json.roughness !== undefined ) material.roughness = json.roughness;
  24721. if ( json.metalness !== undefined ) material.metalness = json.metalness;
  24722. if ( json.sheen !== undefined ) material.sheen = new Color().setHex( json.sheen );
  24723. if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
  24724. if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
  24725. if ( json.shininess !== undefined ) material.shininess = json.shininess;
  24726. if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
  24727. if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
  24728. if ( json.fog !== undefined ) material.fog = json.fog;
  24729. if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
  24730. if ( json.blending !== undefined ) material.blending = json.blending;
  24731. if ( json.combine !== undefined ) material.combine = json.combine;
  24732. if ( json.side !== undefined ) material.side = json.side;
  24733. if ( json.opacity !== undefined ) material.opacity = json.opacity;
  24734. if ( json.transparent !== undefined ) material.transparent = json.transparent;
  24735. if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
  24736. if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
  24737. if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
  24738. if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
  24739. if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
  24740. if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
  24741. if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
  24742. if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
  24743. if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
  24744. if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
  24745. if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
  24746. if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
  24747. if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
  24748. if ( json.wireframelineWidth !== undefined ) material.wireframelineWidth = json.wireframelineWidth;
  24749. if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
  24750. if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
  24751. if ( json.rotation !== undefined ) material.rotation = json.rotation;
  24752. if ( json.lineWidth !== 1 ) material.lineWidth = json.lineWidth;
  24753. if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
  24754. if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
  24755. if ( json.scale !== undefined ) material.scale = json.scale;
  24756. if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
  24757. if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
  24758. if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
  24759. if ( json.skinning !== undefined ) material.skinning = json.skinning;
  24760. if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
  24761. if ( json.morphNormals !== undefined ) material.morphNormals = json.morphNormals;
  24762. if ( json.dithering !== undefined ) material.dithering = json.dithering;
  24763. if ( json.vertexTangents !== undefined ) material.vertexTangents = json.vertexTangents;
  24764. if ( json.visible !== undefined ) material.visible = json.visible;
  24765. if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
  24766. if ( json.userData !== undefined ) material.userData = json.userData;
  24767. if ( json.vertexColors !== undefined ) {
  24768. if ( typeof json.vertexColors === 'number' ) {
  24769. material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
  24770. } else {
  24771. material.vertexColors = json.vertexColors;
  24772. }
  24773. }
  24774. // Shader Material
  24775. if ( json.uniforms !== undefined ) {
  24776. for ( const name in json.uniforms ) {
  24777. const uniform = json.uniforms[ name ];
  24778. material.uniforms[ name ] = {};
  24779. switch ( uniform.type ) {
  24780. case 't':
  24781. material.uniforms[ name ].value = getTexture( uniform.value );
  24782. break;
  24783. case 'c':
  24784. material.uniforms[ name ].value = new Color().setHex( uniform.value );
  24785. break;
  24786. case 'v2':
  24787. material.uniforms[ name ].value = new Vector2$1().fromArray( uniform.value );
  24788. break;
  24789. case 'v3':
  24790. material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
  24791. break;
  24792. case 'v4':
  24793. material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
  24794. break;
  24795. case 'm3':
  24796. material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
  24797. break;
  24798. case 'm4':
  24799. material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
  24800. break;
  24801. default:
  24802. material.uniforms[ name ].value = uniform.value;
  24803. }
  24804. }
  24805. }
  24806. if ( json.defines !== undefined ) material.defines = json.defines;
  24807. if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
  24808. if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
  24809. if ( json.extensions !== undefined ) {
  24810. for ( const key in json.extensions ) {
  24811. material.extensions[ key ] = json.extensions[ key ];
  24812. }
  24813. }
  24814. // Deprecated
  24815. if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading
  24816. // for PointsMaterial
  24817. if ( json.size !== undefined ) material.size = json.size;
  24818. if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
  24819. // maps
  24820. if ( json.map !== undefined ) material.map = getTexture( json.map );
  24821. if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
  24822. if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
  24823. if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
  24824. if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
  24825. if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
  24826. if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
  24827. if ( json.normalScale !== undefined ) {
  24828. let normalScale = json.normalScale;
  24829. if ( Array.isArray( normalScale ) === false ) {
  24830. // Blender exporter used to export a scalar. See #7459
  24831. normalScale = [ normalScale, normalScale ];
  24832. }
  24833. material.normalScale = new Vector2$1().fromArray( normalScale );
  24834. }
  24835. if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
  24836. if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
  24837. if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
  24838. if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
  24839. if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
  24840. if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
  24841. if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
  24842. if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
  24843. if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
  24844. if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
  24845. if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
  24846. if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
  24847. if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
  24848. if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
  24849. if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
  24850. if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
  24851. if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
  24852. if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
  24853. if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
  24854. if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
  24855. if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2$1().fromArray( json.clearcoatNormalScale );
  24856. if ( json.transmission !== undefined ) material.transmission = json.transmission;
  24857. if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
  24858. return material;
  24859. },
  24860. setTextures: function ( value ) {
  24861. this.textures = value;
  24862. return this;
  24863. }
  24864. } );
  24865. const LoaderUtils = {
  24866. decodeText: function ( array ) {
  24867. if ( typeof TextDecoder !== 'undefined' ) {
  24868. return new TextDecoder().decode( array );
  24869. }
  24870. // Avoid the String.fromCharCode.apply(null, array) shortcut, which
  24871. // throws a "maximum call stack size exceeded" error for large arrays.
  24872. let s = '';
  24873. for ( let i = 0, il = array.length; i < il; i ++ ) {
  24874. // Implicitly assumes little-endian.
  24875. s += String.fromCharCode( array[ i ] );
  24876. }
  24877. try {
  24878. // merges multi-byte utf-8 characters.
  24879. return decodeURIComponent( escape( s ) );
  24880. } catch ( e ) { // see #16358
  24881. return s;
  24882. }
  24883. },
  24884. extractUrlBase: function ( url ) {
  24885. const index = url.lastIndexOf( '/' );
  24886. if ( index === - 1 ) return './';
  24887. return url.substr( 0, index + 1 );
  24888. }
  24889. };
  24890. function InstancedBufferGeometry() {
  24891. BufferGeometry.call( this );
  24892. this.type = 'InstancedBufferGeometry';
  24893. this.instanceCount = Infinity;
  24894. }
  24895. InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
  24896. constructor: InstancedBufferGeometry,
  24897. isInstancedBufferGeometry: true,
  24898. copy: function ( source ) {
  24899. BufferGeometry.prototype.copy.call( this, source );
  24900. this.instanceCount = source.instanceCount;
  24901. return this;
  24902. },
  24903. clone: function () {
  24904. return new this.constructor().copy( this );
  24905. },
  24906. toJSON: function () {
  24907. const data = BufferGeometry.prototype.toJSON.call( this );
  24908. data.instanceCount = this.instanceCount;
  24909. data.isInstancedBufferGeometry = true;
  24910. return data;
  24911. }
  24912. } );
  24913. function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) {
  24914. if ( typeof ( normalized ) === 'number' ) {
  24915. meshPerAttribute = normalized;
  24916. normalized = false;
  24917. console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' );
  24918. }
  24919. BufferAttribute.call( this, array, itemSize, normalized );
  24920. this.meshPerAttribute = meshPerAttribute || 1;
  24921. }
  24922. InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
  24923. constructor: InstancedBufferAttribute,
  24924. isInstancedBufferAttribute: true,
  24925. copy: function ( source ) {
  24926. BufferAttribute.prototype.copy.call( this, source );
  24927. this.meshPerAttribute = source.meshPerAttribute;
  24928. return this;
  24929. },
  24930. toJSON: function () {
  24931. const data = BufferAttribute.prototype.toJSON.call( this );
  24932. data.meshPerAttribute = this.meshPerAttribute;
  24933. data.isInstancedBufferAttribute = true;
  24934. return data;
  24935. }
  24936. } );
  24937. function BufferGeometryLoader( manager ) {
  24938. Loader.call( this, manager );
  24939. }
  24940. BufferGeometryLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  24941. constructor: BufferGeometryLoader,
  24942. load: function ( url, onLoad, onProgress, onError ) {
  24943. const scope = this;
  24944. const loader = new FileLoader( scope.manager );
  24945. loader.setPath( scope.path );
  24946. loader.setRequestHeader( scope.requestHeader );
  24947. loader.setWithCredentials( scope.withCredentials );
  24948. loader.load( url, function ( text ) {
  24949. try {
  24950. onLoad( scope.parse( JSON.parse( text ) ) );
  24951. } catch ( e ) {
  24952. if ( onError ) {
  24953. onError( e );
  24954. } else {
  24955. console.error( e );
  24956. }
  24957. scope.manager.itemError( url );
  24958. }
  24959. }, onProgress, onError );
  24960. },
  24961. parse: function ( json ) {
  24962. const interleavedBufferMap = {};
  24963. const arrayBufferMap = {};
  24964. function getInterleavedBuffer( json, uuid ) {
  24965. if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
  24966. const interleavedBuffers = json.interleavedBuffers;
  24967. const interleavedBuffer = interleavedBuffers[ uuid ];
  24968. const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
  24969. const array = getTypedArray( interleavedBuffer.type, buffer );
  24970. const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
  24971. ib.uuid = interleavedBuffer.uuid;
  24972. interleavedBufferMap[ uuid ] = ib;
  24973. return ib;
  24974. }
  24975. function getArrayBuffer( json, uuid ) {
  24976. if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
  24977. const arrayBuffers = json.arrayBuffers;
  24978. const arrayBuffer = arrayBuffers[ uuid ];
  24979. const ab = new Uint32Array( arrayBuffer ).buffer;
  24980. arrayBufferMap[ uuid ] = ab;
  24981. return ab;
  24982. }
  24983. const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
  24984. const index = json.data.index;
  24985. if ( index !== undefined ) {
  24986. const typedArray = getTypedArray( index.type, index.array );
  24987. geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
  24988. }
  24989. const attributes = json.data.attributes;
  24990. for ( const key in attributes ) {
  24991. const attribute = attributes[ key ];
  24992. let bufferAttribute;
  24993. if ( attribute.isInterleavedBufferAttribute ) {
  24994. const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
  24995. bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
  24996. } else {
  24997. const typedArray = getTypedArray( attribute.type, attribute.array );
  24998. const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
  24999. bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
  25000. }
  25001. if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
  25002. geometry.setAttribute( key, bufferAttribute );
  25003. }
  25004. const morphAttributes = json.data.morphAttributes;
  25005. if ( morphAttributes ) {
  25006. for ( const key in morphAttributes ) {
  25007. const attributeArray = morphAttributes[ key ];
  25008. const array = [];
  25009. for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
  25010. const attribute = attributeArray[ i ];
  25011. let bufferAttribute;
  25012. if ( attribute.isInterleavedBufferAttribute ) {
  25013. const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
  25014. bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
  25015. } else {
  25016. const typedArray = getTypedArray( attribute.type, attribute.array );
  25017. bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
  25018. }
  25019. if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
  25020. array.push( bufferAttribute );
  25021. }
  25022. geometry.morphAttributes[ key ] = array;
  25023. }
  25024. }
  25025. const morphTargetsRelative = json.data.morphTargetsRelative;
  25026. if ( morphTargetsRelative ) {
  25027. geometry.morphTargetsRelative = true;
  25028. }
  25029. const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
  25030. if ( groups !== undefined ) {
  25031. for ( let i = 0, n = groups.length; i !== n; ++ i ) {
  25032. const group = groups[ i ];
  25033. geometry.addGroup( group.start, group.count, group.materialIndex );
  25034. }
  25035. }
  25036. const boundingSphere = json.data.boundingSphere;
  25037. if ( boundingSphere !== undefined ) {
  25038. const center = new Vector3();
  25039. if ( boundingSphere.center !== undefined ) {
  25040. center.fromArray( boundingSphere.center );
  25041. }
  25042. geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
  25043. }
  25044. if ( json.name ) geometry.name = json.name;
  25045. if ( json.userData ) geometry.userData = json.userData;
  25046. return geometry;
  25047. }
  25048. } );
  25049. class ObjectLoader extends Loader {
  25050. constructor( manager ) {
  25051. super( manager );
  25052. }
  25053. load( url, onLoad, onProgress, onError ) {
  25054. const scope = this;
  25055. const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
  25056. this.resourcePath = this.resourcePath || path;
  25057. const loader = new FileLoader( this.manager );
  25058. loader.setPath( this.path );
  25059. loader.setRequestHeader( this.requestHeader );
  25060. loader.setWithCredentials( this.withCredentials );
  25061. loader.load( url, function ( text ) {
  25062. let json = null;
  25063. try {
  25064. json = JSON.parse( text );
  25065. } catch ( error ) {
  25066. if ( onError !== undefined ) onError( error );
  25067. console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
  25068. return;
  25069. }
  25070. const metadata = json.metadata;
  25071. if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
  25072. console.error( 'THREE.ObjectLoader: Can\'t load ' + url );
  25073. return;
  25074. }
  25075. scope.parse( json, onLoad );
  25076. }, onProgress, onError );
  25077. }
  25078. parse( json, onLoad ) {
  25079. const animations = this.parseAnimations( json.animations );
  25080. const shapes = this.parseShapes( json.shapes );
  25081. const geometries = this.parseGeometries( json.geometries, shapes );
  25082. const images = this.parseImages( json.images, function () {
  25083. if ( onLoad !== undefined ) onLoad( object );
  25084. } );
  25085. const textures = this.parseTextures( json.textures, images );
  25086. const materials = this.parseMaterials( json.materials, textures );
  25087. const object = this.parseObject( json.object, geometries, materials, animations );
  25088. const skeletons = this.parseSkeletons( json.skeletons, object );
  25089. this.bindSkeletons( object, skeletons );
  25090. //
  25091. if ( onLoad !== undefined ) {
  25092. let hasImages = false;
  25093. for ( const uuid in images ) {
  25094. if ( images[ uuid ] instanceof HTMLImageElement ) {
  25095. hasImages = true;
  25096. break;
  25097. }
  25098. }
  25099. if ( hasImages === false ) onLoad( object );
  25100. }
  25101. return object;
  25102. }
  25103. parseShapes( json ) {
  25104. const shapes = {};
  25105. if ( json !== undefined ) {
  25106. for ( let i = 0, l = json.length; i < l; i ++ ) {
  25107. const shape = new Shape().fromJSON( json[ i ] );
  25108. shapes[ shape.uuid ] = shape;
  25109. }
  25110. }
  25111. return shapes;
  25112. }
  25113. parseSkeletons( json, object ) {
  25114. const skeletons = {};
  25115. const bones = {};
  25116. // generate bone lookup table
  25117. object.traverse( function ( child ) {
  25118. if ( child.isBone ) bones[ child.uuid ] = child;
  25119. } );
  25120. // create skeletons
  25121. if ( json !== undefined ) {
  25122. for ( let i = 0, l = json.length; i < l; i ++ ) {
  25123. const skeleton = new Skeleton().fromJSON( json[ i ], bones );
  25124. skeletons[ skeleton.uuid ] = skeleton;
  25125. }
  25126. }
  25127. return skeletons;
  25128. }
  25129. parseGeometries( json, shapes ) {
  25130. const geometries = {};
  25131. let geometryShapes;
  25132. if ( json !== undefined ) {
  25133. const bufferGeometryLoader = new BufferGeometryLoader();
  25134. for ( let i = 0, l = json.length; i < l; i ++ ) {
  25135. let geometry;
  25136. const data = json[ i ];
  25137. switch ( data.type ) {
  25138. case 'PlaneGeometry':
  25139. case 'PlaneBufferGeometry':
  25140. geometry = new Geometries[ data.type ](
  25141. data.width,
  25142. data.height,
  25143. data.widthSegments,
  25144. data.heightSegments
  25145. );
  25146. break;
  25147. case 'BoxGeometry':
  25148. case 'BoxBufferGeometry':
  25149. case 'CubeGeometry': // backwards compatible
  25150. geometry = new Geometries[ data.type ](
  25151. data.width,
  25152. data.height,
  25153. data.depth,
  25154. data.widthSegments,
  25155. data.heightSegments,
  25156. data.depthSegments
  25157. );
  25158. break;
  25159. case 'CircleGeometry':
  25160. case 'CircleBufferGeometry':
  25161. geometry = new Geometries[ data.type ](
  25162. data.radius,
  25163. data.segments,
  25164. data.thetaStart,
  25165. data.thetaLength
  25166. );
  25167. break;
  25168. case 'CylinderGeometry':
  25169. case 'CylinderBufferGeometry':
  25170. geometry = new Geometries[ data.type ](
  25171. data.radiusTop,
  25172. data.radiusBottom,
  25173. data.height,
  25174. data.radialSegments,
  25175. data.heightSegments,
  25176. data.openEnded,
  25177. data.thetaStart,
  25178. data.thetaLength
  25179. );
  25180. break;
  25181. case 'ConeGeometry':
  25182. case 'ConeBufferGeometry':
  25183. geometry = new Geometries[ data.type ](
  25184. data.radius,
  25185. data.height,
  25186. data.radialSegments,
  25187. data.heightSegments,
  25188. data.openEnded,
  25189. data.thetaStart,
  25190. data.thetaLength
  25191. );
  25192. break;
  25193. case 'SphereGeometry':
  25194. case 'SphereBufferGeometry':
  25195. geometry = new Geometries[ data.type ](
  25196. data.radius,
  25197. data.widthSegments,
  25198. data.heightSegments,
  25199. data.phiStart,
  25200. data.phiLength,
  25201. data.thetaStart,
  25202. data.thetaLength
  25203. );
  25204. break;
  25205. case 'DodecahedronGeometry':
  25206. case 'DodecahedronBufferGeometry':
  25207. case 'IcosahedronGeometry':
  25208. case 'IcosahedronBufferGeometry':
  25209. case 'OctahedronGeometry':
  25210. case 'OctahedronBufferGeometry':
  25211. case 'TetrahedronGeometry':
  25212. case 'TetrahedronBufferGeometry':
  25213. geometry = new Geometries[ data.type ](
  25214. data.radius,
  25215. data.detail
  25216. );
  25217. break;
  25218. case 'RingGeometry':
  25219. case 'RingBufferGeometry':
  25220. geometry = new Geometries[ data.type ](
  25221. data.innerRadius,
  25222. data.outerRadius,
  25223. data.thetaSegments,
  25224. data.phiSegments,
  25225. data.thetaStart,
  25226. data.thetaLength
  25227. );
  25228. break;
  25229. case 'TorusGeometry':
  25230. case 'TorusBufferGeometry':
  25231. geometry = new Geometries[ data.type ](
  25232. data.radius,
  25233. data.tube,
  25234. data.radialSegments,
  25235. data.tubularSegments,
  25236. data.arc
  25237. );
  25238. break;
  25239. case 'TorusKnotGeometry':
  25240. case 'TorusKnotBufferGeometry':
  25241. geometry = new Geometries[ data.type ](
  25242. data.radius,
  25243. data.tube,
  25244. data.tubularSegments,
  25245. data.radialSegments,
  25246. data.p,
  25247. data.q
  25248. );
  25249. break;
  25250. case 'TubeGeometry':
  25251. case 'TubeBufferGeometry':
  25252. // This only works for built-in curves (e.g. CatmullRomCurve3).
  25253. // User defined curves or instances of CurvePath will not be deserialized.
  25254. geometry = new Geometries[ data.type ](
  25255. new Curves[ data.path.type ]().fromJSON( data.path ),
  25256. data.tubularSegments,
  25257. data.radius,
  25258. data.radialSegments,
  25259. data.closed
  25260. );
  25261. break;
  25262. case 'LatheGeometry':
  25263. case 'LatheBufferGeometry':
  25264. geometry = new Geometries[ data.type ](
  25265. data.points,
  25266. data.segments,
  25267. data.phiStart,
  25268. data.phiLength
  25269. );
  25270. break;
  25271. case 'PolyhedronGeometry':
  25272. case 'PolyhedronBufferGeometry':
  25273. geometry = new Geometries[ data.type ](
  25274. data.vertices,
  25275. data.indices,
  25276. data.radius,
  25277. data.details
  25278. );
  25279. break;
  25280. case 'ShapeGeometry':
  25281. case 'ShapeBufferGeometry':
  25282. geometryShapes = [];
  25283. for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
  25284. const shape = shapes[ data.shapes[ j ] ];
  25285. geometryShapes.push( shape );
  25286. }
  25287. geometry = new Geometries[ data.type ](
  25288. geometryShapes,
  25289. data.curveSegments
  25290. );
  25291. break;
  25292. case 'ExtrudeGeometry':
  25293. case 'ExtrudeBufferGeometry':
  25294. geometryShapes = [];
  25295. for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
  25296. const shape = shapes[ data.shapes[ j ] ];
  25297. geometryShapes.push( shape );
  25298. }
  25299. const extrudePath = data.options.extrudePath;
  25300. if ( extrudePath !== undefined ) {
  25301. data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
  25302. }
  25303. geometry = new Geometries[ data.type ](
  25304. geometryShapes,
  25305. data.options
  25306. );
  25307. break;
  25308. case 'BufferGeometry':
  25309. case 'InstancedBufferGeometry':
  25310. geometry = bufferGeometryLoader.parse( data );
  25311. break;
  25312. case 'Geometry':
  25313. console.error( 'THREE.ObjectLoader: Loading "Geometry" is not supported anymore.' );
  25314. break;
  25315. default:
  25316. console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );
  25317. continue;
  25318. }
  25319. geometry.uuid = data.uuid;
  25320. if ( data.name !== undefined ) geometry.name = data.name;
  25321. if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData;
  25322. geometries[ data.uuid ] = geometry;
  25323. }
  25324. }
  25325. return geometries;
  25326. }
  25327. parseMaterials( json, textures ) {
  25328. const cache = {}; // MultiMaterial
  25329. const materials = {};
  25330. if ( json !== undefined ) {
  25331. const loader = new MaterialLoader();
  25332. loader.setTextures( textures );
  25333. for ( let i = 0, l = json.length; i < l; i ++ ) {
  25334. const data = json[ i ];
  25335. if ( data.type === 'MultiMaterial' ) {
  25336. // Deprecated
  25337. const array = [];
  25338. for ( let j = 0; j < data.materials.length; j ++ ) {
  25339. const material = data.materials[ j ];
  25340. if ( cache[ material.uuid ] === undefined ) {
  25341. cache[ material.uuid ] = loader.parse( material );
  25342. }
  25343. array.push( cache[ material.uuid ] );
  25344. }
  25345. materials[ data.uuid ] = array;
  25346. } else {
  25347. if ( cache[ data.uuid ] === undefined ) {
  25348. cache[ data.uuid ] = loader.parse( data );
  25349. }
  25350. materials[ data.uuid ] = cache[ data.uuid ];
  25351. }
  25352. }
  25353. }
  25354. return materials;
  25355. }
  25356. parseAnimations( json ) {
  25357. const animations = {};
  25358. if ( json !== undefined ) {
  25359. for ( let i = 0; i < json.length; i ++ ) {
  25360. const data = json[ i ];
  25361. const clip = AnimationClip.parse( data );
  25362. animations[ clip.uuid ] = clip;
  25363. }
  25364. }
  25365. return animations;
  25366. }
  25367. parseImages( json, onLoad ) {
  25368. const scope = this;
  25369. const images = {};
  25370. let loader;
  25371. function loadImage( url ) {
  25372. scope.manager.itemStart( url );
  25373. return loader.load( url, function () {
  25374. scope.manager.itemEnd( url );
  25375. }, undefined, function () {
  25376. scope.manager.itemError( url );
  25377. scope.manager.itemEnd( url );
  25378. } );
  25379. }
  25380. function deserializeImage( image ) {
  25381. if ( typeof image === 'string' ) {
  25382. const url = image;
  25383. const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
  25384. return loadImage( path );
  25385. } else {
  25386. if ( image.data ) {
  25387. return {
  25388. data: getTypedArray( image.type, image.data ),
  25389. width: image.width,
  25390. height: image.height
  25391. };
  25392. } else {
  25393. return null;
  25394. }
  25395. }
  25396. }
  25397. if ( json !== undefined && json.length > 0 ) {
  25398. const manager = new LoadingManager( onLoad );
  25399. loader = new ImageLoader( manager );
  25400. loader.setCrossOrigin( this.crossOrigin );
  25401. for ( let i = 0, il = json.length; i < il; i ++ ) {
  25402. const image = json[ i ];
  25403. const url = image.url;
  25404. if ( Array.isArray( url ) ) {
  25405. // load array of images e.g CubeTexture
  25406. images[ image.uuid ] = [];
  25407. for ( let j = 0, jl = url.length; j < jl; j ++ ) {
  25408. const currentUrl = url[ j ];
  25409. const deserializedImage = deserializeImage( currentUrl );
  25410. if ( deserializedImage !== null ) {
  25411. if ( deserializedImage instanceof HTMLImageElement ) {
  25412. images[ image.uuid ].push( deserializedImage );
  25413. } else {
  25414. // special case: handle array of data textures for cube textures
  25415. images[ image.uuid ].push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
  25416. }
  25417. }
  25418. }
  25419. } else {
  25420. // load single image
  25421. const deserializedImage = deserializeImage( image.url );
  25422. if ( deserializedImage !== null ) {
  25423. images[ image.uuid ] = deserializedImage;
  25424. }
  25425. }
  25426. }
  25427. }
  25428. return images;
  25429. }
  25430. parseTextures( json, images ) {
  25431. function parseConstant( value, type ) {
  25432. if ( typeof value === 'number' ) return value;
  25433. console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
  25434. return type[ value ];
  25435. }
  25436. const textures = {};
  25437. if ( json !== undefined ) {
  25438. for ( let i = 0, l = json.length; i < l; i ++ ) {
  25439. const data = json[ i ];
  25440. if ( data.image === undefined ) {
  25441. console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
  25442. }
  25443. if ( images[ data.image ] === undefined ) {
  25444. console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
  25445. }
  25446. let texture;
  25447. const image = images[ data.image ];
  25448. if ( Array.isArray( image ) ) {
  25449. texture = new CubeTexture( image );
  25450. if ( image.length === 6 ) texture.needsUpdate = true;
  25451. } else {
  25452. if ( image && image.data ) {
  25453. texture = new DataTexture( image.data, image.width, image.height );
  25454. } else {
  25455. texture = new Texture( image );
  25456. }
  25457. if ( image ) texture.needsUpdate = true; // textures can have undefined image data
  25458. }
  25459. texture.uuid = data.uuid;
  25460. if ( data.name !== undefined ) texture.name = data.name;
  25461. if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
  25462. if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
  25463. if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
  25464. if ( data.center !== undefined ) texture.center.fromArray( data.center );
  25465. if ( data.rotation !== undefined ) texture.rotation = data.rotation;
  25466. if ( data.wrap !== undefined ) {
  25467. texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
  25468. texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
  25469. }
  25470. if ( data.format !== undefined ) texture.format = data.format;
  25471. if ( data.type !== undefined ) texture.type = data.type;
  25472. if ( data.encoding !== undefined ) texture.encoding = data.encoding;
  25473. if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
  25474. if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
  25475. if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
  25476. if ( data.flipY !== undefined ) texture.flipY = data.flipY;
  25477. if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
  25478. if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
  25479. textures[ data.uuid ] = texture;
  25480. }
  25481. }
  25482. return textures;
  25483. }
  25484. parseObject( data, geometries, materials, animations ) {
  25485. let object;
  25486. function getGeometry( name ) {
  25487. if ( geometries[ name ] === undefined ) {
  25488. console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
  25489. }
  25490. return geometries[ name ];
  25491. }
  25492. function getMaterial( name ) {
  25493. if ( name === undefined ) return undefined;
  25494. if ( Array.isArray( name ) ) {
  25495. const array = [];
  25496. for ( let i = 0, l = name.length; i < l; i ++ ) {
  25497. const uuid = name[ i ];
  25498. if ( materials[ uuid ] === undefined ) {
  25499. console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
  25500. }
  25501. array.push( materials[ uuid ] );
  25502. }
  25503. return array;
  25504. }
  25505. if ( materials[ name ] === undefined ) {
  25506. console.warn( 'THREE.ObjectLoader: Undefined material', name );
  25507. }
  25508. return materials[ name ];
  25509. }
  25510. let geometry, material;
  25511. switch ( data.type ) {
  25512. case 'Scene':
  25513. object = new Scene();
  25514. if ( data.background !== undefined ) {
  25515. if ( Number.isInteger( data.background ) ) {
  25516. object.background = new Color( data.background );
  25517. }
  25518. }
  25519. if ( data.fog !== undefined ) {
  25520. if ( data.fog.type === 'Fog' ) {
  25521. object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
  25522. } else if ( data.fog.type === 'FogExp2' ) {
  25523. object.fog = new FogExp2( data.fog.color, data.fog.density );
  25524. }
  25525. }
  25526. break;
  25527. case 'PerspectiveCamera':
  25528. object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
  25529. if ( data.focus !== undefined ) object.focus = data.focus;
  25530. if ( data.zoom !== undefined ) object.zoom = data.zoom;
  25531. if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
  25532. if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
  25533. if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
  25534. break;
  25535. case 'OrthographicCamera':
  25536. object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
  25537. if ( data.zoom !== undefined ) object.zoom = data.zoom;
  25538. if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
  25539. break;
  25540. case 'AmbientLight':
  25541. object = new AmbientLight( data.color, data.intensity );
  25542. break;
  25543. case 'DirectionalLight':
  25544. object = new DirectionalLight( data.color, data.intensity );
  25545. break;
  25546. case 'PointLight':
  25547. object = new PointLight( data.color, data.intensity, data.distance, data.decay );
  25548. break;
  25549. case 'RectAreaLight':
  25550. object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
  25551. break;
  25552. case 'SpotLight':
  25553. object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
  25554. break;
  25555. case 'HemisphereLight':
  25556. object = new HemisphereLight( data.color, data.groundColor, data.intensity );
  25557. break;
  25558. case 'LightProbe':
  25559. object = new LightProbe().fromJSON( data );
  25560. break;
  25561. case 'SkinnedMesh':
  25562. geometry = getGeometry( data.geometry );
  25563. material = getMaterial( data.material );
  25564. object = new SkinnedMesh( geometry, material );
  25565. if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
  25566. if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
  25567. if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
  25568. break;
  25569. case 'Mesh':
  25570. geometry = getGeometry( data.geometry );
  25571. material = getMaterial( data.material );
  25572. object = new Mesh( geometry, material );
  25573. break;
  25574. case 'InstancedMesh':
  25575. geometry = getGeometry( data.geometry );
  25576. material = getMaterial( data.material );
  25577. const count = data.count;
  25578. const instanceMatrix = data.instanceMatrix;
  25579. object = new InstancedMesh( geometry, material, count );
  25580. object.instanceMatrix = new BufferAttribute( new Float32Array( instanceMatrix.array ), 16 );
  25581. break;
  25582. case 'LOD':
  25583. object = new LOD();
  25584. break;
  25585. case 'Line':
  25586. object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );
  25587. break;
  25588. case 'LineLoop':
  25589. object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
  25590. break;
  25591. case 'LineSegments':
  25592. object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
  25593. break;
  25594. case 'PointCloud':
  25595. case 'Points':
  25596. object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
  25597. break;
  25598. case 'Sprite':
  25599. object = new Sprite( getMaterial( data.material ) );
  25600. break;
  25601. case 'Group':
  25602. object = new Group();
  25603. break;
  25604. case 'Bone':
  25605. object = new Bone();
  25606. break;
  25607. default:
  25608. object = new Object3D();
  25609. }
  25610. object.uuid = data.uuid;
  25611. if ( data.name !== undefined ) object.name = data.name;
  25612. if ( data.matrix !== undefined ) {
  25613. object.matrix.fromArray( data.matrix );
  25614. if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
  25615. if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
  25616. } else {
  25617. if ( data.position !== undefined ) object.position.fromArray( data.position );
  25618. if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
  25619. if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
  25620. if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
  25621. }
  25622. if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
  25623. if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
  25624. if ( data.shadow ) {
  25625. if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
  25626. if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;
  25627. if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
  25628. if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
  25629. if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
  25630. }
  25631. if ( data.visible !== undefined ) object.visible = data.visible;
  25632. if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
  25633. if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
  25634. if ( data.userData !== undefined ) object.userData = data.userData;
  25635. if ( data.layers !== undefined ) object.layers.mask = data.layers;
  25636. if ( data.children !== undefined ) {
  25637. const children = data.children;
  25638. for ( let i = 0; i < children.length; i ++ ) {
  25639. object.add( this.parseObject( children[ i ], geometries, materials, animations ) );
  25640. }
  25641. }
  25642. if ( data.animations !== undefined ) {
  25643. const objectAnimations = data.animations;
  25644. for ( let i = 0; i < objectAnimations.length; i ++ ) {
  25645. const uuid = objectAnimations[ i ];
  25646. object.animations.push( animations[ uuid ] );
  25647. }
  25648. }
  25649. if ( data.type === 'LOD' ) {
  25650. if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;
  25651. const levels = data.levels;
  25652. for ( let l = 0; l < levels.length; l ++ ) {
  25653. const level = levels[ l ];
  25654. const child = object.getObjectByProperty( 'uuid', level.object );
  25655. if ( child !== undefined ) {
  25656. object.addLevel( child, level.distance );
  25657. }
  25658. }
  25659. }
  25660. return object;
  25661. }
  25662. bindSkeletons( object, skeletons ) {
  25663. if ( Object.keys( skeletons ).length === 0 ) return;
  25664. object.traverse( function ( child ) {
  25665. if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
  25666. const skeleton = skeletons[ child.skeleton ];
  25667. if ( skeleton === undefined ) {
  25668. console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
  25669. } else {
  25670. child.bind( skeleton, child.bindMatrix );
  25671. }
  25672. }
  25673. } );
  25674. }
  25675. /* DEPRECATED */
  25676. setTexturePath( value ) {
  25677. console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' );
  25678. return this.setResourcePath( value );
  25679. }
  25680. }
  25681. const TEXTURE_MAPPING = {
  25682. UVMapping: UVMapping,
  25683. CubeReflectionMapping: CubeReflectionMapping,
  25684. CubeRefractionMapping: CubeRefractionMapping,
  25685. EquirectangularReflectionMapping: EquirectangularReflectionMapping,
  25686. EquirectangularRefractionMapping: EquirectangularRefractionMapping,
  25687. CubeUVReflectionMapping: CubeUVReflectionMapping,
  25688. CubeUVRefractionMapping: CubeUVRefractionMapping
  25689. };
  25690. const TEXTURE_WRAPPING = {
  25691. RepeatWrapping: RepeatWrapping,
  25692. ClampToEdgeWrapping: ClampToEdgeWrapping,
  25693. MirroredRepeatWrapping: MirroredRepeatWrapping
  25694. };
  25695. const TEXTURE_FILTER = {
  25696. NearestFilter: NearestFilter,
  25697. NearestMipmapNearestFilter: NearestMipmapNearestFilter,
  25698. NearestMipmapLinearFilter: NearestMipmapLinearFilter,
  25699. LinearFilter: LinearFilter,
  25700. LinearMipmapNearestFilter: LinearMipmapNearestFilter,
  25701. LinearMipmapLinearFilter: LinearMipmapLinearFilter
  25702. };
  25703. function ImageBitmapLoader( manager ) {
  25704. if ( typeof createImageBitmap === 'undefined' ) {
  25705. console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
  25706. }
  25707. if ( typeof fetch === 'undefined' ) {
  25708. console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
  25709. }
  25710. Loader.call( this, manager );
  25711. this.options = { premultiplyAlpha: 'none' };
  25712. }
  25713. ImageBitmapLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  25714. constructor: ImageBitmapLoader,
  25715. isImageBitmapLoader: true,
  25716. setOptions: function setOptions( options ) {
  25717. this.options = options;
  25718. return this;
  25719. },
  25720. load: function ( url, onLoad, onProgress, onError ) {
  25721. if ( url === undefined ) url = '';
  25722. if ( this.path !== undefined ) url = this.path + url;
  25723. url = this.manager.resolveURL( url );
  25724. const scope = this;
  25725. const cached = Cache.get( url );
  25726. if ( cached !== undefined ) {
  25727. scope.manager.itemStart( url );
  25728. setTimeout( function () {
  25729. if ( onLoad ) onLoad( cached );
  25730. scope.manager.itemEnd( url );
  25731. }, 0 );
  25732. return cached;
  25733. }
  25734. const fetchOptions = {};
  25735. fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
  25736. fetch( url, fetchOptions ).then( function ( res ) {
  25737. return res.blob();
  25738. } ).then( function ( blob ) {
  25739. return createImageBitmap( blob, scope.options );
  25740. } ).then( function ( imageBitmap ) {
  25741. Cache.add( url, imageBitmap );
  25742. if ( onLoad ) onLoad( imageBitmap );
  25743. scope.manager.itemEnd( url );
  25744. } ).catch( function ( e ) {
  25745. if ( onError ) onError( e );
  25746. scope.manager.itemError( url );
  25747. scope.manager.itemEnd( url );
  25748. } );
  25749. scope.manager.itemStart( url );
  25750. }
  25751. } );
  25752. function ShapePath() {
  25753. this.type = 'ShapePath';
  25754. this.color = new Color();
  25755. this.subPaths = [];
  25756. this.currentPath = null;
  25757. }
  25758. Object.assign( ShapePath.prototype, {
  25759. moveTo: function ( x, y ) {
  25760. this.currentPath = new Path();
  25761. this.subPaths.push( this.currentPath );
  25762. this.currentPath.moveTo( x, y );
  25763. return this;
  25764. },
  25765. lineTo: function ( x, y ) {
  25766. this.currentPath.lineTo( x, y );
  25767. return this;
  25768. },
  25769. quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
  25770. this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
  25771. return this;
  25772. },
  25773. bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
  25774. this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
  25775. return this;
  25776. },
  25777. splineThru: function ( pts ) {
  25778. this.currentPath.splineThru( pts );
  25779. return this;
  25780. },
  25781. toShapes: function ( isCCW, noHoles ) {
  25782. function toShapesNoHoles( inSubpaths ) {
  25783. const shapes = [];
  25784. for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
  25785. const tmpPath = inSubpaths[ i ];
  25786. const tmpShape = new Shape();
  25787. tmpShape.curves = tmpPath.curves;
  25788. shapes.push( tmpShape );
  25789. }
  25790. return shapes;
  25791. }
  25792. function isPointInsidePolygon( inPt, inPolygon ) {
  25793. const polyLen = inPolygon.length;
  25794. // inPt on polygon contour => immediate success or
  25795. // toggling of inside/outside at every single! intersection point of an edge
  25796. // with the horizontal line through inPt, left of inPt
  25797. // not counting lowerY endpoints of edges and whole edges on that line
  25798. let inside = false;
  25799. for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
  25800. let edgeLowPt = inPolygon[ p ];
  25801. let edgeHighPt = inPolygon[ q ];
  25802. let edgeDx = edgeHighPt.x - edgeLowPt.x;
  25803. let edgeDy = edgeHighPt.y - edgeLowPt.y;
  25804. if ( Math.abs( edgeDy ) > Number.EPSILON ) {
  25805. // not parallel
  25806. if ( edgeDy < 0 ) {
  25807. edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
  25808. edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
  25809. }
  25810. if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
  25811. if ( inPt.y === edgeLowPt.y ) {
  25812. if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ?
  25813. // continue; // no intersection or edgeLowPt => doesn't count !!!
  25814. } else {
  25815. const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
  25816. if ( perpEdge === 0 ) return true; // inPt is on contour ?
  25817. if ( perpEdge < 0 ) continue;
  25818. inside = ! inside; // true intersection left of inPt
  25819. }
  25820. } else {
  25821. // parallel or collinear
  25822. if ( inPt.y !== edgeLowPt.y ) continue; // parallel
  25823. // edge lies on the same horizontal line as inPt
  25824. if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
  25825. ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
  25826. // continue;
  25827. }
  25828. }
  25829. return inside;
  25830. }
  25831. const isClockWise = ShapeUtils.isClockWise;
  25832. const subPaths = this.subPaths;
  25833. if ( subPaths.length === 0 ) return [];
  25834. if ( noHoles === true ) return toShapesNoHoles( subPaths );
  25835. let solid, tmpPath, tmpShape;
  25836. const shapes = [];
  25837. if ( subPaths.length === 1 ) {
  25838. tmpPath = subPaths[ 0 ];
  25839. tmpShape = new Shape();
  25840. tmpShape.curves = tmpPath.curves;
  25841. shapes.push( tmpShape );
  25842. return shapes;
  25843. }
  25844. let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
  25845. holesFirst = isCCW ? ! holesFirst : holesFirst;
  25846. // console.log("Holes first", holesFirst);
  25847. const betterShapeHoles = [];
  25848. const newShapes = [];
  25849. let newShapeHoles = [];
  25850. let mainIdx = 0;
  25851. let tmpPoints;
  25852. newShapes[ mainIdx ] = undefined;
  25853. newShapeHoles[ mainIdx ] = [];
  25854. for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
  25855. tmpPath = subPaths[ i ];
  25856. tmpPoints = tmpPath.getPoints();
  25857. solid = isClockWise( tmpPoints );
  25858. solid = isCCW ? ! solid : solid;
  25859. if ( solid ) {
  25860. if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
  25861. newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
  25862. newShapes[ mainIdx ].s.curves = tmpPath.curves;
  25863. if ( holesFirst ) mainIdx ++;
  25864. newShapeHoles[ mainIdx ] = [];
  25865. //console.log('cw', i);
  25866. } else {
  25867. newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
  25868. //console.log('ccw', i);
  25869. }
  25870. }
  25871. // only Holes? -> probably all Shapes with wrong orientation
  25872. if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths );
  25873. if ( newShapes.length > 1 ) {
  25874. let ambiguous = false;
  25875. const toChange = [];
  25876. for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
  25877. betterShapeHoles[ sIdx ] = [];
  25878. }
  25879. for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
  25880. const sho = newShapeHoles[ sIdx ];
  25881. for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
  25882. const ho = sho[ hIdx ];
  25883. let hole_unassigned = true;
  25884. for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
  25885. if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
  25886. if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
  25887. if ( hole_unassigned ) {
  25888. hole_unassigned = false;
  25889. betterShapeHoles[ s2Idx ].push( ho );
  25890. } else {
  25891. ambiguous = true;
  25892. }
  25893. }
  25894. }
  25895. if ( hole_unassigned ) {
  25896. betterShapeHoles[ sIdx ].push( ho );
  25897. }
  25898. }
  25899. }
  25900. // console.log("ambiguous: ", ambiguous);
  25901. if ( toChange.length > 0 ) {
  25902. // console.log("to change: ", toChange);
  25903. if ( ! ambiguous ) newShapeHoles = betterShapeHoles;
  25904. }
  25905. }
  25906. let tmpHoles;
  25907. for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
  25908. tmpShape = newShapes[ i ].s;
  25909. shapes.push( tmpShape );
  25910. tmpHoles = newShapeHoles[ i ];
  25911. for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
  25912. tmpShape.holes.push( tmpHoles[ j ].h );
  25913. }
  25914. }
  25915. //console.log("shape", shapes);
  25916. return shapes;
  25917. }
  25918. } );
  25919. function Font( data ) {
  25920. this.type = 'Font';
  25921. this.data = data;
  25922. }
  25923. Object.assign( Font.prototype, {
  25924. isFont: true,
  25925. generateShapes: function ( text, size = 100 ) {
  25926. const shapes = [];
  25927. const paths = createPaths( text, size, this.data );
  25928. for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
  25929. Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
  25930. }
  25931. return shapes;
  25932. }
  25933. } );
  25934. function createPaths( text, size, data ) {
  25935. const chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // workaround for IE11, see #13988
  25936. const scale = size / data.resolution;
  25937. const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
  25938. const paths = [];
  25939. let offsetX = 0, offsetY = 0;
  25940. for ( let i = 0; i < chars.length; i ++ ) {
  25941. const char = chars[ i ];
  25942. if ( char === '\n' ) {
  25943. offsetX = 0;
  25944. offsetY -= line_height;
  25945. } else {
  25946. const ret = createPath( char, scale, offsetX, offsetY, data );
  25947. offsetX += ret.offsetX;
  25948. paths.push( ret.path );
  25949. }
  25950. }
  25951. return paths;
  25952. }
  25953. function createPath( char, scale, offsetX, offsetY, data ) {
  25954. const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
  25955. if ( ! glyph ) {
  25956. console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
  25957. return;
  25958. }
  25959. const path = new ShapePath();
  25960. let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
  25961. if ( glyph.o ) {
  25962. const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
  25963. for ( let i = 0, l = outline.length; i < l; ) {
  25964. const action = outline[ i ++ ];
  25965. switch ( action ) {
  25966. case 'm': // moveTo
  25967. x = outline[ i ++ ] * scale + offsetX;
  25968. y = outline[ i ++ ] * scale + offsetY;
  25969. path.moveTo( x, y );
  25970. break;
  25971. case 'l': // lineTo
  25972. x = outline[ i ++ ] * scale + offsetX;
  25973. y = outline[ i ++ ] * scale + offsetY;
  25974. path.lineTo( x, y );
  25975. break;
  25976. case 'q': // quadraticCurveTo
  25977. cpx = outline[ i ++ ] * scale + offsetX;
  25978. cpy = outline[ i ++ ] * scale + offsetY;
  25979. cpx1 = outline[ i ++ ] * scale + offsetX;
  25980. cpy1 = outline[ i ++ ] * scale + offsetY;
  25981. path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
  25982. break;
  25983. case 'b': // bezierCurveTo
  25984. cpx = outline[ i ++ ] * scale + offsetX;
  25985. cpy = outline[ i ++ ] * scale + offsetY;
  25986. cpx1 = outline[ i ++ ] * scale + offsetX;
  25987. cpy1 = outline[ i ++ ] * scale + offsetY;
  25988. cpx2 = outline[ i ++ ] * scale + offsetX;
  25989. cpy2 = outline[ i ++ ] * scale + offsetY;
  25990. path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
  25991. break;
  25992. }
  25993. }
  25994. }
  25995. return { offsetX: glyph.ha * scale, path: path };
  25996. }
  25997. function FontLoader( manager ) {
  25998. Loader.call( this, manager );
  25999. }
  26000. FontLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  26001. constructor: FontLoader,
  26002. load: function ( url, onLoad, onProgress, onError ) {
  26003. const scope = this;
  26004. const loader = new FileLoader( this.manager );
  26005. loader.setPath( this.path );
  26006. loader.setRequestHeader( this.requestHeader );
  26007. loader.setWithCredentials( scope.withCredentials );
  26008. loader.load( url, function ( text ) {
  26009. let json;
  26010. try {
  26011. json = JSON.parse( text );
  26012. } catch ( e ) {
  26013. console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
  26014. json = JSON.parse( text.substring( 65, text.length - 2 ) );
  26015. }
  26016. const font = scope.parse( json );
  26017. if ( onLoad ) onLoad( font );
  26018. }, onProgress, onError );
  26019. },
  26020. parse: function ( json ) {
  26021. return new Font( json );
  26022. }
  26023. } );
  26024. let _context;
  26025. const AudioContext = {
  26026. getContext: function () {
  26027. if ( _context === undefined ) {
  26028. _context = new ( window.AudioContext || window.webkitAudioContext )();
  26029. }
  26030. return _context;
  26031. },
  26032. setContext: function ( value ) {
  26033. _context = value;
  26034. }
  26035. };
  26036. function AudioLoader( manager ) {
  26037. Loader.call( this, manager );
  26038. }
  26039. AudioLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  26040. constructor: AudioLoader,
  26041. load: function ( url, onLoad, onProgress, onError ) {
  26042. const scope = this;
  26043. const loader = new FileLoader( scope.manager );
  26044. loader.setResponseType( 'arraybuffer' );
  26045. loader.setPath( scope.path );
  26046. loader.setRequestHeader( scope.requestHeader );
  26047. loader.setWithCredentials( scope.withCredentials );
  26048. loader.load( url, function ( buffer ) {
  26049. try {
  26050. // Create a copy of the buffer. The `decodeAudioData` method
  26051. // detaches the buffer when complete, preventing reuse.
  26052. const bufferCopy = buffer.slice( 0 );
  26053. const context = AudioContext.getContext();
  26054. context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
  26055. onLoad( audioBuffer );
  26056. } );
  26057. } catch ( e ) {
  26058. if ( onError ) {
  26059. onError( e );
  26060. } else {
  26061. console.error( e );
  26062. }
  26063. scope.manager.itemError( url );
  26064. }
  26065. }, onProgress, onError );
  26066. }
  26067. } );
  26068. function HemisphereLightProbe( skyColor, groundColor, intensity ) {
  26069. LightProbe.call( this, undefined, intensity );
  26070. const color1 = new Color().set( skyColor );
  26071. const color2 = new Color().set( groundColor );
  26072. const sky = new Vector3( color1.r, color1.g, color1.b );
  26073. const ground = new Vector3( color2.r, color2.g, color2.b );
  26074. // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI );
  26075. const c0 = Math.sqrt( Math.PI );
  26076. const c1 = c0 * Math.sqrt( 0.75 );
  26077. this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 );
  26078. this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 );
  26079. }
  26080. HemisphereLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
  26081. constructor: HemisphereLightProbe,
  26082. isHemisphereLightProbe: true,
  26083. copy: function ( source ) { // modifying colors not currently supported
  26084. LightProbe.prototype.copy.call( this, source );
  26085. return this;
  26086. },
  26087. toJSON: function ( meta ) {
  26088. const data = LightProbe.prototype.toJSON.call( this, meta );
  26089. // data.sh = this.sh.toArray(); // todo
  26090. return data;
  26091. }
  26092. } );
  26093. function AmbientLightProbe( color, intensity ) {
  26094. LightProbe.call( this, undefined, intensity );
  26095. const color1 = new Color().set( color );
  26096. // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI );
  26097. this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) );
  26098. }
  26099. AmbientLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
  26100. constructor: AmbientLightProbe,
  26101. isAmbientLightProbe: true,
  26102. copy: function ( source ) { // modifying color not currently supported
  26103. LightProbe.prototype.copy.call( this, source );
  26104. return this;
  26105. },
  26106. toJSON: function ( meta ) {
  26107. const data = LightProbe.prototype.toJSON.call( this, meta );
  26108. // data.sh = this.sh.toArray(); // todo
  26109. return data;
  26110. }
  26111. } );
  26112. const _eyeRight = new Matrix4();
  26113. const _eyeLeft = new Matrix4();
  26114. function StereoCamera() {
  26115. this.type = 'StereoCamera';
  26116. this.aspect = 1;
  26117. this.eyeSep = 0.064;
  26118. this.cameraL = new PerspectiveCamera();
  26119. this.cameraL.layers.enable( 1 );
  26120. this.cameraL.matrixAutoUpdate = false;
  26121. this.cameraR = new PerspectiveCamera();
  26122. this.cameraR.layers.enable( 2 );
  26123. this.cameraR.matrixAutoUpdate = false;
  26124. this._cache = {
  26125. focus: null,
  26126. fov: null,
  26127. aspect: null,
  26128. near: null,
  26129. far: null,
  26130. zoom: null,
  26131. eyeSep: null
  26132. };
  26133. }
  26134. Object.assign( StereoCamera.prototype, {
  26135. update: function ( camera ) {
  26136. const cache = this._cache;
  26137. const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
  26138. cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
  26139. cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
  26140. if ( needsUpdate ) {
  26141. cache.focus = camera.focus;
  26142. cache.fov = camera.fov;
  26143. cache.aspect = camera.aspect * this.aspect;
  26144. cache.near = camera.near;
  26145. cache.far = camera.far;
  26146. cache.zoom = camera.zoom;
  26147. cache.eyeSep = this.eyeSep;
  26148. // Off-axis stereoscopic effect based on
  26149. // http://paulbourke.net/stereographics/stereorender/
  26150. const projectionMatrix = camera.projectionMatrix.clone();
  26151. const eyeSepHalf = cache.eyeSep / 2;
  26152. const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
  26153. const ymax = ( cache.near * Math.tan( MathUtils.DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
  26154. let xmin, xmax;
  26155. // translate xOffset
  26156. _eyeLeft.elements[ 12 ] = - eyeSepHalf;
  26157. _eyeRight.elements[ 12 ] = eyeSepHalf;
  26158. // for left eye
  26159. xmin = - ymax * cache.aspect + eyeSepOnProjection;
  26160. xmax = ymax * cache.aspect + eyeSepOnProjection;
  26161. projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
  26162. projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
  26163. this.cameraL.projectionMatrix.copy( projectionMatrix );
  26164. // for right eye
  26165. xmin = - ymax * cache.aspect - eyeSepOnProjection;
  26166. xmax = ymax * cache.aspect - eyeSepOnProjection;
  26167. projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
  26168. projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
  26169. this.cameraR.projectionMatrix.copy( projectionMatrix );
  26170. }
  26171. this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
  26172. this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
  26173. }
  26174. } );
  26175. class Clock {
  26176. constructor( autoStart ) {
  26177. this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
  26178. this.startTime = 0;
  26179. this.oldTime = 0;
  26180. this.elapsedTime = 0;
  26181. this.running = false;
  26182. }
  26183. start() {
  26184. this.startTime = now();
  26185. this.oldTime = this.startTime;
  26186. this.elapsedTime = 0;
  26187. this.running = true;
  26188. }
  26189. stop() {
  26190. this.getElapsedTime();
  26191. this.running = false;
  26192. this.autoStart = false;
  26193. }
  26194. getElapsedTime() {
  26195. this.getDelta();
  26196. return this.elapsedTime;
  26197. }
  26198. getDelta() {
  26199. let diff = 0;
  26200. if ( this.autoStart && ! this.running ) {
  26201. this.start();
  26202. return 0;
  26203. }
  26204. if ( this.running ) {
  26205. const newTime = now();
  26206. diff = ( newTime - this.oldTime ) / 1000;
  26207. this.oldTime = newTime;
  26208. this.elapsedTime += diff;
  26209. }
  26210. return diff;
  26211. }
  26212. }
  26213. function now() {
  26214. return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
  26215. }
  26216. const _position$2 = /*@__PURE__*/ new Vector3();
  26217. const _quaternion$3 = /*@__PURE__*/ new Quaternion();
  26218. const _scale$1 = /*@__PURE__*/ new Vector3();
  26219. const _orientation = /*@__PURE__*/ new Vector3();
  26220. class AudioListener extends Object3D {
  26221. constructor() {
  26222. super();
  26223. this.type = 'AudioListener';
  26224. this.context = AudioContext.getContext();
  26225. this.gain = this.context.createGain();
  26226. this.gain.connect( this.context.destination );
  26227. this.filter = null;
  26228. this.timeDelta = 0;
  26229. // private
  26230. this._clock = new Clock();
  26231. }
  26232. getInput() {
  26233. return this.gain;
  26234. }
  26235. removeFilter() {
  26236. if ( this.filter !== null ) {
  26237. this.gain.disconnect( this.filter );
  26238. this.filter.disconnect( this.context.destination );
  26239. this.gain.connect( this.context.destination );
  26240. this.filter = null;
  26241. }
  26242. return this;
  26243. }
  26244. getFilter() {
  26245. return this.filter;
  26246. }
  26247. setFilter( value ) {
  26248. if ( this.filter !== null ) {
  26249. this.gain.disconnect( this.filter );
  26250. this.filter.disconnect( this.context.destination );
  26251. } else {
  26252. this.gain.disconnect( this.context.destination );
  26253. }
  26254. this.filter = value;
  26255. this.gain.connect( this.filter );
  26256. this.filter.connect( this.context.destination );
  26257. return this;
  26258. }
  26259. getMasterVolume() {
  26260. return this.gain.gain.value;
  26261. }
  26262. setMasterVolume( value ) {
  26263. this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
  26264. return this;
  26265. }
  26266. updateMatrixWorld( force ) {
  26267. super.updateMatrixWorld( force );
  26268. const listener = this.context.listener;
  26269. const up = this.up;
  26270. this.timeDelta = this._clock.getDelta();
  26271. this.matrixWorld.decompose( _position$2, _quaternion$3, _scale$1 );
  26272. _orientation.set( 0, 0, - 1 ).applyQuaternion( _quaternion$3 );
  26273. if ( listener.positionX ) {
  26274. // code path for Chrome (see #14393)
  26275. const endTime = this.context.currentTime + this.timeDelta;
  26276. listener.positionX.linearRampToValueAtTime( _position$2.x, endTime );
  26277. listener.positionY.linearRampToValueAtTime( _position$2.y, endTime );
  26278. listener.positionZ.linearRampToValueAtTime( _position$2.z, endTime );
  26279. listener.forwardX.linearRampToValueAtTime( _orientation.x, endTime );
  26280. listener.forwardY.linearRampToValueAtTime( _orientation.y, endTime );
  26281. listener.forwardZ.linearRampToValueAtTime( _orientation.z, endTime );
  26282. listener.upX.linearRampToValueAtTime( up.x, endTime );
  26283. listener.upY.linearRampToValueAtTime( up.y, endTime );
  26284. listener.upZ.linearRampToValueAtTime( up.z, endTime );
  26285. } else {
  26286. listener.setPosition( _position$2.x, _position$2.y, _position$2.z );
  26287. listener.setOrientation( _orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z );
  26288. }
  26289. }
  26290. }
  26291. class Audio extends Object3D {
  26292. constructor( listener ) {
  26293. super();
  26294. this.type = 'Audio';
  26295. this.listener = listener;
  26296. this.context = listener.context;
  26297. this.gain = this.context.createGain();
  26298. this.gain.connect( listener.getInput() );
  26299. this.autoplay = false;
  26300. this.buffer = null;
  26301. this.detune = 0;
  26302. this.loop = false;
  26303. this.loopStart = 0;
  26304. this.loopEnd = 0;
  26305. this.offset = 0;
  26306. this.duration = undefined;
  26307. this.playbackRate = 1;
  26308. this.isPlaying = false;
  26309. this.hasPlaybackControl = true;
  26310. this.source = null;
  26311. this.sourceType = 'empty';
  26312. this._startedAt = 0;
  26313. this._progress = 0;
  26314. this._connected = false;
  26315. this.filters = [];
  26316. }
  26317. getOutput() {
  26318. return this.gain;
  26319. }
  26320. setNodeSource( audioNode ) {
  26321. this.hasPlaybackControl = false;
  26322. this.sourceType = 'audioNode';
  26323. this.source = audioNode;
  26324. this.connect();
  26325. return this;
  26326. }
  26327. setMediaElementSource( mediaElement ) {
  26328. this.hasPlaybackControl = false;
  26329. this.sourceType = 'mediaNode';
  26330. this.source = this.context.createMediaElementSource( mediaElement );
  26331. this.connect();
  26332. return this;
  26333. }
  26334. setMediaStreamSource( mediaStream ) {
  26335. this.hasPlaybackControl = false;
  26336. this.sourceType = 'mediaStreamNode';
  26337. this.source = this.context.createMediaStreamSource( mediaStream );
  26338. this.connect();
  26339. return this;
  26340. }
  26341. setBuffer( audioBuffer ) {
  26342. this.buffer = audioBuffer;
  26343. this.sourceType = 'buffer';
  26344. if ( this.autoplay ) this.play();
  26345. return this;
  26346. }
  26347. play( delay = 0 ) {
  26348. if ( this.isPlaying === true ) {
  26349. console.warn( 'THREE.Audio: Audio is already playing.' );
  26350. return;
  26351. }
  26352. if ( this.hasPlaybackControl === false ) {
  26353. console.warn( 'THREE.Audio: this Audio has no playback control.' );
  26354. return;
  26355. }
  26356. this._startedAt = this.context.currentTime + delay;
  26357. const source = this.context.createBufferSource();
  26358. source.buffer = this.buffer;
  26359. source.loop = this.loop;
  26360. source.loopStart = this.loopStart;
  26361. source.loopEnd = this.loopEnd;
  26362. source.onended = this.onEnded.bind( this );
  26363. source.start( this._startedAt, this._progress + this.offset, this.duration );
  26364. this.isPlaying = true;
  26365. this.source = source;
  26366. this.setDetune( this.detune );
  26367. this.setPlaybackRate( this.playbackRate );
  26368. return this.connect();
  26369. }
  26370. pause() {
  26371. if ( this.hasPlaybackControl === false ) {
  26372. console.warn( 'THREE.Audio: this Audio has no playback control.' );
  26373. return;
  26374. }
  26375. if ( this.isPlaying === true ) {
  26376. // update current progress
  26377. this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
  26378. if ( this.loop === true ) {
  26379. // ensure _progress does not exceed duration with looped audios
  26380. this._progress = this._progress % ( this.duration || this.buffer.duration );
  26381. }
  26382. this.source.stop();
  26383. this.source.onended = null;
  26384. this.isPlaying = false;
  26385. }
  26386. return this;
  26387. }
  26388. stop() {
  26389. if ( this.hasPlaybackControl === false ) {
  26390. console.warn( 'THREE.Audio: this Audio has no playback control.' );
  26391. return;
  26392. }
  26393. this._progress = 0;
  26394. this.source.stop();
  26395. this.source.onended = null;
  26396. this.isPlaying = false;
  26397. return this;
  26398. }
  26399. connect() {
  26400. if ( this.filters.length > 0 ) {
  26401. this.source.connect( this.filters[ 0 ] );
  26402. for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
  26403. this.filters[ i - 1 ].connect( this.filters[ i ] );
  26404. }
  26405. this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
  26406. } else {
  26407. this.source.connect( this.getOutput() );
  26408. }
  26409. this._connected = true;
  26410. return this;
  26411. }
  26412. disconnect() {
  26413. if ( this.filters.length > 0 ) {
  26414. this.source.disconnect( this.filters[ 0 ] );
  26415. for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
  26416. this.filters[ i - 1 ].disconnect( this.filters[ i ] );
  26417. }
  26418. this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
  26419. } else {
  26420. this.source.disconnect( this.getOutput() );
  26421. }
  26422. this._connected = false;
  26423. return this;
  26424. }
  26425. getFilters() {
  26426. return this.filters;
  26427. }
  26428. setFilters( value ) {
  26429. if ( ! value ) value = [];
  26430. if ( this._connected === true ) {
  26431. this.disconnect();
  26432. this.filters = value.slice();
  26433. this.connect();
  26434. } else {
  26435. this.filters = value.slice();
  26436. }
  26437. return this;
  26438. }
  26439. setDetune( value ) {
  26440. this.detune = value;
  26441. if ( this.source.detune === undefined ) return; // only set detune when available
  26442. if ( this.isPlaying === true ) {
  26443. this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
  26444. }
  26445. return this;
  26446. }
  26447. getDetune() {
  26448. return this.detune;
  26449. }
  26450. getFilter() {
  26451. return this.getFilters()[ 0 ];
  26452. }
  26453. setFilter( filter ) {
  26454. return this.setFilters( filter ? [ filter ] : [] );
  26455. }
  26456. setPlaybackRate( value ) {
  26457. if ( this.hasPlaybackControl === false ) {
  26458. console.warn( 'THREE.Audio: this Audio has no playback control.' );
  26459. return;
  26460. }
  26461. this.playbackRate = value;
  26462. if ( this.isPlaying === true ) {
  26463. this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
  26464. }
  26465. return this;
  26466. }
  26467. getPlaybackRate() {
  26468. return this.playbackRate;
  26469. }
  26470. onEnded() {
  26471. this.isPlaying = false;
  26472. }
  26473. getLoop() {
  26474. if ( this.hasPlaybackControl === false ) {
  26475. console.warn( 'THREE.Audio: this Audio has no playback control.' );
  26476. return false;
  26477. }
  26478. return this.loop;
  26479. }
  26480. setLoop( value ) {
  26481. if ( this.hasPlaybackControl === false ) {
  26482. console.warn( 'THREE.Audio: this Audio has no playback control.' );
  26483. return;
  26484. }
  26485. this.loop = value;
  26486. if ( this.isPlaying === true ) {
  26487. this.source.loop = this.loop;
  26488. }
  26489. return this;
  26490. }
  26491. setLoopStart( value ) {
  26492. this.loopStart = value;
  26493. return this;
  26494. }
  26495. setLoopEnd( value ) {
  26496. this.loopEnd = value;
  26497. return this;
  26498. }
  26499. getVolume() {
  26500. return this.gain.gain.value;
  26501. }
  26502. setVolume( value ) {
  26503. this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
  26504. return this;
  26505. }
  26506. }
  26507. const _position$3 = /*@__PURE__*/ new Vector3();
  26508. const _quaternion$4 = /*@__PURE__*/ new Quaternion();
  26509. const _scale$2 = /*@__PURE__*/ new Vector3();
  26510. const _orientation$1 = /*@__PURE__*/ new Vector3();
  26511. class PositionalAudio extends Audio {
  26512. constructor( listener ) {
  26513. super( listener );
  26514. this.panner = this.context.createPanner();
  26515. this.panner.panningModel = 'HRTF';
  26516. this.panner.connect( this.gain );
  26517. }
  26518. getOutput() {
  26519. return this.panner;
  26520. }
  26521. getRefDistance() {
  26522. return this.panner.refDistance;
  26523. }
  26524. setRefDistance( value ) {
  26525. this.panner.refDistance = value;
  26526. return this;
  26527. }
  26528. getRolloffFactor() {
  26529. return this.panner.rolloffFactor;
  26530. }
  26531. setRolloffFactor( value ) {
  26532. this.panner.rolloffFactor = value;
  26533. return this;
  26534. }
  26535. getDistanceModel() {
  26536. return this.panner.distanceModel;
  26537. }
  26538. setDistanceModel( value ) {
  26539. this.panner.distanceModel = value;
  26540. return this;
  26541. }
  26542. getMaxDistance() {
  26543. return this.panner.maxDistance;
  26544. }
  26545. setMaxDistance( value ) {
  26546. this.panner.maxDistance = value;
  26547. return this;
  26548. }
  26549. setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
  26550. this.panner.coneInnerAngle = coneInnerAngle;
  26551. this.panner.coneOuterAngle = coneOuterAngle;
  26552. this.panner.coneOuterGain = coneOuterGain;
  26553. return this;
  26554. }
  26555. updateMatrixWorld( force ) {
  26556. super.updateMatrixWorld( force );
  26557. if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
  26558. this.matrixWorld.decompose( _position$3, _quaternion$4, _scale$2 );
  26559. _orientation$1.set( 0, 0, 1 ).applyQuaternion( _quaternion$4 );
  26560. const panner = this.panner;
  26561. if ( panner.positionX ) {
  26562. // code path for Chrome and Firefox (see #14393)
  26563. const endTime = this.context.currentTime + this.listener.timeDelta;
  26564. panner.positionX.linearRampToValueAtTime( _position$3.x, endTime );
  26565. panner.positionY.linearRampToValueAtTime( _position$3.y, endTime );
  26566. panner.positionZ.linearRampToValueAtTime( _position$3.z, endTime );
  26567. panner.orientationX.linearRampToValueAtTime( _orientation$1.x, endTime );
  26568. panner.orientationY.linearRampToValueAtTime( _orientation$1.y, endTime );
  26569. panner.orientationZ.linearRampToValueAtTime( _orientation$1.z, endTime );
  26570. } else {
  26571. panner.setPosition( _position$3.x, _position$3.y, _position$3.z );
  26572. panner.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z );
  26573. }
  26574. }
  26575. }
  26576. class AudioAnalyser {
  26577. constructor( audio, fftSize = 2048 ) {
  26578. this.analyser = audio.context.createAnalyser();
  26579. this.analyser.fftSize = fftSize;
  26580. this.data = new Uint8Array( this.analyser.frequencyBinCount );
  26581. audio.getOutput().connect( this.analyser );
  26582. }
  26583. getFrequencyData() {
  26584. this.analyser.getByteFrequencyData( this.data );
  26585. return this.data;
  26586. }
  26587. getAverageFrequency() {
  26588. let value = 0;
  26589. const data = this.getFrequencyData();
  26590. for ( let i = 0; i < data.length; i ++ ) {
  26591. value += data[ i ];
  26592. }
  26593. return value / data.length;
  26594. }
  26595. }
  26596. function PropertyMixer( binding, typeName, valueSize ) {
  26597. this.binding = binding;
  26598. this.valueSize = valueSize;
  26599. let mixFunction,
  26600. mixFunctionAdditive,
  26601. setIdentity;
  26602. // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
  26603. //
  26604. // interpolators can use .buffer as their .result
  26605. // the data then goes to 'incoming'
  26606. //
  26607. // 'accu0' and 'accu1' are used frame-interleaved for
  26608. // the cumulative result and are compared to detect
  26609. // changes
  26610. //
  26611. // 'orig' stores the original state of the property
  26612. //
  26613. // 'add' is used for additive cumulative results
  26614. //
  26615. // 'work' is optional and is only present for quaternion types. It is used
  26616. // to store intermediate quaternion multiplication results
  26617. switch ( typeName ) {
  26618. case 'quaternion':
  26619. mixFunction = this._slerp;
  26620. mixFunctionAdditive = this._slerpAdditive;
  26621. setIdentity = this._setAdditiveIdentityQuaternion;
  26622. this.buffer = new Float64Array( valueSize * 6 );
  26623. this._workIndex = 5;
  26624. break;
  26625. case 'string':
  26626. case 'bool':
  26627. mixFunction = this._select;
  26628. // Use the regular mix function and for additive on these types,
  26629. // additive is not relevant for non-numeric types
  26630. mixFunctionAdditive = this._select;
  26631. setIdentity = this._setAdditiveIdentityOther;
  26632. this.buffer = new Array( valueSize * 5 );
  26633. break;
  26634. default:
  26635. mixFunction = this._lerp;
  26636. mixFunctionAdditive = this._lerpAdditive;
  26637. setIdentity = this._setAdditiveIdentityNumeric;
  26638. this.buffer = new Float64Array( valueSize * 5 );
  26639. }
  26640. this._mixBufferRegion = mixFunction;
  26641. this._mixBufferRegionAdditive = mixFunctionAdditive;
  26642. this._setIdentity = setIdentity;
  26643. this._origIndex = 3;
  26644. this._addIndex = 4;
  26645. this.cumulativeWeight = 0;
  26646. this.cumulativeWeightAdditive = 0;
  26647. this.useCount = 0;
  26648. this.referenceCount = 0;
  26649. }
  26650. Object.assign( PropertyMixer.prototype, {
  26651. // accumulate data in the 'incoming' region into 'accu<i>'
  26652. accumulate: function ( accuIndex, weight ) {
  26653. // note: happily accumulating nothing when weight = 0, the caller knows
  26654. // the weight and shouldn't have made the call in the first place
  26655. const buffer = this.buffer,
  26656. stride = this.valueSize,
  26657. offset = accuIndex * stride + stride;
  26658. let currentWeight = this.cumulativeWeight;
  26659. if ( currentWeight === 0 ) {
  26660. // accuN := incoming * weight
  26661. for ( let i = 0; i !== stride; ++ i ) {
  26662. buffer[ offset + i ] = buffer[ i ];
  26663. }
  26664. currentWeight = weight;
  26665. } else {
  26666. // accuN := accuN + incoming * weight
  26667. currentWeight += weight;
  26668. const mix = weight / currentWeight;
  26669. this._mixBufferRegion( buffer, offset, 0, mix, stride );
  26670. }
  26671. this.cumulativeWeight = currentWeight;
  26672. },
  26673. // accumulate data in the 'incoming' region into 'add'
  26674. accumulateAdditive: function ( weight ) {
  26675. const buffer = this.buffer,
  26676. stride = this.valueSize,
  26677. offset = stride * this._addIndex;
  26678. if ( this.cumulativeWeightAdditive === 0 ) {
  26679. // add = identity
  26680. this._setIdentity();
  26681. }
  26682. // add := add + incoming * weight
  26683. this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
  26684. this.cumulativeWeightAdditive += weight;
  26685. },
  26686. // apply the state of 'accu<i>' to the binding when accus differ
  26687. apply: function ( accuIndex ) {
  26688. const stride = this.valueSize,
  26689. buffer = this.buffer,
  26690. offset = accuIndex * stride + stride,
  26691. weight = this.cumulativeWeight,
  26692. weightAdditive = this.cumulativeWeightAdditive,
  26693. binding = this.binding;
  26694. this.cumulativeWeight = 0;
  26695. this.cumulativeWeightAdditive = 0;
  26696. if ( weight < 1 ) {
  26697. // accuN := accuN + original * ( 1 - cumulativeWeight )
  26698. const originalValueOffset = stride * this._origIndex;
  26699. this._mixBufferRegion(
  26700. buffer, offset, originalValueOffset, 1 - weight, stride );
  26701. }
  26702. if ( weightAdditive > 0 ) {
  26703. // accuN := accuN + additive accuN
  26704. this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
  26705. }
  26706. for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
  26707. if ( buffer[ i ] !== buffer[ i + stride ] ) {
  26708. // value has changed -> update scene graph
  26709. binding.setValue( buffer, offset );
  26710. break;
  26711. }
  26712. }
  26713. },
  26714. // remember the state of the bound property and copy it to both accus
  26715. saveOriginalState: function () {
  26716. const binding = this.binding;
  26717. const buffer = this.buffer,
  26718. stride = this.valueSize,
  26719. originalValueOffset = stride * this._origIndex;
  26720. binding.getValue( buffer, originalValueOffset );
  26721. // accu[0..1] := orig -- initially detect changes against the original
  26722. for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
  26723. buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
  26724. }
  26725. // Add to identity for additive
  26726. this._setIdentity();
  26727. this.cumulativeWeight = 0;
  26728. this.cumulativeWeightAdditive = 0;
  26729. },
  26730. // apply the state previously taken via 'saveOriginalState' to the binding
  26731. restoreOriginalState: function () {
  26732. const originalValueOffset = this.valueSize * 3;
  26733. this.binding.setValue( this.buffer, originalValueOffset );
  26734. },
  26735. _setAdditiveIdentityNumeric: function () {
  26736. const startIndex = this._addIndex * this.valueSize;
  26737. const endIndex = startIndex + this.valueSize;
  26738. for ( let i = startIndex; i < endIndex; i ++ ) {
  26739. this.buffer[ i ] = 0;
  26740. }
  26741. },
  26742. _setAdditiveIdentityQuaternion: function () {
  26743. this._setAdditiveIdentityNumeric();
  26744. this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
  26745. },
  26746. _setAdditiveIdentityOther: function () {
  26747. const startIndex = this._origIndex * this.valueSize;
  26748. const targetIndex = this._addIndex * this.valueSize;
  26749. for ( let i = 0; i < this.valueSize; i ++ ) {
  26750. this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
  26751. }
  26752. },
  26753. // mix functions
  26754. _select: function ( buffer, dstOffset, srcOffset, t, stride ) {
  26755. if ( t >= 0.5 ) {
  26756. for ( let i = 0; i !== stride; ++ i ) {
  26757. buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
  26758. }
  26759. }
  26760. },
  26761. _slerp: function ( buffer, dstOffset, srcOffset, t ) {
  26762. Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
  26763. },
  26764. _slerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
  26765. const workOffset = this._workIndex * stride;
  26766. // Store result in intermediate buffer offset
  26767. Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
  26768. // Slerp to the intermediate result
  26769. Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
  26770. },
  26771. _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {
  26772. const s = 1 - t;
  26773. for ( let i = 0; i !== stride; ++ i ) {
  26774. const j = dstOffset + i;
  26775. buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
  26776. }
  26777. },
  26778. _lerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
  26779. for ( let i = 0; i !== stride; ++ i ) {
  26780. const j = dstOffset + i;
  26781. buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
  26782. }
  26783. }
  26784. } );
  26785. // Characters [].:/ are reserved for track binding syntax.
  26786. const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
  26787. const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
  26788. // Attempts to allow node names from any language. ES5's `\w` regexp matches
  26789. // only latin characters, and the unicode \p{L} is not yet supported. So
  26790. // instead, we exclude reserved characters and match everything else.
  26791. const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
  26792. const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
  26793. // Parent directories, delimited by '/' or ':'. Currently unused, but must
  26794. // be matched to parse the rest of the track name.
  26795. const _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
  26796. // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
  26797. const _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
  26798. // Object on target node, and accessor. May not contain reserved
  26799. // characters. Accessor may contain any character except closing bracket.
  26800. const _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
  26801. // Property and accessor. May not contain reserved characters. Accessor may
  26802. // contain any non-bracket characters.
  26803. const _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
  26804. const _trackRe = new RegExp( ''
  26805. + '^'
  26806. + _directoryRe
  26807. + _nodeRe
  26808. + _objectRe
  26809. + _propertyRe
  26810. + '$'
  26811. );
  26812. const _supportedObjectNames = [ 'material', 'materials', 'bones' ];
  26813. function Composite( targetGroup, path, optionalParsedPath ) {
  26814. const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
  26815. this._targetGroup = targetGroup;
  26816. this._bindings = targetGroup.subscribe_( path, parsedPath );
  26817. }
  26818. Object.assign( Composite.prototype, {
  26819. getValue: function ( array, offset ) {
  26820. this.bind(); // bind all binding
  26821. const firstValidIndex = this._targetGroup.nCachedObjects_,
  26822. binding = this._bindings[ firstValidIndex ];
  26823. // and only call .getValue on the first
  26824. if ( binding !== undefined ) binding.getValue( array, offset );
  26825. },
  26826. setValue: function ( array, offset ) {
  26827. const bindings = this._bindings;
  26828. for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
  26829. bindings[ i ].setValue( array, offset );
  26830. }
  26831. },
  26832. bind: function () {
  26833. const bindings = this._bindings;
  26834. for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
  26835. bindings[ i ].bind();
  26836. }
  26837. },
  26838. unbind: function () {
  26839. const bindings = this._bindings;
  26840. for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
  26841. bindings[ i ].unbind();
  26842. }
  26843. }
  26844. } );
  26845. function PropertyBinding( rootNode, path, parsedPath ) {
  26846. this.path = path;
  26847. this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
  26848. this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
  26849. this.rootNode = rootNode;
  26850. }
  26851. Object.assign( PropertyBinding, {
  26852. Composite: Composite,
  26853. create: function ( root, path, parsedPath ) {
  26854. if ( ! ( root && root.isAnimationObjectGroup ) ) {
  26855. return new PropertyBinding( root, path, parsedPath );
  26856. } else {
  26857. return new PropertyBinding.Composite( root, path, parsedPath );
  26858. }
  26859. },
  26860. /**
  26861. * Replaces spaces with underscores and removes unsupported characters from
  26862. * node names, to ensure compatibility with parseTrackName().
  26863. *
  26864. * @param {string} name Node name to be sanitized.
  26865. * @return {string}
  26866. */
  26867. sanitizeNodeName: function ( name ) {
  26868. return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
  26869. },
  26870. parseTrackName: function ( trackName ) {
  26871. const matches = _trackRe.exec( trackName );
  26872. if ( ! matches ) {
  26873. throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
  26874. }
  26875. const results = {
  26876. // directoryName: matches[ 1 ], // (tschw) currently unused
  26877. nodeName: matches[ 2 ],
  26878. objectName: matches[ 3 ],
  26879. objectIndex: matches[ 4 ],
  26880. propertyName: matches[ 5 ], // required
  26881. propertyIndex: matches[ 6 ]
  26882. };
  26883. const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
  26884. if ( lastDot !== undefined && lastDot !== - 1 ) {
  26885. const objectName = results.nodeName.substring( lastDot + 1 );
  26886. // Object names must be checked against an allowlist. Otherwise, there
  26887. // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
  26888. // 'bar' could be the objectName, or part of a nodeName (which can
  26889. // include '.' characters).
  26890. if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
  26891. results.nodeName = results.nodeName.substring( 0, lastDot );
  26892. results.objectName = objectName;
  26893. }
  26894. }
  26895. if ( results.propertyName === null || results.propertyName.length === 0 ) {
  26896. throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
  26897. }
  26898. return results;
  26899. },
  26900. findNode: function ( root, nodeName ) {
  26901. if ( ! nodeName || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
  26902. return root;
  26903. }
  26904. // search into skeleton bones.
  26905. if ( root.skeleton ) {
  26906. const bone = root.skeleton.getBoneByName( nodeName );
  26907. if ( bone !== undefined ) {
  26908. return bone;
  26909. }
  26910. }
  26911. // search into node subtree.
  26912. if ( root.children ) {
  26913. const searchNodeSubtree = function ( children ) {
  26914. for ( let i = 0; i < children.length; i ++ ) {
  26915. const childNode = children[ i ];
  26916. if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
  26917. return childNode;
  26918. }
  26919. const result = searchNodeSubtree( childNode.children );
  26920. if ( result ) return result;
  26921. }
  26922. return null;
  26923. };
  26924. const subTreeNode = searchNodeSubtree( root.children );
  26925. if ( subTreeNode ) {
  26926. return subTreeNode;
  26927. }
  26928. }
  26929. return null;
  26930. }
  26931. } );
  26932. Object.assign( PropertyBinding.prototype, { // prototype, continued
  26933. // these are used to "bind" a nonexistent property
  26934. _getValue_unavailable: function () {},
  26935. _setValue_unavailable: function () {},
  26936. BindingType: {
  26937. Direct: 0,
  26938. EntireArray: 1,
  26939. ArrayElement: 2,
  26940. HasFromToArray: 3
  26941. },
  26942. Versioning: {
  26943. None: 0,
  26944. NeedsUpdate: 1,
  26945. MatrixWorldNeedsUpdate: 2
  26946. },
  26947. GetterByBindingType: [
  26948. function getValue_direct( buffer, offset ) {
  26949. buffer[ offset ] = this.node[ this.propertyName ];
  26950. },
  26951. function getValue_array( buffer, offset ) {
  26952. const source = this.resolvedProperty;
  26953. for ( let i = 0, n = source.length; i !== n; ++ i ) {
  26954. buffer[ offset ++ ] = source[ i ];
  26955. }
  26956. },
  26957. function getValue_arrayElement( buffer, offset ) {
  26958. buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
  26959. },
  26960. function getValue_toArray( buffer, offset ) {
  26961. this.resolvedProperty.toArray( buffer, offset );
  26962. }
  26963. ],
  26964. SetterByBindingTypeAndVersioning: [
  26965. [
  26966. // Direct
  26967. function setValue_direct( buffer, offset ) {
  26968. this.targetObject[ this.propertyName ] = buffer[ offset ];
  26969. },
  26970. function setValue_direct_setNeedsUpdate( buffer, offset ) {
  26971. this.targetObject[ this.propertyName ] = buffer[ offset ];
  26972. this.targetObject.needsUpdate = true;
  26973. },
  26974. function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
  26975. this.targetObject[ this.propertyName ] = buffer[ offset ];
  26976. this.targetObject.matrixWorldNeedsUpdate = true;
  26977. }
  26978. ], [
  26979. // EntireArray
  26980. function setValue_array( buffer, offset ) {
  26981. const dest = this.resolvedProperty;
  26982. for ( let i = 0, n = dest.length; i !== n; ++ i ) {
  26983. dest[ i ] = buffer[ offset ++ ];
  26984. }
  26985. },
  26986. function setValue_array_setNeedsUpdate( buffer, offset ) {
  26987. const dest = this.resolvedProperty;
  26988. for ( let i = 0, n = dest.length; i !== n; ++ i ) {
  26989. dest[ i ] = buffer[ offset ++ ];
  26990. }
  26991. this.targetObject.needsUpdate = true;
  26992. },
  26993. function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
  26994. const dest = this.resolvedProperty;
  26995. for ( let i = 0, n = dest.length; i !== n; ++ i ) {
  26996. dest[ i ] = buffer[ offset ++ ];
  26997. }
  26998. this.targetObject.matrixWorldNeedsUpdate = true;
  26999. }
  27000. ], [
  27001. // ArrayElement
  27002. function setValue_arrayElement( buffer, offset ) {
  27003. this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
  27004. },
  27005. function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
  27006. this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
  27007. this.targetObject.needsUpdate = true;
  27008. },
  27009. function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
  27010. this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
  27011. this.targetObject.matrixWorldNeedsUpdate = true;
  27012. }
  27013. ], [
  27014. // HasToFromArray
  27015. function setValue_fromArray( buffer, offset ) {
  27016. this.resolvedProperty.fromArray( buffer, offset );
  27017. },
  27018. function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
  27019. this.resolvedProperty.fromArray( buffer, offset );
  27020. this.targetObject.needsUpdate = true;
  27021. },
  27022. function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
  27023. this.resolvedProperty.fromArray( buffer, offset );
  27024. this.targetObject.matrixWorldNeedsUpdate = true;
  27025. }
  27026. ]
  27027. ],
  27028. getValue: function getValue_unbound( targetArray, offset ) {
  27029. this.bind();
  27030. this.getValue( targetArray, offset );
  27031. // Note: This class uses a State pattern on a per-method basis:
  27032. // 'bind' sets 'this.getValue' / 'setValue' and shadows the
  27033. // prototype version of these methods with one that represents
  27034. // the bound state. When the property is not found, the methods
  27035. // become no-ops.
  27036. },
  27037. setValue: function getValue_unbound( sourceArray, offset ) {
  27038. this.bind();
  27039. this.setValue( sourceArray, offset );
  27040. },
  27041. // create getter / setter pair for a property in the scene graph
  27042. bind: function () {
  27043. let targetObject = this.node;
  27044. const parsedPath = this.parsedPath;
  27045. const objectName = parsedPath.objectName;
  27046. const propertyName = parsedPath.propertyName;
  27047. let propertyIndex = parsedPath.propertyIndex;
  27048. if ( ! targetObject ) {
  27049. targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
  27050. this.node = targetObject;
  27051. }
  27052. // set fail state so we can just 'return' on error
  27053. this.getValue = this._getValue_unavailable;
  27054. this.setValue = this._setValue_unavailable;
  27055. // ensure there is a value node
  27056. if ( ! targetObject ) {
  27057. console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
  27058. return;
  27059. }
  27060. if ( objectName ) {
  27061. let objectIndex = parsedPath.objectIndex;
  27062. // special cases were we need to reach deeper into the hierarchy to get the face materials....
  27063. switch ( objectName ) {
  27064. case 'materials':
  27065. if ( ! targetObject.material ) {
  27066. console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
  27067. return;
  27068. }
  27069. if ( ! targetObject.material.materials ) {
  27070. console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
  27071. return;
  27072. }
  27073. targetObject = targetObject.material.materials;
  27074. break;
  27075. case 'bones':
  27076. if ( ! targetObject.skeleton ) {
  27077. console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
  27078. return;
  27079. }
  27080. // potential future optimization: skip this if propertyIndex is already an integer
  27081. // and convert the integer string to a true integer.
  27082. targetObject = targetObject.skeleton.bones;
  27083. // support resolving morphTarget names into indices.
  27084. for ( let i = 0; i < targetObject.length; i ++ ) {
  27085. if ( targetObject[ i ].name === objectIndex ) {
  27086. objectIndex = i;
  27087. break;
  27088. }
  27089. }
  27090. break;
  27091. default:
  27092. if ( targetObject[ objectName ] === undefined ) {
  27093. console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
  27094. return;
  27095. }
  27096. targetObject = targetObject[ objectName ];
  27097. }
  27098. if ( objectIndex !== undefined ) {
  27099. if ( targetObject[ objectIndex ] === undefined ) {
  27100. console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
  27101. return;
  27102. }
  27103. targetObject = targetObject[ objectIndex ];
  27104. }
  27105. }
  27106. // resolve property
  27107. const nodeProperty = targetObject[ propertyName ];
  27108. if ( nodeProperty === undefined ) {
  27109. const nodeName = parsedPath.nodeName;
  27110. console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
  27111. '.' + propertyName + ' but it wasn\'t found.', targetObject );
  27112. return;
  27113. }
  27114. // determine versioning scheme
  27115. let versioning = this.Versioning.None;
  27116. this.targetObject = targetObject;
  27117. if ( targetObject.needsUpdate !== undefined ) { // material
  27118. versioning = this.Versioning.NeedsUpdate;
  27119. } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
  27120. versioning = this.Versioning.MatrixWorldNeedsUpdate;
  27121. }
  27122. // determine how the property gets bound
  27123. let bindingType = this.BindingType.Direct;
  27124. if ( propertyIndex !== undefined ) {
  27125. // access a sub element of the property array (only primitives are supported right now)
  27126. if ( propertyName === 'morphTargetInfluences' ) {
  27127. // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
  27128. // support resolving morphTarget names into indices.
  27129. if ( ! targetObject.geometry ) {
  27130. console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
  27131. return;
  27132. }
  27133. if ( targetObject.geometry.isBufferGeometry ) {
  27134. if ( ! targetObject.geometry.morphAttributes ) {
  27135. console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
  27136. return;
  27137. }
  27138. if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
  27139. propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
  27140. }
  27141. } else {
  27142. console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this );
  27143. return;
  27144. }
  27145. }
  27146. bindingType = this.BindingType.ArrayElement;
  27147. this.resolvedProperty = nodeProperty;
  27148. this.propertyIndex = propertyIndex;
  27149. } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
  27150. // must use copy for Object3D.Euler/Quaternion
  27151. bindingType = this.BindingType.HasFromToArray;
  27152. this.resolvedProperty = nodeProperty;
  27153. } else if ( Array.isArray( nodeProperty ) ) {
  27154. bindingType = this.BindingType.EntireArray;
  27155. this.resolvedProperty = nodeProperty;
  27156. } else {
  27157. this.propertyName = propertyName;
  27158. }
  27159. // select getter / setter
  27160. this.getValue = this.GetterByBindingType[ bindingType ];
  27161. this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
  27162. },
  27163. unbind: function () {
  27164. this.node = null;
  27165. // back to the prototype version of getValue / setValue
  27166. // note: avoiding to mutate the shape of 'this' via 'delete'
  27167. this.getValue = this._getValue_unbound;
  27168. this.setValue = this._setValue_unbound;
  27169. }
  27170. } );
  27171. // DECLARE ALIAS AFTER assign prototype
  27172. Object.assign( PropertyBinding.prototype, {
  27173. // initial state of these methods that calls 'bind'
  27174. _getValue_unbound: PropertyBinding.prototype.getValue,
  27175. _setValue_unbound: PropertyBinding.prototype.setValue,
  27176. } );
  27177. /**
  27178. *
  27179. * A group of objects that receives a shared animation state.
  27180. *
  27181. * Usage:
  27182. *
  27183. * - Add objects you would otherwise pass as 'root' to the
  27184. * constructor or the .clipAction method of AnimationMixer.
  27185. *
  27186. * - Instead pass this object as 'root'.
  27187. *
  27188. * - You can also add and remove objects later when the mixer
  27189. * is running.
  27190. *
  27191. * Note:
  27192. *
  27193. * Objects of this class appear as one object to the mixer,
  27194. * so cache control of the individual objects must be done
  27195. * on the group.
  27196. *
  27197. * Limitation:
  27198. *
  27199. * - The animated properties must be compatible among the
  27200. * all objects in the group.
  27201. *
  27202. * - A single property can either be controlled through a
  27203. * target group or directly, but not both.
  27204. */
  27205. function AnimationObjectGroup() {
  27206. this.uuid = MathUtils.generateUUID();
  27207. // cached objects followed by the active ones
  27208. this._objects = Array.prototype.slice.call( arguments );
  27209. this.nCachedObjects_ = 0; // threshold
  27210. // note: read by PropertyBinding.Composite
  27211. const indices = {};
  27212. this._indicesByUUID = indices; // for bookkeeping
  27213. for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
  27214. indices[ arguments[ i ].uuid ] = i;
  27215. }
  27216. this._paths = []; // inside: string
  27217. this._parsedPaths = []; // inside: { we don't care, here }
  27218. this._bindings = []; // inside: Array< PropertyBinding >
  27219. this._bindingsIndicesByPath = {}; // inside: indices in these arrays
  27220. const scope = this;
  27221. this.stats = {
  27222. objects: {
  27223. get total() {
  27224. return scope._objects.length;
  27225. },
  27226. get inUse() {
  27227. return this.total - scope.nCachedObjects_;
  27228. }
  27229. },
  27230. get bindingsPerObject() {
  27231. return scope._bindings.length;
  27232. }
  27233. };
  27234. }
  27235. Object.assign( AnimationObjectGroup.prototype, {
  27236. isAnimationObjectGroup: true,
  27237. add: function () {
  27238. const objects = this._objects,
  27239. indicesByUUID = this._indicesByUUID,
  27240. paths = this._paths,
  27241. parsedPaths = this._parsedPaths,
  27242. bindings = this._bindings,
  27243. nBindings = bindings.length;
  27244. let knownObject = undefined,
  27245. nObjects = objects.length,
  27246. nCachedObjects = this.nCachedObjects_;
  27247. for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
  27248. const object = arguments[ i ],
  27249. uuid = object.uuid;
  27250. let index = indicesByUUID[ uuid ];
  27251. if ( index === undefined ) {
  27252. // unknown object -> add it to the ACTIVE region
  27253. index = nObjects ++;
  27254. indicesByUUID[ uuid ] = index;
  27255. objects.push( object );
  27256. // accounting is done, now do the same for all bindings
  27257. for ( let j = 0, m = nBindings; j !== m; ++ j ) {
  27258. bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
  27259. }
  27260. } else if ( index < nCachedObjects ) {
  27261. knownObject = objects[ index ];
  27262. // move existing object to the ACTIVE region
  27263. const firstActiveIndex = -- nCachedObjects,
  27264. lastCachedObject = objects[ firstActiveIndex ];
  27265. indicesByUUID[ lastCachedObject.uuid ] = index;
  27266. objects[ index ] = lastCachedObject;
  27267. indicesByUUID[ uuid ] = firstActiveIndex;
  27268. objects[ firstActiveIndex ] = object;
  27269. // accounting is done, now do the same for all bindings
  27270. for ( let j = 0, m = nBindings; j !== m; ++ j ) {
  27271. const bindingsForPath = bindings[ j ],
  27272. lastCached = bindingsForPath[ firstActiveIndex ];
  27273. let binding = bindingsForPath[ index ];
  27274. bindingsForPath[ index ] = lastCached;
  27275. if ( binding === undefined ) {
  27276. // since we do not bother to create new bindings
  27277. // for objects that are cached, the binding may
  27278. // or may not exist
  27279. binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
  27280. }
  27281. bindingsForPath[ firstActiveIndex ] = binding;
  27282. }
  27283. } else if ( objects[ index ] !== knownObject ) {
  27284. console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
  27285. 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
  27286. } // else the object is already where we want it to be
  27287. } // for arguments
  27288. this.nCachedObjects_ = nCachedObjects;
  27289. },
  27290. remove: function () {
  27291. const objects = this._objects,
  27292. indicesByUUID = this._indicesByUUID,
  27293. bindings = this._bindings,
  27294. nBindings = bindings.length;
  27295. let nCachedObjects = this.nCachedObjects_;
  27296. for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
  27297. const object = arguments[ i ],
  27298. uuid = object.uuid,
  27299. index = indicesByUUID[ uuid ];
  27300. if ( index !== undefined && index >= nCachedObjects ) {
  27301. // move existing object into the CACHED region
  27302. const lastCachedIndex = nCachedObjects ++,
  27303. firstActiveObject = objects[ lastCachedIndex ];
  27304. indicesByUUID[ firstActiveObject.uuid ] = index;
  27305. objects[ index ] = firstActiveObject;
  27306. indicesByUUID[ uuid ] = lastCachedIndex;
  27307. objects[ lastCachedIndex ] = object;
  27308. // accounting is done, now do the same for all bindings
  27309. for ( let j = 0, m = nBindings; j !== m; ++ j ) {
  27310. const bindingsForPath = bindings[ j ],
  27311. firstActive = bindingsForPath[ lastCachedIndex ],
  27312. binding = bindingsForPath[ index ];
  27313. bindingsForPath[ index ] = firstActive;
  27314. bindingsForPath[ lastCachedIndex ] = binding;
  27315. }
  27316. }
  27317. } // for arguments
  27318. this.nCachedObjects_ = nCachedObjects;
  27319. },
  27320. // remove & forget
  27321. uncache: function () {
  27322. const objects = this._objects,
  27323. indicesByUUID = this._indicesByUUID,
  27324. bindings = this._bindings,
  27325. nBindings = bindings.length;
  27326. let nCachedObjects = this.nCachedObjects_,
  27327. nObjects = objects.length;
  27328. for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
  27329. const object = arguments[ i ],
  27330. uuid = object.uuid,
  27331. index = indicesByUUID[ uuid ];
  27332. if ( index !== undefined ) {
  27333. delete indicesByUUID[ uuid ];
  27334. if ( index < nCachedObjects ) {
  27335. // object is cached, shrink the CACHED region
  27336. const firstActiveIndex = -- nCachedObjects,
  27337. lastCachedObject = objects[ firstActiveIndex ],
  27338. lastIndex = -- nObjects,
  27339. lastObject = objects[ lastIndex ];
  27340. // last cached object takes this object's place
  27341. indicesByUUID[ lastCachedObject.uuid ] = index;
  27342. objects[ index ] = lastCachedObject;
  27343. // last object goes to the activated slot and pop
  27344. indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
  27345. objects[ firstActiveIndex ] = lastObject;
  27346. objects.pop();
  27347. // accounting is done, now do the same for all bindings
  27348. for ( let j = 0, m = nBindings; j !== m; ++ j ) {
  27349. const bindingsForPath = bindings[ j ],
  27350. lastCached = bindingsForPath[ firstActiveIndex ],
  27351. last = bindingsForPath[ lastIndex ];
  27352. bindingsForPath[ index ] = lastCached;
  27353. bindingsForPath[ firstActiveIndex ] = last;
  27354. bindingsForPath.pop();
  27355. }
  27356. } else {
  27357. // object is active, just swap with the last and pop
  27358. const lastIndex = -- nObjects,
  27359. lastObject = objects[ lastIndex ];
  27360. if ( lastIndex > 0 ) {
  27361. indicesByUUID[ lastObject.uuid ] = index;
  27362. }
  27363. objects[ index ] = lastObject;
  27364. objects.pop();
  27365. // accounting is done, now do the same for all bindings
  27366. for ( let j = 0, m = nBindings; j !== m; ++ j ) {
  27367. const bindingsForPath = bindings[ j ];
  27368. bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
  27369. bindingsForPath.pop();
  27370. }
  27371. } // cached or active
  27372. } // if object is known
  27373. } // for arguments
  27374. this.nCachedObjects_ = nCachedObjects;
  27375. },
  27376. // Internal interface used by befriended PropertyBinding.Composite:
  27377. subscribe_: function ( path, parsedPath ) {
  27378. // returns an array of bindings for the given path that is changed
  27379. // according to the contained objects in the group
  27380. const indicesByPath = this._bindingsIndicesByPath;
  27381. let index = indicesByPath[ path ];
  27382. const bindings = this._bindings;
  27383. if ( index !== undefined ) return bindings[ index ];
  27384. const paths = this._paths,
  27385. parsedPaths = this._parsedPaths,
  27386. objects = this._objects,
  27387. nObjects = objects.length,
  27388. nCachedObjects = this.nCachedObjects_,
  27389. bindingsForPath = new Array( nObjects );
  27390. index = bindings.length;
  27391. indicesByPath[ path ] = index;
  27392. paths.push( path );
  27393. parsedPaths.push( parsedPath );
  27394. bindings.push( bindingsForPath );
  27395. for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
  27396. const object = objects[ i ];
  27397. bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
  27398. }
  27399. return bindingsForPath;
  27400. },
  27401. unsubscribe_: function ( path ) {
  27402. // tells the group to forget about a property path and no longer
  27403. // update the array previously obtained with 'subscribe_'
  27404. const indicesByPath = this._bindingsIndicesByPath,
  27405. index = indicesByPath[ path ];
  27406. if ( index !== undefined ) {
  27407. const paths = this._paths,
  27408. parsedPaths = this._parsedPaths,
  27409. bindings = this._bindings,
  27410. lastBindingsIndex = bindings.length - 1,
  27411. lastBindings = bindings[ lastBindingsIndex ],
  27412. lastBindingsPath = path[ lastBindingsIndex ];
  27413. indicesByPath[ lastBindingsPath ] = index;
  27414. bindings[ index ] = lastBindings;
  27415. bindings.pop();
  27416. parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
  27417. parsedPaths.pop();
  27418. paths[ index ] = paths[ lastBindingsIndex ];
  27419. paths.pop();
  27420. }
  27421. }
  27422. } );
  27423. class AnimationAction {
  27424. constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
  27425. this._mixer = mixer;
  27426. this._clip = clip;
  27427. this._localRoot = localRoot;
  27428. this.blendMode = blendMode;
  27429. const tracks = clip.tracks,
  27430. nTracks = tracks.length,
  27431. interpolants = new Array( nTracks );
  27432. const interpolantSettings = {
  27433. endingStart: ZeroCurvatureEnding,
  27434. endingEnd: ZeroCurvatureEnding
  27435. };
  27436. for ( let i = 0; i !== nTracks; ++ i ) {
  27437. const interpolant = tracks[ i ].createInterpolant( null );
  27438. interpolants[ i ] = interpolant;
  27439. interpolant.settings = interpolantSettings;
  27440. }
  27441. this._interpolantSettings = interpolantSettings;
  27442. this._interpolants = interpolants; // bound by the mixer
  27443. // inside: PropertyMixer (managed by the mixer)
  27444. this._propertyBindings = new Array( nTracks );
  27445. this._cacheIndex = null; // for the memory manager
  27446. this._byClipCacheIndex = null; // for the memory manager
  27447. this._timeScaleInterpolant = null;
  27448. this._weightInterpolant = null;
  27449. this.loop = LoopRepeat;
  27450. this._loopCount = - 1;
  27451. // global mixer time when the action is to be started
  27452. // it's set back to 'null' upon start of the action
  27453. this._startTime = null;
  27454. // scaled local time of the action
  27455. // gets clamped or wrapped to 0..clip.duration according to loop
  27456. this.time = 0;
  27457. this.timeScale = 1;
  27458. this._effectiveTimeScale = 1;
  27459. this.weight = 1;
  27460. this._effectiveWeight = 1;
  27461. this.repetitions = Infinity; // no. of repetitions when looping
  27462. this.paused = false; // true -> zero effective time scale
  27463. this.enabled = true; // false -> zero effective weight
  27464. this.clampWhenFinished = false;// keep feeding the last frame?
  27465. this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
  27466. this.zeroSlopeAtEnd = true;// clips for start, loop and end
  27467. }
  27468. // State & Scheduling
  27469. play() {
  27470. this._mixer._activateAction( this );
  27471. return this;
  27472. }
  27473. stop() {
  27474. this._mixer._deactivateAction( this );
  27475. return this.reset();
  27476. }
  27477. reset() {
  27478. this.paused = false;
  27479. this.enabled = true;
  27480. this.time = 0; // restart clip
  27481. this._loopCount = - 1;// forget previous loops
  27482. this._startTime = null;// forget scheduling
  27483. return this.stopFading().stopWarping();
  27484. }
  27485. isRunning() {
  27486. return this.enabled && ! this.paused && this.timeScale !== 0 &&
  27487. this._startTime === null && this._mixer._isActiveAction( this );
  27488. }
  27489. // return true when play has been called
  27490. isScheduled() {
  27491. return this._mixer._isActiveAction( this );
  27492. }
  27493. startAt( time ) {
  27494. this._startTime = time;
  27495. return this;
  27496. }
  27497. setLoop( mode, repetitions ) {
  27498. this.loop = mode;
  27499. this.repetitions = repetitions;
  27500. return this;
  27501. }
  27502. // Weight
  27503. // set the weight stopping any scheduled fading
  27504. // although .enabled = false yields an effective weight of zero, this
  27505. // method does *not* change .enabled, because it would be confusing
  27506. setEffectiveWeight( weight ) {
  27507. this.weight = weight;
  27508. // note: same logic as when updated at runtime
  27509. this._effectiveWeight = this.enabled ? weight : 0;
  27510. return this.stopFading();
  27511. }
  27512. // return the weight considering fading and .enabled
  27513. getEffectiveWeight() {
  27514. return this._effectiveWeight;
  27515. }
  27516. fadeIn( duration ) {
  27517. return this._scheduleFading( duration, 0, 1 );
  27518. }
  27519. fadeOut( duration ) {
  27520. return this._scheduleFading( duration, 1, 0 );
  27521. }
  27522. crossFadeFrom( fadeOutAction, duration, warp ) {
  27523. fadeOutAction.fadeOut( duration );
  27524. this.fadeIn( duration );
  27525. if ( warp ) {
  27526. const fadeInDuration = this._clip.duration,
  27527. fadeOutDuration = fadeOutAction._clip.duration,
  27528. startEndRatio = fadeOutDuration / fadeInDuration,
  27529. endStartRatio = fadeInDuration / fadeOutDuration;
  27530. fadeOutAction.warp( 1.0, startEndRatio, duration );
  27531. this.warp( endStartRatio, 1.0, duration );
  27532. }
  27533. return this;
  27534. }
  27535. crossFadeTo( fadeInAction, duration, warp ) {
  27536. return fadeInAction.crossFadeFrom( this, duration, warp );
  27537. }
  27538. stopFading() {
  27539. const weightInterpolant = this._weightInterpolant;
  27540. if ( weightInterpolant !== null ) {
  27541. this._weightInterpolant = null;
  27542. this._mixer._takeBackControlInterpolant( weightInterpolant );
  27543. }
  27544. return this;
  27545. }
  27546. // Time Scale Control
  27547. // set the time scale stopping any scheduled warping
  27548. // although .paused = true yields an effective time scale of zero, this
  27549. // method does *not* change .paused, because it would be confusing
  27550. setEffectiveTimeScale( timeScale ) {
  27551. this.timeScale = timeScale;
  27552. this._effectiveTimeScale = this.paused ? 0 : timeScale;
  27553. return this.stopWarping();
  27554. }
  27555. // return the time scale considering warping and .paused
  27556. getEffectiveTimeScale() {
  27557. return this._effectiveTimeScale;
  27558. }
  27559. setDuration( duration ) {
  27560. this.timeScale = this._clip.duration / duration;
  27561. return this.stopWarping();
  27562. }
  27563. syncWith( action ) {
  27564. this.time = action.time;
  27565. this.timeScale = action.timeScale;
  27566. return this.stopWarping();
  27567. }
  27568. halt( duration ) {
  27569. return this.warp( this._effectiveTimeScale, 0, duration );
  27570. }
  27571. warp( startTimeScale, endTimeScale, duration ) {
  27572. const mixer = this._mixer,
  27573. now = mixer.time,
  27574. timeScale = this.timeScale;
  27575. let interpolant = this._timeScaleInterpolant;
  27576. if ( interpolant === null ) {
  27577. interpolant = mixer._lendControlInterpolant();
  27578. this._timeScaleInterpolant = interpolant;
  27579. }
  27580. const times = interpolant.parameterPositions,
  27581. values = interpolant.sampleValues;
  27582. times[ 0 ] = now;
  27583. times[ 1 ] = now + duration;
  27584. values[ 0 ] = startTimeScale / timeScale;
  27585. values[ 1 ] = endTimeScale / timeScale;
  27586. return this;
  27587. }
  27588. stopWarping() {
  27589. const timeScaleInterpolant = this._timeScaleInterpolant;
  27590. if ( timeScaleInterpolant !== null ) {
  27591. this._timeScaleInterpolant = null;
  27592. this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
  27593. }
  27594. return this;
  27595. }
  27596. // Object Accessors
  27597. getMixer() {
  27598. return this._mixer;
  27599. }
  27600. getClip() {
  27601. return this._clip;
  27602. }
  27603. getRoot() {
  27604. return this._localRoot || this._mixer._root;
  27605. }
  27606. // Interna
  27607. _update( time, deltaTime, timeDirection, accuIndex ) {
  27608. // called by the mixer
  27609. if ( ! this.enabled ) {
  27610. // call ._updateWeight() to update ._effectiveWeight
  27611. this._updateWeight( time );
  27612. return;
  27613. }
  27614. const startTime = this._startTime;
  27615. if ( startTime !== null ) {
  27616. // check for scheduled start of action
  27617. const timeRunning = ( time - startTime ) * timeDirection;
  27618. if ( timeRunning < 0 || timeDirection === 0 ) {
  27619. return; // yet to come / don't decide when delta = 0
  27620. }
  27621. // start
  27622. this._startTime = null; // unschedule
  27623. deltaTime = timeDirection * timeRunning;
  27624. }
  27625. // apply time scale and advance time
  27626. deltaTime *= this._updateTimeScale( time );
  27627. const clipTime = this._updateTime( deltaTime );
  27628. // note: _updateTime may disable the action resulting in
  27629. // an effective weight of 0
  27630. const weight = this._updateWeight( time );
  27631. if ( weight > 0 ) {
  27632. const interpolants = this._interpolants;
  27633. const propertyMixers = this._propertyBindings;
  27634. switch ( this.blendMode ) {
  27635. case AdditiveAnimationBlendMode:
  27636. for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
  27637. interpolants[ j ].evaluate( clipTime );
  27638. propertyMixers[ j ].accumulateAdditive( weight );
  27639. }
  27640. break;
  27641. case NormalAnimationBlendMode:
  27642. default:
  27643. for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
  27644. interpolants[ j ].evaluate( clipTime );
  27645. propertyMixers[ j ].accumulate( accuIndex, weight );
  27646. }
  27647. }
  27648. }
  27649. }
  27650. _updateWeight( time ) {
  27651. let weight = 0;
  27652. if ( this.enabled ) {
  27653. weight = this.weight;
  27654. const interpolant = this._weightInterpolant;
  27655. if ( interpolant !== null ) {
  27656. const interpolantValue = interpolant.evaluate( time )[ 0 ];
  27657. weight *= interpolantValue;
  27658. if ( time > interpolant.parameterPositions[ 1 ] ) {
  27659. this.stopFading();
  27660. if ( interpolantValue === 0 ) {
  27661. // faded out, disable
  27662. this.enabled = false;
  27663. }
  27664. }
  27665. }
  27666. }
  27667. this._effectiveWeight = weight;
  27668. return weight;
  27669. }
  27670. _updateTimeScale( time ) {
  27671. let timeScale = 0;
  27672. if ( ! this.paused ) {
  27673. timeScale = this.timeScale;
  27674. const interpolant = this._timeScaleInterpolant;
  27675. if ( interpolant !== null ) {
  27676. const interpolantValue = interpolant.evaluate( time )[ 0 ];
  27677. timeScale *= interpolantValue;
  27678. if ( time > interpolant.parameterPositions[ 1 ] ) {
  27679. this.stopWarping();
  27680. if ( timeScale === 0 ) {
  27681. // motion has halted, pause
  27682. this.paused = true;
  27683. } else {
  27684. // warp done - apply final time scale
  27685. this.timeScale = timeScale;
  27686. }
  27687. }
  27688. }
  27689. }
  27690. this._effectiveTimeScale = timeScale;
  27691. return timeScale;
  27692. }
  27693. _updateTime( deltaTime ) {
  27694. const duration = this._clip.duration;
  27695. const loop = this.loop;
  27696. let time = this.time + deltaTime;
  27697. let loopCount = this._loopCount;
  27698. const pingPong = ( loop === LoopPingPong );
  27699. if ( deltaTime === 0 ) {
  27700. if ( loopCount === - 1 ) return time;
  27701. return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
  27702. }
  27703. if ( loop === LoopOnce ) {
  27704. if ( loopCount === - 1 ) {
  27705. // just started
  27706. this._loopCount = 0;
  27707. this._setEndings( true, true, false );
  27708. }
  27709. handle_stop: {
  27710. if ( time >= duration ) {
  27711. time = duration;
  27712. } else if ( time < 0 ) {
  27713. time = 0;
  27714. } else {
  27715. this.time = time;
  27716. break handle_stop;
  27717. }
  27718. if ( this.clampWhenFinished ) this.paused = true;
  27719. else this.enabled = false;
  27720. this.time = time;
  27721. this._mixer.dispatchEvent( {
  27722. type: 'finished', action: this,
  27723. direction: deltaTime < 0 ? - 1 : 1
  27724. } );
  27725. }
  27726. } else { // repetitive Repeat or PingPong
  27727. if ( loopCount === - 1 ) {
  27728. // just started
  27729. if ( deltaTime >= 0 ) {
  27730. loopCount = 0;
  27731. this._setEndings( true, this.repetitions === 0, pingPong );
  27732. } else {
  27733. // when looping in reverse direction, the initial
  27734. // transition through zero counts as a repetition,
  27735. // so leave loopCount at -1
  27736. this._setEndings( this.repetitions === 0, true, pingPong );
  27737. }
  27738. }
  27739. if ( time >= duration || time < 0 ) {
  27740. // wrap around
  27741. const loopDelta = Math.floor( time / duration ); // signed
  27742. time -= duration * loopDelta;
  27743. loopCount += Math.abs( loopDelta );
  27744. const pending = this.repetitions - loopCount;
  27745. if ( pending <= 0 ) {
  27746. // have to stop (switch state, clamp time, fire event)
  27747. if ( this.clampWhenFinished ) this.paused = true;
  27748. else this.enabled = false;
  27749. time = deltaTime > 0 ? duration : 0;
  27750. this.time = time;
  27751. this._mixer.dispatchEvent( {
  27752. type: 'finished', action: this,
  27753. direction: deltaTime > 0 ? 1 : - 1
  27754. } );
  27755. } else {
  27756. // keep running
  27757. if ( pending === 1 ) {
  27758. // entering the last round
  27759. const atStart = deltaTime < 0;
  27760. this._setEndings( atStart, ! atStart, pingPong );
  27761. } else {
  27762. this._setEndings( false, false, pingPong );
  27763. }
  27764. this._loopCount = loopCount;
  27765. this.time = time;
  27766. this._mixer.dispatchEvent( {
  27767. type: 'loop', action: this, loopDelta: loopDelta
  27768. } );
  27769. }
  27770. } else {
  27771. this.time = time;
  27772. }
  27773. if ( pingPong && ( loopCount & 1 ) === 1 ) {
  27774. // invert time for the "pong round"
  27775. return duration - time;
  27776. }
  27777. }
  27778. return time;
  27779. }
  27780. _setEndings( atStart, atEnd, pingPong ) {
  27781. const settings = this._interpolantSettings;
  27782. if ( pingPong ) {
  27783. settings.endingStart = ZeroSlopeEnding;
  27784. settings.endingEnd = ZeroSlopeEnding;
  27785. } else {
  27786. // assuming for LoopOnce atStart == atEnd == true
  27787. if ( atStart ) {
  27788. settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
  27789. } else {
  27790. settings.endingStart = WrapAroundEnding;
  27791. }
  27792. if ( atEnd ) {
  27793. settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
  27794. } else {
  27795. settings.endingEnd = WrapAroundEnding;
  27796. }
  27797. }
  27798. }
  27799. _scheduleFading( duration, weightNow, weightThen ) {
  27800. const mixer = this._mixer, now = mixer.time;
  27801. let interpolant = this._weightInterpolant;
  27802. if ( interpolant === null ) {
  27803. interpolant = mixer._lendControlInterpolant();
  27804. this._weightInterpolant = interpolant;
  27805. }
  27806. const times = interpolant.parameterPositions,
  27807. values = interpolant.sampleValues;
  27808. times[ 0 ] = now;
  27809. values[ 0 ] = weightNow;
  27810. times[ 1 ] = now + duration;
  27811. values[ 1 ] = weightThen;
  27812. return this;
  27813. }
  27814. }
  27815. function AnimationMixer( root ) {
  27816. this._root = root;
  27817. this._initMemoryManager();
  27818. this._accuIndex = 0;
  27819. this.time = 0;
  27820. this.timeScale = 1.0;
  27821. }
  27822. AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  27823. constructor: AnimationMixer,
  27824. _bindAction: function ( action, prototypeAction ) {
  27825. const root = action._localRoot || this._root,
  27826. tracks = action._clip.tracks,
  27827. nTracks = tracks.length,
  27828. bindings = action._propertyBindings,
  27829. interpolants = action._interpolants,
  27830. rootUuid = root.uuid,
  27831. bindingsByRoot = this._bindingsByRootAndName;
  27832. let bindingsByName = bindingsByRoot[ rootUuid ];
  27833. if ( bindingsByName === undefined ) {
  27834. bindingsByName = {};
  27835. bindingsByRoot[ rootUuid ] = bindingsByName;
  27836. }
  27837. for ( let i = 0; i !== nTracks; ++ i ) {
  27838. const track = tracks[ i ],
  27839. trackName = track.name;
  27840. let binding = bindingsByName[ trackName ];
  27841. if ( binding !== undefined ) {
  27842. bindings[ i ] = binding;
  27843. } else {
  27844. binding = bindings[ i ];
  27845. if ( binding !== undefined ) {
  27846. // existing binding, make sure the cache knows
  27847. if ( binding._cacheIndex === null ) {
  27848. ++ binding.referenceCount;
  27849. this._addInactiveBinding( binding, rootUuid, trackName );
  27850. }
  27851. continue;
  27852. }
  27853. const path = prototypeAction && prototypeAction.
  27854. _propertyBindings[ i ].binding.parsedPath;
  27855. binding = new PropertyMixer(
  27856. PropertyBinding.create( root, trackName, path ),
  27857. track.ValueTypeName, track.getValueSize() );
  27858. ++ binding.referenceCount;
  27859. this._addInactiveBinding( binding, rootUuid, trackName );
  27860. bindings[ i ] = binding;
  27861. }
  27862. interpolants[ i ].resultBuffer = binding.buffer;
  27863. }
  27864. },
  27865. _activateAction: function ( action ) {
  27866. if ( ! this._isActiveAction( action ) ) {
  27867. if ( action._cacheIndex === null ) {
  27868. // this action has been forgotten by the cache, but the user
  27869. // appears to be still using it -> rebind
  27870. const rootUuid = ( action._localRoot || this._root ).uuid,
  27871. clipUuid = action._clip.uuid,
  27872. actionsForClip = this._actionsByClip[ clipUuid ];
  27873. this._bindAction( action,
  27874. actionsForClip && actionsForClip.knownActions[ 0 ] );
  27875. this._addInactiveAction( action, clipUuid, rootUuid );
  27876. }
  27877. const bindings = action._propertyBindings;
  27878. // increment reference counts / sort out state
  27879. for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
  27880. const binding = bindings[ i ];
  27881. if ( binding.useCount ++ === 0 ) {
  27882. this._lendBinding( binding );
  27883. binding.saveOriginalState();
  27884. }
  27885. }
  27886. this._lendAction( action );
  27887. }
  27888. },
  27889. _deactivateAction: function ( action ) {
  27890. if ( this._isActiveAction( action ) ) {
  27891. const bindings = action._propertyBindings;
  27892. // decrement reference counts / sort out state
  27893. for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
  27894. const binding = bindings[ i ];
  27895. if ( -- binding.useCount === 0 ) {
  27896. binding.restoreOriginalState();
  27897. this._takeBackBinding( binding );
  27898. }
  27899. }
  27900. this._takeBackAction( action );
  27901. }
  27902. },
  27903. // Memory manager
  27904. _initMemoryManager: function () {
  27905. this._actions = []; // 'nActiveActions' followed by inactive ones
  27906. this._nActiveActions = 0;
  27907. this._actionsByClip = {};
  27908. // inside:
  27909. // {
  27910. // knownActions: Array< AnimationAction > - used as prototypes
  27911. // actionByRoot: AnimationAction - lookup
  27912. // }
  27913. this._bindings = []; // 'nActiveBindings' followed by inactive ones
  27914. this._nActiveBindings = 0;
  27915. this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
  27916. this._controlInterpolants = []; // same game as above
  27917. this._nActiveControlInterpolants = 0;
  27918. const scope = this;
  27919. this.stats = {
  27920. actions: {
  27921. get total() {
  27922. return scope._actions.length;
  27923. },
  27924. get inUse() {
  27925. return scope._nActiveActions;
  27926. }
  27927. },
  27928. bindings: {
  27929. get total() {
  27930. return scope._bindings.length;
  27931. },
  27932. get inUse() {
  27933. return scope._nActiveBindings;
  27934. }
  27935. },
  27936. controlInterpolants: {
  27937. get total() {
  27938. return scope._controlInterpolants.length;
  27939. },
  27940. get inUse() {
  27941. return scope._nActiveControlInterpolants;
  27942. }
  27943. }
  27944. };
  27945. },
  27946. // Memory management for AnimationAction objects
  27947. _isActiveAction: function ( action ) {
  27948. const index = action._cacheIndex;
  27949. return index !== null && index < this._nActiveActions;
  27950. },
  27951. _addInactiveAction: function ( action, clipUuid, rootUuid ) {
  27952. const actions = this._actions,
  27953. actionsByClip = this._actionsByClip;
  27954. let actionsForClip = actionsByClip[ clipUuid ];
  27955. if ( actionsForClip === undefined ) {
  27956. actionsForClip = {
  27957. knownActions: [ action ],
  27958. actionByRoot: {}
  27959. };
  27960. action._byClipCacheIndex = 0;
  27961. actionsByClip[ clipUuid ] = actionsForClip;
  27962. } else {
  27963. const knownActions = actionsForClip.knownActions;
  27964. action._byClipCacheIndex = knownActions.length;
  27965. knownActions.push( action );
  27966. }
  27967. action._cacheIndex = actions.length;
  27968. actions.push( action );
  27969. actionsForClip.actionByRoot[ rootUuid ] = action;
  27970. },
  27971. _removeInactiveAction: function ( action ) {
  27972. const actions = this._actions,
  27973. lastInactiveAction = actions[ actions.length - 1 ],
  27974. cacheIndex = action._cacheIndex;
  27975. lastInactiveAction._cacheIndex = cacheIndex;
  27976. actions[ cacheIndex ] = lastInactiveAction;
  27977. actions.pop();
  27978. action._cacheIndex = null;
  27979. const clipUuid = action._clip.uuid,
  27980. actionsByClip = this._actionsByClip,
  27981. actionsForClip = actionsByClip[ clipUuid ],
  27982. knownActionsForClip = actionsForClip.knownActions,
  27983. lastKnownAction =
  27984. knownActionsForClip[ knownActionsForClip.length - 1 ],
  27985. byClipCacheIndex = action._byClipCacheIndex;
  27986. lastKnownAction._byClipCacheIndex = byClipCacheIndex;
  27987. knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
  27988. knownActionsForClip.pop();
  27989. action._byClipCacheIndex = null;
  27990. const actionByRoot = actionsForClip.actionByRoot,
  27991. rootUuid = ( action._localRoot || this._root ).uuid;
  27992. delete actionByRoot[ rootUuid ];
  27993. if ( knownActionsForClip.length === 0 ) {
  27994. delete actionsByClip[ clipUuid ];
  27995. }
  27996. this._removeInactiveBindingsForAction( action );
  27997. },
  27998. _removeInactiveBindingsForAction: function ( action ) {
  27999. const bindings = action._propertyBindings;
  28000. for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
  28001. const binding = bindings[ i ];
  28002. if ( -- binding.referenceCount === 0 ) {
  28003. this._removeInactiveBinding( binding );
  28004. }
  28005. }
  28006. },
  28007. _lendAction: function ( action ) {
  28008. // [ active actions | inactive actions ]
  28009. // [ active actions >| inactive actions ]
  28010. // s a
  28011. // <-swap->
  28012. // a s
  28013. const actions = this._actions,
  28014. prevIndex = action._cacheIndex,
  28015. lastActiveIndex = this._nActiveActions ++,
  28016. firstInactiveAction = actions[ lastActiveIndex ];
  28017. action._cacheIndex = lastActiveIndex;
  28018. actions[ lastActiveIndex ] = action;
  28019. firstInactiveAction._cacheIndex = prevIndex;
  28020. actions[ prevIndex ] = firstInactiveAction;
  28021. },
  28022. _takeBackAction: function ( action ) {
  28023. // [ active actions | inactive actions ]
  28024. // [ active actions |< inactive actions ]
  28025. // a s
  28026. // <-swap->
  28027. // s a
  28028. const actions = this._actions,
  28029. prevIndex = action._cacheIndex,
  28030. firstInactiveIndex = -- this._nActiveActions,
  28031. lastActiveAction = actions[ firstInactiveIndex ];
  28032. action._cacheIndex = firstInactiveIndex;
  28033. actions[ firstInactiveIndex ] = action;
  28034. lastActiveAction._cacheIndex = prevIndex;
  28035. actions[ prevIndex ] = lastActiveAction;
  28036. },
  28037. // Memory management for PropertyMixer objects
  28038. _addInactiveBinding: function ( binding, rootUuid, trackName ) {
  28039. const bindingsByRoot = this._bindingsByRootAndName,
  28040. bindings = this._bindings;
  28041. let bindingByName = bindingsByRoot[ rootUuid ];
  28042. if ( bindingByName === undefined ) {
  28043. bindingByName = {};
  28044. bindingsByRoot[ rootUuid ] = bindingByName;
  28045. }
  28046. bindingByName[ trackName ] = binding;
  28047. binding._cacheIndex = bindings.length;
  28048. bindings.push( binding );
  28049. },
  28050. _removeInactiveBinding: function ( binding ) {
  28051. const bindings = this._bindings,
  28052. propBinding = binding.binding,
  28053. rootUuid = propBinding.rootNode.uuid,
  28054. trackName = propBinding.path,
  28055. bindingsByRoot = this._bindingsByRootAndName,
  28056. bindingByName = bindingsByRoot[ rootUuid ],
  28057. lastInactiveBinding = bindings[ bindings.length - 1 ],
  28058. cacheIndex = binding._cacheIndex;
  28059. lastInactiveBinding._cacheIndex = cacheIndex;
  28060. bindings[ cacheIndex ] = lastInactiveBinding;
  28061. bindings.pop();
  28062. delete bindingByName[ trackName ];
  28063. if ( Object.keys( bindingByName ).length === 0 ) {
  28064. delete bindingsByRoot[ rootUuid ];
  28065. }
  28066. },
  28067. _lendBinding: function ( binding ) {
  28068. const bindings = this._bindings,
  28069. prevIndex = binding._cacheIndex,
  28070. lastActiveIndex = this._nActiveBindings ++,
  28071. firstInactiveBinding = bindings[ lastActiveIndex ];
  28072. binding._cacheIndex = lastActiveIndex;
  28073. bindings[ lastActiveIndex ] = binding;
  28074. firstInactiveBinding._cacheIndex = prevIndex;
  28075. bindings[ prevIndex ] = firstInactiveBinding;
  28076. },
  28077. _takeBackBinding: function ( binding ) {
  28078. const bindings = this._bindings,
  28079. prevIndex = binding._cacheIndex,
  28080. firstInactiveIndex = -- this._nActiveBindings,
  28081. lastActiveBinding = bindings[ firstInactiveIndex ];
  28082. binding._cacheIndex = firstInactiveIndex;
  28083. bindings[ firstInactiveIndex ] = binding;
  28084. lastActiveBinding._cacheIndex = prevIndex;
  28085. bindings[ prevIndex ] = lastActiveBinding;
  28086. },
  28087. // Memory management of Interpolants for weight and time scale
  28088. _lendControlInterpolant: function () {
  28089. const interpolants = this._controlInterpolants,
  28090. lastActiveIndex = this._nActiveControlInterpolants ++;
  28091. let interpolant = interpolants[ lastActiveIndex ];
  28092. if ( interpolant === undefined ) {
  28093. interpolant = new LinearInterpolant(
  28094. new Float32Array( 2 ), new Float32Array( 2 ),
  28095. 1, this._controlInterpolantsResultBuffer );
  28096. interpolant.__cacheIndex = lastActiveIndex;
  28097. interpolants[ lastActiveIndex ] = interpolant;
  28098. }
  28099. return interpolant;
  28100. },
  28101. _takeBackControlInterpolant: function ( interpolant ) {
  28102. const interpolants = this._controlInterpolants,
  28103. prevIndex = interpolant.__cacheIndex,
  28104. firstInactiveIndex = -- this._nActiveControlInterpolants,
  28105. lastActiveInterpolant = interpolants[ firstInactiveIndex ];
  28106. interpolant.__cacheIndex = firstInactiveIndex;
  28107. interpolants[ firstInactiveIndex ] = interpolant;
  28108. lastActiveInterpolant.__cacheIndex = prevIndex;
  28109. interpolants[ prevIndex ] = lastActiveInterpolant;
  28110. },
  28111. _controlInterpolantsResultBuffer: new Float32Array( 1 ),
  28112. // return an action for a clip optionally using a custom root target
  28113. // object (this method allocates a lot of dynamic memory in case a
  28114. // previously unknown clip/root combination is specified)
  28115. clipAction: function ( clip, optionalRoot, blendMode ) {
  28116. const root = optionalRoot || this._root,
  28117. rootUuid = root.uuid;
  28118. let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
  28119. const clipUuid = clipObject !== null ? clipObject.uuid : clip;
  28120. const actionsForClip = this._actionsByClip[ clipUuid ];
  28121. let prototypeAction = null;
  28122. if ( blendMode === undefined ) {
  28123. if ( clipObject !== null ) {
  28124. blendMode = clipObject.blendMode;
  28125. } else {
  28126. blendMode = NormalAnimationBlendMode;
  28127. }
  28128. }
  28129. if ( actionsForClip !== undefined ) {
  28130. const existingAction = actionsForClip.actionByRoot[ rootUuid ];
  28131. if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
  28132. return existingAction;
  28133. }
  28134. // we know the clip, so we don't have to parse all
  28135. // the bindings again but can just copy
  28136. prototypeAction = actionsForClip.knownActions[ 0 ];
  28137. // also, take the clip from the prototype action
  28138. if ( clipObject === null )
  28139. clipObject = prototypeAction._clip;
  28140. }
  28141. // clip must be known when specified via string
  28142. if ( clipObject === null ) return null;
  28143. // allocate all resources required to run it
  28144. const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
  28145. this._bindAction( newAction, prototypeAction );
  28146. // and make the action known to the memory manager
  28147. this._addInactiveAction( newAction, clipUuid, rootUuid );
  28148. return newAction;
  28149. },
  28150. // get an existing action
  28151. existingAction: function ( clip, optionalRoot ) {
  28152. const root = optionalRoot || this._root,
  28153. rootUuid = root.uuid,
  28154. clipObject = typeof clip === 'string' ?
  28155. AnimationClip.findByName( root, clip ) : clip,
  28156. clipUuid = clipObject ? clipObject.uuid : clip,
  28157. actionsForClip = this._actionsByClip[ clipUuid ];
  28158. if ( actionsForClip !== undefined ) {
  28159. return actionsForClip.actionByRoot[ rootUuid ] || null;
  28160. }
  28161. return null;
  28162. },
  28163. // deactivates all previously scheduled actions
  28164. stopAllAction: function () {
  28165. const actions = this._actions,
  28166. nActions = this._nActiveActions;
  28167. for ( let i = nActions - 1; i >= 0; -- i ) {
  28168. actions[ i ].stop();
  28169. }
  28170. return this;
  28171. },
  28172. // advance the time and update apply the animation
  28173. update: function ( deltaTime ) {
  28174. deltaTime *= this.timeScale;
  28175. const actions = this._actions,
  28176. nActions = this._nActiveActions,
  28177. time = this.time += deltaTime,
  28178. timeDirection = Math.sign( deltaTime ),
  28179. accuIndex = this._accuIndex ^= 1;
  28180. // run active actions
  28181. for ( let i = 0; i !== nActions; ++ i ) {
  28182. const action = actions[ i ];
  28183. action._update( time, deltaTime, timeDirection, accuIndex );
  28184. }
  28185. // update scene graph
  28186. const bindings = this._bindings,
  28187. nBindings = this._nActiveBindings;
  28188. for ( let i = 0; i !== nBindings; ++ i ) {
  28189. bindings[ i ].apply( accuIndex );
  28190. }
  28191. return this;
  28192. },
  28193. // Allows you to seek to a specific time in an animation.
  28194. setTime: function ( timeInSeconds ) {
  28195. this.time = 0; // Zero out time attribute for AnimationMixer object;
  28196. for ( let i = 0; i < this._actions.length; i ++ ) {
  28197. this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
  28198. }
  28199. return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
  28200. },
  28201. // return this mixer's root target object
  28202. getRoot: function () {
  28203. return this._root;
  28204. },
  28205. // free all resources specific to a particular clip
  28206. uncacheClip: function ( clip ) {
  28207. const actions = this._actions,
  28208. clipUuid = clip.uuid,
  28209. actionsByClip = this._actionsByClip,
  28210. actionsForClip = actionsByClip[ clipUuid ];
  28211. if ( actionsForClip !== undefined ) {
  28212. // note: just calling _removeInactiveAction would mess up the
  28213. // iteration state and also require updating the state we can
  28214. // just throw away
  28215. const actionsToRemove = actionsForClip.knownActions;
  28216. for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
  28217. const action = actionsToRemove[ i ];
  28218. this._deactivateAction( action );
  28219. const cacheIndex = action._cacheIndex,
  28220. lastInactiveAction = actions[ actions.length - 1 ];
  28221. action._cacheIndex = null;
  28222. action._byClipCacheIndex = null;
  28223. lastInactiveAction._cacheIndex = cacheIndex;
  28224. actions[ cacheIndex ] = lastInactiveAction;
  28225. actions.pop();
  28226. this._removeInactiveBindingsForAction( action );
  28227. }
  28228. delete actionsByClip[ clipUuid ];
  28229. }
  28230. },
  28231. // free all resources specific to a particular root target object
  28232. uncacheRoot: function ( root ) {
  28233. const rootUuid = root.uuid,
  28234. actionsByClip = this._actionsByClip;
  28235. for ( const clipUuid in actionsByClip ) {
  28236. const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
  28237. action = actionByRoot[ rootUuid ];
  28238. if ( action !== undefined ) {
  28239. this._deactivateAction( action );
  28240. this._removeInactiveAction( action );
  28241. }
  28242. }
  28243. const bindingsByRoot = this._bindingsByRootAndName,
  28244. bindingByName = bindingsByRoot[ rootUuid ];
  28245. if ( bindingByName !== undefined ) {
  28246. for ( const trackName in bindingByName ) {
  28247. const binding = bindingByName[ trackName ];
  28248. binding.restoreOriginalState();
  28249. this._removeInactiveBinding( binding );
  28250. }
  28251. }
  28252. },
  28253. // remove a targeted clip from the cache
  28254. uncacheAction: function ( clip, optionalRoot ) {
  28255. const action = this.existingAction( clip, optionalRoot );
  28256. if ( action !== null ) {
  28257. this._deactivateAction( action );
  28258. this._removeInactiveAction( action );
  28259. }
  28260. }
  28261. } );
  28262. class Uniform {
  28263. constructor( value ) {
  28264. if ( typeof value === 'string' ) {
  28265. console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
  28266. value = arguments[ 1 ];
  28267. }
  28268. this.value = value;
  28269. }
  28270. clone() {
  28271. return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
  28272. }
  28273. }
  28274. function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
  28275. InterleavedBuffer.call( this, array, stride );
  28276. this.meshPerAttribute = meshPerAttribute || 1;
  28277. }
  28278. InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
  28279. constructor: InstancedInterleavedBuffer,
  28280. isInstancedInterleavedBuffer: true,
  28281. copy: function ( source ) {
  28282. InterleavedBuffer.prototype.copy.call( this, source );
  28283. this.meshPerAttribute = source.meshPerAttribute;
  28284. return this;
  28285. },
  28286. clone: function ( data ) {
  28287. const ib = InterleavedBuffer.prototype.clone.call( this, data );
  28288. ib.meshPerAttribute = this.meshPerAttribute;
  28289. return ib;
  28290. },
  28291. toJSON: function ( data ) {
  28292. const json = InterleavedBuffer.prototype.toJSON.call( this, data );
  28293. json.isInstancedInterleavedBuffer = true;
  28294. json.meshPerAttribute = this.meshPerAttribute;
  28295. return json;
  28296. }
  28297. } );
  28298. function GLBufferAttribute( buffer, type, itemSize, elementSize, count ) {
  28299. this.buffer = buffer;
  28300. this.type = type;
  28301. this.itemSize = itemSize;
  28302. this.elementSize = elementSize;
  28303. this.count = count;
  28304. this.version = 0;
  28305. }
  28306. Object.defineProperty( GLBufferAttribute.prototype, 'needsUpdate', {
  28307. set: function ( value ) {
  28308. if ( value === true ) this.version ++;
  28309. }
  28310. } );
  28311. Object.assign( GLBufferAttribute.prototype, {
  28312. isGLBufferAttribute: true,
  28313. setBuffer: function ( buffer ) {
  28314. this.buffer = buffer;
  28315. return this;
  28316. },
  28317. setType: function ( type, elementSize ) {
  28318. this.type = type;
  28319. this.elementSize = elementSize;
  28320. return this;
  28321. },
  28322. setItemSize: function ( itemSize ) {
  28323. this.itemSize = itemSize;
  28324. return this;
  28325. },
  28326. setCount: function ( count ) {
  28327. this.count = count;
  28328. return this;
  28329. },
  28330. } );
  28331. function Raycaster( origin, direction, near, far ) {
  28332. this.ray = new Ray( origin, direction );
  28333. // direction is assumed to be normalized (for accurate distance calculations)
  28334. this.near = near || 0;
  28335. this.far = far || Infinity;
  28336. this.camera = null;
  28337. this.layers = new Layers();
  28338. this.params = {
  28339. Mesh: {},
  28340. Line: { threshold: 1 },
  28341. LOD: {},
  28342. Points: { threshold: 1 },
  28343. Sprite: {}
  28344. };
  28345. Object.defineProperties( this.params, {
  28346. PointCloud: {
  28347. get: function () {
  28348. console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
  28349. return this.Points;
  28350. }
  28351. }
  28352. } );
  28353. }
  28354. function ascSort( a, b ) {
  28355. return a.distance - b.distance;
  28356. }
  28357. function intersectObject( object, raycaster, intersects, recursive ) {
  28358. if ( object.layers.test( raycaster.layers ) ) {
  28359. object.raycast( raycaster, intersects );
  28360. }
  28361. if ( recursive === true ) {
  28362. const children = object.children;
  28363. for ( let i = 0, l = children.length; i < l; i ++ ) {
  28364. intersectObject( children[ i ], raycaster, intersects, true );
  28365. }
  28366. }
  28367. }
  28368. Object.assign( Raycaster.prototype, {
  28369. set: function ( origin, direction ) {
  28370. // direction is assumed to be normalized (for accurate distance calculations)
  28371. this.ray.set( origin, direction );
  28372. },
  28373. setFromCamera: function ( coords, camera ) {
  28374. if ( camera && camera.isPerspectiveCamera ) {
  28375. this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
  28376. this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
  28377. this.camera = camera;
  28378. } else if ( camera && camera.isOrthographicCamera ) {
  28379. this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
  28380. this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
  28381. this.camera = camera;
  28382. } else {
  28383. console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
  28384. }
  28385. },
  28386. intersectObject: function ( object, recursive, optionalTarget ) {
  28387. const intersects = optionalTarget || [];
  28388. intersectObject( object, this, intersects, recursive );
  28389. intersects.sort( ascSort );
  28390. return intersects;
  28391. },
  28392. intersectObjects: function ( objects, recursive, optionalTarget ) {
  28393. const intersects = optionalTarget || [];
  28394. if ( Array.isArray( objects ) === false ) {
  28395. console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
  28396. return intersects;
  28397. }
  28398. for ( let i = 0, l = objects.length; i < l; i ++ ) {
  28399. intersectObject( objects[ i ], this, intersects, recursive );
  28400. }
  28401. intersects.sort( ascSort );
  28402. return intersects;
  28403. }
  28404. } );
  28405. /**
  28406. * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
  28407. *
  28408. * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
  28409. * The azimuthal angle (theta) is measured from the positive z-axis.
  28410. */
  28411. class Spherical {
  28412. constructor( radius = 1, phi = 0, theta = 0 ) {
  28413. this.radius = radius;
  28414. this.phi = phi; // polar angle
  28415. this.theta = theta; // azimuthal angle
  28416. return this;
  28417. }
  28418. set( radius, phi, theta ) {
  28419. this.radius = radius;
  28420. this.phi = phi;
  28421. this.theta = theta;
  28422. return this;
  28423. }
  28424. clone() {
  28425. return new this.constructor().copy( this );
  28426. }
  28427. copy( other ) {
  28428. this.radius = other.radius;
  28429. this.phi = other.phi;
  28430. this.theta = other.theta;
  28431. return this;
  28432. }
  28433. // restrict phi to be betwee EPS and PI-EPS
  28434. makeSafe() {
  28435. const EPS = 0.000001;
  28436. this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
  28437. return this;
  28438. }
  28439. setFromVector3( v ) {
  28440. return this.setFromCartesianCoords( v.x, v.y, v.z );
  28441. }
  28442. setFromCartesianCoords( x, y, z ) {
  28443. this.radius = Math.sqrt( x * x + y * y + z * z );
  28444. if ( this.radius === 0 ) {
  28445. this.theta = 0;
  28446. this.phi = 0;
  28447. } else {
  28448. this.theta = Math.atan2( x, z );
  28449. this.phi = Math.acos( MathUtils.clamp( y / this.radius, - 1, 1 ) );
  28450. }
  28451. return this;
  28452. }
  28453. }
  28454. /**
  28455. * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
  28456. */
  28457. class Cylindrical {
  28458. constructor( radius, theta, y ) {
  28459. this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
  28460. this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
  28461. this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
  28462. return this;
  28463. }
  28464. set( radius, theta, y ) {
  28465. this.radius = radius;
  28466. this.theta = theta;
  28467. this.y = y;
  28468. return this;
  28469. }
  28470. clone() {
  28471. return new this.constructor().copy( this );
  28472. }
  28473. copy( other ) {
  28474. this.radius = other.radius;
  28475. this.theta = other.theta;
  28476. this.y = other.y;
  28477. return this;
  28478. }
  28479. setFromVector3( v ) {
  28480. return this.setFromCartesianCoords( v.x, v.y, v.z );
  28481. }
  28482. setFromCartesianCoords( x, y, z ) {
  28483. this.radius = Math.sqrt( x * x + z * z );
  28484. this.theta = Math.atan2( x, z );
  28485. this.y = y;
  28486. return this;
  28487. }
  28488. }
  28489. const _vector$8 = /*@__PURE__*/ new Vector2$1();
  28490. class Box2 {
  28491. constructor( min, max ) {
  28492. Object.defineProperty( this, 'isBox2', { value: true } );
  28493. this.min = ( min !== undefined ) ? min : new Vector2$1( + Infinity, + Infinity );
  28494. this.max = ( max !== undefined ) ? max : new Vector2$1( - Infinity, - Infinity );
  28495. }
  28496. set( min, max ) {
  28497. this.min.copy( min );
  28498. this.max.copy( max );
  28499. return this;
  28500. }
  28501. setFromPoints( points ) {
  28502. this.makeEmpty();
  28503. for ( let i = 0, il = points.length; i < il; i ++ ) {
  28504. this.expandByPoint( points[ i ] );
  28505. }
  28506. return this;
  28507. }
  28508. setFromCenterAndSize( center, size ) {
  28509. const halfSize = _vector$8.copy( size ).multiplyScalar( 0.5 );
  28510. this.min.copy( center ).sub( halfSize );
  28511. this.max.copy( center ).add( halfSize );
  28512. return this;
  28513. }
  28514. clone() {
  28515. return new this.constructor().copy( this );
  28516. }
  28517. copy( box ) {
  28518. this.min.copy( box.min );
  28519. this.max.copy( box.max );
  28520. return this;
  28521. }
  28522. makeEmpty() {
  28523. this.min.x = this.min.y = + Infinity;
  28524. this.max.x = this.max.y = - Infinity;
  28525. return this;
  28526. }
  28527. isEmpty() {
  28528. // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
  28529. return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
  28530. }
  28531. getCenter( target ) {
  28532. if ( target === undefined ) {
  28533. console.warn( 'THREE.Box2: .getCenter() target is now required' );
  28534. target = new Vector2$1();
  28535. }
  28536. return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
  28537. }
  28538. getSize( target ) {
  28539. if ( target === undefined ) {
  28540. console.warn( 'THREE.Box2: .getSize() target is now required' );
  28541. target = new Vector2$1();
  28542. }
  28543. return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
  28544. }
  28545. expandByPoint( point ) {
  28546. this.min.min( point );
  28547. this.max.max( point );
  28548. return this;
  28549. }
  28550. expandByVector( vector ) {
  28551. this.min.sub( vector );
  28552. this.max.add( vector );
  28553. return this;
  28554. }
  28555. expandByScalar( scalar ) {
  28556. this.min.addScalar( - scalar );
  28557. this.max.addScalar( scalar );
  28558. return this;
  28559. }
  28560. containsPoint( point ) {
  28561. return point.x < this.min.x || point.x > this.max.x ||
  28562. point.y < this.min.y || point.y > this.max.y ? false : true;
  28563. }
  28564. containsBox( box ) {
  28565. return this.min.x <= box.min.x && box.max.x <= this.max.x &&
  28566. this.min.y <= box.min.y && box.max.y <= this.max.y;
  28567. }
  28568. getParameter( point, target ) {
  28569. // This can potentially have a divide by zero if the box
  28570. // has a size dimension of 0.
  28571. if ( target === undefined ) {
  28572. console.warn( 'THREE.Box2: .getParameter() target is now required' );
  28573. target = new Vector2$1();
  28574. }
  28575. return target.set(
  28576. ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
  28577. ( point.y - this.min.y ) / ( this.max.y - this.min.y )
  28578. );
  28579. }
  28580. intersectsBox( box ) {
  28581. // using 4 splitting planes to rule out intersections
  28582. return box.max.x < this.min.x || box.min.x > this.max.x ||
  28583. box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
  28584. }
  28585. clampPoint( point, target ) {
  28586. if ( target === undefined ) {
  28587. console.warn( 'THREE.Box2: .clampPoint() target is now required' );
  28588. target = new Vector2$1();
  28589. }
  28590. return target.copy( point ).clamp( this.min, this.max );
  28591. }
  28592. distanceToPoint( point ) {
  28593. const clampedPoint = _vector$8.copy( point ).clamp( this.min, this.max );
  28594. return clampedPoint.sub( point ).length();
  28595. }
  28596. intersect( box ) {
  28597. this.min.max( box.min );
  28598. this.max.min( box.max );
  28599. return this;
  28600. }
  28601. union( box ) {
  28602. this.min.min( box.min );
  28603. this.max.max( box.max );
  28604. return this;
  28605. }
  28606. translate( offset ) {
  28607. this.min.add( offset );
  28608. this.max.add( offset );
  28609. return this;
  28610. }
  28611. equals( box ) {
  28612. return box.min.equals( this.min ) && box.max.equals( this.max );
  28613. }
  28614. }
  28615. const _startP = /*@__PURE__*/ new Vector3();
  28616. const _startEnd = /*@__PURE__*/ new Vector3();
  28617. class Line3 {
  28618. constructor( start, end ) {
  28619. this.start = ( start !== undefined ) ? start : new Vector3();
  28620. this.end = ( end !== undefined ) ? end : new Vector3();
  28621. }
  28622. set( start, end ) {
  28623. this.start.copy( start );
  28624. this.end.copy( end );
  28625. return this;
  28626. }
  28627. clone() {
  28628. return new this.constructor().copy( this );
  28629. }
  28630. copy( line ) {
  28631. this.start.copy( line.start );
  28632. this.end.copy( line.end );
  28633. return this;
  28634. }
  28635. getCenter( target ) {
  28636. if ( target === undefined ) {
  28637. console.warn( 'THREE.Line3: .getCenter() target is now required' );
  28638. target = new Vector3();
  28639. }
  28640. return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
  28641. }
  28642. delta( target ) {
  28643. if ( target === undefined ) {
  28644. console.warn( 'THREE.Line3: .delta() target is now required' );
  28645. target = new Vector3();
  28646. }
  28647. return target.subVectors( this.end, this.start );
  28648. }
  28649. distanceSq() {
  28650. return this.start.distanceToSquared( this.end );
  28651. }
  28652. distance() {
  28653. return this.start.distanceTo( this.end );
  28654. }
  28655. at( t, target ) {
  28656. if ( target === undefined ) {
  28657. console.warn( 'THREE.Line3: .at() target is now required' );
  28658. target = new Vector3();
  28659. }
  28660. return this.delta( target ).multiplyScalar( t ).add( this.start );
  28661. }
  28662. closestPointToPointParameter( point, clampToLine ) {
  28663. _startP.subVectors( point, this.start );
  28664. _startEnd.subVectors( this.end, this.start );
  28665. const startEnd2 = _startEnd.dot( _startEnd );
  28666. const startEnd_startP = _startEnd.dot( _startP );
  28667. let t = startEnd_startP / startEnd2;
  28668. if ( clampToLine ) {
  28669. t = MathUtils.clamp( t, 0, 1 );
  28670. }
  28671. return t;
  28672. }
  28673. closestPointToPoint( point, clampToLine, target ) {
  28674. const t = this.closestPointToPointParameter( point, clampToLine );
  28675. if ( target === undefined ) {
  28676. console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' );
  28677. target = new Vector3();
  28678. }
  28679. return this.delta( target ).multiplyScalar( t ).add( this.start );
  28680. }
  28681. applyMatrix4( matrix ) {
  28682. this.start.applyMatrix4( matrix );
  28683. this.end.applyMatrix4( matrix );
  28684. return this;
  28685. }
  28686. equals( line ) {
  28687. return line.start.equals( this.start ) && line.end.equals( this.end );
  28688. }
  28689. }
  28690. function ImmediateRenderObject( material ) {
  28691. Object3D.call( this );
  28692. this.material = material;
  28693. this.render = function ( /* renderCallback */ ) {};
  28694. this.hasPositions = false;
  28695. this.hasNormals = false;
  28696. this.hasColors = false;
  28697. this.hasUvs = false;
  28698. this.positionArray = null;
  28699. this.normalArray = null;
  28700. this.colorArray = null;
  28701. this.uvArray = null;
  28702. this.count = 0;
  28703. }
  28704. ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
  28705. ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
  28706. ImmediateRenderObject.prototype.isImmediateRenderObject = true;
  28707. const _vector$9 = /*@__PURE__*/ new Vector3();
  28708. class SpotLightHelper extends Object3D {
  28709. constructor( light, color ) {
  28710. super();
  28711. this.light = light;
  28712. this.light.updateMatrixWorld();
  28713. this.matrix = light.matrixWorld;
  28714. this.matrixAutoUpdate = false;
  28715. this.color = color;
  28716. const geometry = new BufferGeometry();
  28717. const positions = [
  28718. 0, 0, 0, 0, 0, 1,
  28719. 0, 0, 0, 1, 0, 1,
  28720. 0, 0, 0, - 1, 0, 1,
  28721. 0, 0, 0, 0, 1, 1,
  28722. 0, 0, 0, 0, - 1, 1
  28723. ];
  28724. for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
  28725. const p1 = ( i / l ) * Math.PI * 2;
  28726. const p2 = ( j / l ) * Math.PI * 2;
  28727. positions.push(
  28728. Math.cos( p1 ), Math.sin( p1 ), 1,
  28729. Math.cos( p2 ), Math.sin( p2 ), 1
  28730. );
  28731. }
  28732. geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
  28733. const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
  28734. this.cone = new LineSegments( geometry, material );
  28735. this.add( this.cone );
  28736. this.update();
  28737. }
  28738. dispose() {
  28739. this.cone.geometry.dispose();
  28740. this.cone.material.dispose();
  28741. }
  28742. update() {
  28743. this.light.updateMatrixWorld();
  28744. const coneLength = this.light.distance ? this.light.distance : 1000;
  28745. const coneWidth = coneLength * Math.tan( this.light.angle );
  28746. this.cone.scale.set( coneWidth, coneWidth, coneLength );
  28747. _vector$9.setFromMatrixPosition( this.light.target.matrixWorld );
  28748. this.cone.lookAt( _vector$9 );
  28749. if ( this.color !== undefined ) {
  28750. this.cone.material.color.set( this.color );
  28751. } else {
  28752. this.cone.material.color.copy( this.light.color );
  28753. }
  28754. }
  28755. }
  28756. const _vector$a = /*@__PURE__*/ new Vector3();
  28757. const _boneMatrix = /*@__PURE__*/ new Matrix4();
  28758. const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
  28759. class SkeletonHelper extends LineSegments {
  28760. constructor( object ) {
  28761. const bones = getBoneList( object );
  28762. const geometry = new BufferGeometry();
  28763. const vertices = [];
  28764. const colors = [];
  28765. const color1 = new Color( 0, 0, 1 );
  28766. const color2 = new Color( 0, 1, 0 );
  28767. for ( let i = 0; i < bones.length; i ++ ) {
  28768. const bone = bones[ i ];
  28769. if ( bone.parent && bone.parent.isBone ) {
  28770. vertices.push( 0, 0, 0 );
  28771. vertices.push( 0, 0, 0 );
  28772. colors.push( color1.r, color1.g, color1.b );
  28773. colors.push( color2.r, color2.g, color2.b );
  28774. }
  28775. }
  28776. geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  28777. geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
  28778. const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
  28779. super( geometry, material );
  28780. this.type = 'SkeletonHelper';
  28781. this.isSkeletonHelper = true;
  28782. this.root = object;
  28783. this.bones = bones;
  28784. this.matrix = object.matrixWorld;
  28785. this.matrixAutoUpdate = false;
  28786. }
  28787. updateMatrixWorld( force ) {
  28788. const bones = this.bones;
  28789. const geometry = this.geometry;
  28790. const position = geometry.getAttribute( 'position' );
  28791. _matrixWorldInv.copy( this.root.matrixWorld ).invert();
  28792. for ( let i = 0, j = 0; i < bones.length; i ++ ) {
  28793. const bone = bones[ i ];
  28794. if ( bone.parent && bone.parent.isBone ) {
  28795. _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
  28796. _vector$a.setFromMatrixPosition( _boneMatrix );
  28797. position.setXYZ( j, _vector$a.x, _vector$a.y, _vector$a.z );
  28798. _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
  28799. _vector$a.setFromMatrixPosition( _boneMatrix );
  28800. position.setXYZ( j + 1, _vector$a.x, _vector$a.y, _vector$a.z );
  28801. j += 2;
  28802. }
  28803. }
  28804. geometry.getAttribute( 'position' ).needsUpdate = true;
  28805. super.updateMatrixWorld( force );
  28806. }
  28807. }
  28808. function getBoneList( object ) {
  28809. const boneList = [];
  28810. if ( object && object.isBone ) {
  28811. boneList.push( object );
  28812. }
  28813. for ( let i = 0; i < object.children.length; i ++ ) {
  28814. boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
  28815. }
  28816. return boneList;
  28817. }
  28818. class PointLightHelper extends Mesh {
  28819. constructor( light, sphereSize, color ) {
  28820. const geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
  28821. const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
  28822. super( geometry, material );
  28823. this.light = light;
  28824. this.light.updateMatrixWorld();
  28825. this.color = color;
  28826. this.type = 'PointLightHelper';
  28827. this.matrix = this.light.matrixWorld;
  28828. this.matrixAutoUpdate = false;
  28829. this.update();
  28830. /*
  28831. // TODO: delete this comment?
  28832. const distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 );
  28833. const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
  28834. this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
  28835. this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
  28836. const d = light.distance;
  28837. if ( d === 0.0 ) {
  28838. this.lightDistance.visible = false;
  28839. } else {
  28840. this.lightDistance.scale.set( d, d, d );
  28841. }
  28842. this.add( this.lightDistance );
  28843. */
  28844. }
  28845. dispose() {
  28846. this.geometry.dispose();
  28847. this.material.dispose();
  28848. }
  28849. update() {
  28850. if ( this.color !== undefined ) {
  28851. this.material.color.set( this.color );
  28852. } else {
  28853. this.material.color.copy( this.light.color );
  28854. }
  28855. /*
  28856. const d = this.light.distance;
  28857. if ( d === 0.0 ) {
  28858. this.lightDistance.visible = false;
  28859. } else {
  28860. this.lightDistance.visible = true;
  28861. this.lightDistance.scale.set( d, d, d );
  28862. }
  28863. */
  28864. }
  28865. }
  28866. const _vector$b = /*@__PURE__*/ new Vector3();
  28867. const _color1 = /*@__PURE__*/ new Color();
  28868. const _color2 = /*@__PURE__*/ new Color();
  28869. class HemisphereLightHelper extends Object3D {
  28870. constructor( light, size, color ) {
  28871. super();
  28872. this.light = light;
  28873. this.light.updateMatrixWorld();
  28874. this.matrix = light.matrixWorld;
  28875. this.matrixAutoUpdate = false;
  28876. this.color = color;
  28877. const geometry = new OctahedronBufferGeometry( size );
  28878. geometry.rotateY( Math.PI * 0.5 );
  28879. this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
  28880. if ( this.color === undefined ) this.material.vertexColors = true;
  28881. const position = geometry.getAttribute( 'position' );
  28882. const colors = new Float32Array( position.count * 3 );
  28883. geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
  28884. this.add( new Mesh( geometry, this.material ) );
  28885. this.update();
  28886. }
  28887. dispose() {
  28888. this.children[ 0 ].geometry.dispose();
  28889. this.children[ 0 ].material.dispose();
  28890. }
  28891. update() {
  28892. const mesh = this.children[ 0 ];
  28893. if ( this.color !== undefined ) {
  28894. this.material.color.set( this.color );
  28895. } else {
  28896. const colors = mesh.geometry.getAttribute( 'color' );
  28897. _color1.copy( this.light.color );
  28898. _color2.copy( this.light.groundColor );
  28899. for ( let i = 0, l = colors.count; i < l; i ++ ) {
  28900. const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
  28901. colors.setXYZ( i, color.r, color.g, color.b );
  28902. }
  28903. colors.needsUpdate = true;
  28904. }
  28905. mesh.lookAt( _vector$b.setFromMatrixPosition( this.light.matrixWorld ).negate() );
  28906. }
  28907. }
  28908. class GridHelper extends LineSegments {
  28909. constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
  28910. color1 = new Color( color1 );
  28911. color2 = new Color( color2 );
  28912. const center = divisions / 2;
  28913. const step = size / divisions;
  28914. const halfSize = size / 2;
  28915. const vertices = [], colors = [];
  28916. for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
  28917. vertices.push( - halfSize, 0, k, halfSize, 0, k );
  28918. vertices.push( k, 0, - halfSize, k, 0, halfSize );
  28919. const color = i === center ? color1 : color2;
  28920. color.toArray( colors, j ); j += 3;
  28921. color.toArray( colors, j ); j += 3;
  28922. color.toArray( colors, j ); j += 3;
  28923. color.toArray( colors, j ); j += 3;
  28924. }
  28925. const geometry = new BufferGeometry();
  28926. geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  28927. geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
  28928. const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
  28929. super( geometry, material );
  28930. this.type = 'GridHelper';
  28931. }
  28932. }
  28933. class PolarGridHelper extends LineSegments {
  28934. constructor( radius = 10, radials = 16, circles = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {
  28935. color1 = new Color( color1 );
  28936. color2 = new Color( color2 );
  28937. const vertices = [];
  28938. const colors = [];
  28939. // create the radials
  28940. for ( let i = 0; i <= radials; i ++ ) {
  28941. const v = ( i / radials ) * ( Math.PI * 2 );
  28942. const x = Math.sin( v ) * radius;
  28943. const z = Math.cos( v ) * radius;
  28944. vertices.push( 0, 0, 0 );
  28945. vertices.push( x, 0, z );
  28946. const color = ( i & 1 ) ? color1 : color2;
  28947. colors.push( color.r, color.g, color.b );
  28948. colors.push( color.r, color.g, color.b );
  28949. }
  28950. // create the circles
  28951. for ( let i = 0; i <= circles; i ++ ) {
  28952. const color = ( i & 1 ) ? color1 : color2;
  28953. const r = radius - ( radius / circles * i );
  28954. for ( let j = 0; j < divisions; j ++ ) {
  28955. // first vertex
  28956. let v = ( j / divisions ) * ( Math.PI * 2 );
  28957. let x = Math.sin( v ) * r;
  28958. let z = Math.cos( v ) * r;
  28959. vertices.push( x, 0, z );
  28960. colors.push( color.r, color.g, color.b );
  28961. // second vertex
  28962. v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
  28963. x = Math.sin( v ) * r;
  28964. z = Math.cos( v ) * r;
  28965. vertices.push( x, 0, z );
  28966. colors.push( color.r, color.g, color.b );
  28967. }
  28968. }
  28969. const geometry = new BufferGeometry();
  28970. geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  28971. geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
  28972. const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
  28973. super( geometry, material );
  28974. this.type = 'PolarGridHelper';
  28975. }
  28976. }
  28977. const _v1$6 = /*@__PURE__*/ new Vector3();
  28978. const _v2$3 = /*@__PURE__*/ new Vector3();
  28979. const _v3$1 = /*@__PURE__*/ new Vector3();
  28980. class DirectionalLightHelper extends Object3D {
  28981. constructor( light, size, color ) {
  28982. super();
  28983. this.light = light;
  28984. this.light.updateMatrixWorld();
  28985. this.matrix = light.matrixWorld;
  28986. this.matrixAutoUpdate = false;
  28987. this.color = color;
  28988. if ( size === undefined ) size = 1;
  28989. let geometry = new BufferGeometry();
  28990. geometry.setAttribute( 'position', new Float32BufferAttribute( [
  28991. - size, size, 0,
  28992. size, size, 0,
  28993. size, - size, 0,
  28994. - size, - size, 0,
  28995. - size, size, 0
  28996. ], 3 ) );
  28997. const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
  28998. this.lightPlane = new Line( geometry, material );
  28999. this.add( this.lightPlane );
  29000. geometry = new BufferGeometry();
  29001. geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
  29002. this.targetLine = new Line( geometry, material );
  29003. this.add( this.targetLine );
  29004. this.update();
  29005. }
  29006. dispose() {
  29007. this.lightPlane.geometry.dispose();
  29008. this.lightPlane.material.dispose();
  29009. this.targetLine.geometry.dispose();
  29010. this.targetLine.material.dispose();
  29011. }
  29012. update() {
  29013. _v1$6.setFromMatrixPosition( this.light.matrixWorld );
  29014. _v2$3.setFromMatrixPosition( this.light.target.matrixWorld );
  29015. _v3$1.subVectors( _v2$3, _v1$6 );
  29016. this.lightPlane.lookAt( _v2$3 );
  29017. if ( this.color !== undefined ) {
  29018. this.lightPlane.material.color.set( this.color );
  29019. this.targetLine.material.color.set( this.color );
  29020. } else {
  29021. this.lightPlane.material.color.copy( this.light.color );
  29022. this.targetLine.material.color.copy( this.light.color );
  29023. }
  29024. this.targetLine.lookAt( _v2$3 );
  29025. this.targetLine.scale.z = _v3$1.length();
  29026. }
  29027. }
  29028. const _vector$c = /*@__PURE__*/ new Vector3();
  29029. const _camera = /*@__PURE__*/ new Camera();
  29030. /**
  29031. * - shows frustum, line of sight and up of the camera
  29032. * - suitable for fast updates
  29033. * - based on frustum visualization in lightgl.js shadowmap example
  29034. * http://evanw.github.com/lightgl.js/tests/shadowmap.html
  29035. */
  29036. class CameraHelper extends LineSegments {
  29037. constructor( camera ) {
  29038. const geometry = new BufferGeometry();
  29039. const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
  29040. const vertices = [];
  29041. const colors = [];
  29042. const pointMap = {};
  29043. // colors
  29044. const colorFrustum = new Color( 0xffaa00 );
  29045. const colorCone = new Color( 0xff0000 );
  29046. const colorUp = new Color( 0x00aaff );
  29047. const colorTarget = new Color( 0xffffff );
  29048. const colorCross = new Color( 0x333333 );
  29049. // near
  29050. addLine( 'n1', 'n2', colorFrustum );
  29051. addLine( 'n2', 'n4', colorFrustum );
  29052. addLine( 'n4', 'n3', colorFrustum );
  29053. addLine( 'n3', 'n1', colorFrustum );
  29054. // far
  29055. addLine( 'f1', 'f2', colorFrustum );
  29056. addLine( 'f2', 'f4', colorFrustum );
  29057. addLine( 'f4', 'f3', colorFrustum );
  29058. addLine( 'f3', 'f1', colorFrustum );
  29059. // sides
  29060. addLine( 'n1', 'f1', colorFrustum );
  29061. addLine( 'n2', 'f2', colorFrustum );
  29062. addLine( 'n3', 'f3', colorFrustum );
  29063. addLine( 'n4', 'f4', colorFrustum );
  29064. // cone
  29065. addLine( 'p', 'n1', colorCone );
  29066. addLine( 'p', 'n2', colorCone );
  29067. addLine( 'p', 'n3', colorCone );
  29068. addLine( 'p', 'n4', colorCone );
  29069. // up
  29070. addLine( 'u1', 'u2', colorUp );
  29071. addLine( 'u2', 'u3', colorUp );
  29072. addLine( 'u3', 'u1', colorUp );
  29073. // target
  29074. addLine( 'c', 't', colorTarget );
  29075. addLine( 'p', 'c', colorCross );
  29076. // cross
  29077. addLine( 'cn1', 'cn2', colorCross );
  29078. addLine( 'cn3', 'cn4', colorCross );
  29079. addLine( 'cf1', 'cf2', colorCross );
  29080. addLine( 'cf3', 'cf4', colorCross );
  29081. function addLine( a, b, color ) {
  29082. addPoint( a, color );
  29083. addPoint( b, color );
  29084. }
  29085. function addPoint( id, color ) {
  29086. vertices.push( 0, 0, 0 );
  29087. colors.push( color.r, color.g, color.b );
  29088. if ( pointMap[ id ] === undefined ) {
  29089. pointMap[ id ] = [];
  29090. }
  29091. pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
  29092. }
  29093. geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  29094. geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
  29095. super( geometry, material );
  29096. this.type = 'CameraHelper';
  29097. this.camera = camera;
  29098. if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
  29099. this.matrix = camera.matrixWorld;
  29100. this.matrixAutoUpdate = false;
  29101. this.pointMap = pointMap;
  29102. this.update();
  29103. }
  29104. update() {
  29105. const geometry = this.geometry;
  29106. const pointMap = this.pointMap;
  29107. const w = 1, h = 1;
  29108. // we need just camera projection matrix inverse
  29109. // world matrix must be identity
  29110. _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
  29111. // center / target
  29112. setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
  29113. setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
  29114. // near
  29115. setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
  29116. setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
  29117. setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
  29118. setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
  29119. // far
  29120. setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
  29121. setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
  29122. setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
  29123. setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
  29124. // up
  29125. setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
  29126. setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
  29127. setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
  29128. // cross
  29129. setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
  29130. setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
  29131. setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
  29132. setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
  29133. setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
  29134. setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
  29135. setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
  29136. setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
  29137. geometry.getAttribute( 'position' ).needsUpdate = true;
  29138. }
  29139. }
  29140. function setPoint( point, pointMap, geometry, camera, x, y, z ) {
  29141. _vector$c.set( x, y, z ).unproject( camera );
  29142. const points = pointMap[ point ];
  29143. if ( points !== undefined ) {
  29144. const position = geometry.getAttribute( 'position' );
  29145. for ( let i = 0, l = points.length; i < l; i ++ ) {
  29146. position.setXYZ( points[ i ], _vector$c.x, _vector$c.y, _vector$c.z );
  29147. }
  29148. }
  29149. }
  29150. const _box$3 = /*@__PURE__*/ new Box3();
  29151. class BoxHelper extends LineSegments {
  29152. constructor( object, color = 0xffff00 ) {
  29153. const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
  29154. const positions = new Float32Array( 8 * 3 );
  29155. const geometry = new BufferGeometry();
  29156. geometry.setIndex( new BufferAttribute( indices, 1 ) );
  29157. geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
  29158. super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
  29159. this.object = object;
  29160. this.type = 'BoxHelper';
  29161. this.matrixAutoUpdate = false;
  29162. this.update();
  29163. }
  29164. update( object ) {
  29165. if ( object !== undefined ) {
  29166. console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
  29167. }
  29168. if ( this.object !== undefined ) {
  29169. _box$3.setFromObject( this.object );
  29170. }
  29171. if ( _box$3.isEmpty() ) return;
  29172. const min = _box$3.min;
  29173. const max = _box$3.max;
  29174. /*
  29175. 5____4
  29176. 1/___0/|
  29177. | 6__|_7
  29178. 2/___3/
  29179. 0: max.x, max.y, max.z
  29180. 1: min.x, max.y, max.z
  29181. 2: min.x, min.y, max.z
  29182. 3: max.x, min.y, max.z
  29183. 4: max.x, max.y, min.z
  29184. 5: min.x, max.y, min.z
  29185. 6: min.x, min.y, min.z
  29186. 7: max.x, min.y, min.z
  29187. */
  29188. const position = this.geometry.attributes.position;
  29189. const array = position.array;
  29190. array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
  29191. array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
  29192. array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
  29193. array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
  29194. array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
  29195. array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
  29196. array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
  29197. array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
  29198. position.needsUpdate = true;
  29199. this.geometry.computeBoundingSphere();
  29200. }
  29201. setFromObject( object ) {
  29202. this.object = object;
  29203. this.update();
  29204. return this;
  29205. }
  29206. copy( source ) {
  29207. LineSegments.prototype.copy.call( this, source );
  29208. this.object = source.object;
  29209. return this;
  29210. }
  29211. }
  29212. class Box3Helper extends LineSegments {
  29213. constructor( box, color = 0xffff00 ) {
  29214. const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
  29215. const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
  29216. const geometry = new BufferGeometry();
  29217. geometry.setIndex( new BufferAttribute( indices, 1 ) );
  29218. geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
  29219. super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
  29220. this.box = box;
  29221. this.type = 'Box3Helper';
  29222. this.geometry.computeBoundingSphere();
  29223. }
  29224. updateMatrixWorld( force ) {
  29225. const box = this.box;
  29226. if ( box.isEmpty() ) return;
  29227. box.getCenter( this.position );
  29228. box.getSize( this.scale );
  29229. this.scale.multiplyScalar( 0.5 );
  29230. super.updateMatrixWorld( force );
  29231. }
  29232. }
  29233. class PlaneHelper extends Line {
  29234. constructor( plane, size = 1, hex = 0xffff00 ) {
  29235. const color = hex;
  29236. const positions = [ 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, 0, 1, 0, 0, 0 ];
  29237. const geometry = new BufferGeometry();
  29238. geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
  29239. geometry.computeBoundingSphere();
  29240. super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
  29241. this.type = 'PlaneHelper';
  29242. this.plane = plane;
  29243. this.size = size;
  29244. const positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
  29245. const geometry2 = new BufferGeometry();
  29246. geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
  29247. geometry2.computeBoundingSphere();
  29248. this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
  29249. }
  29250. updateMatrixWorld( force ) {
  29251. let scale = - this.plane.constant;
  29252. if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
  29253. this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
  29254. this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
  29255. this.lookAt( this.plane.normal );
  29256. super.updateMatrixWorld( force );
  29257. }
  29258. }
  29259. const _axis = /*@__PURE__*/ new Vector3();
  29260. let _lineGeometry, _coneGeometry;
  29261. class ArrowHelper extends Object3D {
  29262. constructor( dir, origin, length, color, headLength, headWidth ) {
  29263. super();
  29264. // dir is assumed to be normalized
  29265. this.type = 'ArrowHelper';
  29266. if ( dir === undefined ) dir = new Vector3( 0, 0, 1 );
  29267. if ( origin === undefined ) origin = new Vector3( 0, 0, 0 );
  29268. if ( length === undefined ) length = 1;
  29269. if ( color === undefined ) color = 0xffff00;
  29270. if ( headLength === undefined ) headLength = 0.2 * length;
  29271. if ( headWidth === undefined ) headWidth = 0.2 * headLength;
  29272. if ( _lineGeometry === undefined ) {
  29273. _lineGeometry = new BufferGeometry();
  29274. _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
  29275. _coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
  29276. _coneGeometry.translate( 0, - 0.5, 0 );
  29277. }
  29278. this.position.copy( origin );
  29279. this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
  29280. this.line.matrixAutoUpdate = false;
  29281. this.add( this.line );
  29282. this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
  29283. this.cone.matrixAutoUpdate = false;
  29284. this.add( this.cone );
  29285. this.setDirection( dir );
  29286. this.setLength( length, headLength, headWidth );
  29287. }
  29288. setDirection( dir ) {
  29289. // dir is assumed to be normalized
  29290. if ( dir.y > 0.99999 ) {
  29291. this.quaternion.set( 0, 0, 0, 1 );
  29292. } else if ( dir.y < - 0.99999 ) {
  29293. this.quaternion.set( 1, 0, 0, 0 );
  29294. } else {
  29295. _axis.set( dir.z, 0, - dir.x ).normalize();
  29296. const radians = Math.acos( dir.y );
  29297. this.quaternion.setFromAxisAngle( _axis, radians );
  29298. }
  29299. }
  29300. setLength( length, headLength, headWidth ) {
  29301. if ( headLength === undefined ) headLength = 0.2 * length;
  29302. if ( headWidth === undefined ) headWidth = 0.2 * headLength;
  29303. this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
  29304. this.line.updateMatrix();
  29305. this.cone.scale.set( headWidth, headLength, headWidth );
  29306. this.cone.position.y = length;
  29307. this.cone.updateMatrix();
  29308. }
  29309. setColor( color ) {
  29310. this.line.material.color.set( color );
  29311. this.cone.material.color.set( color );
  29312. }
  29313. copy( source ) {
  29314. super.copy( source, false );
  29315. this.line.copy( source.line );
  29316. this.cone.copy( source.cone );
  29317. return this;
  29318. }
  29319. }
  29320. class AxesHelper extends LineSegments {
  29321. constructor( size = 1 ) {
  29322. const vertices = [
  29323. 0, 0, 0, size, 0, 0,
  29324. 0, 0, 0, 0, size, 0,
  29325. 0, 0, 0, 0, 0, size
  29326. ];
  29327. const colors = [
  29328. 1, 0, 0, 1, 0.6, 0,
  29329. 0, 1, 0, 0.6, 1, 0,
  29330. 0, 0, 1, 0, 0.6, 1
  29331. ];
  29332. const geometry = new BufferGeometry();
  29333. geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  29334. geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
  29335. const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
  29336. super( geometry, material );
  29337. this.type = 'AxesHelper';
  29338. }
  29339. }
  29340. const _floatView = new Float32Array( 1 );
  29341. const _int32View = new Int32Array( _floatView.buffer );
  29342. const DataUtils = {
  29343. // Converts float32 to float16 (stored as uint16 value).
  29344. toHalfFloat: function ( val ) {
  29345. // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
  29346. /* This method is faster than the OpenEXR implementation (very often
  29347. * used, eg. in Ogre), with the additional benefit of rounding, inspired
  29348. * by James Tursa?s half-precision code. */
  29349. _floatView[ 0 ] = val;
  29350. const x = _int32View[ 0 ];
  29351. let bits = ( x >> 16 ) & 0x8000; /* Get the sign */
  29352. let m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */
  29353. const e = ( x >> 23 ) & 0xff; /* Using int is faster here */
  29354. /* If zero, or denormal, or exponent underflows too much for a denormal
  29355. * half, return signed zero. */
  29356. if ( e < 103 ) return bits;
  29357. /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
  29358. if ( e > 142 ) {
  29359. bits |= 0x7c00;
  29360. /* If exponent was 0xff and one mantissa bit was set, it means NaN,
  29361. * not Inf, so make sure we set one mantissa bit too. */
  29362. bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff );
  29363. return bits;
  29364. }
  29365. /* If exponent underflows but not too much, return a denormal */
  29366. if ( e < 113 ) {
  29367. m |= 0x0800;
  29368. /* Extra rounding may overflow and set mantissa to 0 and exponent
  29369. * to 1, which is OK. */
  29370. bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 );
  29371. return bits;
  29372. }
  29373. bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 );
  29374. /* Extra rounding. An overflow will set mantissa to 0 and increment
  29375. * the exponent, which is OK. */
  29376. bits += m & 1;
  29377. return bits;
  29378. }
  29379. };
  29380. const LOD_MIN = 4;
  29381. const LOD_MAX = 8;
  29382. const SIZE_MAX = Math.pow( 2, LOD_MAX );
  29383. // The standard deviations (radians) associated with the extra mips. These are
  29384. // chosen to approximate a Trowbridge-Reitz distribution function times the
  29385. // geometric shadowing function. These sigma values squared must match the
  29386. // variance #defines in cube_uv_reflection_fragment.glsl.js.
  29387. const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
  29388. const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
  29389. // The maximum length of the blur for loop. Smaller sigmas will use fewer
  29390. // samples and exit early, but not recompile the shader.
  29391. const MAX_SAMPLES = 20;
  29392. const ENCODINGS = {
  29393. [ LinearEncoding ]: 0,
  29394. [ sRGBEncoding ]: 1,
  29395. [ RGBEEncoding ]: 2,
  29396. [ RGBM7Encoding ]: 3,
  29397. [ RGBM16Encoding ]: 4,
  29398. [ RGBDEncoding ]: 5,
  29399. [ GammaEncoding ]: 6
  29400. };
  29401. const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
  29402. const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
  29403. const _clearColor = /*@__PURE__*/ new Color();
  29404. let _oldTarget = null;
  29405. // Golden Ratio
  29406. const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
  29407. const INV_PHI = 1 / PHI;
  29408. // Vertices of a dodecahedron (except the opposites, which represent the
  29409. // same axis), used as axis directions evenly spread on a sphere.
  29410. const _axisDirections = [
  29411. /*@__PURE__*/ new Vector3( 1, 1, 1 ),
  29412. /*@__PURE__*/ new Vector3( - 1, 1, 1 ),
  29413. /*@__PURE__*/ new Vector3( 1, 1, - 1 ),
  29414. /*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
  29415. /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
  29416. /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
  29417. /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
  29418. /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
  29419. /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
  29420. /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
  29421. /**
  29422. * This class generates a Prefiltered, Mipmapped Radiance Environment Map
  29423. * (PMREM) from a cubeMap environment texture. This allows different levels of
  29424. * blur to be quickly accessed based on material roughness. It is packed into a
  29425. * special CubeUV format that allows us to perform custom interpolation so that
  29426. * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
  29427. * chain, it only goes down to the LOD_MIN level (above), and then creates extra
  29428. * even more filtered 'mips' at the same LOD_MIN resolution, associated with
  29429. * higher roughness levels. In this way we maintain resolution to smoothly
  29430. * interpolate diffuse lighting while limiting sampling computation.
  29431. */
  29432. class PMREMGenerator {
  29433. constructor( renderer ) {
  29434. this._renderer = renderer;
  29435. this._pingPongRenderTarget = null;
  29436. this._blurMaterial = _getBlurShader( MAX_SAMPLES );
  29437. this._equirectShader = null;
  29438. this._cubemapShader = null;
  29439. this._compileMaterial( this._blurMaterial );
  29440. }
  29441. /**
  29442. * Generates a PMREM from a supplied Scene, which can be faster than using an
  29443. * image if networking bandwidth is low. Optional sigma specifies a blur radius
  29444. * in radians to be applied to the scene before PMREM generation. Optional near
  29445. * and far planes ensure the scene is rendered in its entirety (the cubeCamera
  29446. * is placed at the origin).
  29447. */
  29448. fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
  29449. _oldTarget = this._renderer.getRenderTarget();
  29450. const cubeUVRenderTarget = this._allocateTargets();
  29451. this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
  29452. if ( sigma > 0 ) {
  29453. this._blur( cubeUVRenderTarget, 0, 0, sigma );
  29454. }
  29455. this._applyPMREM( cubeUVRenderTarget );
  29456. this._cleanup( cubeUVRenderTarget );
  29457. return cubeUVRenderTarget;
  29458. }
  29459. /**
  29460. * Generates a PMREM from an equirectangular texture, which can be either LDR
  29461. * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512),
  29462. * as this matches best with the 256 x 256 cubemap output.
  29463. */
  29464. fromEquirectangular( equirectangular ) {
  29465. return this._fromTexture( equirectangular );
  29466. }
  29467. /**
  29468. * Generates a PMREM from an cubemap texture, which can be either LDR
  29469. * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256,
  29470. * as this matches best with the 256 x 256 cubemap output.
  29471. */
  29472. fromCubemap( cubemap ) {
  29473. return this._fromTexture( cubemap );
  29474. }
  29475. /**
  29476. * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
  29477. * your texture's network fetch for increased concurrency.
  29478. */
  29479. compileCubemapShader() {
  29480. if ( this._cubemapShader === null ) {
  29481. this._cubemapShader = _getCubemapShader();
  29482. this._compileMaterial( this._cubemapShader );
  29483. }
  29484. }
  29485. /**
  29486. * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
  29487. * your texture's network fetch for increased concurrency.
  29488. */
  29489. compileEquirectangularShader() {
  29490. if ( this._equirectShader === null ) {
  29491. this._equirectShader = _getEquirectShader();
  29492. this._compileMaterial( this._equirectShader );
  29493. }
  29494. }
  29495. /**
  29496. * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
  29497. * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
  29498. * one of them will cause any others to also become unusable.
  29499. */
  29500. dispose() {
  29501. this._blurMaterial.dispose();
  29502. if ( this._cubemapShader !== null ) this._cubemapShader.dispose();
  29503. if ( this._equirectShader !== null ) this._equirectShader.dispose();
  29504. for ( let i = 0; i < _lodPlanes.length; i ++ ) {
  29505. _lodPlanes[ i ].dispose();
  29506. }
  29507. }
  29508. // private interface
  29509. _cleanup( outputTarget ) {
  29510. this._pingPongRenderTarget.dispose();
  29511. this._renderer.setRenderTarget( _oldTarget );
  29512. outputTarget.scissorTest = false;
  29513. _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
  29514. }
  29515. _fromTexture( texture ) {
  29516. _oldTarget = this._renderer.getRenderTarget();
  29517. const cubeUVRenderTarget = this._allocateTargets( texture );
  29518. this._textureToCubeUV( texture, cubeUVRenderTarget );
  29519. this._applyPMREM( cubeUVRenderTarget );
  29520. this._cleanup( cubeUVRenderTarget );
  29521. return cubeUVRenderTarget;
  29522. }
  29523. _allocateTargets( texture ) { // warning: null texture is valid
  29524. const params = {
  29525. magFilter: NearestFilter,
  29526. minFilter: NearestFilter,
  29527. generateMipmaps: false,
  29528. type: UnsignedByteType,
  29529. format: RGBEFormat,
  29530. encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding,
  29531. depthBuffer: false
  29532. };
  29533. const cubeUVRenderTarget = _createRenderTarget( params );
  29534. cubeUVRenderTarget.depthBuffer = texture ? false : true;
  29535. this._pingPongRenderTarget = _createRenderTarget( params );
  29536. return cubeUVRenderTarget;
  29537. }
  29538. _compileMaterial( material ) {
  29539. const tmpMesh = new Mesh( _lodPlanes[ 0 ], material );
  29540. this._renderer.compile( tmpMesh, _flatCamera );
  29541. }
  29542. _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
  29543. const fov = 90;
  29544. const aspect = 1;
  29545. const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
  29546. const upSign = [ 1, - 1, 1, 1, 1, 1 ];
  29547. const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
  29548. const renderer = this._renderer;
  29549. const outputEncoding = renderer.outputEncoding;
  29550. const toneMapping = renderer.toneMapping;
  29551. renderer.getClearColor( _clearColor );
  29552. const clearAlpha = renderer.getClearAlpha();
  29553. renderer.toneMapping = NoToneMapping;
  29554. renderer.outputEncoding = LinearEncoding;
  29555. let background = scene.background;
  29556. if ( background && background.isColor ) {
  29557. background.convertSRGBToLinear();
  29558. // Convert linear to RGBE
  29559. const maxComponent = Math.max( background.r, background.g, background.b );
  29560. const fExp = Math.min( Math.max( Math.ceil( Math.log2( maxComponent ) ), - 128.0 ), 127.0 );
  29561. background = background.multiplyScalar( Math.pow( 2.0, - fExp ) );
  29562. const alpha = ( fExp + 128.0 ) / 255.0;
  29563. renderer.setClearColor( background, alpha );
  29564. scene.background = null;
  29565. }
  29566. for ( let i = 0; i < 6; i ++ ) {
  29567. const col = i % 3;
  29568. if ( col == 0 ) {
  29569. cubeCamera.up.set( 0, upSign[ i ], 0 );
  29570. cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
  29571. } else if ( col == 1 ) {
  29572. cubeCamera.up.set( 0, 0, upSign[ i ] );
  29573. cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
  29574. } else {
  29575. cubeCamera.up.set( 0, upSign[ i ], 0 );
  29576. cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
  29577. }
  29578. _setViewport( cubeUVRenderTarget,
  29579. col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX );
  29580. renderer.setRenderTarget( cubeUVRenderTarget );
  29581. renderer.render( scene, cubeCamera );
  29582. }
  29583. renderer.toneMapping = toneMapping;
  29584. renderer.outputEncoding = outputEncoding;
  29585. renderer.setClearColor( _clearColor, clearAlpha );
  29586. }
  29587. _textureToCubeUV( texture, cubeUVRenderTarget ) {
  29588. const renderer = this._renderer;
  29589. if ( texture.isCubeTexture ) {
  29590. if ( this._cubemapShader == null ) {
  29591. this._cubemapShader = _getCubemapShader();
  29592. }
  29593. } else {
  29594. if ( this._equirectShader == null ) {
  29595. this._equirectShader = _getEquirectShader();
  29596. }
  29597. }
  29598. const material = texture.isCubeTexture ? this._cubemapShader : this._equirectShader;
  29599. const mesh = new Mesh( _lodPlanes[ 0 ], material );
  29600. const uniforms = material.uniforms;
  29601. uniforms[ 'envMap' ].value = texture;
  29602. if ( ! texture.isCubeTexture ) {
  29603. uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height );
  29604. }
  29605. uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ];
  29606. uniforms[ 'outputEncoding' ].value = ENCODINGS[ cubeUVRenderTarget.texture.encoding ];
  29607. _setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
  29608. renderer.setRenderTarget( cubeUVRenderTarget );
  29609. renderer.render( mesh, _flatCamera );
  29610. }
  29611. _applyPMREM( cubeUVRenderTarget ) {
  29612. const renderer = this._renderer;
  29613. const autoClear = renderer.autoClear;
  29614. renderer.autoClear = false;
  29615. for ( let i = 1; i < TOTAL_LODS; i ++ ) {
  29616. const sigma = Math.sqrt( _sigmas[ i ] * _sigmas[ i ] - _sigmas[ i - 1 ] * _sigmas[ i - 1 ] );
  29617. const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
  29618. this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
  29619. }
  29620. renderer.autoClear = autoClear;
  29621. }
  29622. /**
  29623. * This is a two-pass Gaussian blur for a cubemap. Normally this is done
  29624. * vertically and horizontally, but this breaks down on a cube. Here we apply
  29625. * the blur latitudinally (around the poles), and then longitudinally (towards
  29626. * the poles) to approximate the orthogonally-separable blur. It is least
  29627. * accurate at the poles, but still does a decent job.
  29628. */
  29629. _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
  29630. const pingPongRenderTarget = this._pingPongRenderTarget;
  29631. this._halfBlur(
  29632. cubeUVRenderTarget,
  29633. pingPongRenderTarget,
  29634. lodIn,
  29635. lodOut,
  29636. sigma,
  29637. 'latitudinal',
  29638. poleAxis );
  29639. this._halfBlur(
  29640. pingPongRenderTarget,
  29641. cubeUVRenderTarget,
  29642. lodOut,
  29643. lodOut,
  29644. sigma,
  29645. 'longitudinal',
  29646. poleAxis );
  29647. }
  29648. _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
  29649. const renderer = this._renderer;
  29650. const blurMaterial = this._blurMaterial;
  29651. if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
  29652. console.error(
  29653. 'blur direction must be either latitudinal or longitudinal!' );
  29654. }
  29655. // Number of standard deviations at which to cut off the discrete approximation.
  29656. const STANDARD_DEVIATIONS = 3;
  29657. const blurMesh = new Mesh( _lodPlanes[ lodOut ], blurMaterial );
  29658. const blurUniforms = blurMaterial.uniforms;
  29659. const pixels = _sizeLods[ lodIn ] - 1;
  29660. const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
  29661. const sigmaPixels = sigmaRadians / radiansPerPixel;
  29662. const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
  29663. if ( samples > MAX_SAMPLES ) {
  29664. console.warn( `sigmaRadians, ${
  29665. sigmaRadians}, is too large and will clip, as it requested ${
  29666. samples} samples when the maximum is set to ${MAX_SAMPLES}` );
  29667. }
  29668. const weights = [];
  29669. let sum = 0;
  29670. for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
  29671. const x = i / sigmaPixels;
  29672. const weight = Math.exp( - x * x / 2 );
  29673. weights.push( weight );
  29674. if ( i == 0 ) {
  29675. sum += weight;
  29676. } else if ( i < samples ) {
  29677. sum += 2 * weight;
  29678. }
  29679. }
  29680. for ( let i = 0; i < weights.length; i ++ ) {
  29681. weights[ i ] = weights[ i ] / sum;
  29682. }
  29683. blurUniforms[ 'envMap' ].value = targetIn.texture;
  29684. blurUniforms[ 'samples' ].value = samples;
  29685. blurUniforms[ 'weights' ].value = weights;
  29686. blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
  29687. if ( poleAxis ) {
  29688. blurUniforms[ 'poleAxis' ].value = poleAxis;
  29689. }
  29690. blurUniforms[ 'dTheta' ].value = radiansPerPixel;
  29691. blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn;
  29692. blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
  29693. blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
  29694. const outputSize = _sizeLods[ lodOut ];
  29695. const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize );
  29696. const y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + 2 * outputSize * ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 );
  29697. _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
  29698. renderer.setRenderTarget( targetOut );
  29699. renderer.render( blurMesh, _flatCamera );
  29700. }
  29701. }
  29702. function _isLDR( texture ) {
  29703. if ( texture === undefined || texture.type !== UnsignedByteType ) return false;
  29704. return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding;
  29705. }
  29706. function _createPlanes() {
  29707. const _lodPlanes = [];
  29708. const _sizeLods = [];
  29709. const _sigmas = [];
  29710. let lod = LOD_MAX;
  29711. for ( let i = 0; i < TOTAL_LODS; i ++ ) {
  29712. const sizeLod = Math.pow( 2, lod );
  29713. _sizeLods.push( sizeLod );
  29714. let sigma = 1.0 / sizeLod;
  29715. if ( i > LOD_MAX - LOD_MIN ) {
  29716. sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ];
  29717. } else if ( i == 0 ) {
  29718. sigma = 0;
  29719. }
  29720. _sigmas.push( sigma );
  29721. const texelSize = 1.0 / ( sizeLod - 1 );
  29722. const min = - texelSize / 2;
  29723. const max = 1 + texelSize / 2;
  29724. const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
  29725. const cubeFaces = 6;
  29726. const vertices = 6;
  29727. const positionSize = 3;
  29728. const uvSize = 2;
  29729. const faceIndexSize = 1;
  29730. const position = new Float32Array( positionSize * vertices * cubeFaces );
  29731. const uv = new Float32Array( uvSize * vertices * cubeFaces );
  29732. const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
  29733. for ( let face = 0; face < cubeFaces; face ++ ) {
  29734. const x = ( face % 3 ) * 2 / 3 - 1;
  29735. const y = face > 2 ? 0 : - 1;
  29736. const coordinates = [
  29737. x, y, 0,
  29738. x + 2 / 3, y, 0,
  29739. x + 2 / 3, y + 1, 0,
  29740. x, y, 0,
  29741. x + 2 / 3, y + 1, 0,
  29742. x, y + 1, 0
  29743. ];
  29744. position.set( coordinates, positionSize * vertices * face );
  29745. uv.set( uv1, uvSize * vertices * face );
  29746. const fill = [ face, face, face, face, face, face ];
  29747. faceIndex.set( fill, faceIndexSize * vertices * face );
  29748. }
  29749. const planes = new BufferGeometry();
  29750. planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
  29751. planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
  29752. planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
  29753. _lodPlanes.push( planes );
  29754. if ( lod > LOD_MIN ) {
  29755. lod --;
  29756. }
  29757. }
  29758. return { _lodPlanes, _sizeLods, _sigmas };
  29759. }
  29760. function _createRenderTarget( params ) {
  29761. const cubeUVRenderTarget = new WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params );
  29762. cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
  29763. cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
  29764. cubeUVRenderTarget.scissorTest = true;
  29765. return cubeUVRenderTarget;
  29766. }
  29767. function _setViewport( target, x, y, width, height ) {
  29768. target.viewport.set( x, y, width, height );
  29769. target.scissor.set( x, y, width, height );
  29770. }
  29771. function _getBlurShader( maxSamples ) {
  29772. const weights = new Float32Array( maxSamples );
  29773. const poleAxis = new Vector3( 0, 1, 0 );
  29774. const shaderMaterial = new RawShaderMaterial( {
  29775. name: 'SphericalGaussianBlur',
  29776. defines: { 'n': maxSamples },
  29777. uniforms: {
  29778. 'envMap': { value: null },
  29779. 'samples': { value: 1 },
  29780. 'weights': { value: weights },
  29781. 'latitudinal': { value: false },
  29782. 'dTheta': { value: 0 },
  29783. 'mipInt': { value: 0 },
  29784. 'poleAxis': { value: poleAxis },
  29785. 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
  29786. 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
  29787. },
  29788. vertexShader: _getCommonVertexShader(),
  29789. fragmentShader: /* glsl */`
  29790. precision mediump float;
  29791. precision mediump int;
  29792. varying vec3 vOutputDirection;
  29793. uniform sampler2D envMap;
  29794. uniform int samples;
  29795. uniform float weights[ n ];
  29796. uniform bool latitudinal;
  29797. uniform float dTheta;
  29798. uniform float mipInt;
  29799. uniform vec3 poleAxis;
  29800. ${ _getEncodings() }
  29801. #define ENVMAP_TYPE_CUBE_UV
  29802. #include <cube_uv_reflection_fragment>
  29803. vec3 getSample( float theta, vec3 axis ) {
  29804. float cosTheta = cos( theta );
  29805. // Rodrigues' axis-angle rotation
  29806. vec3 sampleDirection = vOutputDirection * cosTheta
  29807. + cross( axis, vOutputDirection ) * sin( theta )
  29808. + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
  29809. return bilinearCubeUV( envMap, sampleDirection, mipInt );
  29810. }
  29811. void main() {
  29812. vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
  29813. if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
  29814. axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
  29815. }
  29816. axis = normalize( axis );
  29817. gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
  29818. gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
  29819. for ( int i = 1; i < n; i++ ) {
  29820. if ( i >= samples ) {
  29821. break;
  29822. }
  29823. float theta = dTheta * float( i );
  29824. gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
  29825. gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
  29826. }
  29827. gl_FragColor = linearToOutputTexel( gl_FragColor );
  29828. }
  29829. `,
  29830. blending: NoBlending,
  29831. depthTest: false,
  29832. depthWrite: false
  29833. } );
  29834. return shaderMaterial;
  29835. }
  29836. function _getEquirectShader() {
  29837. const texelSize = new Vector2$1( 1, 1 );
  29838. const shaderMaterial = new RawShaderMaterial( {
  29839. name: 'EquirectangularToCubeUV',
  29840. uniforms: {
  29841. 'envMap': { value: null },
  29842. 'texelSize': { value: texelSize },
  29843. 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
  29844. 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
  29845. },
  29846. vertexShader: _getCommonVertexShader(),
  29847. fragmentShader: /* glsl */`
  29848. precision mediump float;
  29849. precision mediump int;
  29850. varying vec3 vOutputDirection;
  29851. uniform sampler2D envMap;
  29852. uniform vec2 texelSize;
  29853. ${ _getEncodings() }
  29854. #include <common>
  29855. void main() {
  29856. gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
  29857. vec3 outputDirection = normalize( vOutputDirection );
  29858. vec2 uv = equirectUv( outputDirection );
  29859. vec2 f = fract( uv / texelSize - 0.5 );
  29860. uv -= f * texelSize;
  29861. vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
  29862. uv.x += texelSize.x;
  29863. vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
  29864. uv.y += texelSize.y;
  29865. vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
  29866. uv.x -= texelSize.x;
  29867. vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
  29868. vec3 tm = mix( tl, tr, f.x );
  29869. vec3 bm = mix( bl, br, f.x );
  29870. gl_FragColor.rgb = mix( tm, bm, f.y );
  29871. gl_FragColor = linearToOutputTexel( gl_FragColor );
  29872. }
  29873. `,
  29874. blending: NoBlending,
  29875. depthTest: false,
  29876. depthWrite: false
  29877. } );
  29878. return shaderMaterial;
  29879. }
  29880. function _getCubemapShader() {
  29881. const shaderMaterial = new RawShaderMaterial( {
  29882. name: 'CubemapToCubeUV',
  29883. uniforms: {
  29884. 'envMap': { value: null },
  29885. 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
  29886. 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
  29887. },
  29888. vertexShader: _getCommonVertexShader(),
  29889. fragmentShader: /* glsl */`
  29890. precision mediump float;
  29891. precision mediump int;
  29892. varying vec3 vOutputDirection;
  29893. uniform samplerCube envMap;
  29894. ${ _getEncodings() }
  29895. void main() {
  29896. gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
  29897. gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;
  29898. gl_FragColor = linearToOutputTexel( gl_FragColor );
  29899. }
  29900. `,
  29901. blending: NoBlending,
  29902. depthTest: false,
  29903. depthWrite: false
  29904. } );
  29905. return shaderMaterial;
  29906. }
  29907. function _getCommonVertexShader() {
  29908. return /* glsl */`
  29909. precision mediump float;
  29910. precision mediump int;
  29911. attribute vec3 position;
  29912. attribute vec2 uv;
  29913. attribute float faceIndex;
  29914. varying vec3 vOutputDirection;
  29915. // RH coordinate system; PMREM face-indexing convention
  29916. vec3 getDirection( vec2 uv, float face ) {
  29917. uv = 2.0 * uv - 1.0;
  29918. vec3 direction = vec3( uv, 1.0 );
  29919. if ( face == 0.0 ) {
  29920. direction = direction.zyx; // ( 1, v, u ) pos x
  29921. } else if ( face == 1.0 ) {
  29922. direction = direction.xzy;
  29923. direction.xz *= -1.0; // ( -u, 1, -v ) pos y
  29924. } else if ( face == 2.0 ) {
  29925. direction.x *= -1.0; // ( -u, v, 1 ) pos z
  29926. } else if ( face == 3.0 ) {
  29927. direction = direction.zyx;
  29928. direction.xz *= -1.0; // ( -1, v, -u ) neg x
  29929. } else if ( face == 4.0 ) {
  29930. direction = direction.xzy;
  29931. direction.xy *= -1.0; // ( -u, -1, v ) neg y
  29932. } else if ( face == 5.0 ) {
  29933. direction.z *= -1.0; // ( u, v, -1 ) neg z
  29934. }
  29935. return direction;
  29936. }
  29937. void main() {
  29938. vOutputDirection = getDirection( uv, faceIndex );
  29939. gl_Position = vec4( position, 1.0 );
  29940. }
  29941. `;
  29942. }
  29943. function _getEncodings() {
  29944. return /* glsl */`
  29945. uniform int inputEncoding;
  29946. uniform int outputEncoding;
  29947. #include <encodings_pars_fragment>
  29948. vec4 inputTexelToLinear( vec4 value ) {
  29949. if ( inputEncoding == 0 ) {
  29950. return value;
  29951. } else if ( inputEncoding == 1 ) {
  29952. return sRGBToLinear( value );
  29953. } else if ( inputEncoding == 2 ) {
  29954. return RGBEToLinear( value );
  29955. } else if ( inputEncoding == 3 ) {
  29956. return RGBMToLinear( value, 7.0 );
  29957. } else if ( inputEncoding == 4 ) {
  29958. return RGBMToLinear( value, 16.0 );
  29959. } else if ( inputEncoding == 5 ) {
  29960. return RGBDToLinear( value, 256.0 );
  29961. } else {
  29962. return GammaToLinear( value, 2.2 );
  29963. }
  29964. }
  29965. vec4 linearToOutputTexel( vec4 value ) {
  29966. if ( outputEncoding == 0 ) {
  29967. return value;
  29968. } else if ( outputEncoding == 1 ) {
  29969. return LinearTosRGB( value );
  29970. } else if ( outputEncoding == 2 ) {
  29971. return LinearToRGBE( value );
  29972. } else if ( outputEncoding == 3 ) {
  29973. return LinearToRGBM( value, 7.0 );
  29974. } else if ( outputEncoding == 4 ) {
  29975. return LinearToRGBM( value, 16.0 );
  29976. } else if ( outputEncoding == 5 ) {
  29977. return LinearToRGBD( value, 256.0 );
  29978. } else {
  29979. return LinearToGamma( value, 2.2 );
  29980. }
  29981. }
  29982. vec4 envMapTexelToLinear( vec4 color ) {
  29983. return inputTexelToLinear( color );
  29984. }
  29985. `;
  29986. }
  29987. function Face4( a, b, c, d, normal, color, materialIndex ) {
  29988. console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );
  29989. return new Face3( a, b, c, normal, color, materialIndex );
  29990. }
  29991. const LineStrip = 0;
  29992. const LinePieces = 1;
  29993. const NoColors = 0;
  29994. const FaceColors = 1;
  29995. const VertexColors = 2;
  29996. function MeshFaceMaterial( materials ) {
  29997. console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' );
  29998. return materials;
  29999. }
  30000. function MultiMaterial( materials = [] ) {
  30001. console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' );
  30002. materials.isMultiMaterial = true;
  30003. materials.materials = materials;
  30004. materials.clone = function () {
  30005. return materials.slice();
  30006. };
  30007. return materials;
  30008. }
  30009. function PointCloud( geometry, material ) {
  30010. console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );
  30011. return new Points( geometry, material );
  30012. }
  30013. function Particle( material ) {
  30014. console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );
  30015. return new Sprite( material );
  30016. }
  30017. function ParticleSystem( geometry, material ) {
  30018. console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );
  30019. return new Points( geometry, material );
  30020. }
  30021. function PointCloudMaterial( parameters ) {
  30022. console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );
  30023. return new PointsMaterial( parameters );
  30024. }
  30025. function ParticleBasicMaterial( parameters ) {
  30026. console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );
  30027. return new PointsMaterial( parameters );
  30028. }
  30029. function ParticleSystemMaterial( parameters ) {
  30030. console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );
  30031. return new PointsMaterial( parameters );
  30032. }
  30033. function Vertex( x, y, z ) {
  30034. console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );
  30035. return new Vector3( x, y, z );
  30036. }
  30037. //
  30038. function DynamicBufferAttribute( array, itemSize ) {
  30039. console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead.' );
  30040. return new BufferAttribute( array, itemSize ).setUsage( DynamicDrawUsage );
  30041. }
  30042. function Int8Attribute( array, itemSize ) {
  30043. console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );
  30044. return new Int8BufferAttribute( array, itemSize );
  30045. }
  30046. function Uint8Attribute( array, itemSize ) {
  30047. console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );
  30048. return new Uint8BufferAttribute( array, itemSize );
  30049. }
  30050. function Uint8ClampedAttribute( array, itemSize ) {
  30051. console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );
  30052. return new Uint8ClampedBufferAttribute( array, itemSize );
  30053. }
  30054. function Int16Attribute( array, itemSize ) {
  30055. console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );
  30056. return new Int16BufferAttribute( array, itemSize );
  30057. }
  30058. function Uint16Attribute( array, itemSize ) {
  30059. console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );
  30060. return new Uint16BufferAttribute( array, itemSize );
  30061. }
  30062. function Int32Attribute( array, itemSize ) {
  30063. console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );
  30064. return new Int32BufferAttribute( array, itemSize );
  30065. }
  30066. function Uint32Attribute( array, itemSize ) {
  30067. console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );
  30068. return new Uint32BufferAttribute( array, itemSize );
  30069. }
  30070. function Float32Attribute( array, itemSize ) {
  30071. console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );
  30072. return new Float32BufferAttribute( array, itemSize );
  30073. }
  30074. function Float64Attribute( array, itemSize ) {
  30075. console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );
  30076. return new Float64BufferAttribute( array, itemSize );
  30077. }
  30078. //
  30079. Curve.create = function ( construct, getPoint ) {
  30080. console.log( 'THREE.Curve.create() has been deprecated' );
  30081. construct.prototype = Object.create( Curve.prototype );
  30082. construct.prototype.constructor = construct;
  30083. construct.prototype.getPoint = getPoint;
  30084. return construct;
  30085. };
  30086. //
  30087. Object.assign( CurvePath.prototype, {
  30088. createPointsGeometry: function ( divisions ) {
  30089. console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
  30090. // generate geometry from path points (for Line or Points objects)
  30091. const pts = this.getPoints( divisions );
  30092. return this.createGeometry( pts );
  30093. },
  30094. createSpacedPointsGeometry: function ( divisions ) {
  30095. console.warn( 'THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
  30096. // generate geometry from equidistant sampling along the path
  30097. const pts = this.getSpacedPoints( divisions );
  30098. return this.createGeometry( pts );
  30099. },
  30100. createGeometry: function ( points ) {
  30101. console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
  30102. const geometry = new Geometry();
  30103. for ( let i = 0, l = points.length; i < l; i ++ ) {
  30104. const point = points[ i ];
  30105. geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
  30106. }
  30107. return geometry;
  30108. }
  30109. } );
  30110. //
  30111. Object.assign( Path.prototype, {
  30112. fromPoints: function ( points ) {
  30113. console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' );
  30114. return this.setFromPoints( points );
  30115. }
  30116. } );
  30117. //
  30118. function ClosedSplineCurve3( points ) {
  30119. console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
  30120. CatmullRomCurve3.call( this, points );
  30121. this.type = 'catmullrom';
  30122. this.closed = true;
  30123. }
  30124. ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
  30125. //
  30126. function SplineCurve3( points ) {
  30127. console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
  30128. CatmullRomCurve3.call( this, points );
  30129. this.type = 'catmullrom';
  30130. }
  30131. SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
  30132. //
  30133. function Spline( points ) {
  30134. console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
  30135. CatmullRomCurve3.call( this, points );
  30136. this.type = 'catmullrom';
  30137. }
  30138. Spline.prototype = Object.create( CatmullRomCurve3.prototype );
  30139. Object.assign( Spline.prototype, {
  30140. initFromArray: function ( /* a */ ) {
  30141. console.error( 'THREE.Spline: .initFromArray() has been removed.' );
  30142. },
  30143. getControlPointsArray: function ( /* optionalTarget */ ) {
  30144. console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
  30145. },
  30146. reparametrizeByArcLength: function ( /* samplingCoef */ ) {
  30147. console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
  30148. }
  30149. } );
  30150. //
  30151. function AxisHelper( size ) {
  30152. console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' );
  30153. return new AxesHelper( size );
  30154. }
  30155. function BoundingBoxHelper( object, color ) {
  30156. console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );
  30157. return new BoxHelper( object, color );
  30158. }
  30159. function EdgesHelper( object, hex ) {
  30160. console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );
  30161. return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
  30162. }
  30163. GridHelper.prototype.setColors = function () {
  30164. console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
  30165. };
  30166. SkeletonHelper.prototype.update = function () {
  30167. console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
  30168. };
  30169. function WireframeHelper( object, hex ) {
  30170. console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );
  30171. return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
  30172. }
  30173. //
  30174. Object.assign( Loader.prototype, {
  30175. extractUrlBase: function ( url ) {
  30176. console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' );
  30177. return LoaderUtils.extractUrlBase( url );
  30178. }
  30179. } );
  30180. Loader.Handlers = {
  30181. add: function ( /* regex, loader */ ) {
  30182. console.error( 'THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.' );
  30183. },
  30184. get: function ( /* file */ ) {
  30185. console.error( 'THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.' );
  30186. }
  30187. };
  30188. function XHRLoader( manager ) {
  30189. console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );
  30190. return new FileLoader( manager );
  30191. }
  30192. function BinaryTextureLoader( manager ) {
  30193. console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );
  30194. return new DataTextureLoader( manager );
  30195. }
  30196. //
  30197. Object.assign( Box2.prototype, {
  30198. center: function ( optionalTarget ) {
  30199. console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
  30200. return this.getCenter( optionalTarget );
  30201. },
  30202. empty: function () {
  30203. console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
  30204. return this.isEmpty();
  30205. },
  30206. isIntersectionBox: function ( box ) {
  30207. console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
  30208. return this.intersectsBox( box );
  30209. },
  30210. size: function ( optionalTarget ) {
  30211. console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
  30212. return this.getSize( optionalTarget );
  30213. }
  30214. } );
  30215. Object.assign( Box3.prototype, {
  30216. center: function ( optionalTarget ) {
  30217. console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
  30218. return this.getCenter( optionalTarget );
  30219. },
  30220. empty: function () {
  30221. console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
  30222. return this.isEmpty();
  30223. },
  30224. isIntersectionBox: function ( box ) {
  30225. console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
  30226. return this.intersectsBox( box );
  30227. },
  30228. isIntersectionSphere: function ( sphere ) {
  30229. console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
  30230. return this.intersectsSphere( sphere );
  30231. },
  30232. size: function ( optionalTarget ) {
  30233. console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
  30234. return this.getSize( optionalTarget );
  30235. }
  30236. } );
  30237. Object.assign( Sphere.prototype, {
  30238. empty: function () {
  30239. console.warn( 'THREE.Sphere: .empty() has been renamed to .isEmpty().' );
  30240. return this.isEmpty();
  30241. },
  30242. } );
  30243. Frustum.prototype.setFromMatrix = function ( m ) {
  30244. console.warn( 'THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix().' );
  30245. return this.setFromProjectionMatrix( m );
  30246. };
  30247. Line3.prototype.center = function ( optionalTarget ) {
  30248. console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
  30249. return this.getCenter( optionalTarget );
  30250. };
  30251. Object.assign( MathUtils, {
  30252. random16: function () {
  30253. console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' );
  30254. return Math.random();
  30255. },
  30256. nearestPowerOfTwo: function ( value ) {
  30257. console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' );
  30258. return MathUtils.floorPowerOfTwo( value );
  30259. },
  30260. nextPowerOfTwo: function ( value ) {
  30261. console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' );
  30262. return MathUtils.ceilPowerOfTwo( value );
  30263. }
  30264. } );
  30265. Object.assign( Matrix3.prototype, {
  30266. flattenToArrayOffset: function ( array, offset ) {
  30267. console.warn( 'THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
  30268. return this.toArray( array, offset );
  30269. },
  30270. multiplyVector3: function ( vector ) {
  30271. console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
  30272. return vector.applyMatrix3( this );
  30273. },
  30274. multiplyVector3Array: function ( /* a */ ) {
  30275. console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
  30276. },
  30277. applyToBufferAttribute: function ( attribute ) {
  30278. console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' );
  30279. return attribute.applyMatrix3( this );
  30280. },
  30281. applyToVector3Array: function ( /* array, offset, length */ ) {
  30282. console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
  30283. },
  30284. getInverse: function ( matrix ) {
  30285. console.warn( 'THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
  30286. return this.copy( matrix ).invert();
  30287. }
  30288. } );
  30289. Object.assign( Matrix4.prototype, {
  30290. extractPosition: function ( m ) {
  30291. console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
  30292. return this.copyPosition( m );
  30293. },
  30294. flattenToArrayOffset: function ( array, offset ) {
  30295. console.warn( 'THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
  30296. return this.toArray( array, offset );
  30297. },
  30298. getPosition: function () {
  30299. console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
  30300. return new Vector3().setFromMatrixColumn( this, 3 );
  30301. },
  30302. setRotationFromQuaternion: function ( q ) {
  30303. console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
  30304. return this.makeRotationFromQuaternion( q );
  30305. },
  30306. multiplyToArray: function () {
  30307. console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
  30308. },
  30309. multiplyVector3: function ( vector ) {
  30310. console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
  30311. return vector.applyMatrix4( this );
  30312. },
  30313. multiplyVector4: function ( vector ) {
  30314. console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
  30315. return vector.applyMatrix4( this );
  30316. },
  30317. multiplyVector3Array: function ( /* a */ ) {
  30318. console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
  30319. },
  30320. rotateAxis: function ( v ) {
  30321. console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
  30322. v.transformDirection( this );
  30323. },
  30324. crossVector: function ( vector ) {
  30325. console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
  30326. return vector.applyMatrix4( this );
  30327. },
  30328. translate: function () {
  30329. console.error( 'THREE.Matrix4: .translate() has been removed.' );
  30330. },
  30331. rotateX: function () {
  30332. console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
  30333. },
  30334. rotateY: function () {
  30335. console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
  30336. },
  30337. rotateZ: function () {
  30338. console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
  30339. },
  30340. rotateByAxis: function () {
  30341. console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
  30342. },
  30343. applyToBufferAttribute: function ( attribute ) {
  30344. console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' );
  30345. return attribute.applyMatrix4( this );
  30346. },
  30347. applyToVector3Array: function ( /* array, offset, length */ ) {
  30348. console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
  30349. },
  30350. makeFrustum: function ( left, right, bottom, top, near, far ) {
  30351. console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
  30352. return this.makePerspective( left, right, top, bottom, near, far );
  30353. },
  30354. getInverse: function ( matrix ) {
  30355. console.warn( 'THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
  30356. return this.copy( matrix ).invert();
  30357. }
  30358. } );
  30359. Plane.prototype.isIntersectionLine = function ( line ) {
  30360. console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
  30361. return this.intersectsLine( line );
  30362. };
  30363. Object.assign( Quaternion.prototype, {
  30364. multiplyVector3: function ( vector ) {
  30365. console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
  30366. return vector.applyQuaternion( this );
  30367. },
  30368. inverse: function ( ) {
  30369. console.warn( 'THREE.Quaternion: .inverse() has been renamed to invert().' );
  30370. return this.invert();
  30371. }
  30372. } );
  30373. Object.assign( Ray.prototype, {
  30374. isIntersectionBox: function ( box ) {
  30375. console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
  30376. return this.intersectsBox( box );
  30377. },
  30378. isIntersectionPlane: function ( plane ) {
  30379. console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
  30380. return this.intersectsPlane( plane );
  30381. },
  30382. isIntersectionSphere: function ( sphere ) {
  30383. console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
  30384. return this.intersectsSphere( sphere );
  30385. }
  30386. } );
  30387. Object.assign( Triangle.prototype, {
  30388. area: function () {
  30389. console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' );
  30390. return this.getArea();
  30391. },
  30392. barycoordFromPoint: function ( point, target ) {
  30393. console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
  30394. return this.getBarycoord( point, target );
  30395. },
  30396. midpoint: function ( target ) {
  30397. console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' );
  30398. return this.getMidpoint( target );
  30399. },
  30400. normal: function ( target ) {
  30401. console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
  30402. return this.getNormal( target );
  30403. },
  30404. plane: function ( target ) {
  30405. console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' );
  30406. return this.getPlane( target );
  30407. }
  30408. } );
  30409. Object.assign( Triangle, {
  30410. barycoordFromPoint: function ( point, a, b, c, target ) {
  30411. console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
  30412. return Triangle.getBarycoord( point, a, b, c, target );
  30413. },
  30414. normal: function ( a, b, c, target ) {
  30415. console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
  30416. return Triangle.getNormal( a, b, c, target );
  30417. }
  30418. } );
  30419. Object.assign( Shape.prototype, {
  30420. extractAllPoints: function ( divisions ) {
  30421. console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' );
  30422. return this.extractPoints( divisions );
  30423. },
  30424. extrude: function ( options ) {
  30425. console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
  30426. return new ExtrudeGeometry( this, options );
  30427. },
  30428. makeGeometry: function ( options ) {
  30429. console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
  30430. return new ShapeGeometry( this, options );
  30431. }
  30432. } );
  30433. Object.assign( Vector2$1.prototype, {
  30434. fromAttribute: function ( attribute, index, offset ) {
  30435. console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
  30436. return this.fromBufferAttribute( attribute, index, offset );
  30437. },
  30438. distanceToManhattan: function ( v ) {
  30439. console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
  30440. return this.manhattanDistanceTo( v );
  30441. },
  30442. lengthManhattan: function () {
  30443. console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' );
  30444. return this.manhattanLength();
  30445. }
  30446. } );
  30447. Object.assign( Vector3.prototype, {
  30448. setEulerFromRotationMatrix: function () {
  30449. console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
  30450. },
  30451. setEulerFromQuaternion: function () {
  30452. console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
  30453. },
  30454. getPositionFromMatrix: function ( m ) {
  30455. console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
  30456. return this.setFromMatrixPosition( m );
  30457. },
  30458. getScaleFromMatrix: function ( m ) {
  30459. console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
  30460. return this.setFromMatrixScale( m );
  30461. },
  30462. getColumnFromMatrix: function ( index, matrix ) {
  30463. console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
  30464. return this.setFromMatrixColumn( matrix, index );
  30465. },
  30466. applyProjection: function ( m ) {
  30467. console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
  30468. return this.applyMatrix4( m );
  30469. },
  30470. fromAttribute: function ( attribute, index, offset ) {
  30471. console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
  30472. return this.fromBufferAttribute( attribute, index, offset );
  30473. },
  30474. distanceToManhattan: function ( v ) {
  30475. console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
  30476. return this.manhattanDistanceTo( v );
  30477. },
  30478. lengthManhattan: function () {
  30479. console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' );
  30480. return this.manhattanLength();
  30481. }
  30482. } );
  30483. Object.assign( Vector4.prototype, {
  30484. fromAttribute: function ( attribute, index, offset ) {
  30485. console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
  30486. return this.fromBufferAttribute( attribute, index, offset );
  30487. },
  30488. lengthManhattan: function () {
  30489. console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
  30490. return this.manhattanLength();
  30491. }
  30492. } );
  30493. //
  30494. Object.assign( Geometry.prototype, {
  30495. computeTangents: function () {
  30496. console.error( 'THREE.Geometry: .computeTangents() has been removed.' );
  30497. },
  30498. computeLineDistances: function () {
  30499. console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' );
  30500. },
  30501. applyMatrix: function ( matrix ) {
  30502. console.warn( 'THREE.Geometry: .applyMatrix() has been renamed to .applyMatrix4().' );
  30503. return this.applyMatrix4( matrix );
  30504. }
  30505. } );
  30506. Object.assign( Object3D.prototype, {
  30507. getChildByName: function ( name ) {
  30508. console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
  30509. return this.getObjectByName( name );
  30510. },
  30511. renderDepth: function () {
  30512. console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
  30513. },
  30514. translate: function ( distance, axis ) {
  30515. console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
  30516. return this.translateOnAxis( axis, distance );
  30517. },
  30518. getWorldRotation: function () {
  30519. console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' );
  30520. },
  30521. applyMatrix: function ( matrix ) {
  30522. console.warn( 'THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4().' );
  30523. return this.applyMatrix4( matrix );
  30524. }
  30525. } );
  30526. Object.defineProperties( Object3D.prototype, {
  30527. eulerOrder: {
  30528. get: function () {
  30529. console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
  30530. return this.rotation.order;
  30531. },
  30532. set: function ( value ) {
  30533. console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
  30534. this.rotation.order = value;
  30535. }
  30536. },
  30537. useQuaternion: {
  30538. get: function () {
  30539. console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
  30540. },
  30541. set: function () {
  30542. console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
  30543. }
  30544. }
  30545. } );
  30546. Object.assign( Mesh.prototype, {
  30547. setDrawMode: function () {
  30548. console.error( 'THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
  30549. },
  30550. } );
  30551. Object.defineProperties( Mesh.prototype, {
  30552. drawMode: {
  30553. get: function () {
  30554. console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode.' );
  30555. return TrianglesDrawMode;
  30556. },
  30557. set: function () {
  30558. console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
  30559. }
  30560. }
  30561. } );
  30562. Object.defineProperties( LOD.prototype, {
  30563. objects: {
  30564. get: function () {
  30565. console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
  30566. return this.levels;
  30567. }
  30568. }
  30569. } );
  30570. Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {
  30571. get: function () {
  30572. console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
  30573. },
  30574. set: function () {
  30575. console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
  30576. }
  30577. } );
  30578. SkinnedMesh.prototype.initBones = function () {
  30579. console.error( 'THREE.SkinnedMesh: initBones() has been removed.' );
  30580. };
  30581. Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {
  30582. get: function () {
  30583. console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
  30584. return this.arcLengthDivisions;
  30585. },
  30586. set: function ( value ) {
  30587. console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
  30588. this.arcLengthDivisions = value;
  30589. }
  30590. } );
  30591. //
  30592. PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
  30593. console.warn( 'THREE.PerspectiveCamera.setLens is deprecated. ' +
  30594. 'Use .setFocalLength and .filmGauge for a photographic setup.' );
  30595. if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
  30596. this.setFocalLength( focalLength );
  30597. };
  30598. //
  30599. Object.defineProperties( Light.prototype, {
  30600. onlyShadow: {
  30601. set: function () {
  30602. console.warn( 'THREE.Light: .onlyShadow has been removed.' );
  30603. }
  30604. },
  30605. shadowCameraFov: {
  30606. set: function ( value ) {
  30607. console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
  30608. this.shadow.camera.fov = value;
  30609. }
  30610. },
  30611. shadowCameraLeft: {
  30612. set: function ( value ) {
  30613. console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
  30614. this.shadow.camera.left = value;
  30615. }
  30616. },
  30617. shadowCameraRight: {
  30618. set: function ( value ) {
  30619. console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
  30620. this.shadow.camera.right = value;
  30621. }
  30622. },
  30623. shadowCameraTop: {
  30624. set: function ( value ) {
  30625. console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
  30626. this.shadow.camera.top = value;
  30627. }
  30628. },
  30629. shadowCameraBottom: {
  30630. set: function ( value ) {
  30631. console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
  30632. this.shadow.camera.bottom = value;
  30633. }
  30634. },
  30635. shadowCameraNear: {
  30636. set: function ( value ) {
  30637. console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
  30638. this.shadow.camera.near = value;
  30639. }
  30640. },
  30641. shadowCameraFar: {
  30642. set: function ( value ) {
  30643. console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
  30644. this.shadow.camera.far = value;
  30645. }
  30646. },
  30647. shadowCameraVisible: {
  30648. set: function () {
  30649. console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
  30650. }
  30651. },
  30652. shadowBias: {
  30653. set: function ( value ) {
  30654. console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
  30655. this.shadow.bias = value;
  30656. }
  30657. },
  30658. shadowDarkness: {
  30659. set: function () {
  30660. console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
  30661. }
  30662. },
  30663. shadowMapWidth: {
  30664. set: function ( value ) {
  30665. console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
  30666. this.shadow.mapSize.width = value;
  30667. }
  30668. },
  30669. shadowMapHeight: {
  30670. set: function ( value ) {
  30671. console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
  30672. this.shadow.mapSize.height = value;
  30673. }
  30674. }
  30675. } );
  30676. //
  30677. Object.defineProperties( BufferAttribute.prototype, {
  30678. length: {
  30679. get: function () {
  30680. console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
  30681. return this.array.length;
  30682. }
  30683. },
  30684. dynamic: {
  30685. get: function () {
  30686. console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
  30687. return this.usage === DynamicDrawUsage;
  30688. },
  30689. set: function ( /* value */ ) {
  30690. console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
  30691. this.setUsage( DynamicDrawUsage );
  30692. }
  30693. }
  30694. } );
  30695. Object.assign( BufferAttribute.prototype, {
  30696. setDynamic: function ( value ) {
  30697. //console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' );
  30698. this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
  30699. return this;
  30700. },
  30701. copyIndicesArray: function ( /* indices */ ) {
  30702. console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' );
  30703. },
  30704. setArray: function ( /* array */ ) {
  30705. console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
  30706. }
  30707. } );
  30708. Object.assign( BufferGeometry.prototype, {
  30709. addIndex: function ( index ) {
  30710. console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
  30711. this.setIndex( index );
  30712. },
  30713. addAttribute: function ( name, attribute ) {
  30714. console.warn( 'THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().' );
  30715. if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
  30716. console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
  30717. return this.setAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
  30718. }
  30719. if ( name === 'index' ) {
  30720. console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
  30721. this.setIndex( attribute );
  30722. return this;
  30723. }
  30724. return this.setAttribute( name, attribute );
  30725. },
  30726. addDrawCall: function ( start, count, indexOffset ) {
  30727. if ( indexOffset !== undefined ) {
  30728. console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
  30729. }
  30730. console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
  30731. this.addGroup( start, count );
  30732. },
  30733. clearDrawCalls: function () {
  30734. console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
  30735. this.clearGroups();
  30736. },
  30737. computeTangents: function () {
  30738. console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );
  30739. },
  30740. computeOffsets: function () {
  30741. console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
  30742. },
  30743. removeAttribute: function ( name ) {
  30744. console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' );
  30745. return this.deleteAttribute( name );
  30746. },
  30747. applyMatrix: function ( matrix ) {
  30748. console.warn( 'THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4().' );
  30749. return this.applyMatrix4( matrix );
  30750. }
  30751. } );
  30752. Object.defineProperties( BufferGeometry.prototype, {
  30753. drawcalls: {
  30754. get: function () {
  30755. console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
  30756. return this.groups;
  30757. }
  30758. },
  30759. offsets: {
  30760. get: function () {
  30761. console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
  30762. return this.groups;
  30763. }
  30764. }
  30765. } );
  30766. Object.defineProperties( InstancedBufferGeometry.prototype, {
  30767. maxInstancedCount: {
  30768. get: function () {
  30769. console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
  30770. return this.instanceCount;
  30771. },
  30772. set: function ( value ) {
  30773. console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
  30774. this.instanceCount = value;
  30775. }
  30776. }
  30777. } );
  30778. Object.defineProperties( Raycaster.prototype, {
  30779. linePrecision: {
  30780. get: function () {
  30781. console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
  30782. return this.params.Line.threshold;
  30783. },
  30784. set: function ( value ) {
  30785. console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
  30786. this.params.Line.threshold = value;
  30787. }
  30788. }
  30789. } );
  30790. Object.defineProperties( InterleavedBuffer.prototype, {
  30791. dynamic: {
  30792. get: function () {
  30793. console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
  30794. return this.usage === DynamicDrawUsage;
  30795. },
  30796. set: function ( value ) {
  30797. console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
  30798. this.setUsage( value );
  30799. }
  30800. }
  30801. } );
  30802. Object.assign( InterleavedBuffer.prototype, {
  30803. setDynamic: function ( value ) {
  30804. console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' );
  30805. this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
  30806. return this;
  30807. },
  30808. setArray: function ( /* array */ ) {
  30809. console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
  30810. }
  30811. } );
  30812. //
  30813. Object.assign( ExtrudeBufferGeometry.prototype, {
  30814. getArrays: function () {
  30815. console.error( 'THREE.ExtrudeBufferGeometry: .getArrays() has been removed.' );
  30816. },
  30817. addShapeList: function () {
  30818. console.error( 'THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.' );
  30819. },
  30820. addShape: function () {
  30821. console.error( 'THREE.ExtrudeBufferGeometry: .addShape() has been removed.' );
  30822. }
  30823. } );
  30824. //
  30825. Object.assign( Scene.prototype, {
  30826. dispose: function () {
  30827. console.error( 'THREE.Scene: .dispose() has been removed.' );
  30828. }
  30829. } );
  30830. //
  30831. Object.defineProperties( Uniform.prototype, {
  30832. dynamic: {
  30833. set: function () {
  30834. console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
  30835. }
  30836. },
  30837. onUpdate: {
  30838. value: function () {
  30839. console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
  30840. return this;
  30841. }
  30842. }
  30843. } );
  30844. //
  30845. Object.defineProperties( Material.prototype, {
  30846. wrapAround: {
  30847. get: function () {
  30848. console.warn( 'THREE.Material: .wrapAround has been removed.' );
  30849. },
  30850. set: function () {
  30851. console.warn( 'THREE.Material: .wrapAround has been removed.' );
  30852. }
  30853. },
  30854. overdraw: {
  30855. get: function () {
  30856. console.warn( 'THREE.Material: .overdraw has been removed.' );
  30857. },
  30858. set: function () {
  30859. console.warn( 'THREE.Material: .overdraw has been removed.' );
  30860. }
  30861. },
  30862. wrapRGB: {
  30863. get: function () {
  30864. console.warn( 'THREE.Material: .wrapRGB has been removed.' );
  30865. return new Color();
  30866. }
  30867. },
  30868. shading: {
  30869. get: function () {
  30870. console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
  30871. },
  30872. set: function ( value ) {
  30873. console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
  30874. this.flatShading = ( value === FlatShading );
  30875. }
  30876. },
  30877. stencilMask: {
  30878. get: function () {
  30879. console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
  30880. return this.stencilFuncMask;
  30881. },
  30882. set: function ( value ) {
  30883. console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
  30884. this.stencilFuncMask = value;
  30885. }
  30886. }
  30887. } );
  30888. Object.defineProperties( MeshPhongMaterial.prototype, {
  30889. metal: {
  30890. get: function () {
  30891. console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
  30892. return false;
  30893. },
  30894. set: function () {
  30895. console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
  30896. }
  30897. }
  30898. } );
  30899. Object.defineProperties( MeshPhysicalMaterial.prototype, {
  30900. transparency: {
  30901. get: function () {
  30902. console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
  30903. return this.transmission;
  30904. },
  30905. set: function ( value ) {
  30906. console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
  30907. this.transmission = value;
  30908. }
  30909. }
  30910. } );
  30911. Object.defineProperties( ShaderMaterial.prototype, {
  30912. derivatives: {
  30913. get: function () {
  30914. console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
  30915. return this.extensions.derivatives;
  30916. },
  30917. set: function ( value ) {
  30918. console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
  30919. this.extensions.derivatives = value;
  30920. }
  30921. }
  30922. } );
  30923. //
  30924. Object.assign( WebGLRenderer.prototype, {
  30925. clearTarget: function ( renderTarget, color, depth, stencil ) {
  30926. console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' );
  30927. this.setRenderTarget( renderTarget );
  30928. this.clear( color, depth, stencil );
  30929. },
  30930. animate: function ( callback ) {
  30931. console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' );
  30932. this.setAnimationLoop( callback );
  30933. },
  30934. getCurrentRenderTarget: function () {
  30935. console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
  30936. return this.getRenderTarget();
  30937. },
  30938. getMaxAnisotropy: function () {
  30939. console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
  30940. return this.capabilities.getMaxAnisotropy();
  30941. },
  30942. getPrecision: function () {
  30943. console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
  30944. return this.capabilities.precision;
  30945. },
  30946. resetGLState: function () {
  30947. console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' );
  30948. return this.state.reset();
  30949. },
  30950. supportsFloatTextures: function () {
  30951. console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
  30952. return this.extensions.get( 'OES_texture_float' );
  30953. },
  30954. supportsHalfFloatTextures: function () {
  30955. console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
  30956. return this.extensions.get( 'OES_texture_half_float' );
  30957. },
  30958. supportsStandardDerivatives: function () {
  30959. console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
  30960. return this.extensions.get( 'OES_standard_derivatives' );
  30961. },
  30962. supportsCompressedTextureS3TC: function () {
  30963. console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
  30964. return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
  30965. },
  30966. supportsCompressedTexturePVRTC: function () {
  30967. console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
  30968. return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
  30969. },
  30970. supportsBlendMinMax: function () {
  30971. console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
  30972. return this.extensions.get( 'EXT_blend_minmax' );
  30973. },
  30974. supportsVertexTextures: function () {
  30975. console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
  30976. return this.capabilities.vertexTextures;
  30977. },
  30978. supportsInstancedArrays: function () {
  30979. console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
  30980. return this.extensions.get( 'ANGLE_instanced_arrays' );
  30981. },
  30982. enableScissorTest: function ( boolean ) {
  30983. console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
  30984. this.setScissorTest( boolean );
  30985. },
  30986. initMaterial: function () {
  30987. console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
  30988. },
  30989. addPrePlugin: function () {
  30990. console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
  30991. },
  30992. addPostPlugin: function () {
  30993. console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
  30994. },
  30995. updateShadowMap: function () {
  30996. console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
  30997. },
  30998. setFaceCulling: function () {
  30999. console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' );
  31000. },
  31001. allocTextureUnit: function () {
  31002. console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' );
  31003. },
  31004. setTexture: function () {
  31005. console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' );
  31006. },
  31007. setTexture2D: function () {
  31008. console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' );
  31009. },
  31010. setTextureCube: function () {
  31011. console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' );
  31012. },
  31013. getActiveMipMapLevel: function () {
  31014. console.warn( 'THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel().' );
  31015. return this.getActiveMipmapLevel();
  31016. }
  31017. } );
  31018. Object.defineProperties( WebGLRenderer.prototype, {
  31019. shadowMapEnabled: {
  31020. get: function () {
  31021. return this.shadowMap.enabled;
  31022. },
  31023. set: function ( value ) {
  31024. console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
  31025. this.shadowMap.enabled = value;
  31026. }
  31027. },
  31028. shadowMapType: {
  31029. get: function () {
  31030. return this.shadowMap.type;
  31031. },
  31032. set: function ( value ) {
  31033. console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
  31034. this.shadowMap.type = value;
  31035. }
  31036. },
  31037. shadowMapCullFace: {
  31038. get: function () {
  31039. console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
  31040. return undefined;
  31041. },
  31042. set: function ( /* value */ ) {
  31043. console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
  31044. }
  31045. },
  31046. context: {
  31047. get: function () {
  31048. console.warn( 'THREE.WebGLRenderer: .context has been removed. Use .getContext() instead.' );
  31049. return this.getContext();
  31050. }
  31051. },
  31052. vr: {
  31053. get: function () {
  31054. console.warn( 'THREE.WebGLRenderer: .vr has been renamed to .xr' );
  31055. return this.xr;
  31056. }
  31057. },
  31058. gammaInput: {
  31059. get: function () {
  31060. console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
  31061. return false;
  31062. },
  31063. set: function () {
  31064. console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
  31065. }
  31066. },
  31067. gammaOutput: {
  31068. get: function () {
  31069. console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
  31070. return false;
  31071. },
  31072. set: function ( value ) {
  31073. console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
  31074. this.outputEncoding = ( value === true ) ? sRGBEncoding : LinearEncoding;
  31075. }
  31076. },
  31077. toneMappingWhitePoint: {
  31078. get: function () {
  31079. console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
  31080. return 1.0;
  31081. },
  31082. set: function () {
  31083. console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
  31084. }
  31085. },
  31086. } );
  31087. Object.defineProperties( WebGLShadowMap.prototype, {
  31088. cullFace: {
  31089. get: function () {
  31090. console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
  31091. return undefined;
  31092. },
  31093. set: function ( /* cullFace */ ) {
  31094. console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
  31095. }
  31096. },
  31097. renderReverseSided: {
  31098. get: function () {
  31099. console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
  31100. return undefined;
  31101. },
  31102. set: function () {
  31103. console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
  31104. }
  31105. },
  31106. renderSingleSided: {
  31107. get: function () {
  31108. console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
  31109. return undefined;
  31110. },
  31111. set: function () {
  31112. console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
  31113. }
  31114. }
  31115. } );
  31116. function WebGLRenderTargetCube( width, height, options ) {
  31117. console.warn( 'THREE.WebGLRenderTargetCube( width, height, options ) is now WebGLCubeRenderTarget( size, options ).' );
  31118. return new WebGLCubeRenderTarget( width, options );
  31119. }
  31120. //
  31121. Object.defineProperties( WebGLRenderTarget.prototype, {
  31122. wrapS: {
  31123. get: function () {
  31124. console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
  31125. return this.texture.wrapS;
  31126. },
  31127. set: function ( value ) {
  31128. console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
  31129. this.texture.wrapS = value;
  31130. }
  31131. },
  31132. wrapT: {
  31133. get: function () {
  31134. console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
  31135. return this.texture.wrapT;
  31136. },
  31137. set: function ( value ) {
  31138. console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
  31139. this.texture.wrapT = value;
  31140. }
  31141. },
  31142. magFilter: {
  31143. get: function () {
  31144. console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
  31145. return this.texture.magFilter;
  31146. },
  31147. set: function ( value ) {
  31148. console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
  31149. this.texture.magFilter = value;
  31150. }
  31151. },
  31152. minFilter: {
  31153. get: function () {
  31154. console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
  31155. return this.texture.minFilter;
  31156. },
  31157. set: function ( value ) {
  31158. console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
  31159. this.texture.minFilter = value;
  31160. }
  31161. },
  31162. anisotropy: {
  31163. get: function () {
  31164. console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
  31165. return this.texture.anisotropy;
  31166. },
  31167. set: function ( value ) {
  31168. console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
  31169. this.texture.anisotropy = value;
  31170. }
  31171. },
  31172. offset: {
  31173. get: function () {
  31174. console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
  31175. return this.texture.offset;
  31176. },
  31177. set: function ( value ) {
  31178. console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
  31179. this.texture.offset = value;
  31180. }
  31181. },
  31182. repeat: {
  31183. get: function () {
  31184. console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
  31185. return this.texture.repeat;
  31186. },
  31187. set: function ( value ) {
  31188. console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
  31189. this.texture.repeat = value;
  31190. }
  31191. },
  31192. format: {
  31193. get: function () {
  31194. console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
  31195. return this.texture.format;
  31196. },
  31197. set: function ( value ) {
  31198. console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
  31199. this.texture.format = value;
  31200. }
  31201. },
  31202. type: {
  31203. get: function () {
  31204. console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
  31205. return this.texture.type;
  31206. },
  31207. set: function ( value ) {
  31208. console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
  31209. this.texture.type = value;
  31210. }
  31211. },
  31212. generateMipmaps: {
  31213. get: function () {
  31214. console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
  31215. return this.texture.generateMipmaps;
  31216. },
  31217. set: function ( value ) {
  31218. console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
  31219. this.texture.generateMipmaps = value;
  31220. }
  31221. }
  31222. } );
  31223. //
  31224. Object.defineProperties( Audio.prototype, {
  31225. load: {
  31226. value: function ( file ) {
  31227. console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
  31228. const scope = this;
  31229. const audioLoader = new AudioLoader();
  31230. audioLoader.load( file, function ( buffer ) {
  31231. scope.setBuffer( buffer );
  31232. } );
  31233. return this;
  31234. }
  31235. },
  31236. startTime: {
  31237. set: function () {
  31238. console.warn( 'THREE.Audio: .startTime is now .play( delay ).' );
  31239. }
  31240. }
  31241. } );
  31242. AudioAnalyser.prototype.getData = function () {
  31243. console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
  31244. return this.getFrequencyData();
  31245. };
  31246. //
  31247. CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
  31248. console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
  31249. return this.update( renderer, scene );
  31250. };
  31251. CubeCamera.prototype.clear = function ( renderer, color, depth, stencil ) {
  31252. console.warn( 'THREE.CubeCamera: .clear() is now .renderTarget.clear().' );
  31253. return this.renderTarget.clear( renderer, color, depth, stencil );
  31254. };
  31255. //
  31256. const GeometryUtils = {
  31257. merge: function ( geometry1, geometry2, materialIndexOffset ) {
  31258. console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
  31259. let matrix;
  31260. if ( geometry2.isMesh ) {
  31261. geometry2.matrixAutoUpdate && geometry2.updateMatrix();
  31262. matrix = geometry2.matrix;
  31263. geometry2 = geometry2.geometry;
  31264. }
  31265. geometry1.merge( geometry2, matrix, materialIndexOffset );
  31266. },
  31267. center: function ( geometry ) {
  31268. console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
  31269. return geometry.center();
  31270. }
  31271. };
  31272. ImageUtils.crossOrigin = undefined;
  31273. ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) {
  31274. console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
  31275. const loader = new TextureLoader();
  31276. loader.setCrossOrigin( this.crossOrigin );
  31277. const texture = loader.load( url, onLoad, undefined, onError );
  31278. if ( mapping ) texture.mapping = mapping;
  31279. return texture;
  31280. };
  31281. ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) {
  31282. console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
  31283. const loader = new CubeTextureLoader();
  31284. loader.setCrossOrigin( this.crossOrigin );
  31285. const texture = loader.load( urls, onLoad, undefined, onError );
  31286. if ( mapping ) texture.mapping = mapping;
  31287. return texture;
  31288. };
  31289. ImageUtils.loadCompressedTexture = function () {
  31290. console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
  31291. };
  31292. ImageUtils.loadCompressedTextureCube = function () {
  31293. console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
  31294. };
  31295. //
  31296. function CanvasRenderer() {
  31297. console.error( 'THREE.CanvasRenderer has been removed' );
  31298. }
  31299. //
  31300. function JSONLoader() {
  31301. console.error( 'THREE.JSONLoader has been removed.' );
  31302. }
  31303. //
  31304. const SceneUtils = {
  31305. createMultiMaterialObject: function ( /* geometry, materials */ ) {
  31306. console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
  31307. },
  31308. detach: function ( /* child, parent, scene */ ) {
  31309. console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
  31310. },
  31311. attach: function ( /* child, scene, parent */ ) {
  31312. console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
  31313. }
  31314. };
  31315. //
  31316. function LensFlare() {
  31317. console.error( 'THREE.LensFlare has been moved to /examples/jsm/objects/Lensflare.js' );
  31318. }
  31319. if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
  31320. /* eslint-disable no-undef */
  31321. __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
  31322. revision: REVISION,
  31323. } } ) );
  31324. /* eslint-enable no-undef */
  31325. }
  31326. var THREE$1 = /*#__PURE__*/Object.freeze({
  31327. __proto__: null,
  31328. ACESFilmicToneMapping: ACESFilmicToneMapping,
  31329. AddEquation: AddEquation,
  31330. AddOperation: AddOperation,
  31331. AdditiveAnimationBlendMode: AdditiveAnimationBlendMode,
  31332. AdditiveBlending: AdditiveBlending,
  31333. AlphaFormat: AlphaFormat,
  31334. AlwaysDepth: AlwaysDepth,
  31335. AlwaysStencilFunc: AlwaysStencilFunc,
  31336. AmbientLight: AmbientLight,
  31337. AmbientLightProbe: AmbientLightProbe,
  31338. AnimationClip: AnimationClip,
  31339. AnimationLoader: AnimationLoader,
  31340. AnimationMixer: AnimationMixer,
  31341. AnimationObjectGroup: AnimationObjectGroup,
  31342. AnimationUtils: AnimationUtils,
  31343. ArcCurve: ArcCurve,
  31344. ArrayCamera: ArrayCamera,
  31345. ArrowHelper: ArrowHelper,
  31346. Audio: Audio,
  31347. AudioAnalyser: AudioAnalyser,
  31348. AudioContext: AudioContext,
  31349. AudioListener: AudioListener,
  31350. AudioLoader: AudioLoader,
  31351. AxesHelper: AxesHelper,
  31352. AxisHelper: AxisHelper,
  31353. BackSide: BackSide,
  31354. BasicDepthPacking: BasicDepthPacking,
  31355. BasicShadowMap: BasicShadowMap,
  31356. BinaryTextureLoader: BinaryTextureLoader,
  31357. Bone: Bone,
  31358. BooleanKeyframeTrack: BooleanKeyframeTrack,
  31359. BoundingBoxHelper: BoundingBoxHelper,
  31360. Box2: Box2,
  31361. Box3: Box3,
  31362. Box3Helper: Box3Helper,
  31363. BoxBufferGeometry: BoxBufferGeometry,
  31364. BoxGeometry: BoxGeometry,
  31365. BoxHelper: BoxHelper,
  31366. BufferAttribute: BufferAttribute,
  31367. BufferGeometry: BufferGeometry,
  31368. BufferGeometryLoader: BufferGeometryLoader,
  31369. ByteType: ByteType,
  31370. Cache: Cache,
  31371. Camera: Camera,
  31372. CameraHelper: CameraHelper,
  31373. CanvasRenderer: CanvasRenderer,
  31374. CanvasTexture: CanvasTexture,
  31375. CatmullRomCurve3: CatmullRomCurve3,
  31376. CineonToneMapping: CineonToneMapping,
  31377. CircleBufferGeometry: CircleBufferGeometry,
  31378. CircleGeometry: CircleGeometry,
  31379. ClampToEdgeWrapping: ClampToEdgeWrapping,
  31380. Clock: Clock,
  31381. ClosedSplineCurve3: ClosedSplineCurve3,
  31382. Color: Color,
  31383. ColorKeyframeTrack: ColorKeyframeTrack,
  31384. CompressedTexture: CompressedTexture,
  31385. CompressedTextureLoader: CompressedTextureLoader,
  31386. ConeBufferGeometry: ConeBufferGeometry,
  31387. ConeGeometry: ConeGeometry,
  31388. CubeCamera: CubeCamera,
  31389. CubeGeometry: BoxGeometry,
  31390. CubeReflectionMapping: CubeReflectionMapping,
  31391. CubeRefractionMapping: CubeRefractionMapping,
  31392. CubeTexture: CubeTexture,
  31393. CubeTextureLoader: CubeTextureLoader,
  31394. CubeUVReflectionMapping: CubeUVReflectionMapping,
  31395. CubeUVRefractionMapping: CubeUVRefractionMapping,
  31396. CubicBezierCurve: CubicBezierCurve,
  31397. CubicBezierCurve3: CubicBezierCurve3,
  31398. CubicInterpolant: CubicInterpolant,
  31399. CullFaceBack: CullFaceBack,
  31400. CullFaceFront: CullFaceFront,
  31401. CullFaceFrontBack: CullFaceFrontBack,
  31402. CullFaceNone: CullFaceNone,
  31403. Curve: Curve,
  31404. CurvePath: CurvePath,
  31405. CustomBlending: CustomBlending,
  31406. CustomToneMapping: CustomToneMapping,
  31407. CylinderBufferGeometry: CylinderBufferGeometry,
  31408. CylinderGeometry: CylinderGeometry,
  31409. Cylindrical: Cylindrical,
  31410. DataTexture: DataTexture,
  31411. DataTexture2DArray: DataTexture2DArray,
  31412. DataTexture3D: DataTexture3D,
  31413. DataTextureLoader: DataTextureLoader,
  31414. DataUtils: DataUtils,
  31415. DecrementStencilOp: DecrementStencilOp,
  31416. DecrementWrapStencilOp: DecrementWrapStencilOp,
  31417. DefaultLoadingManager: DefaultLoadingManager,
  31418. DepthFormat: DepthFormat,
  31419. DepthStencilFormat: DepthStencilFormat,
  31420. DepthTexture: DepthTexture,
  31421. DirectionalLight: DirectionalLight,
  31422. DirectionalLightHelper: DirectionalLightHelper,
  31423. DiscreteInterpolant: DiscreteInterpolant,
  31424. DodecahedronBufferGeometry: DodecahedronBufferGeometry,
  31425. DodecahedronGeometry: DodecahedronGeometry,
  31426. DoubleSide: DoubleSide,
  31427. DstAlphaFactor: DstAlphaFactor,
  31428. DstColorFactor: DstColorFactor,
  31429. DynamicBufferAttribute: DynamicBufferAttribute,
  31430. DynamicCopyUsage: DynamicCopyUsage,
  31431. DynamicDrawUsage: DynamicDrawUsage,
  31432. DynamicReadUsage: DynamicReadUsage,
  31433. EdgesGeometry: EdgesGeometry,
  31434. EdgesHelper: EdgesHelper,
  31435. EllipseCurve: EllipseCurve,
  31436. EqualDepth: EqualDepth,
  31437. EqualStencilFunc: EqualStencilFunc,
  31438. EquirectangularReflectionMapping: EquirectangularReflectionMapping,
  31439. EquirectangularRefractionMapping: EquirectangularRefractionMapping,
  31440. Euler: Euler,
  31441. EventDispatcher: EventDispatcher,
  31442. ExtrudeBufferGeometry: ExtrudeBufferGeometry,
  31443. ExtrudeGeometry: ExtrudeGeometry,
  31444. Face3: Face3,
  31445. Face4: Face4,
  31446. FaceColors: FaceColors,
  31447. FileLoader: FileLoader,
  31448. FlatShading: FlatShading,
  31449. Float16BufferAttribute: Float16BufferAttribute,
  31450. Float32Attribute: Float32Attribute,
  31451. Float32BufferAttribute: Float32BufferAttribute,
  31452. Float64Attribute: Float64Attribute,
  31453. Float64BufferAttribute: Float64BufferAttribute,
  31454. FloatType: FloatType,
  31455. Fog: Fog,
  31456. FogExp2: FogExp2,
  31457. Font: Font,
  31458. FontLoader: FontLoader,
  31459. FrontSide: FrontSide,
  31460. Frustum: Frustum,
  31461. GLBufferAttribute: GLBufferAttribute,
  31462. GLSL1: GLSL1,
  31463. GLSL3: GLSL3,
  31464. GammaEncoding: GammaEncoding,
  31465. Geometry: Geometry,
  31466. GeometryUtils: GeometryUtils,
  31467. GreaterDepth: GreaterDepth,
  31468. GreaterEqualDepth: GreaterEqualDepth,
  31469. GreaterEqualStencilFunc: GreaterEqualStencilFunc,
  31470. GreaterStencilFunc: GreaterStencilFunc,
  31471. GridHelper: GridHelper,
  31472. Group: Group,
  31473. HalfFloatType: HalfFloatType,
  31474. HemisphereLight: HemisphereLight,
  31475. HemisphereLightHelper: HemisphereLightHelper,
  31476. HemisphereLightProbe: HemisphereLightProbe,
  31477. IcosahedronBufferGeometry: IcosahedronBufferGeometry,
  31478. IcosahedronGeometry: IcosahedronGeometry,
  31479. ImageBitmapLoader: ImageBitmapLoader,
  31480. ImageLoader: ImageLoader,
  31481. ImageUtils: ImageUtils,
  31482. ImmediateRenderObject: ImmediateRenderObject,
  31483. IncrementStencilOp: IncrementStencilOp,
  31484. IncrementWrapStencilOp: IncrementWrapStencilOp,
  31485. InstancedBufferAttribute: InstancedBufferAttribute,
  31486. InstancedBufferGeometry: InstancedBufferGeometry,
  31487. InstancedInterleavedBuffer: InstancedInterleavedBuffer,
  31488. InstancedMesh: InstancedMesh,
  31489. Int16Attribute: Int16Attribute,
  31490. Int16BufferAttribute: Int16BufferAttribute,
  31491. Int32Attribute: Int32Attribute,
  31492. Int32BufferAttribute: Int32BufferAttribute,
  31493. Int8Attribute: Int8Attribute,
  31494. Int8BufferAttribute: Int8BufferAttribute,
  31495. IntType: IntType,
  31496. InterleavedBuffer: InterleavedBuffer,
  31497. InterleavedBufferAttribute: InterleavedBufferAttribute,
  31498. Interpolant: Interpolant,
  31499. InterpolateDiscrete: InterpolateDiscrete,
  31500. InterpolateLinear: InterpolateLinear,
  31501. InterpolateSmooth: InterpolateSmooth,
  31502. InvertStencilOp: InvertStencilOp,
  31503. JSONLoader: JSONLoader,
  31504. KeepStencilOp: KeepStencilOp,
  31505. KeyframeTrack: KeyframeTrack,
  31506. LOD: LOD,
  31507. LatheBufferGeometry: LatheBufferGeometry,
  31508. LatheGeometry: LatheGeometry,
  31509. Layers: Layers,
  31510. LensFlare: LensFlare,
  31511. LessDepth: LessDepth,
  31512. LessEqualDepth: LessEqualDepth,
  31513. LessEqualStencilFunc: LessEqualStencilFunc,
  31514. LessStencilFunc: LessStencilFunc,
  31515. Light: Light,
  31516. LightProbe: LightProbe,
  31517. Line: Line,
  31518. Line3: Line3,
  31519. LineBasicMaterial: LineBasicMaterial,
  31520. LineCurve: LineCurve,
  31521. LineCurve3: LineCurve3,
  31522. LineDashedMaterial: LineDashedMaterial,
  31523. LineLoop: LineLoop,
  31524. LinePieces: LinePieces,
  31525. LineSegments: LineSegments,
  31526. LineStrip: LineStrip,
  31527. LinearEncoding: LinearEncoding,
  31528. LinearFilter: LinearFilter,
  31529. LinearInterpolant: LinearInterpolant,
  31530. LinearMipMapLinearFilter: LinearMipMapLinearFilter,
  31531. LinearMipMapNearestFilter: LinearMipMapNearestFilter,
  31532. LinearMipmapLinearFilter: LinearMipmapLinearFilter,
  31533. LinearMipmapNearestFilter: LinearMipmapNearestFilter,
  31534. LinearToneMapping: LinearToneMapping,
  31535. Loader: Loader,
  31536. LoaderUtils: LoaderUtils,
  31537. LoadingManager: LoadingManager,
  31538. LogLuvEncoding: LogLuvEncoding,
  31539. LoopOnce: LoopOnce,
  31540. LoopPingPong: LoopPingPong,
  31541. LoopRepeat: LoopRepeat,
  31542. LuminanceAlphaFormat: LuminanceAlphaFormat,
  31543. LuminanceFormat: LuminanceFormat,
  31544. MOUSE: MOUSE,
  31545. Material: Material,
  31546. MaterialLoader: MaterialLoader,
  31547. Math: MathUtils,
  31548. MathUtils: MathUtils,
  31549. Matrix3: Matrix3,
  31550. Matrix4: Matrix4,
  31551. MaxEquation: MaxEquation,
  31552. Mesh: Mesh,
  31553. MeshBasicMaterial: MeshBasicMaterial,
  31554. MeshDepthMaterial: MeshDepthMaterial,
  31555. MeshDistanceMaterial: MeshDistanceMaterial,
  31556. MeshFaceMaterial: MeshFaceMaterial,
  31557. MeshLambertMaterial: MeshLambertMaterial,
  31558. MeshMatcapMaterial: MeshMatcapMaterial,
  31559. MeshNormalMaterial: MeshNormalMaterial,
  31560. MeshPhongMaterial: MeshPhongMaterial,
  31561. MeshPhysicalMaterial: MeshPhysicalMaterial,
  31562. MeshStandardMaterial: MeshStandardMaterial,
  31563. MeshToonMaterial: MeshToonMaterial,
  31564. MinEquation: MinEquation,
  31565. MirroredRepeatWrapping: MirroredRepeatWrapping,
  31566. MixOperation: MixOperation,
  31567. MultiMaterial: MultiMaterial,
  31568. MultiplyBlending: MultiplyBlending,
  31569. MultiplyOperation: MultiplyOperation,
  31570. NearestFilter: NearestFilter,
  31571. NearestMipMapLinearFilter: NearestMipMapLinearFilter,
  31572. NearestMipMapNearestFilter: NearestMipMapNearestFilter,
  31573. NearestMipmapLinearFilter: NearestMipmapLinearFilter,
  31574. NearestMipmapNearestFilter: NearestMipmapNearestFilter,
  31575. NeverDepth: NeverDepth,
  31576. NeverStencilFunc: NeverStencilFunc,
  31577. NoBlending: NoBlending,
  31578. NoColors: NoColors,
  31579. NoToneMapping: NoToneMapping,
  31580. NormalAnimationBlendMode: NormalAnimationBlendMode,
  31581. NormalBlending: NormalBlending,
  31582. NotEqualDepth: NotEqualDepth,
  31583. NotEqualStencilFunc: NotEqualStencilFunc,
  31584. NumberKeyframeTrack: NumberKeyframeTrack,
  31585. Object3D: Object3D,
  31586. ObjectLoader: ObjectLoader,
  31587. ObjectSpaceNormalMap: ObjectSpaceNormalMap,
  31588. OctahedronBufferGeometry: OctahedronBufferGeometry,
  31589. OctahedronGeometry: OctahedronGeometry,
  31590. OneFactor: OneFactor,
  31591. OneMinusDstAlphaFactor: OneMinusDstAlphaFactor,
  31592. OneMinusDstColorFactor: OneMinusDstColorFactor,
  31593. OneMinusSrcAlphaFactor: OneMinusSrcAlphaFactor,
  31594. OneMinusSrcColorFactor: OneMinusSrcColorFactor,
  31595. OrthographicCamera: OrthographicCamera,
  31596. PCFShadowMap: PCFShadowMap,
  31597. PCFSoftShadowMap: PCFSoftShadowMap,
  31598. PMREMGenerator: PMREMGenerator,
  31599. ParametricBufferGeometry: ParametricBufferGeometry,
  31600. ParametricGeometry: ParametricGeometry,
  31601. Particle: Particle,
  31602. ParticleBasicMaterial: ParticleBasicMaterial,
  31603. ParticleSystem: ParticleSystem,
  31604. ParticleSystemMaterial: ParticleSystemMaterial,
  31605. Path: Path,
  31606. PerspectiveCamera: PerspectiveCamera,
  31607. Plane: Plane,
  31608. PlaneBufferGeometry: PlaneBufferGeometry,
  31609. PlaneGeometry: PlaneGeometry,
  31610. PlaneHelper: PlaneHelper,
  31611. PointCloud: PointCloud,
  31612. PointCloudMaterial: PointCloudMaterial,
  31613. PointLight: PointLight,
  31614. PointLightHelper: PointLightHelper,
  31615. Points: Points,
  31616. PointsMaterial: PointsMaterial,
  31617. PolarGridHelper: PolarGridHelper,
  31618. PolyhedronBufferGeometry: PolyhedronBufferGeometry,
  31619. PolyhedronGeometry: PolyhedronGeometry,
  31620. PositionalAudio: PositionalAudio,
  31621. PropertyBinding: PropertyBinding,
  31622. PropertyMixer: PropertyMixer,
  31623. QuadraticBezierCurve: QuadraticBezierCurve,
  31624. QuadraticBezierCurve3: QuadraticBezierCurve3,
  31625. Quaternion: Quaternion,
  31626. QuaternionKeyframeTrack: QuaternionKeyframeTrack,
  31627. QuaternionLinearInterpolant: QuaternionLinearInterpolant,
  31628. REVISION: REVISION,
  31629. RGBADepthPacking: RGBADepthPacking,
  31630. RGBAFormat: RGBAFormat,
  31631. RGBAIntegerFormat: RGBAIntegerFormat,
  31632. RGBA_ASTC_10x10_Format: RGBA_ASTC_10x10_Format,
  31633. RGBA_ASTC_10x5_Format: RGBA_ASTC_10x5_Format,
  31634. RGBA_ASTC_10x6_Format: RGBA_ASTC_10x6_Format,
  31635. RGBA_ASTC_10x8_Format: RGBA_ASTC_10x8_Format,
  31636. RGBA_ASTC_12x10_Format: RGBA_ASTC_12x10_Format,
  31637. RGBA_ASTC_12x12_Format: RGBA_ASTC_12x12_Format,
  31638. RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
  31639. RGBA_ASTC_5x4_Format: RGBA_ASTC_5x4_Format,
  31640. RGBA_ASTC_5x5_Format: RGBA_ASTC_5x5_Format,
  31641. RGBA_ASTC_6x5_Format: RGBA_ASTC_6x5_Format,
  31642. RGBA_ASTC_6x6_Format: RGBA_ASTC_6x6_Format,
  31643. RGBA_ASTC_8x5_Format: RGBA_ASTC_8x5_Format,
  31644. RGBA_ASTC_8x6_Format: RGBA_ASTC_8x6_Format,
  31645. RGBA_ASTC_8x8_Format: RGBA_ASTC_8x8_Format,
  31646. RGBA_BPTC_Format: RGBA_BPTC_Format,
  31647. RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
  31648. RGBA_PVRTC_2BPPV1_Format: RGBA_PVRTC_2BPPV1_Format,
  31649. RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
  31650. RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format$1,
  31651. RGBA_S3TC_DXT3_Format: RGBA_S3TC_DXT3_Format,
  31652. RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format$1,
  31653. RGBDEncoding: RGBDEncoding,
  31654. RGBEEncoding: RGBEEncoding,
  31655. RGBEFormat: RGBEFormat,
  31656. RGBFormat: RGBFormat,
  31657. RGBIntegerFormat: RGBIntegerFormat,
  31658. RGBM16Encoding: RGBM16Encoding,
  31659. RGBM7Encoding: RGBM7Encoding,
  31660. RGB_ETC1_Format: RGB_ETC1_Format,
  31661. RGB_ETC2_Format: RGB_ETC2_Format,
  31662. RGB_PVRTC_2BPPV1_Format: RGB_PVRTC_2BPPV1_Format,
  31663. RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
  31664. RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format,
  31665. RGFormat: RGFormat,
  31666. RGIntegerFormat: RGIntegerFormat,
  31667. RawShaderMaterial: RawShaderMaterial,
  31668. Ray: Ray,
  31669. Raycaster: Raycaster,
  31670. RectAreaLight: RectAreaLight,
  31671. RedFormat: RedFormat,
  31672. RedIntegerFormat: RedIntegerFormat,
  31673. ReinhardToneMapping: ReinhardToneMapping,
  31674. RepeatWrapping: RepeatWrapping,
  31675. ReplaceStencilOp: ReplaceStencilOp,
  31676. ReverseSubtractEquation: ReverseSubtractEquation,
  31677. RingBufferGeometry: RingBufferGeometry,
  31678. RingGeometry: RingGeometry,
  31679. SRGB8_ALPHA8_ASTC_10x10_Format: SRGB8_ALPHA8_ASTC_10x10_Format,
  31680. SRGB8_ALPHA8_ASTC_10x5_Format: SRGB8_ALPHA8_ASTC_10x5_Format,
  31681. SRGB8_ALPHA8_ASTC_10x6_Format: SRGB8_ALPHA8_ASTC_10x6_Format,
  31682. SRGB8_ALPHA8_ASTC_10x8_Format: SRGB8_ALPHA8_ASTC_10x8_Format,
  31683. SRGB8_ALPHA8_ASTC_12x10_Format: SRGB8_ALPHA8_ASTC_12x10_Format,
  31684. SRGB8_ALPHA8_ASTC_12x12_Format: SRGB8_ALPHA8_ASTC_12x12_Format,
  31685. SRGB8_ALPHA8_ASTC_4x4_Format: SRGB8_ALPHA8_ASTC_4x4_Format,
  31686. SRGB8_ALPHA8_ASTC_5x4_Format: SRGB8_ALPHA8_ASTC_5x4_Format,
  31687. SRGB8_ALPHA8_ASTC_5x5_Format: SRGB8_ALPHA8_ASTC_5x5_Format,
  31688. SRGB8_ALPHA8_ASTC_6x5_Format: SRGB8_ALPHA8_ASTC_6x5_Format,
  31689. SRGB8_ALPHA8_ASTC_6x6_Format: SRGB8_ALPHA8_ASTC_6x6_Format,
  31690. SRGB8_ALPHA8_ASTC_8x5_Format: SRGB8_ALPHA8_ASTC_8x5_Format,
  31691. SRGB8_ALPHA8_ASTC_8x6_Format: SRGB8_ALPHA8_ASTC_8x6_Format,
  31692. SRGB8_ALPHA8_ASTC_8x8_Format: SRGB8_ALPHA8_ASTC_8x8_Format,
  31693. Scene: Scene,
  31694. SceneUtils: SceneUtils,
  31695. ShaderChunk: ShaderChunk,
  31696. ShaderLib: ShaderLib,
  31697. ShaderMaterial: ShaderMaterial,
  31698. ShadowMaterial: ShadowMaterial,
  31699. Shape: Shape,
  31700. ShapeBufferGeometry: ShapeBufferGeometry,
  31701. ShapeGeometry: ShapeGeometry,
  31702. ShapePath: ShapePath,
  31703. ShapeUtils: ShapeUtils,
  31704. ShortType: ShortType,
  31705. Skeleton: Skeleton,
  31706. SkeletonHelper: SkeletonHelper,
  31707. SkinnedMesh: SkinnedMesh,
  31708. SmoothShading: SmoothShading,
  31709. Sphere: Sphere,
  31710. SphereBufferGeometry: SphereBufferGeometry,
  31711. SphereGeometry: SphereGeometry,
  31712. Spherical: Spherical,
  31713. SphericalHarmonics3: SphericalHarmonics3,
  31714. Spline: Spline,
  31715. SplineCurve: SplineCurve,
  31716. SplineCurve3: SplineCurve3,
  31717. SpotLight: SpotLight,
  31718. SpotLightHelper: SpotLightHelper,
  31719. Sprite: Sprite,
  31720. SpriteMaterial: SpriteMaterial,
  31721. SrcAlphaFactor: SrcAlphaFactor,
  31722. SrcAlphaSaturateFactor: SrcAlphaSaturateFactor,
  31723. SrcColorFactor: SrcColorFactor,
  31724. StaticCopyUsage: StaticCopyUsage,
  31725. StaticDrawUsage: StaticDrawUsage,
  31726. StaticReadUsage: StaticReadUsage,
  31727. StereoCamera: StereoCamera,
  31728. StreamCopyUsage: StreamCopyUsage,
  31729. StreamDrawUsage: StreamDrawUsage,
  31730. StreamReadUsage: StreamReadUsage,
  31731. StringKeyframeTrack: StringKeyframeTrack,
  31732. SubtractEquation: SubtractEquation,
  31733. SubtractiveBlending: SubtractiveBlending,
  31734. TOUCH: TOUCH,
  31735. TangentSpaceNormalMap: TangentSpaceNormalMap,
  31736. TetrahedronBufferGeometry: TetrahedronBufferGeometry,
  31737. TetrahedronGeometry: TetrahedronGeometry,
  31738. TextBufferGeometry: TextBufferGeometry,
  31739. TextGeometry: TextGeometry,
  31740. Texture: Texture,
  31741. TextureLoader: TextureLoader,
  31742. TorusBufferGeometry: TorusBufferGeometry,
  31743. TorusGeometry: TorusGeometry,
  31744. TorusKnotBufferGeometry: TorusKnotBufferGeometry,
  31745. TorusKnotGeometry: TorusKnotGeometry,
  31746. Triangle: Triangle,
  31747. TriangleFanDrawMode: TriangleFanDrawMode,
  31748. TriangleStripDrawMode: TriangleStripDrawMode,
  31749. TrianglesDrawMode: TrianglesDrawMode,
  31750. TubeBufferGeometry: TubeBufferGeometry,
  31751. TubeGeometry: TubeGeometry,
  31752. UVMapping: UVMapping,
  31753. Uint16Attribute: Uint16Attribute,
  31754. Uint16BufferAttribute: Uint16BufferAttribute,
  31755. Uint32Attribute: Uint32Attribute,
  31756. Uint32BufferAttribute: Uint32BufferAttribute,
  31757. Uint8Attribute: Uint8Attribute,
  31758. Uint8BufferAttribute: Uint8BufferAttribute,
  31759. Uint8ClampedAttribute: Uint8ClampedAttribute,
  31760. Uint8ClampedBufferAttribute: Uint8ClampedBufferAttribute,
  31761. Uniform: Uniform,
  31762. UniformsLib: UniformsLib,
  31763. UniformsUtils: UniformsUtils,
  31764. UnsignedByteType: UnsignedByteType,
  31765. UnsignedInt248Type: UnsignedInt248Type$1,
  31766. UnsignedIntType: UnsignedIntType,
  31767. UnsignedShort4444Type: UnsignedShort4444Type,
  31768. UnsignedShort5551Type: UnsignedShort5551Type,
  31769. UnsignedShort565Type: UnsignedShort565Type,
  31770. UnsignedShortType: UnsignedShortType,
  31771. VSMShadowMap: VSMShadowMap,
  31772. Vector2: Vector2$1,
  31773. Vector3: Vector3,
  31774. Vector4: Vector4,
  31775. VectorKeyframeTrack: VectorKeyframeTrack,
  31776. Vertex: Vertex,
  31777. VertexColors: VertexColors,
  31778. VideoTexture: VideoTexture,
  31779. WebGL1Renderer: WebGL1Renderer,
  31780. WebGLCubeRenderTarget: WebGLCubeRenderTarget,
  31781. WebGLMultisampleRenderTarget: WebGLMultisampleRenderTarget,
  31782. WebGLRenderTarget: WebGLRenderTarget,
  31783. WebGLRenderTargetCube: WebGLRenderTargetCube,
  31784. WebGLRenderer: WebGLRenderer,
  31785. WebGLUtils: WebGLUtils,
  31786. WireframeGeometry: WireframeGeometry,
  31787. WireframeHelper: WireframeHelper,
  31788. WrapAroundEnding: WrapAroundEnding,
  31789. XHRLoader: XHRLoader,
  31790. ZeroCurvatureEnding: ZeroCurvatureEnding,
  31791. ZeroFactor: ZeroFactor,
  31792. ZeroSlopeEnding: ZeroSlopeEnding,
  31793. ZeroStencilOp: ZeroStencilOp,
  31794. sRGBEncoding: sRGBEncoding
  31795. });
  31796. var points = [];
  31797. var lines = [];
  31798. var rings = [];
  31799. var precision = 0.1; //容错精度 //正常是0.01 但是在编辑时容易出现交错的线看不出来,导致需要getSliceLines 然后多出新增点
  31800. var getPoint = function(o, type){
  31801. var point;
  31802. if(typeof o == "string" || typeof o == "number")point = points.find(p=> p.ids.includes(o));
  31803. else {
  31804. point = points.find(p=> math.closeTo(p.x , o.x, precision) && math.closeTo(p.y , o.y, precision) );
  31805. if(!point) point = new Point(o.x, o.y,{record:true, id:o.id}, type);
  31806. else {
  31807. //console.log('addPoint', point, o)
  31808. point.addPoint(o.id);
  31809. }
  31810. }
  31811. if(!point){
  31812. console.log("no point!");
  31813. }
  31814. return point
  31815. };
  31816. var getLine = function(id){
  31817. return lines.find(line=> line.ids.includes(id));
  31818. };
  31819. var getAngleInfo = function(points){
  31820. var info = {};
  31821. info.angle = points[1].clone().sub(points[0]).angle();
  31822. if(math.closeTo(info.angle, Math.PI*2)){ //如360-0.01
  31823. info.angle -= Math.PI*2; //有可能得到负数-0.001
  31824. }else if(info.angle > Math.PI || math.closeTo(info.angle, Math.PI)){//如180+-0.01
  31825. info.angle -= Math.PI;
  31826. info.reverse = true;
  31827. }
  31828. return info //结果大约是 0 - 3.14
  31829. };
  31830. class Point extends Vector2$1{
  31831. constructor(x, y, o={}){
  31832. super(x, y);
  31833. if(o.record){
  31834. this.id = o.id;
  31835. if(this.id == void 0) this.id = "add_"+points.length;
  31836. this.ids = [this.id] ;//存储拥有该坐标的点原始数据的id
  31837. points.push(this);
  31838. }
  31839. this.type = o.type || "";
  31840. this.lines = [];
  31841. }
  31842. addPoint(id){
  31843. this.ids.push(id);
  31844. }
  31845. searchLineByFactor(dir, type, comeLine){
  31846. var lines = this.lines.filter(line=>line.searchTime<2);
  31847. if(lines.length==0)return;
  31848. else if(lines.length==1)return lines[0];
  31849. else lines = lines.filter(line=>line!=comeLine);
  31850. if(lines.length==1)return lines[0];
  31851. var result;
  31852. lines.forEach(line=>{
  31853. var vec = line.getVector();
  31854. if(line.points[1] == this) vec.negate();
  31855. var factor = math.getVec2Angle(dir, vec);
  31856. if(new Vector3(dir.x, dir.y, 0).cross(new Vector3(vec.x, vec.y, 0)).z<0) factor*= -1; /////
  31857. if(!result){
  31858. result = {line, factor};
  31859. }
  31860. else {
  31861. if(type == "min" && factor<result.factor || type == "max" && factor>result.factor) result = {line, factor};
  31862. }
  31863. });
  31864. return result.line;
  31865. }
  31866. }
  31867. var lineLen=0;
  31868. class Line$1{
  31869. constructor(o){
  31870. if(o.points[0] == o.points[1])return;
  31871. this.points = o.points;
  31872. this.type = o.type || 'line';
  31873. if(this.type == 'line'){
  31874. var oldLine = lines.find(line=>line.points.includes(o.points[0]) && line.points.includes(o.points[1]));
  31875. if(oldLine){
  31876. o.id != void 0 && oldLine.ids.push(o.id);
  31877. return oldLine;
  31878. }
  31879. this.id = o.id == void 0 ? ("line"+lineLen ++) : o.id;
  31880. this.ids = [this.id];
  31881. o.dontWriteToPoint || this.points.forEach((point)=>{point.lines.push(this);});
  31882. o.isChild || lines.push(this);
  31883. this.searchTime = 0; // 最多两次
  31884. }
  31885. this.children = [];//分割
  31886. this.parents = [];//分割
  31887. this.match = [];
  31888. }
  31889. getAngleInfo(){
  31890. var angleInfo = getAngleInfo(this.points);
  31891. this.angle = angleInfo.angle;
  31892. this.reverse = angleInfo.reverse;
  31893. }
  31894. getIntersectWithLine(line, precision){
  31895. var joint = line.points.find(point=>this.points.includes(point));
  31896. if(joint)return {point:joint, type:"joint"};
  31897. var intersect = math.isLineIntersect( line.points , this.points , false, precision );
  31898. if(intersect) return {point: intersect, type:"intersect"};
  31899. }
  31900. writeToPoint(){
  31901. this.points.forEach((point)=>{point.lines.includes(this) || point.lines.push(this);});
  31902. }
  31903. checkIfParent(line){
  31904. if(this == line){
  31905. return true;//原因就是slice的点和端点很近 误差导致
  31906. }
  31907. else return this.parents.find(e=>e.checkIfParent(line))
  31908. }
  31909. splitByPoint(point){
  31910. var line1 = new Line$1({points:[point, this.points[0]], dontWriteToPoint:true, hasntsure:true});
  31911. var line2 = new Line$1({points:[point, this.points[1]], dontWriteToPoint:true, hasntsure:true});
  31912. if(!line1.points || !line2.points){//有至少一个是点相同的,没写到group.lines里
  31913. console.warn('splitByPoint 线有点相同');
  31914. return;
  31915. }
  31916. if(this.checkIfParent(line1)||this.checkIfParent(line2) || line1.checkIfParent(this) || line2.checkIfParent(this)){
  31917. console.warn("splitByPoint 发现parent和children一样");//,请检查getSliceWalls,尤其 if(math.closeTo(line1.angle,line2.angle)){ 处
  31918. return;
  31919. }
  31920. var deal = (line)=>{
  31921. this.children.push(line);
  31922. line.parents.push(this);
  31923. if(!lines.includes(line))lines.push(line);
  31924. line.writeToPoint();
  31925. };
  31926. deal(line1);
  31927. deal(line2);
  31928. var index = this.points[0].lines.indexOf(this);
  31929. index > -1 && this.points[0].lines.splice(index,1);
  31930. var index = this.points[1].lines.indexOf(this);
  31931. index > -1 && this.points[1].lines.splice(index,1);
  31932. return [line1,line2]
  31933. }
  31934. splitByPoints(points){
  31935. points = points.map(point=>{return {dis:point.distanceTo(this.points[0]), point:point}});
  31936. points.sort((point1, point2)=>{return point1.dis - point2.dis});
  31937. var children = [];
  31938. points.forEach((point, index)=>{
  31939. var line1 = new Line$1({points:[point.point, index==0?this.points[0]:points[index-1].point ],group:this.group , dontWriteToPoint:true, hasntsure:true});
  31940. children.push(line1);
  31941. });
  31942. var line2 = new Line$1({points:[points[points.length-1].point, this.points[1] ],group:this.group , dontWriteToPoint:true, hasntsure:true});
  31943. children.push(line2);
  31944. var a = children.find(line=> !line.points || this.checkIfParent(line) || line.checkIfParent(this));
  31945. if(a){
  31946. console.error("splitByPoints return");
  31947. return;
  31948. }
  31949. children.forEach(line=>{
  31950. this.children.push(line);
  31951. line.parents.push(this);
  31952. if(!lines.includes(line))lines.push(line);
  31953. line.writeToPoint();
  31954. line.writeToPoint();
  31955. });
  31956. var index = this.points[0].lines.indexOf(this);
  31957. index > -1 && this.points[0].lines.splice(index,1);
  31958. var index = this.points[1].lines.indexOf(this);
  31959. index > -1 && this.points[1].lines.splice(index,1);
  31960. }
  31961. getAllSlices(){//如果有被分割的片段 就返回片段,否则返回自身
  31962. var children = [];
  31963. var traverse = function(elem){
  31964. if(elem.children.length == 0) children.push(elem);
  31965. else elem.children.forEach(traverse);
  31966. };
  31967. traverse(this);
  31968. return children
  31969. }
  31970. getVector(){
  31971. return this.points[1].clone().sub(this.points[0]);
  31972. }
  31973. getLength(){
  31974. return this.points[0].distanceTo(this.points[1])
  31975. }
  31976. getCenter(){
  31977. return this.points[1].clone().add(this.points[0]).multiplyScalar(.5);
  31978. }
  31979. }
  31980. var getMixedSet = function(arr1, arr2){//交集
  31981. return arr1.filter(item=>arr2.includes(item));
  31982. };
  31983. var getUnionSet = function(arr1, arr2){//并集
  31984. return arr1.concat(arr2.filter(item=>!arr1.includes(item)))
  31985. };
  31986. var getDifferenceSet = function(arr1, arr2){//差集
  31987. var arr11 = arr1.filter(item=>!arr2.includes(item));
  31988. var arr22 = arr2.filter(item=>!arr1.includes(item));
  31989. return arr11.concat(arr22)
  31990. };
  31991. var getDifferenceSetMuti = function(arr){//收集绝对没有重复的元素,也就是判断出现次数=1的
  31992. var set = [];
  31993. arr.forEach(arr1=>{
  31994. arr1.forEach(item=>{
  31995. var index = set.indexOf(item);
  31996. if(index>-1){
  31997. set.splice(index, 1);
  31998. }else {
  31999. set.push(item);
  32000. }
  32001. });
  32002. });
  32003. return set;
  32004. };
  32005. function DoorAtWhichLine(points, lines){
  32006. var mid = points[0].clone().add(points[1]).multiplyScalar(0.5);
  32007. lines = lines.filter(line=>math.ifPointAtLineBound(mid, line.points, precision));
  32008. if(lines.length == 0)return
  32009. var result = {line:null, dis:Infinity};
  32010. lines.forEach(line=>{
  32011. var foot = math.getFootPoint(mid, line.points[0], line.points[1] );
  32012. var dis = foot.distanceTo(mid);
  32013. if(dis<result.dis){
  32014. result.line = line; result.dis = dis;
  32015. }
  32016. });
  32017. return result
  32018. }
  32019. var ringLen = 0;
  32020. class Ring{
  32021. constructor(o){
  32022. this.id = ringLen ++;
  32023. this.type = o.type || 'normal';
  32024. this.points = o.points;
  32025. this.lines = o.lines;
  32026. rings.push(this);
  32027. this.child = [];//包含的环
  32028. this.parent = [];//被包含的环
  32029. this.smallNeibours = [];//相邻最小环(存在和它有一个以上的相同边的最小环)
  32030. var area = math.getArea(this.points);
  32031. this.area = Math.abs(area);
  32032. this.isClockwise = area<0;//是否逆时针。一般都是逆时针得到的,如果是顺时针,可能是贪吃蛇的情况,可能不是最小环,需要去掉。
  32033. }
  32034. }
  32035. var findLine = function(p1,p2){
  32036. return lines.find(line=>line.points.includes(p1) && line.points.includes(p2) )
  32037. };
  32038. var ifSamePart = function(checkPart , part){//checkPart中所包含的part片段是否和基准part的顺序一样(逆序也可以, 中间有其他数也可以,起始不同也行。比如 01234和204一样的)
  32039. var axis, startIndex, newCheckPart=[];
  32040. for(var j=0,len1 = checkPart.length; j<len1; j++){//将checkPart中比part多的数除去,使两个数组中包含的数完全相同。
  32041. if(part.indexOf(checkPart[j])>-1)newCheckPart.push(checkPart[j]);
  32042. }
  32043. for(var i=0,len = part.length; i<len; i++){
  32044. var index = newCheckPart.indexOf(part[i]);
  32045. if(index == -1)return false;
  32046. if(i == 0) startIndex = index;//标记第一个查找点对应的index
  32047. else if(i == 1){//标记查找顺序是正还是逆
  32048. axis = index - startIndex;
  32049. if(axis == len - 1) axis = -1;//刚好是首和尾
  32050. else if(axis == 1- len) axis = 1;
  32051. if(axis != -1 && axis != 1){
  32052. return false
  32053. }
  32054. }else {//判断是否是按顺序的
  32055. if(index != ((startIndex+axis * i + len) % len) ) return false;
  32056. }
  32057. }
  32058. return {sameAxis:axis>0}; //如果一样的话返回正逆是否相同
  32059. };
  32060. //或者判断是否有相同边(但是相同点是可以组成不同环)
  32061. var ifSameRing = function(ring1, ring2){//判断两个环是否相等。 除了可以逆向外顺序要对
  32062. if(ring1 instanceof Ring)ring1 = ring1.points;
  32063. if(ring2 instanceof Ring)ring2 = ring2.points;
  32064. if(ring1.length != ring2.length)return false;
  32065. if(ring1.lines && ring2.lines){
  32066. if(getDifferenceSet(ring1.lines , ring2.lines).length == 0)return true;//差集个数为0
  32067. }else {
  32068. if(ifSamePart(ring1, ring2))return true
  32069. }
  32070. };
  32071. var atWhichChildLine = function(point, line, precision){
  32072. if(line.children.length == 0){//这里可能要放低精度 保证能找到
  32073. if(math.ifPointAtLineBound(point, line.points, precision)) return line;
  32074. }else {
  32075. for(var i=0;i<line.children.length;i++){
  32076. var at = atWhichChildLine(point, line.children[i], precision);
  32077. if(at)return at
  32078. }
  32079. }
  32080. };
  32081. function getSliceLines(){
  32082. var len = lines.length;
  32083. var deal = function(line1,line2){
  32084. if(line1 == line2)return;
  32085. if(line1.angle == void 0) line1.getAngleInfo();
  32086. if(line2.angle == void 0) line2.getAngleInfo();
  32087. var intersect = line1.getIntersectWithLine(line2, precision);
  32088. if(intersect){
  32089. var point; //得到交点
  32090. if(intersect.type == "intersect"){
  32091. point = getPoint(intersect.point, "whenGetSliceLines");
  32092. var line1_ = atWhichChildLine(point, line1);
  32093. var line2_ = atWhichChildLine(point, line2);
  32094. //重合的情况还没考虑(平行)
  32095. if(!line1_) line1_ = atWhichChildLine(point, line1, precision);//降低精度
  32096. if(!line1_) line1_ = atWhichChildLine(point, line1, precision*2);//降低精度
  32097. if(!line2_) line2_ = atWhichChildLine(point, line2, precision);
  32098. if(!line2_) line2_ = atWhichChildLine(point, line2, precision*2);//降低精度
  32099. //拆分线条:
  32100. //如果还报错,找不到ChildLine,就直接返回吧 或者搞个循环 逐渐降低精度
  32101. if(!line1_ || !line2_){
  32102. console.warn("atWhichChildLine仍旧找不到 :" + line1.id + ',' + line2.id + ", pointId: "+point.id);
  32103. line1_ || console.warn("找不到line1");
  32104. line2_ || console.warn("找不到line2");
  32105. return;
  32106. }
  32107. if(line1_.points.find(p=>p == point) && line2_.points.find(p=>p == point)){//这个点是line1_、 line2_端点,不做处理
  32108. //console.log("joint型 "+point.id)
  32109. }else if(line1_.points.find(p=>p == point)){//T型交叉
  32110. line2_.splitByPoint(point);//加入到母线中,之后还先用母线判断交点
  32111. //console.log("T型交叉1 "+point.id)
  32112. }else if(line2_.points.find(p=>p == point)){//T型交叉
  32113. line1_.splitByPoint(point);
  32114. //console.log("T型交叉2 "+point.id)
  32115. }else {//十字交叉
  32116. line1_.splitByPoint(point);
  32117. line2_.splitByPoint(point);
  32118. }
  32119. }else {
  32120. point = intersect.point;//交点是端点
  32121. if(math.closeTo(line1.angle,line2.angle)){ //重合一部分
  32122. var children1 = line1.getAllSlices();
  32123. var children2 = line2.getAllSlices();
  32124. if(children1.length>1 || children2.length>1){ //使用最小分割片段来比较
  32125. children1.forEach(child1=>{
  32126. children2.forEach(child2=>{
  32127. deal(child1, child2);
  32128. });
  32129. });
  32130. return;
  32131. }
  32132. var anotherPoint1 = line1.points.find(point_=>point_!=point);
  32133. var anotherPoint2 = line2.points.find(point_=>point_!=point);
  32134. if(math.ifPointAtLineBound(anotherPoint1, line2.points)){
  32135. line2.splitByPoint(anotherPoint1);
  32136. }else if(math.ifPointAtLineBound(anotherPoint2, line1.points)){
  32137. line1.splitByPoint(anotherPoint2);
  32138. }
  32139. }
  32140. }
  32141. }else if(math.closeTo(line1.angle,line2.angle)){
  32142. var vec1 = line1.getVector();
  32143. var vec = line1.points[0].clone().sub(line2.points[0]);
  32144. var cos = math.getVec2Cos(vec1, vec);
  32145. if(math.closeTo(cos, -1, 1e-4) || math.closeTo(cos, 1, 1e-4)){ //共线
  32146. var children1 = line1.getAllSlices();
  32147. var children2 = line2.getAllSlices();
  32148. if(children1.length>1 || children2.length>1){ //使用最小分割片段来比较
  32149. children1.forEach(child1=>{
  32150. children2.forEach(child2=>{
  32151. deal(child1, child2);
  32152. });
  32153. });
  32154. return;
  32155. }
  32156. //判断是否重叠
  32157. var A = line1.points[0];
  32158. var C = line1.reverse == line2.reverse ? line2.points[0] : line2.points[1];
  32159. var B = line1.points[1];
  32160. var D = line1.reverse == line2.reverse ? line2.points[1] : line2.points[0];
  32161. var BC = C.clone().sub(B);
  32162. var AD = D.clone().sub(A);
  32163. if(BC.length()<AD.length()){
  32164. var BA = A.clone().sub(B);
  32165. if(math.getVec2Angle(BC, BA) >= 1.57 )return;//没有重叠部分
  32166. }else {
  32167. var AB = B.clone().sub(A);
  32168. if(math.getVec2Angle(AD, AB) >= 1.57 )return;
  32169. }
  32170. var f = function(line1,line2){
  32171. var one = math.ifPointAtLineBound(line1.points[0], line2.points);
  32172. var two = math.ifPointAtLineBound(line1.points[1], line2.points);
  32173. if(one && two){//line1在line2上
  32174. line2.splitByPoints( line1.points );
  32175. return true
  32176. }else if(one || two){//错开
  32177. var point1 = one ? line1.points[0] : line1.points[1];
  32178. var anotherPoint1 = one ? line1.points[1] : line1.points[0];
  32179. var dis1 = line2.points[0].distanceTo(anotherPoint1);
  32180. var dis2 = line2.points[1].distanceTo(anotherPoint1);
  32181. var point2 = dis1 < dis2 ? line2.points[0] : line2.points[1];
  32182. line1.splitByPoint(point2);
  32183. line2.splitByPoint(point1);
  32184. return true
  32185. }
  32186. };
  32187. f(line1, line2) || f(line2, line1);
  32188. }
  32189. }
  32190. };
  32191. for(let i=0;i<len;i++){
  32192. let line1 = lines[i];
  32193. for(let j=i+1;j<len;j++){
  32194. let line2 = lines[j];
  32195. deal(line1,line2);
  32196. }
  32197. }
  32198. //console.log("原有线条个数:"+len)
  32199. //lines = lines.filter((line)=>{return line.children.length == 0})
  32200. //console.log("现有线条个数:"+lines.length)
  32201. }
  32202. var bound = new Box2();
  32203. var build = function(o){
  32204. //融合了相近点
  32205. //根据bound 处理precision
  32206. o.points.forEach(p=>{
  32207. bound.expandByPoint(new Vector2$1(p.x,p.y));
  32208. });
  32209. if(o.precision != void 0){
  32210. precision = o.precision;
  32211. }else {
  32212. var boundSize = bound.getSize(new Vector2$1);
  32213. precision = MathUtils.clamp(Math.max(boundSize.x, boundSize.y) / 70, 0.2, 2);
  32214. }
  32215. o.points.forEach(point=>getPoint(point));//{x:..,y:..}
  32216. o.lines.forEach(line=>{ //{p1:id1. p2:id2}
  32217. new Line$1({points:[getPoint(line.p1), getPoint(line.p2)], id:line.id });
  32218. });
  32219. //注意:不能出现一条线的两个点坐标一致,否则寻路时方向出错。 所以手动融合下相近点。
  32220. };
  32221. var searchRings = function(o={}){
  32222. points = [];
  32223. lines = [];
  32224. rings = [];
  32225. lineLen = ringLen = 0;
  32226. o.points = o.points || [];
  32227. o.lines = o.lines || [];
  32228. build(o);
  32229. if(!o.dontSliceLines){
  32230. getSliceLines();
  32231. }
  32232. //查找最小回路:
  32233. //参考: 引入方向因子的最小回路、最大回路搜索算法.pdf
  32234. //方法: 逆时针寻找(标记)最外层大环 -->从走过的点开始逆时针寻找最小环(直到所有可走的路被走过两次)-->逆时针寻找最外层大环(直到所有可走的路被走过两次)-->..
  32235. //其中找大环时选择方向因子最小的路, 而小环则相反(但只有开始第一条路是一样的, 都是选择最左边的点的因子最小的路)。
  32236. //标记方法: 每条线需要被搜索两次才算完毕。搜索完毕的线退出搜索。(依据:搜索完全部最小回路后 , 在无向图中删除搜索过 2 次的边及孤立节点得到退化图 , 恰好构成最大回路。)
  32237. var searchTime = 0;
  32238. var addRingJudgeCount = 0;
  32239. var addRingJudge = function(ring, lines, connectedLines, type){// 处理拣出的片段
  32240. addRingJudgeCount++;
  32241. //console.log("addRingJudge points("+ type+"):"+ ring.map(point=>point.id) )
  32242. if(o.onlyGetOutRing && type == "small")return
  32243. if(type == "small" || o.onlyGetOutRing){//挑出回路:
  32244. var newRings = [];
  32245. while(ring.length){
  32246. var road = [];
  32247. var turnBack = false;
  32248. for(let i=0;i<ring.length;i++){
  32249. if(road.includes(ring[i])){//如果走到方才的点,可能形成回路。 无论是不是回路都要摘去这段。
  32250. var index = road.indexOf(ring[i]);
  32251. var pointArr = ring.slice(index, i);
  32252. var linesArr = lines.slice(index, i);
  32253. ring.splice(index,i-index);
  32254. lines.splice(index,i-index);
  32255. if(pointArr.length>2){// 如果只有两个数,代表原路返回, 如 1->2(->1)
  32256. if( !rings.find(ring_=>ifSameRing(pointArr, ring_))) newRings.push( new Ring({points: pointArr, lines:linesArr}) );
  32257. }
  32258. turnBack = true;
  32259. break;
  32260. }else {
  32261. road.push(ring[i]);
  32262. turnBack = false;
  32263. }
  32264. }
  32265. if(!turnBack){//没有重复的点,那么就直接处理整条。
  32266. if(ring.length>2){// 如果只有两个数,代表原路返回, 如 1->2(->1)
  32267. if( !rings.find(ring_=>ifSameRing(ring, ring_))) newRings.push( new Ring({points: ring, lines}) );
  32268. }
  32269. break;
  32270. }
  32271. }
  32272. if(type != 'small'){
  32273. newRings.forEach(e=>e.isOutRing = true);
  32274. }
  32275. //console.log(newRings)
  32276. }else {
  32277. return ring
  32278. }
  32279. };
  32280. var search = function(point2d, comeRoad, type, connectedLines){
  32281. searchTime++;
  32282. var goLine;
  32283. var direction;
  32284. if(type.includes("big")){
  32285. if(!comeRoad){
  32286. if(type.includes("Left")){//逆时针
  32287. direction = new Vector2$1(1,0);
  32288. }else {
  32289. direction = new Vector2$1(-1,0);
  32290. }
  32291. goLine = point2d.searchLineByFactor(direction,"min");
  32292. }else {
  32293. var lastPoint = comeRoad.points[comeRoad.points.length-1];
  32294. direction = point2d.clone().sub(lastPoint);
  32295. goLine = point2d.searchLineByFactor(direction,"min", findLine(point2d, lastPoint));
  32296. }
  32297. }else {
  32298. if(!comeRoad){
  32299. //似乎找最小环时,第一条线也是找最小的因子,这样才能保证逆时针(除非只有顺时针一条路)
  32300. direction = new Vector2$1(1,0);
  32301. goLine = point2d.searchLineByFactor(direction,"min");
  32302. }else {
  32303. var lastPoint = comeRoad.points[comeRoad.points.length-1];
  32304. direction = point2d.clone().sub(lastPoint);
  32305. goLine = point2d.searchLineByFactor(direction,"max", findLine(point2d, lastPoint));
  32306. }
  32307. }
  32308. if(!goLine)return
  32309. goLine.searchTime++;
  32310. connectedLines.includes(goLine) || connectedLines.push(goLine);
  32311. var nextPoint = goLine.points.find( point => point2d!=point );
  32312. //if( comeRoad && comeRoad.points[comeRoad.points.length - 1] == nextPoint ) return;//不能查找来时的方向(反方向)
  32313. //走不通就原路返回
  32314. var roadPoints = comeRoad ? comeRoad.points.concat([point2d]) : [point2d];//每个分叉都能构成一条新的road
  32315. var roadLines = comeRoad ? comeRoad.lines.concat([goLine]) : [goLine];
  32316. //走到第一个点就算停止,这时候可能得到一个环、或者一段走了两遍的线、或者一条线上带了些环。
  32317. if(nextPoint == roadPoints[0]) return addRingJudge(roadPoints, roadLines, connectedLines, type) //形成环
  32318. else {
  32319. /* var len = roadPoints.indexOf(nextPoint);
  32320. if( len > -1){ //走到走过的路的某一点 构成这段路的回路
  32321. var points = roadPoints.slice(len, roadPoints.length);
  32322. var lines = roadLines.slice(len, roadPoints.length);
  32323. addRingJudge(points, lines)
  32324. }else{ */
  32325. return search(nextPoint, {lines:roadLines, points:roadPoints}, type, connectedLines);//继续寻路
  32326. //}
  32327. }
  32328. };
  32329. while(1){//搜寻一次大环
  32330. var connectedLines = [];//被搜寻过的且searchTime<2的线。一旦全部搜完就说明该连通区域搜寻完毕,继续查下一个连通区域。
  32331. var startPoint = null;
  32332. points.forEach(point=>{//找出x最小的点
  32333. if(!point.lines.find(line=>line.searchTime<2))return;
  32334. if(!startPoint)startPoint = point;
  32335. else if(point.x < startPoint.x)startPoint = point;
  32336. });
  32337. if(!startPoint)break; //说明全部找完
  32338. var ring = search(startPoint, null, "bigLeft", connectedLines);//逆时针
  32339. //search(startPoint, null, "bigRight", connectedLines);//顺时针(为了防止最外层不是回路之前写了顺时针,但如果是回路就会走重复。后来发现只要逆时针即可,因为走完后剩下的可以再次找大环)
  32340. connectedLines = connectedLines.filter(line=>line.searchTime<2);
  32341. while(connectedLines.length>0){//目标是顺着connectedLines把所有连通的小环都找到
  32342. let points_ = [];//connectedLines中所有的点
  32343. connectedLines.forEach(line=>line.points.forEach(point=>{if(!points_.includes(point))points_.push(point); }));
  32344. var startPoint = null;
  32345. points_.forEach(point=>{//找出x最小的点
  32346. if(!point.lines.find(line=>line.searchTime<2))return;
  32347. if(!startPoint)startPoint = point;
  32348. else if(point.x < startPoint.x)startPoint = point;
  32349. });
  32350. if(!startPoint)break;
  32351. search(startPoint, null, "small", connectedLines);
  32352. connectedLines = connectedLines.filter(line=>line.searchTime<2);
  32353. }
  32354. }
  32355. /* if(o.onlyGetOutRing){
  32356. rings = rings.filter(e=>e.isOutRing)
  32357. } */
  32358. //console.log("searchTime "+searchTime + ", addRingJudgeCount " +addRingJudgeCount)
  32359. //找出所有的相邻关系,包括公共边
  32360. var len = rings.length;
  32361. for(let i=0; i<len; i++){
  32362. let ring1 = rings[i];
  32363. for(let j=i+1; j<len; j++){
  32364. let ring2 = rings[j];
  32365. var bothHasLines = getMixedSet(ring1.lines, ring2.lines);
  32366. if(bothHasLines.length){//ring1oíring2?àáú
  32367. ring1.smallNeibours.push(ring2);
  32368. ring2.smallNeibours.push(ring1);
  32369. }else {
  32370. }
  32371. }
  32372. }
  32373. rings.forEach(ring1=>{
  32374. for(let i=0; i<len; i++){
  32375. var ring2 = rings[i];
  32376. if(ring1 == ring2 || ring1.smallNeibours.includes(ring2))continue;
  32377. let inside;
  32378. for(let u=0;u<ring1.points.length;u++){
  32379. inside = math.isPointInArea(ring2.points, null, ring1.points[u]);
  32380. if(!inside)break
  32381. else if(inside && !inside.atLine){
  32382. break
  32383. }
  32384. }
  32385. if(inside){ //只要其中一个点在ring2内,就说明ring1是内环
  32386. if(inside.atLine){//(还是会存在点全在线上的情况,这时候判断中心点)
  32387. var center = math.getCenterOfGravityPoint(ring1.points);
  32388. let inside1 = math.isPointInArea(ring2.points, null, center);
  32389. if(!inside1){
  32390. continue
  32391. }
  32392. }
  32393. ring2.child.push(ring1);
  32394. ring1.parent.push(ring2);
  32395. }
  32396. }
  32397. });
  32398. //去除非最小的ring 是否应该检测parent child?
  32399. /*
  32400. like this:
  32401. |———————————————————————|
  32402. |———|———————|———————| |
  32403. | | | | |
  32404. | |———————|———————| |
  32405. |———————————————————————|
  32406. */
  32407. var wiseRings = rings.filter(r=>!r.isClockwise);//一般都是逆时针得到的,如果是顺时针,可能是贪吃蛇的情况,可能不是最小环,需要去掉。
  32408. if(wiseRings.length > 0){
  32409. //console.log('%c存在非最小的ring! 进行处理:',"color:#00f");
  32410. wiseRings.forEach(ring=>{ //(此案例验证出smallNeibours就是它的最小构成,可以再看看别的案例)
  32411. if(ring.smallNeibours.length>0){//另:如果内部只有一个,说明它是最小环,不需要处理
  32412. var is = false;
  32413. var difference = getDifferenceSet(ring.lines , getDifferenceSetMuti(ring.smallNeibours.concat(ring.child).map(ring=>ring.lines)));//获取所有smallNeibours和child的边中没有重复过的边(就是outline) 和该ring的线比较
  32414. is = difference.every(line=> ring.child.find(r=>r.lines.includes(line)) ); //多出的线只能是child中的线
  32415. if(is){
  32416. console.log('%c删除非最小环 ring'+ring.id,"color:#00f");
  32417. console.log(ring);
  32418. rings.splice(rings.indexOf(ring), 1);
  32419. ring.child.forEach(c=>{var index = c.parent.indexOf(ring);index>-1 && c.parent.splice(index,1);});
  32420. ring.parent.forEach(c=>{var index = c.child.indexOf(ring);index>-1 && c.child.splice(index,1);});
  32421. ring.smallNeibours.forEach(c=>{var index = c.smallNeibours.indexOf(ring);index>-1 && c.smallNeibours.splice(index,1);});
  32422. }
  32423. }
  32424. });
  32425. }
  32426. /* rings = rings.filter(ring=>{
  32427. rings = rings.filter(ring=>{
  32428. var enoughSize = ring.area > 0.5
  32429. if(!enoughSize){console.log('因面积过小去除ring '+ring.id + " , area: "+ring.area)}
  32430. return enoughSize
  32431. })
  32432. rings.forEach(ring=>{
  32433. if(ring.closetChilds){
  32434. ring.closetChilds = ring.closetChilds.filter(e=>rings.includes(e))
  32435. }
  32436. })
  32437. return rings
  32438. }) */ //在dealRings前不能随意删除rings,因为判断是否是最小环时需要全部的环
  32439. rings.forEach(ring=>{ //这里和cad中的不太一样, cad中双数个parent算外环,单数内环; 这里不分内外, 只看有无parent child
  32440. if(ring.parent.length){
  32441. ring.closetParent = ring.parent.find(ring_ => ring_.parent.length == ring.parent.length - 1);//最近一层的大环就是比它的parent个数少一的
  32442. ring.closetParent.closetChilds || (ring.closetParent.closetChilds = []);//内环可能多个
  32443. ring.closetParent.closetChilds.push(ring);
  32444. }
  32445. });
  32446. //console.log(rings)
  32447. var _ring = rings.map(ring=>{
  32448. var data = {
  32449. id: ring.id,
  32450. points: ring.points.map(point=>{return {id: point.ids[0], x:point.x, y:point.y}}),
  32451. /* doors : o.doors.filter(door=>{
  32452. if(ring.closetChilds){
  32453. var childOutLines = getDifferenceSetMuti(ring.closetChilds.map(ring=>ring.lines)) //最近子环的外边
  32454. return ring.lines.concat(childOutLines).includes(door.atLine)
  32455. }else{
  32456. return ring.lines.includes(door.atLine)
  32457. }
  32458. }), */
  32459. area:ring.area,
  32460. closetParent : ring.closetParent && ring.closetParent.id,
  32461. closetChilds : ring.closetChilds && ring.closetChilds.map(e=>e.id)
  32462. };
  32463. return data
  32464. });
  32465. //console.log(JSON.stringify(_ring))
  32466. return _ring
  32467. };
  32468. var math = {
  32469. getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) . Math.log 返回一个数的自然对数
  32470. return Math.log(y) / Math.log(x);
  32471. }
  32472. ,
  32473. convertVector : {
  32474. ZupToYup: function(e){//navvis -> 4dkk
  32475. return new Vector3(e.x,e.z,-e.y)
  32476. },
  32477. YupToZup: function(e){//4dkk -> navvis
  32478. return new Vector3(e.x,-e.z,e.y)
  32479. },
  32480. },
  32481. convertQuaternion: {
  32482. ZupToYup: function(e){//navvis -> 4dkk //不同于convertVisionQuaternion
  32483. let rotation = new Euler(-Math.PI/2,0,0);
  32484. let quaternion = new Quaternion().setFromEuler(rotation);
  32485. return e.clone().premultiply(quaternion)
  32486. //return new THREE.Quaternion(e.x,e.z,-e.y,e.w).multiply((new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(1,0,0), THREE.Math.degToRad(90)))
  32487. },
  32488. YupToZup: function(e){//4dkk -> navvis
  32489. let rotation = new Euler(Math.PI/2,0,0);
  32490. let quaternion = new Quaternion().setFromEuler(rotation);
  32491. return e.clone().premultiply(quaternion)
  32492. },
  32493. },
  32494. convertVisionQuaternion: function(e) {
  32495. return new Quaternion(e.x,e.z,-e.y,e.w).multiply((new Quaternion).setFromAxisAngle(new Vector3(0,1,0), MathUtils.degToRad(90)))
  32496. },
  32497. invertVisionQuaternion : function(e) {//反转给算法部
  32498. var a = e.clone().multiply((new Quaternion).setFromAxisAngle(new Vector3(0,1,0), MathUtils.degToRad(-90)));
  32499. return new Quaternion(a.x,-a.z,a.y,a.w)
  32500. },
  32501. //------------
  32502. getVec2Angle : function(dir1,dir2){
  32503. return Math.acos( MathUtils.clamp(this.getVec2Cos(dir1,dir2), -1,1) )
  32504. },
  32505. getVec2Cos : function(dir1,dir2){
  32506. return dir1.dot(dir2) / dir1.length() / dir2.length()
  32507. },
  32508. getAngle:function(vec1, vec2, axis){//带方向的角度 vector3
  32509. var angle = vec1.angleTo(vec2);
  32510. var axis_ = vec1.clone().cross(vec2);
  32511. if(axis_[axis] < 0){
  32512. angle *= -1;
  32513. }
  32514. return angle
  32515. },
  32516. closeTo : function(a,b, precision=1e-6){
  32517. let f = (a,b)=>{
  32518. return Math.abs(a-b) < precision;
  32519. };
  32520. if(typeof (a) == 'number'){
  32521. return f(a, b);
  32522. }else {
  32523. let judge = (name)=>{
  32524. if(a[name] == void 0)return true //有值就判断,没值就不判断
  32525. else return f(a[name],b[name])
  32526. };
  32527. return judge('x') && judge('y') && judge('z') && judge('w')
  32528. }
  32529. },
  32530. toPrecision: function (e, t) {//xzw change 保留小数
  32531. var f = function (e, t) {
  32532. var i = Math.pow(10, t);
  32533. return Math.round(e * i) / i
  32534. };
  32535. if (e instanceof Array) {
  32536. for (var s = 0; s < e.length; s++) {
  32537. e[s] = f(e[s], t);
  32538. }
  32539. return e;
  32540. } else if (e instanceof Object) {
  32541. for (var s in e) {
  32542. e[s] = f(e[s], t);
  32543. }
  32544. return e;
  32545. } else return f(e, t)
  32546. },
  32547. isEmptyQuaternion: function(e) {
  32548. return 0 === Math.abs(e.x) && 0 === Math.abs(e.y) && 0 === Math.abs(e.z) && 0 === Math.abs(e.w)
  32549. },
  32550. projectPositionToCanvas: function(e, t, i) {
  32551. i = i || new Vector3,
  32552. i.copy(e);
  32553. var r = .5 * $('#player').width()
  32554. , o = .5 * $('#player').height();
  32555. return i.project(t),
  32556. i.x = i.x * r + r,
  32557. i.y = -(i.y * o) + o,
  32558. i
  32559. },
  32560. handelPadResize:false,
  32561. /* handelPadding : function () { //去除player左边和上面的宽高,因为pc的player左上有其他element 许钟文
  32562. var pads = [];//记录下来避免反复计算
  32563. var index = [];
  32564. var resetPad = function(){
  32565. pads = [];
  32566. index = [];
  32567. math.handelPadResize = false; //switchview时resized为true
  32568. }
  32569. if(config.isEdit && !config.isMobile){
  32570. window.addEventListener('resize',resetPad);
  32571. }
  32572. return function(x, y, domE){
  32573. if(!config.isEdit || config.isMobile) {
  32574. return {
  32575. x: x,
  32576. y: y
  32577. }
  32578. }
  32579. if(this.handelPadResize)resetPad();
  32580. domE = domE || $('#player')[0];
  32581. var pad;
  32582. var i = index.indexOf(domE);
  32583. if (i == -1){
  32584. index.push(domE);
  32585. pad = {
  32586. x: this.getOffset("left", domE),
  32587. y: this.getOffset("top", domE)
  32588. }
  32589. pads.push(pad)
  32590. }
  32591. else pad = pads[i];
  32592. return {
  32593. x: x - pad.x,
  32594. y: y - pad.y
  32595. }
  32596. }
  32597. }(), */
  32598. getOffset: function (type, element, parent) {//获取元素的边距 许钟文
  32599. var offset = (type == "left") ? element.offsetLeft : element.offsetTop;
  32600. if (!parent) parent = $("body")[0];
  32601. while (element = element.offsetParent) {
  32602. if (element == parent) break;
  32603. offset += (type == "left") ? element.offsetLeft : element.offsetTop;
  32604. }
  32605. return offset;
  32606. }
  32607. ,
  32608. constrainedTurn: function(e) {
  32609. var t = e % (2 * Math.PI);
  32610. return t = t > Math.PI ? t -= 2 * Math.PI : t < -Math.PI ? t += 2 * Math.PI : t
  32611. },
  32612. getFOVDotThreshold: function(e) {
  32613. return Math.cos(MathUtils.degToRad(e / 2))
  32614. },
  32615. transform2DForwardVectorByCubeFace: function(e, t, i, n) {
  32616. switch (e) {
  32617. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  32618. i.set(1, t.y, t.x);
  32619. break;
  32620. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  32621. i.set(-1, t.y, -t.x);
  32622. break;
  32623. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
  32624. i.set(-t.x, 1, -t.y);
  32625. break;
  32626. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  32627. i.set(-t.x, -1, t.y);
  32628. break;
  32629. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  32630. i.set(-t.x, t.y, 1);
  32631. break;
  32632. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  32633. i.set(t.x, t.y, -1);
  32634. }
  32635. n && i.normalize();
  32636. },
  32637. getFootPoint : function(oldPos, p1, p2, restricInline){ //找oldPos在线段p1, p2上的垂足
  32638. /* if(isWorld){//输出全局坐标 需要考虑meshGroup.position
  32639. p1 = p1.clone();
  32640. p2 = p2.clone();
  32641. p1.y += mainDesign.meshGroup.position.y;
  32642. p2.y += mainDesign.meshGroup.position.y;
  32643. } */
  32644. if(p1.equals(p2))return p1.clone()
  32645. var op1 = oldPos.clone().sub(p1);
  32646. var p1p2 = p1.clone().sub(p2);
  32647. var p1p2Len = p1p2.length();
  32648. var leftLen = op1.dot(p1p2) / p1p2Len;
  32649. var pos = p1.clone().add(p1p2.multiplyScalar( leftLen/p1p2Len ));
  32650. if(restricInline && pos.clone().sub(p1).dot( pos.clone().sub(p2) ) > 0){//foot不在线段上
  32651. if(pos.distanceTo(p1) < pos.distanceTo(p2)) pos = p1.clone();
  32652. else pos = p2.clone();
  32653. }
  32654. return pos;
  32655. },
  32656. /**
  32657. * 计算多边形的重心
  32658. * @param {*} points
  32659. */
  32660. getCenterOfGravityPoint : function(mPoints){
  32661. var area = 0.0;//多边形面积
  32662. var Gx = 0.0, Gy = 0.0;// 重心的x、y
  32663. for (var i = 1; i <= mPoints.length; i++) {
  32664. var ix = mPoints[i % mPoints.length].x;
  32665. var iy = mPoints[i % mPoints.length].y;
  32666. var nx = mPoints[i - 1].x;
  32667. var ny = mPoints[i - 1].y;
  32668. var temp = (ix * ny - iy * nx) / 2.0;
  32669. area += temp;
  32670. Gx += temp * (ix + nx) / 3.0;
  32671. Gy += temp * (iy + ny) / 3.0;
  32672. }
  32673. Gx = Gx / area;
  32674. Gy = Gy / area;
  32675. return { x: Gx, y: Gy };
  32676. },
  32677. getBound : function(ring){
  32678. var bound = new Box2();
  32679. for(var j=0,len = ring.length; j<len; j++){
  32680. bound.expandByPoint(ring[j]);
  32681. }
  32682. return bound;
  32683. },
  32684. isPointInArea : function(ring, holes, point, ifAtLine){//判断点是否在某个环内, 若传递了holes代表还要不能在内环内
  32685. var bound = this.getBound(ring);
  32686. if(point.x < bound.min.x || point.x > bound.max.x || point.y < bound.min.y || point.y > bound.max.y)return false;
  32687. var inside = false;
  32688. var x = point.x,
  32689. y = point.y;
  32690. for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
  32691. var xi = ring[i].x,
  32692. yi = ring[i].y;
  32693. var xj = ring[j].x,
  32694. yj = ring[j].y;
  32695. if((xi - x)*(yj - y) == (xi - x)*(yi - y) && x>=Math.min(xi,xj) && x<=Math.max(xi,xj)//xzw add
  32696. && y>=Math.min(yi,yj) && y<=Math.max(yi,yj)
  32697. ){
  32698. //return !!ifAtLine;//在线段上,则判断为…… (默认在外)
  32699. return {atLine:true}
  32700. }
  32701. if (((yi > y) != (yj > y)) &&
  32702. (x < (xj - xi) * (y - yi) / (yj - yi) + xi)
  32703. ) {
  32704. inside = !inside;
  32705. }
  32706. }
  32707. if(inside && holes){
  32708. return !holes.some(ring=>this.isPointInArea(ring, null, point, ifAtLine) ) //不能存在于任何一个二级内环内
  32709. }else {
  32710. return inside;
  32711. }
  32712. },
  32713. getArea : function (ring) { //求面积 顺时针为正 来自three shape
  32714. for (var t = ring.length, i = 0, n = t - 1, r = 0; r < t; n = r++)
  32715. i += ring[n].x * ring[r].y - ring[r].x * ring[n].y;
  32716. return -.5 * i
  32717. },
  32718. isInBetween : function(a, b, c, precision) {
  32719. // 如果b几乎等于a或c,返回false.为了避免浮点运行时两值几乎相等,但存在相差0.00000...0001的这种情况出现使用下面方式进行避免
  32720. /* if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) {
  32721. return false;
  32722. }
  32723. return (a <= b && b <= c) || (c <= b && b <= a);*/
  32724. //更改:如果b和a或c中一个接近 就算在a和c之间
  32725. return (a <= b && b <= c) || (c <= b && b <= a) || this.closeTo(a,b,precision) || this.closeTo(b,c,precision);
  32726. },
  32727. ifPointAtLineBound:function(point, linePoints, precision){
  32728. //待验证 横线和竖线比较特殊
  32729. return math.isInBetween(linePoints[0].x, point.x, linePoints[1].x, precision) && math.isInBetween(linePoints[0].y, point.y, linePoints[1].y, precision)
  32730. }
  32731. ,
  32732. isLineIntersect: function (line1, line2, notSegment, precision) {//线段和线段是否有交点. notSegment代表是直线而不是线段
  32733. var a1 = line1[1].y - line1[0].y;
  32734. var b1 = line1[0].x - line1[1].x;
  32735. var c1 = a1 * line1[0].x + b1 * line1[0].y;
  32736. //转换成一般式: Ax+By = C
  32737. var a2 = line2[1].y - line2[0].y;
  32738. var b2 = line2[0].x - line2[1].x;
  32739. var c2 = a2 * line2[0].x + b2 * line2[0].y;
  32740. // 计算交点
  32741. var d = a1 * b2 - a2 * b1;
  32742. // 当d==0时,两线平行
  32743. if (d == 0) {
  32744. return false;
  32745. } else {
  32746. var x = (b2 * c1 - b1 * c2) / d;
  32747. var y = (a1 * c2 - a2 * c1) / d;
  32748. // 检测交点是否在两条线段上
  32749. /* if (notSegment || (isInBetween(line1[0].x, x, line1[1].x) || isInBetween(line1[0].y, y, line1[1].y)) &&
  32750. (isInBetween(line2[0].x, x, line2[1].x) || isInBetween(line2[0].y, y, line2[1].y))) {
  32751. return {x,y};
  32752. } */
  32753. if (notSegment || math.ifPointAtLineBound({x,y}, line1, precision) && math.ifPointAtLineBound({x,y}, line2, precision)){
  32754. return {x,y};
  32755. }
  32756. }
  32757. },
  32758. getNormal2d : function(o={} ){//获取二维法向量 方向向内
  32759. var x,y, x1,y1;
  32760. //line2d的向量
  32761. if(o.vec){
  32762. x1 = o.vec.x; y1 = o.vec.y;
  32763. }else {
  32764. x1 = o.p1.x - o.p2.x;
  32765. y1 = o.p1.y - o.p2.y;
  32766. }
  32767. //假设法向量的x或y固定为1或-1
  32768. if(y1 != 0){
  32769. x = 1;
  32770. y = - (x1 * x) / y1;
  32771. }else if(x1 != 0){//y如果为0,正常情况x不会是0
  32772. y = 1;
  32773. x = - (y1 * y) / x1;
  32774. }else {
  32775. console.log("两个点一样");
  32776. return null;
  32777. }
  32778. //判断方向里或者外:
  32779. var vNormal = new Vector3(x, 0, y);
  32780. var vLine = new Vector3(x1, 0, y1);
  32781. var vDir = vNormal.cross(vLine);
  32782. if(vDir.y>0){
  32783. x *= -1;
  32784. y *= -1;
  32785. }
  32786. return new Vector2$1(x, y).normalize();
  32787. },
  32788. getQuaBetween2Vector:function(oriVec, newVec, upVec){ //获取从oriVec旋转到newVec可以应用的quaternion
  32789. var angle = oriVec.angleTo(newVec);
  32790. var axis = oriVec.clone().cross( newVec).normalize();//两个up之间
  32791. if(axis.length() == 0){//当夹角为180 或 0 度时,得到的axis为(0,0,0),故使用备用的指定upVec
  32792. return new Quaternion().setFromAxisAngle( upVec, angle );
  32793. }
  32794. return new Quaternion().setFromAxisAngle( axis, angle );
  32795. }
  32796. /* ,
  32797. getQuaBetween2Vector2 : function(oriVec, newVec ){//not camera
  32798. var _ = (new THREE.Matrix4).lookAt( oriVec, new THREE.Vector3, new THREE.Vector3(0,1,0))
  32799. var aimQua = (new THREE.Quaternion).setFromRotationMatrix(_)
  32800. var _2 = (new THREE.Matrix4).lookAt( newVec, new THREE.Vector3, new THREE.Vector3(0,1,0))
  32801. var aimQua2 = (new THREE.Quaternion).setFromRotationMatrix(_2)
  32802. return aimQua2.multiply(aimQua.clone().inverse())
  32803. } */
  32804. ,
  32805. getScaleForConstantSize : function(){ //获得规定二维大小的mesh的scale值。可以避免因camera的projection造成的mesh视觉大小改变。 来源:tag.updateDisc
  32806. var w;
  32807. var i = new Vector3, o = new Vector3, l = new Vector3, c = new Vector3, h = new Vector3;
  32808. return function(op={}){
  32809. if(op.width2d) w = op.width2d; //如果恒定二维宽度
  32810. else {//否则考虑上距离,加一丢丢近大远小的效果
  32811. var currentDis, nearBound, farBound;
  32812. if(op.camera.type == "OrthographicCamera"){
  32813. currentDis = 200 / op.camera.zoom; //(op.camera.right - op.camera.left) / op.camera.zoom
  32814. }else {
  32815. currentDis = op.position.distanceTo(op.camera.position);
  32816. }
  32817. w = op.maxSize - ( op.maxSize - op.minSize) * MathUtils.smoothstep(currentDis, op.nearBound, op.farBound);
  32818. //maxSize : mesh要表现的最大像素宽度; nearBound: 最近距离,若比nearBound近,则使用maxSize
  32819. }
  32820. i.copy(op.position).project(op.camera), //tag中心在屏幕上的二维坐标
  32821. o.set(op.resolution.x / 2, op.resolution.y / 2, 1).multiply(i), //转化成px -w/2 到 w/2的范围
  32822. l.set(w / 2, 0, 0).add(o), //加上tag宽度的一半
  32823. c.set(2 / op.resolution.x, 2 / op.resolution.y, 1).multiply(l), //再转回 -1 到 1的范围
  32824. h.copy(c).unproject(op.camera);//再转成三维坐标,求得tag边缘的位置
  32825. var g = h.distanceTo(op.position);//就能得到tag的三维半径
  32826. //这里使用的都是resolution2, 好处是手机端不会太小, 坏处是pc更改网页显示百分比时显示的大小会变(或许可以自己算出设备真实的deviceRatio, 因window.screen是不会改变的),但考虑到用户可以自行调节字大小也许是好的
  32827. return g //可能NAN 当相机和position重叠时
  32828. }
  32829. }()
  32830. ,
  32831. //W , H, left, top分别是rect的宽、高、左、上
  32832. getCrossPointAtRect : function(p1, aim, W , H, left, top){//求射线p1-aim在rect边界上的交点,其中aim在rect范围内,p1则不一定(交点在aim这边的延长线上)
  32833. var x,y, borderX;
  32834. var r = (aim.x - p1.x) / (aim.y - p1.y);//根据相似三角形原理先求出这个比值
  32835. var getX = function(y){
  32836. return r * (y-p1.y) + p1.x;
  32837. };
  32838. var getY = function(x){
  32839. return 1/r * (x-p1.x) + p1.y;
  32840. };
  32841. if(aim.x >= p1.x){
  32842. borderX = W+left;
  32843. }else {
  32844. borderX = left;
  32845. }
  32846. x = borderX;
  32847. y = getY(x);
  32848. if(y < top || y > top+H){
  32849. if(y < top){
  32850. y = top;
  32851. }else {
  32852. y = top+H;
  32853. }
  32854. x = getX(y);
  32855. }
  32856. return new Vector2$1(x, y);
  32857. },
  32858. getDirFromUV : function(uv){ //获取dir 反向计算 - - 二维转三维比较麻烦
  32859. var dirB; //所求 单位向量
  32860. var y = Math.cos(uv.y * Math.PI); //uv中纵向可以直接确定y, 根据上面getUVfromDir的反向计算
  32861. // 故 uv.y * Math.PI 就是到垂直线(向上)的夹角
  32862. var angle = 2 * Math.PI * uv.x - Math.PI; //x/z代表的是角度
  32863. var axisX, axisZ; //axis为1代表是正,-1是负数
  32864. if (-Math.PI <= angle && angle < 0) {
  32865. axisX = -1; //下半圆
  32866. } else {
  32867. axisX = 1; //上半圆
  32868. }
  32869. if (-Math.PI / 2 <= angle && angle < Math.PI / 2) {
  32870. axisZ = 1; //右半圆
  32871. } else {
  32872. axisZ = -1; //左半圆
  32873. }
  32874. var XDivideZ = Math.tan(angle);
  32875. var z = Math.sqrt((1 - y * y) / (1 + XDivideZ * XDivideZ));
  32876. var x = XDivideZ * z;
  32877. if (z * axisZ < 0) { //异号
  32878. z *= -1;
  32879. x *= -1;
  32880. if (x * axisX < 0) {
  32881. // console.log("wrong!!!!!??????????")
  32882. }
  32883. }
  32884. x *= -1; //计算完成后这里不能漏掉 *= -1
  32885. dirB = this.convertVector.YupToZup(new Vector3(x, y, z));
  32886. //理想状态下x和z和anotherDir相同
  32887. return dirB
  32888. },
  32889. getUVfromDir : function(dir) { //获取UV 同shader里的计算
  32890. var dir = this.convertVector.ZupToYup(dir);
  32891. dir.x *= -1; //计算前这里不能漏掉 *= -1 见shader
  32892. var tx = Math.atan2(dir.x, dir.z) / (Math.PI * 2.0) + 0.5; //atan2(y,x) 返回从 X 轴正向逆时针旋转到点 (x,y) 时经过的角度。区间是-PI 到 PI 之间的值
  32893. var ty = Math.acos(dir.y) / Math.PI;
  32894. return new Vector2$1(tx, ty)
  32895. //理想状态下tx相同
  32896. },
  32897. getDirByLonLat : function(lon,lat){
  32898. var dir = new Vector3;
  32899. var phi = MathUtils.degToRad(90 - lat);
  32900. var theta = MathUtils.degToRad(lon);
  32901. dir.x = Math.sin(phi) * Math.cos(theta);
  32902. dir.y = Math.cos(phi);
  32903. dir.z = Math.sin(phi) * Math.sin(theta);
  32904. return dir
  32905. } //0,0 => (1,0,0) 270=>(0,0,-1)
  32906. ,
  32907. projectPointAtPlane:function(o={}){//获取一个点在一个面上的投影 {facePoints:[a,b,c], point:}
  32908. var plane = new Plane().setFromCoplanarPoints(...o.facePoints);
  32909. return plane.projectPoint(o.point, new Vector3() )
  32910. }
  32911. ,
  32912. getPolygonsMixedRings:function( polygons, onlyGetOutRing){//{points:[vector2,...],holes:[[],[]]}
  32913. let points = [];
  32914. let lines = [];
  32915. let i = 0;
  32916. polygons.forEach(e=> points.push(...e.map(a=>new Vector2$1().copy(a) )) );
  32917. polygons.forEach((ps,j)=>{
  32918. let length = ps.length;
  32919. let index = 0;
  32920. while(index<length){
  32921. lines.push({p1:index+i,p2:(index+1)%length+i});
  32922. index ++;
  32923. }
  32924. i+=length;
  32925. });
  32926. points.forEach((p,j)=>{p.id = j;});
  32927. let rings = searchRings({
  32928. points,
  32929. lines,
  32930. onlyGetOutRing
  32931. });
  32932. //console.log(rings)
  32933. rings = rings.filter(e=>e.closetParent == void 0);// 子环不加,被外环包含了
  32934. return rings
  32935. },
  32936. getQuaFromPosAim( position, target ){
  32937. let matrix = (new Matrix4).lookAt(position, target, new Vector3(0,0,1));
  32938. return (new Quaternion).setFromRotationMatrix(matrix)
  32939. },
  32940. getBoundByPoints(points, minSize){
  32941. var bound = new Box3;
  32942. points.forEach(point=>{
  32943. bound.expandByPoint(point);
  32944. });
  32945. let center = bound.getCenter(new Vector3);
  32946. if(minSize){
  32947. let minBound = (new Box3()).setFromCenterAndSize(center, minSize);
  32948. bound.union(minBound);
  32949. }
  32950. return {
  32951. bounding:bound,
  32952. size: bound.getSize(new Vector3),
  32953. center,
  32954. }
  32955. },
  32956. };
  32957. Potree.math = math;
  32958. !function() {
  32959. if ("performance"in window == 0 && (window.performance = {}),
  32960. "now"in window.performance == 0) {
  32961. var e = Date.now();
  32962. performance.timing && performance.timing.navigationStart && (e = performance.timing.navigationStart),
  32963. window.performance.now = function() {
  32964. return Date.now() - e
  32965. };
  32966. }
  32967. }(),
  32968. WebGLRenderer.prototype.paramThreeToGL = function(e) {
  32969. var t, i = this.extensions, r = this.getContext();//context;
  32970. if (e === RepeatWrapping)
  32971. return r.REPEAT;
  32972. if (e === ClampToEdgeWrapping)
  32973. return r.CLAMP_TO_EDGE;
  32974. if (e === MirroredRepeatWrapping)
  32975. return r.MIRRORED_REPEAT;
  32976. if (e === NearestFilter)
  32977. return r.NEAREST;
  32978. if (e === NearestMipMapNearestFilter)
  32979. return r.NEAREST_MIPMAP_NEAREST;
  32980. if (e === NearestMipMapLinearFilter)
  32981. return r.NEAREST_MIPMAP_LINEAR;
  32982. if (e === LinearFilter)
  32983. return r.LINEAR;
  32984. if (e === LinearMipMapNearestFilter)
  32985. return r.LINEAR_MIPMAP_NEAREST;
  32986. if (e === LinearMipMapLinearFilter)
  32987. return r.LINEAR_MIPMAP_LINEAR;
  32988. if (e === UnsignedByteType)
  32989. return r.UNSIGNED_BYTE;
  32990. if (e === UnsignedShort4444Type)
  32991. return r.UNSIGNED_SHORT_4_4_4_4;
  32992. if (e === UnsignedShort5551Type)
  32993. return r.UNSIGNED_SHORT_5_5_5_1;
  32994. if (e === UnsignedShort565Type)
  32995. return r.UNSIGNED_SHORT_5_6_5;
  32996. if (e === ByteType)
  32997. return r.BYTE;
  32998. if (e === ShortType)
  32999. return r.SHORT;
  33000. if (e === UnsignedShortType)
  33001. return r.UNSIGNED_SHORT;
  33002. if (e === IntType)
  33003. return r.INT;
  33004. if (e === UnsignedIntType)
  33005. return r.UNSIGNED_INT;
  33006. if (e === FloatType)
  33007. return r.FLOAT;
  33008. if (t = i.get("OES_texture_half_float"),
  33009. null !== t && e === HalfFloatType)
  33010. return t.HALF_FLOAT_OES;
  33011. if (e === AlphaFormat)
  33012. return r.ALPHA;
  33013. if (e === RGBFormat)
  33014. return r.RGB;
  33015. if (e === RGBAFormat)
  33016. return r.RGBA;
  33017. if (e === LuminanceFormat)
  33018. return r.LUMINANCE;
  33019. if (e === LuminanceAlphaFormat)
  33020. return r.LUMINANCE_ALPHA;
  33021. if (e === AddEquation)
  33022. return r.FUNC_ADD;
  33023. if (e === SubtractEquation)
  33024. return r.FUNC_SUBTRACT;
  33025. if (e === ReverseSubtractEquation)
  33026. return r.FUNC_REVERSE_SUBTRACT;
  33027. if (e === ZeroFactor)
  33028. return r.ZERO;
  33029. if (e === OneFactor)
  33030. return r.ONE;
  33031. if (e === SrcColorFactor)
  33032. return r.SRC_COLOR;
  33033. if (e === OneMinusSrcColorFactor)
  33034. return r.ONE_MINUS_SRC_COLOR;
  33035. if (e === SrcAlphaFactor)
  33036. return r.SRC_ALPHA;
  33037. if (e === OneMinusSrcAlphaFactor)
  33038. return r.ONE_MINUS_SRC_ALPHA;
  33039. if (e === DstAlphaFactor)
  33040. return r.DST_ALPHA;
  33041. if (e === OneMinusDstAlphaFactor)
  33042. return r.ONE_MINUS_DST_ALPHA;
  33043. if (e === DstColorFactor)
  33044. return r.DST_COLOR;
  33045. if (e === OneMinusDstColorFactor)
  33046. return r.ONE_MINUS_DST_COLOR;
  33047. if (e === SrcAlphaSaturateFactor)
  33048. return r.SRC_ALPHA_SATURATE;
  33049. if (t = i.get("WEBGL_compressed_texture_s3tc"),
  33050. null !== t) {
  33051. if (e === RGB_S3TC_DXT1_Format)
  33052. return t.COMPRESSED_RGB_S3TC_DXT1_EXT;
  33053. if (e === RGBA_S3TC_DXT1_Format$1)
  33054. return t.COMPRESSED_RGBA_S3TC_DXT1_EXT;
  33055. if (e === RGBA_S3TC_DXT3_Format)
  33056. return t.COMPRESSED_RGBA_S3TC_DXT3_EXT;
  33057. if (e === RGBA_S3TC_DXT5_Format$1)
  33058. return t.COMPRESSED_RGBA_S3TC_DXT5_EXT
  33059. }
  33060. if (t = i.get("WEBGL_compressed_texture_pvrtc"),
  33061. null !== t) {
  33062. if (e === RGB_PVRTC_4BPPV1_Format)
  33063. return t.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
  33064. if (e === RGB_PVRTC_2BPPV1_Format)
  33065. return t.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  33066. if (e === RGBA_PVRTC_4BPPV1_Format)
  33067. return t.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
  33068. if (e === RGBA_PVRTC_2BPPV1_Format)
  33069. return t.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
  33070. }
  33071. if (t = i.get("WEBGL_compressed_texture_etc1"),
  33072. null !== t && e === RGB_ETC1_Format)
  33073. return t.COMPRESSED_RGB_ETC1_WEBGL;
  33074. if (t = i.get("EXT_blend_minmax"),
  33075. null !== t) {
  33076. if (e === MinEquation)
  33077. return t.MIN_EXT;
  33078. if (e === MaxEquation)
  33079. return t.MAX_EXT
  33080. }
  33081. return 0
  33082. };
  33083. /* ,
  33084. THREE.WebGLState = function(e, t, i) {
  33085. var r = this
  33086. , o = new THREE.Vector4
  33087. , a = e.getParameter(e.MAX_VERTEX_ATTRIBS)
  33088. , s = new Uint8Array(a)
  33089. , l = new Uint8Array(a)
  33090. , c = new Uint8Array(a)
  33091. , h = {}
  33092. , u = null
  33093. , d = null
  33094. , p = null
  33095. , f = null
  33096. , g = null
  33097. , m = null
  33098. , v = null
  33099. , A = null
  33100. , y = !1
  33101. , C = null
  33102. , I = null
  33103. , E = null
  33104. , b = null
  33105. , w = null
  33106. , _ = null
  33107. , T = null
  33108. , x = null
  33109. , S = null
  33110. , M = null
  33111. , R = null
  33112. , P = null
  33113. , O = null
  33114. , L = null
  33115. , D = null
  33116. , N = e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS)
  33117. , B = void 0
  33118. , F = {}
  33119. , V = new THREE.Vector4
  33120. , U = null
  33121. , k = null
  33122. , H = new THREE.Vector4
  33123. , G = new THREE.Vector4;
  33124. this.init = function() {
  33125. this.clearColor(0, 0, 0, 1),
  33126. this.clearDepth(1),
  33127. this.clearStencil(0),
  33128. this.enable(e.DEPTH_TEST),
  33129. e.depthFunc(e.LEQUAL),
  33130. e.frontFace(e.CCW),
  33131. e.cullFace(e.BACK),
  33132. this.enable(e.CULL_FACE),
  33133. this.enable(e.BLEND),
  33134. e.blendEquation(e.FUNC_ADD),
  33135. e.blendFunc(e.SRC_ALPHA, e.ONE_MINUS_SRC_ALPHA)
  33136. }
  33137. ,
  33138. this.initAttributes = function() {
  33139. for (var e = 0, t = s.length; e < t; e++)
  33140. s[e] = 0
  33141. }
  33142. ,
  33143. this.enableAttribute = function(i) {
  33144. if (s[i] = 1,
  33145. 0 === l[i] && (e.enableVertexAttribArray(i),
  33146. l[i] = 1),
  33147. 0 !== c[i]) {
  33148. var n = t.get("ANGLE_instanced_arrays");
  33149. n.vertexAttribDivisorANGLE(i, 0),
  33150. c[i] = 0
  33151. }
  33152. }
  33153. ,
  33154. this.enableAttributeAndDivisor = function(t, i, n) {
  33155. s[t] = 1,
  33156. 0 === l[t] && (e.enableVertexAttribArray(t),
  33157. l[t] = 1),
  33158. c[t] !== i && (n.vertexAttribDivisorANGLE(t, i),
  33159. c[t] = i)
  33160. }
  33161. ,
  33162. this.disableUnusedAttributes = function() {
  33163. for (var t = 0, i = l.length; t < i; t++)
  33164. l[t] !== s[t] && (e.disableVertexAttribArray(t),
  33165. l[t] = 0)
  33166. }
  33167. ,
  33168. this.enable = function(t) {
  33169. h[t] !== !0 && (e.enable(t),
  33170. h[t] = !0)
  33171. }
  33172. ,
  33173. this.disable = function(t) {
  33174. h[t] !== !1 && (e.disable(t),
  33175. h[t] = !1)
  33176. }
  33177. ,
  33178. this.getCompressedTextureFormats = function() {
  33179. if (null === u && (u = [],
  33180. t.get("WEBGL_compressed_texture_pvrtc") || t.get("WEBGL_compressed_texture_s3tc") || t.get("WEBGL_compressed_texture_etc1")))
  33181. for (var i = e.getParameter(e.COMPRESSED_TEXTURE_FORMATS), n = 0; n < i.length; n++)
  33182. u.push(i[n]);
  33183. return u
  33184. }
  33185. ,
  33186. this.setBlending = function(t, r, o, a, s, l, c, h) {
  33187. t === THREE.NoBlending ? this.disable(e.BLEND) : this.enable(e.BLEND),
  33188. t === d && h === y || (t === THREE.AdditiveBlending ? h ? (e.blendEquationSeparate(e.FUNC_ADD, e.FUNC_ADD),
  33189. e.blendFuncSeparate(e.ONE, e.ONE, e.ONE, e.ONE)) : (e.blendEquation(e.FUNC_ADD),
  33190. e.blendFunc(e.SRC_ALPHA, e.ONE)) : t === THREE.SubtractiveBlending ? h ? (e.blendEquationSeparate(e.FUNC_ADD, e.FUNC_ADD),
  33191. e.blendFuncSeparate(e.ZERO, e.ZERO, e.ONE_MINUS_SRC_COLOR, e.ONE_MINUS_SRC_ALPHA)) : (e.blendEquation(e.FUNC_ADD),
  33192. e.blendFunc(e.ZERO, e.ONE_MINUS_SRC_COLOR)) : t === THREE.MultiplyBlending ? h ? (e.blendEquationSeparate(e.FUNC_ADD, e.FUNC_ADD),
  33193. e.blendFuncSeparate(e.ZERO, e.ZERO, e.SRC_COLOR, e.SRC_ALPHA)) : (e.blendEquation(e.FUNC_ADD),
  33194. e.blendFunc(e.ZERO, e.SRC_COLOR)) : h ? (e.blendEquationSeparate(e.FUNC_ADD, e.FUNC_ADD),
  33195. e.blendFuncSeparate(e.ONE, e.ONE_MINUS_SRC_ALPHA, e.ONE, e.ONE_MINUS_SRC_ALPHA)) : (e.blendEquationSeparate(e.FUNC_ADD, e.FUNC_ADD),
  33196. e.blendFuncSeparate(e.SRC_ALPHA, e.ONE_MINUS_SRC_ALPHA, e.ONE, e.ONE_MINUS_SRC_ALPHA)),
  33197. d = t,
  33198. y = h),
  33199. t === THREE.CustomBlending ? (s = s || r,
  33200. l = l || o,
  33201. c = c || a,
  33202. r === p && s === m || (e.blendEquationSeparate(i(r), i(s)),
  33203. p = r,
  33204. m = s),
  33205. o === f && a === g && l === v && c === A || (e.blendFuncSeparate(i(o), i(a), i(l), i(c)),
  33206. f = o,
  33207. g = a,
  33208. v = l,
  33209. A = c)) : (p = null,
  33210. f = null,
  33211. g = null,
  33212. m = null,
  33213. v = null,
  33214. A = null)
  33215. }
  33216. ,
  33217. this.setDepthFunc = function(t) {
  33218. if (C !== t) {
  33219. if (t)
  33220. switch (t) {
  33221. case THREE.NeverDepth:
  33222. e.depthFunc(e.NEVER);
  33223. break;
  33224. case THREE.AlwaysDepth:
  33225. e.depthFunc(e.ALWAYS);
  33226. break;
  33227. case THREE.LessDepth:
  33228. e.depthFunc(e.LESS);
  33229. break;
  33230. case THREE.LessEqualDepth:
  33231. e.depthFunc(e.LEQUAL);
  33232. break;
  33233. case THREE.EqualDepth:
  33234. e.depthFunc(e.EQUAL);
  33235. break;
  33236. case THREE.GreaterEqualDepth:
  33237. e.depthFunc(e.GEQUAL);
  33238. break;
  33239. case THREE.GreaterDepth:
  33240. e.depthFunc(e.GREATER);
  33241. break;
  33242. case THREE.NotEqualDepth:
  33243. e.depthFunc(e.NOTEQUAL);
  33244. break;
  33245. default:
  33246. e.depthFunc(e.LEQUAL)
  33247. }
  33248. else
  33249. e.depthFunc(e.LEQUAL);
  33250. C = t
  33251. }
  33252. }
  33253. ,
  33254. this.setDepthTest = function(t) {
  33255. t ? this.enable(e.DEPTH_TEST) : this.disable(e.DEPTH_TEST)
  33256. }
  33257. ,
  33258. this.setDepthWrite = function(t) {
  33259. I !== t && (e.depthMask(t),
  33260. I = t)
  33261. }
  33262. ,
  33263. this.setColorWrite = function(t) {
  33264. E !== t && (e.colorMask(t, t, t, t),
  33265. E = t)
  33266. }
  33267. ,
  33268. this.setStencilFunc = function(t, i, n) {
  33269. w === t && _ === i && T === n || (e.stencilFunc(t, i, n),
  33270. w = t,
  33271. _ = i,
  33272. T = n)
  33273. }
  33274. ,
  33275. this.setStencilOp = function(t, i, n) {
  33276. x === t && S === i && M === n || (e.stencilOp(t, i, n),
  33277. x = t,
  33278. S = i,
  33279. M = n)
  33280. }
  33281. ,
  33282. this.setStencilTest = function(t) {
  33283. t ? this.enable(e.STENCIL_TEST) : this.disable(e.STENCIL_TEST)
  33284. }
  33285. ,
  33286. this.setStencilWrite = function(t) {
  33287. b !== t && (e.stencilMask(t),
  33288. b = t)
  33289. }
  33290. ,
  33291. this.setFlipSided = function(t) {
  33292. R !== t && (t ? e.frontFace(e.CW) : e.frontFace(e.CCW),
  33293. R = t)
  33294. }
  33295. ,
  33296. this.setLineWidth = function(t) {
  33297. t !== P && (e.lineWidth(t),
  33298. P = t)
  33299. }
  33300. ,
  33301. this.setPolygonOffset = function(t, i, n) {
  33302. t ? this.enable(e.POLYGON_OFFSET_FILL) : this.disable(e.POLYGON_OFFSET_FILL),
  33303. !t || O === i && L === n || (e.polygonOffset(i, n),
  33304. O = i,
  33305. L = n)
  33306. }
  33307. ,
  33308. this.getScissorTest = function() {
  33309. return D
  33310. }
  33311. ,
  33312. this.setScissorTest = function(t) {
  33313. D = t,
  33314. t ? this.enable(e.SCISSOR_TEST) : this.disable(e.SCISSOR_TEST)
  33315. }
  33316. ,
  33317. this.activeTexture = function(t) {
  33318. void 0 === t && (t = e.TEXTURE0 + N - 1),
  33319. B !== t && (e.activeTexture(t),
  33320. B = t)
  33321. }
  33322. ,
  33323. this.bindTexture = function(t, i) {
  33324. void 0 === B && r.activeTexture();
  33325. var n = F[B];
  33326. void 0 === n && (n = {
  33327. type: void 0,
  33328. texture: void 0
  33329. },
  33330. F[B] = n),
  33331. n.type === t && n.texture === i || (e.bindTexture(t, i),
  33332. n.type = t,
  33333. n.texture = i)
  33334. }
  33335. ,
  33336. this.compressedTexImage2D = function() {
  33337. try {
  33338. e.compressedTexImage2D.apply(e, arguments)
  33339. } catch (e) {
  33340. console.error(e)
  33341. }
  33342. }
  33343. ,
  33344. this.texImage2D = function() {
  33345. try {
  33346. e.texImage2D.apply(e, arguments)
  33347. } catch (e) {
  33348. console.error(e)
  33349. }
  33350. }
  33351. ,
  33352. this.clearColor = function(t, i, n, r) {
  33353. o.set(t, i, n, r),
  33354. V.equals(o) === !1 && (e.clearColor(t, i, n, r),
  33355. V.copy(o))
  33356. }
  33357. ,
  33358. this.clearDepth = function(t) {
  33359. U !== t && (e.clearDepth(t),
  33360. U = t)
  33361. }
  33362. ,
  33363. this.clearStencil = function(t) {
  33364. k !== t && (e.clearStencil(t),
  33365. k = t)
  33366. }
  33367. ,
  33368. this.scissor = function(t) {
  33369. H.equals(t) === !1 && (e.scissor(t.x, t.y, t.z, t.w),
  33370. H.copy(t))
  33371. }
  33372. ,
  33373. this.viewport = function(t) {
  33374. G.equals(t) === !1 && (e.viewport(t.x, t.y, t.z, t.w),
  33375. G.copy(t))
  33376. }
  33377. ,
  33378. this.reset = function() {
  33379. for (var t = 0; t < l.length; t++)
  33380. 1 === l[t] && (e.disableVertexAttribArray(t),
  33381. l[t] = 0);
  33382. h = {},
  33383. u = null,
  33384. B = void 0,
  33385. F = {},
  33386. d = null,
  33387. E = null,
  33388. I = null,
  33389. b = null,
  33390. R = null
  33391. }
  33392. } */
  33393. const XHRFactory = {
  33394. config: {
  33395. withCredentials: false,
  33396. customHeaders: [
  33397. { header: null, value: null }
  33398. ]
  33399. },
  33400. createXMLHttpRequest: function () {
  33401. let xhr = new XMLHttpRequest();
  33402. if (this.config.customHeaders &&
  33403. Array.isArray(this.config.customHeaders) &&
  33404. this.config.customHeaders.length > 0) {
  33405. let baseOpen = xhr.open;
  33406. let customHeaders = this.config.customHeaders;
  33407. xhr.open = function () {
  33408. baseOpen.apply(this, [].slice.call(arguments));
  33409. customHeaders.forEach(function (customHeader) {
  33410. if (!!customHeader.header && !!customHeader.value) {
  33411. xhr.setRequestHeader(customHeader.header, customHeader.value);
  33412. }
  33413. });
  33414. };
  33415. }
  33416. return xhr;
  33417. }
  33418. };
  33419. let Shaders = {};
  33420. Shaders["pointcloud.vs"] = `
  33421. precision highp float;
  33422. precision highp int;
  33423. #define max_clip_polygons 8
  33424. #define PI 3.141592653589793
  33425. #if defined(usePanoMap)
  33426. uniform samplerCube pano0Map; //随便设置一个samplerCube去使用都会让点云消失
  33427. uniform samplerCube pano1Map;
  33428. uniform float progress;
  33429. uniform float easeInOutRatio;
  33430. uniform vec3 pano0Position;
  33431. uniform mat4 pano0Matrix;
  33432. uniform vec3 pano1Position;
  33433. uniform mat4 pano1Matrix;
  33434. /*
  33435. varying vec3 vWorldPosition0;
  33436. varying vec3 vWorldPosition1;
  33437. */
  33438. #endif
  33439. //--------------
  33440. attribute vec3 position;
  33441. attribute vec3 color;
  33442. attribute float intensity;
  33443. attribute float classification;
  33444. attribute float returnNumber;
  33445. attribute float numberOfReturns;
  33446. attribute float pointSourceID;
  33447. attribute vec4 indices; //每个点的index
  33448. attribute float spacing;
  33449. attribute float gpsTime;
  33450. attribute vec3 normal;
  33451. attribute float aExtra;
  33452. uniform mat4 modelMatrix;
  33453. uniform mat4 modelViewMatrix;
  33454. uniform mat4 projectionMatrix;
  33455. uniform mat4 viewMatrix;
  33456. uniform mat4 uViewInv;
  33457. //uniform float uScreenWidth;
  33458. //uniform float uScreenHeight;
  33459. uniform vec2 resolution;
  33460. uniform float fov;
  33461. uniform float near;
  33462. uniform float far;
  33463. uniform bool uDebug;
  33464. uniform bool uUseOrthographicCamera;
  33465. uniform float uOrthoWidth;
  33466. uniform float uOrthoHeight;
  33467. #define CLIPTASK_NONE 0
  33468. #define CLIPTASK_HIGHLIGHT 1
  33469. #define CLIPTASK_SHOW_INSIDE 2
  33470. #define CLIPTASK_SHOW_OUTSIDE 3
  33471. #define CLIPMETHOD_INSIDE_ANY 0
  33472. #define CLIPMETHOD_INSIDE_ALL 1
  33473. uniform int clipTask;
  33474. uniform int clipMethod;
  33475. #if defined(num_clipboxes) && num_clipboxes > 0
  33476. uniform mat4 clipBoxes[num_clipboxes];
  33477. #endif
  33478. #if defined(num_clipspheres) && num_clipspheres > 0
  33479. uniform mat4 uClipSpheres[num_clipspheres];
  33480. #endif
  33481. #if defined(num_clippolygons) && num_clippolygons > 0
  33482. uniform int uClipPolygonVCount[num_clippolygons];
  33483. uniform vec3 uClipPolygonVertices[num_clippolygons * 8];
  33484. uniform mat4 uClipPolygonWVP[num_clippolygons];
  33485. #endif
  33486. uniform float size;
  33487. uniform float minSize;
  33488. uniform float maxSize;
  33489. uniform float uPCIndex;
  33490. uniform float uOctreeSpacing;
  33491. uniform float uNodeSpacing;
  33492. uniform float uOctreeSize;
  33493. uniform vec3 uBBSize;
  33494. uniform float uLevel;
  33495. uniform float uVNStart;
  33496. uniform bool uIsLeafNode;
  33497. uniform vec3 uColor;
  33498. uniform float uOpacity;
  33499. varying float vOpacity; //add
  33500. uniform vec2 elevationRange;
  33501. uniform vec2 intensityRange;
  33502. uniform vec2 uFilterReturnNumberRange;
  33503. uniform vec2 uFilterNumberOfReturnsRange;
  33504. uniform vec2 uFilterPointSourceIDClipRange;
  33505. uniform vec2 uFilterGPSTimeClipRange;
  33506. //uniform float ufilterByNormalThreshold;
  33507. uniform float uGpsScale;
  33508. uniform float uGpsOffset;
  33509. uniform vec2 uNormalizedGpsBufferRange;
  33510. uniform vec3 uIntensity_gbc;
  33511. uniform vec3 uRGB_gbc;
  33512. uniform vec3 uExtra_gbc;
  33513. uniform float uTransition;
  33514. uniform float wRGB;
  33515. uniform float wIntensity;
  33516. uniform float wElevation;
  33517. uniform float wClassification;
  33518. uniform float wReturnNumber;
  33519. uniform float wSourceID;
  33520. uniform vec2 uExtraNormalizedRange;
  33521. uniform vec2 uExtraRange;
  33522. uniform float uExtraScale;
  33523. uniform float uExtraOffset;
  33524. uniform vec3 uShadowColor;
  33525. uniform sampler2D visibleNodes;
  33526. uniform sampler2D gradient;
  33527. uniform sampler2D classificationLUT;
  33528. #if defined(color_type_matcap)
  33529. uniform sampler2D matcapTextureUniform;
  33530. #endif
  33531. uniform bool backfaceCulling;
  33532. #if defined(num_shadowmaps) && num_shadowmaps > 0
  33533. uniform sampler2D uShadowMap[num_shadowmaps];
  33534. uniform mat4 uShadowWorldView[num_shadowmaps];
  33535. uniform mat4 uShadowProj[num_shadowmaps];
  33536. #endif
  33537. varying vec3 vColor;
  33538. varying float vLogDepth;
  33539. varying vec3 vViewPosition;
  33540. varying float vRadius;
  33541. varying float vPointSize;
  33542. float round(float number){
  33543. return floor(number + 0.5);
  33544. }
  33545. //
  33546. // ### ######## ### ######## ######## #### ## ## ######## ###### #### ######## ######## ######
  33547. // ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  33548. // ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  33549. // ## ## ## ## ## ## ######## ## ## ## ## ###### ###### ## ## ###### ######
  33550. // ######### ## ## ######### ## ## ## ## ## ## ## ## ## ## ##
  33551. // ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  33552. // ## ## ######## ## ## ## ## #### ### ######## ###### #### ######## ######## ######
  33553. //
  33554. // ---------------------
  33555. // OCTREE
  33556. // ---------------------
  33557. #if (defined(adaptive_point_size) || defined(color_type_level_of_detail)) && defined(tree_type_octree)
  33558. /**
  33559. * number of 1-bits up to inclusive index position
  33560. * number is treated as if it were an integer in the range 0-255
  33561. *
  33562. */
  33563. int numberOfOnes(int number, int index){
  33564. int numOnes = 0;
  33565. int tmp = 128;
  33566. for(int i = 7; i >= 0; i--){
  33567. if(number >= tmp){
  33568. number = number - tmp;
  33569. if(i <= index){
  33570. numOnes++;
  33571. }
  33572. }
  33573. tmp = tmp / 2;
  33574. }
  33575. return numOnes;
  33576. }
  33577. /**
  33578. * checks whether the bit at index is 1
  33579. * number is treated as if it were an integer in the range 0-255
  33580. *
  33581. */
  33582. bool isBitSet(int number, int index){
  33583. // weird multi else if due to lack of proper array, int and bitwise support in WebGL 1.0
  33584. int powi = 1;
  33585. if(index == 0){
  33586. powi = 1;
  33587. }else if(index == 1){
  33588. powi = 2;
  33589. }else if(index == 2){
  33590. powi = 4;
  33591. }else if(index == 3){
  33592. powi = 8;
  33593. }else if(index == 4){
  33594. powi = 16;
  33595. }else if(index == 5){
  33596. powi = 32;
  33597. }else if(index == 6){
  33598. powi = 64;
  33599. }else if(index == 7){
  33600. powi = 128;
  33601. }else{
  33602. return false;
  33603. }
  33604. int ndp = number / powi;
  33605. return mod(float(ndp), 2.0) != 0.0;
  33606. }
  33607. /**
  33608. * find the LOD at the point position
  33609. */
  33610. float getLOD(){//////
  33611. vec3 offset = vec3(0.0, 0.0, 0.0);
  33612. int iOffset = int(uVNStart);
  33613. float depth = uLevel;
  33614. for(float i = 0.0; i <= 30.0; i++){
  33615. float nodeSizeAtLevel = uOctreeSize / pow(2.0, i + uLevel + 0.0);
  33616. vec3 index3d = (position-offset) / nodeSizeAtLevel;
  33617. index3d = floor(index3d + 0.5);
  33618. int index = int(round(4.0 * index3d.x + 2.0 * index3d.y + index3d.z));
  33619. vec4 value = texture2D(visibleNodes, vec2(float(iOffset) / 2048.0, 0.0));
  33620. int mask = int(round(value.r * 255.0));
  33621. if(isBitSet(mask, index)){
  33622. // there are more visible child nodes at this position
  33623. int advanceG = int(round(value.g * 255.0)) * 256;
  33624. int advanceB = int(round(value.b * 255.0));
  33625. int advanceChild = numberOfOnes(mask, index - 1);
  33626. int advance = advanceG + advanceB + advanceChild;
  33627. iOffset = iOffset + advance;
  33628. depth++;
  33629. }else{
  33630. // no more visible child nodes at this position
  33631. //return value.a * 255.0;
  33632. float lodOffset = (255.0 * value.a) / 10.0 - 10.0;
  33633. return depth + lodOffset;
  33634. }
  33635. offset = offset + (vec3(1.0, 1.0, 1.0) * nodeSizeAtLevel * 0.5) * index3d;
  33636. }
  33637. return depth;
  33638. }
  33639. float getSpacing(){
  33640. vec3 offset = vec3(0.0, 0.0, 0.0);
  33641. int iOffset = int(uVNStart);
  33642. float depth = uLevel;
  33643. float spacing = uNodeSpacing;
  33644. for(float i = 0.0; i <= 30.0; i++){
  33645. float nodeSizeAtLevel = uOctreeSize / pow(2.0, i + uLevel + 0.0);
  33646. vec3 index3d = (position-offset) / nodeSizeAtLevel;
  33647. index3d = floor(index3d + 0.5);
  33648. int index = int(round(4.0 * index3d.x + 2.0 * index3d.y + index3d.z));
  33649. vec4 value = texture2D(visibleNodes, vec2(float(iOffset) / 2048.0, 0.0));
  33650. int mask = int(round(value.r * 255.0));
  33651. float spacingFactor = value.a;
  33652. if(i > 0.0){
  33653. spacing = spacing / (255.0 * spacingFactor);
  33654. }
  33655. if(isBitSet(mask, index)){
  33656. // there are more visible child nodes at this position
  33657. int advanceG = int(round(value.g * 255.0)) * 256;
  33658. int advanceB = int(round(value.b * 255.0));
  33659. int advanceChild = numberOfOnes(mask, index - 1);
  33660. int advance = advanceG + advanceB + advanceChild;
  33661. iOffset = iOffset + advance;
  33662. //spacing = spacing / (255.0 * spacingFactor);
  33663. //spacing = spacing / 3.0;
  33664. depth++;
  33665. }else{
  33666. // no more visible child nodes at this position
  33667. return spacing;
  33668. }
  33669. offset = offset + (vec3(1.0, 1.0, 1.0) * nodeSizeAtLevel * 0.5) * index3d;
  33670. }
  33671. return spacing;
  33672. }
  33673. float getPointSizeAttenuation(){
  33674. return pow(2.0, getLOD());
  33675. }
  33676. #endif
  33677. // ---------------------
  33678. // KD-TREE
  33679. // ---------------------
  33680. #if (defined(adaptive_point_size) || defined(color_type_level_of_detail)) && defined(tree_type_kdtree)
  33681. float getLOD(){
  33682. vec3 offset = vec3(0.0, 0.0, 0.0);
  33683. float iOffset = 0.0;
  33684. float depth = 0.0;
  33685. vec3 size = uBBSize;
  33686. vec3 pos = position;
  33687. for(float i = 0.0; i <= 1000.0; i++){
  33688. vec4 value = texture2D(visibleNodes, vec2(iOffset / 2048.0, 0.0));
  33689. int children = int(value.r * 255.0);
  33690. float next = value.g * 255.0;
  33691. int split = int(value.b * 255.0);
  33692. if(next == 0.0){
  33693. return depth;
  33694. }
  33695. vec3 splitv = vec3(0.0, 0.0, 0.0);
  33696. if(split == 1){
  33697. splitv.x = 1.0;
  33698. }else if(split == 2){
  33699. splitv.y = 1.0;
  33700. }else if(split == 4){
  33701. splitv.z = 1.0;
  33702. }
  33703. iOffset = iOffset + next;
  33704. float factor = length(pos * splitv / size);
  33705. if(factor < 0.5){
  33706. // left
  33707. if(children == 0 || children == 2){
  33708. return depth;
  33709. }
  33710. }else{
  33711. // right
  33712. pos = pos - size * splitv * 0.5;
  33713. if(children == 0 || children == 1){
  33714. return depth;
  33715. }
  33716. if(children == 3){
  33717. iOffset = iOffset + 1.0;
  33718. }
  33719. }
  33720. size = size * ((1.0 - (splitv + 1.0) / 2.0) + 0.5);
  33721. depth++;
  33722. }
  33723. return depth;
  33724. }
  33725. float getPointSizeAttenuation(){
  33726. return 0.5 * pow(1.3, getLOD());
  33727. }
  33728. #endif
  33729. //
  33730. // ### ######## ######## ######## #### ######## ## ## ######## ######## ######
  33731. // ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  33732. // ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  33733. // ## ## ## ## ######## ## ######## ## ## ## ###### ######
  33734. // ######### ## ## ## ## ## ## ## ## ## ## ## ##
  33735. // ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  33736. // ## ## ## ## ## ## #### ######## ####### ## ######## ######
  33737. //
  33738. // formula adapted from: http://www.dfstudios.co.uk/articles/programming/image-programming-algorithms/image-processing-algorithms-part-5-contrast-adjustment/
  33739. float getContrastFactor(float contrast){
  33740. return (1.0158730158730156 * (contrast + 1.0)) / (1.0158730158730156 - contrast);
  33741. }
  33742. vec3 getRGB(){
  33743. vec3 rgb = color;
  33744. rgb = pow(rgb, vec3(uRGB_gbc.x));
  33745. rgb = rgb + uRGB_gbc.y;
  33746. rgb = (rgb - 0.5) * getContrastFactor(uRGB_gbc.z) + 0.5;
  33747. rgb = clamp(rgb, 0.0, 1.0);
  33748. return rgb;
  33749. }
  33750. float getIntensity(){
  33751. float w = (intensity - intensityRange.x) / (intensityRange.y - intensityRange.x);
  33752. w = pow(w, uIntensity_gbc.x);
  33753. w = w + uIntensity_gbc.y;
  33754. w = (w - 0.5) * getContrastFactor(uIntensity_gbc.z) + 0.5;
  33755. w = clamp(w, 0.0, 1.0);
  33756. return w;
  33757. }
  33758. vec3 getGpsTime(){
  33759. float w = (gpsTime + uGpsOffset) * uGpsScale;
  33760. vec3 c = texture2D(gradient, vec2(w, 1.0 - w)).rgb;
  33761. // vec2 r = uNormalizedGpsBufferRange;
  33762. // float w = gpsTime * (r.y - r.x) + r.x;
  33763. // w = clamp(w, 0.0, 1.0);
  33764. // vec3 c = texture2D(gradient, vec2(w,1.0-w)).rgb;
  33765. return c;
  33766. }
  33767. vec3 getElevation(){
  33768. vec4 world = modelMatrix * vec4( position, 1.0 );
  33769. float w = (world.z - elevationRange.x) / (elevationRange.y - elevationRange.x);
  33770. vec3 cElevation = texture2D(gradient, vec2(w,1.0-w)).rgb;
  33771. return cElevation;
  33772. }
  33773. vec4 getClassification(){
  33774. vec2 uv = vec2(classification / 255.0, 0.5);
  33775. vec4 classColor = texture2D(classificationLUT, uv);
  33776. return classColor;
  33777. }
  33778. vec3 getReturns(){
  33779. // 0b 00_000_111
  33780. float rn = mod(returnNumber, 8.0);
  33781. // 0b 00_111_000
  33782. float nr = mod(returnNumber / 8.0, 8.0);
  33783. if(nr <= 1.0){
  33784. return vec3(1.0, 0.0, 0.0);
  33785. }else{
  33786. return vec3(0.0, 1.0, 0.0);
  33787. }
  33788. // return vec3(nr / 4.0, 0.0, 0.0);
  33789. // if(nr == 1.0){
  33790. // return vec3(1.0, 1.0, 0.0);
  33791. // }else{
  33792. // if(rn == 1.0){
  33793. // return vec3(1.0, 0.0, 0.0);
  33794. // }else if(rn == nr){
  33795. // return vec3(0.0, 0.0, 1.0);
  33796. // }else{
  33797. // return vec3(0.0, 1.0, 0.0);
  33798. // }
  33799. // }
  33800. // if(numberOfReturns == 1.0){
  33801. // return vec3(1.0, 1.0, 0.0);
  33802. // }else{
  33803. // if(returnNumber == 1.0){
  33804. // return vec3(1.0, 0.0, 0.0);
  33805. // }else if(returnNumber == numberOfReturns){
  33806. // return vec3(0.0, 0.0, 1.0);
  33807. // }else{
  33808. // return vec3(0.0, 1.0, 0.0);
  33809. // }
  33810. // }
  33811. }
  33812. vec3 getReturnNumber(){
  33813. if(numberOfReturns == 1.0){
  33814. return vec3(1.0, 1.0, 0.0);
  33815. }else{
  33816. if(returnNumber == 1.0){
  33817. return vec3(1.0, 0.0, 0.0);
  33818. }else if(returnNumber == numberOfReturns){
  33819. return vec3(0.0, 0.0, 1.0);
  33820. }else{
  33821. return vec3(0.0, 1.0, 0.0);
  33822. }
  33823. }
  33824. }
  33825. vec3 getNumberOfReturns(){
  33826. float value = numberOfReturns;
  33827. float w = value / 6.0;
  33828. vec3 color = texture2D(gradient, vec2(w, 1.0 - w)).rgb;
  33829. return color;
  33830. }
  33831. vec3 getSourceID(){
  33832. float w = mod(pointSourceID, 10.0) / 10.0;
  33833. return texture2D(gradient, vec2(w,1.0 - w)).rgb;
  33834. }
  33835. vec3 getCompositeColor(){
  33836. vec3 c;
  33837. float w;
  33838. c += wRGB * getRGB();
  33839. w += wRGB;
  33840. c += wIntensity * getIntensity() * vec3(1.0, 1.0, 1.0);
  33841. w += wIntensity;
  33842. c += wElevation * getElevation();
  33843. w += wElevation;
  33844. c += wReturnNumber * getReturnNumber();
  33845. w += wReturnNumber;
  33846. c += wSourceID * getSourceID();
  33847. w += wSourceID;
  33848. vec4 cl = wClassification * getClassification();
  33849. c += cl.a * cl.rgb;
  33850. w += wClassification * cl.a;
  33851. c = c / w;
  33852. if(w == 0.0){
  33853. //c = color;
  33854. gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
  33855. }
  33856. return c;
  33857. }
  33858. vec3 getNormal(){
  33859. //vec3 n_hsv = vec3( modelMatrix * vec4( normal, 0.0 )) * 0.5 + 0.5; // (n_world.xyz + vec3(1.,1.,1.)) / 2.;
  33860. vec3 n_view = normalize( vec3(modelViewMatrix * vec4( normal, 0.0 )) );
  33861. return n_view;
  33862. }
  33863. bool applyBackfaceCulling() {
  33864. // Black not facing vertices / Backface culling
  33865. vec3 e = normalize(vec3(modelViewMatrix * vec4( position, 1. )));
  33866. vec3 n = getNormal(); // normalize( vec3(modelViewMatrix * vec4( normal, 0.0 )) );
  33867. if((uUseOrthographicCamera && n.z <= 0.) || (!uUseOrthographicCamera && dot( n, e ) >= 0.)) {
  33868. return true;
  33869. } else {
  33870. return false;
  33871. }
  33872. }
  33873. #if defined(color_type_matcap)
  33874. // Matcap Material
  33875. vec3 getMatcap(){
  33876. vec3 eye = normalize( vec3( modelViewMatrix * vec4( position, 1. ) ) );
  33877. if(uUseOrthographicCamera) {
  33878. eye = vec3(0., 0., -1.);
  33879. }
  33880. vec3 r_en = reflect( eye, getNormal() ); // or r_en = e - 2. * dot( n, e ) * n;
  33881. float m = 2. * sqrt(pow( r_en.x, 2. ) + pow( r_en.y, 2. ) + pow( r_en.z + 1., 2. ));
  33882. vec2 vN = r_en.xy / m + .5;
  33883. return texture2D(matcapTextureUniform, vN).rgb;
  33884. }
  33885. #endif
  33886. vec3 getExtra(){
  33887. float w = (aExtra + uExtraOffset) * uExtraScale;
  33888. w = clamp(w, 0.0, 1.0);
  33889. vec3 color = texture2D(gradient, vec2(w,1.0-w)).rgb;
  33890. // vec2 r = uExtraNormalizedRange;
  33891. // float w = aExtra * (r.y - r.x) + r.x;
  33892. // w = (w - uExtraRange.x) / (uExtraRange.y - uExtraRange.x);
  33893. // w = clamp(w, 0.0, 1.0);
  33894. // vec3 color = texture2D(gradient, vec2(w,1.0-w)).rgb;
  33895. return color;
  33896. }
  33897. vec3 getColor(){
  33898. vec3 color;
  33899. #ifdef color_type_rgba
  33900. color = getRGB();
  33901. #elif defined color_type_height || defined color_type_elevation
  33902. color = getElevation();
  33903. #elif defined color_type_rgb_height
  33904. vec3 cHeight = getElevation();
  33905. color = (1.0 - uTransition) * getRGB() + uTransition * cHeight;
  33906. #elif defined color_type_depth
  33907. float linearDepth = gl_Position.w;
  33908. float expDepth = (gl_Position.z / gl_Position.w) * 0.5 + 0.5;
  33909. color = vec3(linearDepth, expDepth, 0.0);
  33910. //color = vec3(1.0, 0.5, 0.3);
  33911. #elif defined color_type_intensity
  33912. float w = getIntensity();
  33913. color = vec3(w, w, w);
  33914. #elif defined color_type_gps_time
  33915. color = getGpsTime();
  33916. #elif defined color_type_intensity_gradient
  33917. float w = getIntensity();
  33918. color = texture2D(gradient, vec2(w,1.0-w)).rgb;
  33919. #elif defined color_type_color
  33920. color = uColor;
  33921. #elif defined color_type_level_of_detail
  33922. float depth = getLOD();
  33923. float w = depth / 10.0;
  33924. color = texture2D(gradient, vec2(w,1.0-w)).rgb;
  33925. #elif defined color_type_indices
  33926. color = indices.rgb;
  33927. #elif defined color_type_classification
  33928. vec4 cl = getClassification();
  33929. color = cl.rgb;
  33930. #elif defined color_type_return_number
  33931. color = getReturnNumber();
  33932. #elif defined color_type_returns
  33933. color = getReturns();
  33934. #elif defined color_type_number_of_returns
  33935. color = getNumberOfReturns();
  33936. #elif defined color_type_source_id
  33937. color = getSourceID();
  33938. #elif defined color_type_point_source_id
  33939. color = getSourceID();
  33940. #elif defined color_type_normal
  33941. color = (modelMatrix * vec4(normal, 0.0)).xyz;
  33942. #elif defined color_type_phong
  33943. color = color;
  33944. #elif defined color_type_composite
  33945. color = getCompositeColor();
  33946. #elif defined color_type_matcap
  33947. color = getMatcap();
  33948. #else
  33949. color = getExtra();
  33950. #endif
  33951. if (backfaceCulling && applyBackfaceCulling()){
  33952. //color = vec3(0.);
  33953. }
  33954. //applyBackfaceCulling直接返回false或者注释color = vec3(0.);都没问题
  33955. return color;
  33956. }
  33957. float getPointSize(){
  33958. float pointSize = 1.0;
  33959. float slope = tan(fov / 2.0);
  33960. float projFactor = -0.5 * resolution.y / (slope * vViewPosition.z);
  33961. /*
  33962. float scale = length(
  33963. modelViewMatrix * vec4(0, 0, 0, 1) -
  33964. modelViewMatrix * vec4(uOctreeSpacing, 0, 0, 1)
  33965. ) / uOctreeSpacing;
  33966. projFactor = projFactor * scale;
  33967. */
  33968. float r = uOctreeSpacing * 1.7;
  33969. //vRadius = r;
  33970. #if defined fixed_point_size
  33971. pointSize = size;
  33972. #elif defined attenuated_point_size
  33973. if(uUseOrthographicCamera){
  33974. pointSize = size * 10.0; //加个乘数
  33975. }else{ //近大远小,模拟真实mesh,边缘放大
  33976. //pointSize = size * spacing * projFactor; //spacing是attribute 为空 如果有这个值就能更自适应填补
  33977. //pointSize = size * uOctreeSpacing * projFactor / 18.0; //直接用cloud的spacing里,不过因为都一样所以可能没有什么意义
  33978. //pointSize = pointSize * projFactor;
  33979. pointSize = size * projFactor ;
  33980. }
  33981. #elif defined adaptive_point_size
  33982. if(uUseOrthographicCamera) {
  33983. float worldSpaceSize = 1.0 * size * r / getPointSizeAttenuation();
  33984. pointSize = (worldSpaceSize / uOrthoWidth) * resolution.x; //uScreenWidth;
  33985. } else {
  33986. float worldSpaceSize = 1.0 * size * r / getPointSizeAttenuation();
  33987. pointSize = worldSpaceSize * projFactor;
  33988. }
  33989. #endif
  33990. pointSize = max(minSize, pointSize);
  33991. pointSize = min(maxSize, pointSize);
  33992. vRadius = pointSize / projFactor;
  33993. return pointSize;
  33994. }
  33995. #if defined(num_clippolygons) && num_clippolygons > 0
  33996. bool pointInClipPolygon(vec3 point, int polyIdx) {
  33997. mat4 wvp = uClipPolygonWVP[polyIdx];
  33998. //vec4 screenClipPos = uClipPolygonVP[polyIdx] * modelMatrix * vec4(point, 1.0);
  33999. //screenClipPos.xy = screenClipPos.xy / screenClipPos.w * 0.5 + 0.5;
  34000. vec4 pointNDC = wvp * vec4(point, 1.0);
  34001. pointNDC.xy = pointNDC.xy / pointNDC.w;
  34002. int j = uClipPolygonVCount[polyIdx] - 1;
  34003. bool c = false;
  34004. for(int i = 0; i < 8; i++) {
  34005. if(i == uClipPolygonVCount[polyIdx]) {
  34006. break;
  34007. }
  34008. //vec4 verti = wvp * vec4(uClipPolygonVertices[polyIdx * 8 + i], 1);
  34009. //vec4 vertj = wvp * vec4(uClipPolygonVertices[polyIdx * 8 + j], 1);
  34010. //verti.xy = verti.xy / verti.w;
  34011. //vertj.xy = vertj.xy / vertj.w;
  34012. //verti.xy = verti.xy / verti.w * 0.5 + 0.5;
  34013. //vertj.xy = vertj.xy / vertj.w * 0.5 + 0.5;
  34014. vec3 verti = uClipPolygonVertices[polyIdx * 8 + i];
  34015. vec3 vertj = uClipPolygonVertices[polyIdx * 8 + j];
  34016. if( ((verti.y > pointNDC.y) != (vertj.y > pointNDC.y)) &&
  34017. (pointNDC.x < (vertj.x-verti.x) * (pointNDC.y-verti.y) / (vertj.y-verti.y) + verti.x) ) {
  34018. c = !c;
  34019. }
  34020. j = i;
  34021. }
  34022. return c;
  34023. }
  34024. #endif
  34025. void doClipping(){
  34026. {
  34027. vec4 cl = getClassification();
  34028. if(cl.a == 0.0){
  34029. gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
  34030. return;
  34031. }
  34032. }
  34033. #if defined(clip_return_number_enabled)
  34034. { // return number filter
  34035. vec2 range = uFilterReturnNumberRange;
  34036. if(returnNumber < range.x || returnNumber > range.y){
  34037. gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
  34038. return;
  34039. }
  34040. }
  34041. #endif
  34042. #if defined(clip_number_of_returns_enabled)
  34043. { // number of return filter
  34044. vec2 range = uFilterNumberOfReturnsRange;
  34045. if(numberOfReturns < range.x || numberOfReturns > range.y){
  34046. gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
  34047. return;
  34048. }
  34049. }
  34050. #endif
  34051. #if defined(clip_gps_enabled)
  34052. { // GPS time filter
  34053. float time = (gpsTime + uGpsOffset) * uGpsScale;
  34054. vec2 range = uFilterGPSTimeClipRange;
  34055. if(time < range.x || time > range.y){
  34056. gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
  34057. return;
  34058. }
  34059. }
  34060. #endif
  34061. #if defined(clip_point_source_id_enabled)
  34062. { // point source id filter
  34063. vec2 range = uFilterPointSourceIDClipRange;
  34064. if(pointSourceID < range.x || pointSourceID > range.y){
  34065. gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
  34066. return;
  34067. }
  34068. }
  34069. #endif
  34070. int clipVolumesCount = 0;
  34071. int insideCount = 0;
  34072. #if defined(num_clipboxes) && num_clipboxes > 0
  34073. for(int i = 0; i < num_clipboxes; i++){
  34074. vec4 clipPosition = clipBoxes[i] * modelMatrix * vec4( position, 1.0 );
  34075. bool inside = -0.5 <= clipPosition.x && clipPosition.x <= 0.5;
  34076. inside = inside && -0.5 <= clipPosition.y && clipPosition.y <= 0.5;
  34077. inside = inside && -0.5 <= clipPosition.z && clipPosition.z <= 0.5;
  34078. insideCount = insideCount + (inside ? 1 : 0);
  34079. clipVolumesCount++;
  34080. }
  34081. #endif
  34082. #if defined(num_clippolygons) && num_clippolygons > 0
  34083. for(int i = 0; i < num_clippolygons; i++) {
  34084. bool inside = pointInClipPolygon(position, i);
  34085. insideCount = insideCount + (inside ? 1 : 0);
  34086. clipVolumesCount++;
  34087. }
  34088. #endif
  34089. bool insideAny = insideCount > 0;
  34090. bool insideAll = (clipVolumesCount > 0) && (clipVolumesCount == insideCount);
  34091. if(clipMethod == CLIPMETHOD_INSIDE_ANY){
  34092. if(insideAny && clipTask == CLIPTASK_HIGHLIGHT){
  34093. vColor.r += 0.5;
  34094. }else if(!insideAny && clipTask == CLIPTASK_SHOW_INSIDE){
  34095. gl_Position = vec4(100.0, 100.0, 100.0, 1.0);
  34096. }else if(insideAny && clipTask == CLIPTASK_SHOW_OUTSIDE){
  34097. gl_Position = vec4(100.0, 100.0, 100.0, 1.0);
  34098. }
  34099. }else if(clipMethod == CLIPMETHOD_INSIDE_ALL){
  34100. if(insideAll && clipTask == CLIPTASK_HIGHLIGHT){
  34101. vColor.r += 0.5;
  34102. }else if(!insideAll && clipTask == CLIPTASK_SHOW_INSIDE){
  34103. gl_Position = vec4(100.0, 100.0, 100.0, 1.0);
  34104. }else if(insideAll && clipTask == CLIPTASK_SHOW_OUTSIDE){
  34105. gl_Position = vec4(100.0, 100.0, 100.0, 1.0);
  34106. }
  34107. }
  34108. }
  34109. //
  34110. // ## ## ### #### ## ##
  34111. // ### ### ## ## ## ### ##
  34112. // #### #### ## ## ## #### ##
  34113. // ## ### ## ## ## ## ## ## ##
  34114. // ## ## ######### ## ## ####
  34115. // ## ## ## ## ## ## ###
  34116. // ## ## ## ## #### ## ##
  34117. //
  34118. vec2 getSamplerCoord( vec3 direction )
  34119. {
  34120. direction = normalize(direction);
  34121. float tx=atan(direction.x,-direction.y)/(PI*2.0)+0.5;
  34122. float ty=acos(direction.z)/PI;
  34123. return vec2(tx,ty);
  34124. }
  34125. vec3 transformAxis( vec3 direction ) //navvis->4dkk
  34126. {
  34127. float y = direction.y;
  34128. direction.y = direction.z;
  34129. direction.z = -y;
  34130. return direction;
  34131. }
  34132. void main() {
  34133. //bool filtered_by_normal = false;
  34134. float normalZ = 0.0;
  34135. #ifdef use_filter_by_normal
  34136. /*if(abs(getNormal().z) > 0.4) { //ufilterByNormalThreshold 暂定 3
  34137. // Move point outside clip space space to discard it.
  34138. //gl_Position = vec4(0.0, 0.0, 2.0, 1.0); //gl_Position的可视区域是 x,y,z都是[-1,1]
  34139. //return;
  34140. //filtered_by_normal = true; //标记一下。不直接不绘制,因为有的法线都是垂直向上
  34141. }*/
  34142. normalZ = abs(getNormal().z);
  34143. #endif
  34144. vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
  34145. vViewPosition = mvPosition.xyz;
  34146. gl_Position = projectionMatrix * mvPosition;
  34147. vLogDepth = log2(-mvPosition.z);
  34148. // COLOR
  34149. //加-------------------
  34150. #if defined(usePanoMap)
  34151. vec4 worldPosition = modelMatrix * vec4(position, 1.0);
  34152. vec3 positionLocalToPanoCenter0 = worldPosition.xyz - pano0Position;
  34153. vec3 vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz;
  34154. vWorldPosition0.x *= -1.0;
  34155. vWorldPosition0 = transformAxis(vWorldPosition0);
  34156. vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position;
  34157. vec3 vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz;
  34158. vWorldPosition1.x *= -1.0;
  34159. vWorldPosition1 = transformAxis(vWorldPosition1);
  34160. /*
  34161. vec2 samplerCoord0 = getSamplerCoord(vWorldPosition0.xyz);
  34162. vec2 samplerCoord1 = getSamplerCoord(vWorldPosition1.xyz);
  34163. vec4 colorFromPano0 = texture2D(pano0Map,samplerCoord0);
  34164. vec4 colorFromPano1 = texture2D(pano1Map,samplerCoord1);
  34165. */
  34166. vec4 colorFromPano0=textureCube(pano0Map,vWorldPosition0.xyz);
  34167. vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1.xyz);
  34168. vColor = mix(colorFromPano0,colorFromPano1,progress).xyz;
  34169. //float easeInOutRatio = 0.0; //缓冲,渐变点云到贴图的颜色
  34170. if(progress < easeInOutRatio){
  34171. float easeProgress = (easeInOutRatio - progress) / easeInOutRatio;
  34172. vec3 vColor1 = getColor();
  34173. vColor = mix(vColor,vColor1,easeProgress);
  34174. }else if(progress > 1.0 - easeInOutRatio){
  34175. float easeProgress = (progress - (1.0 - easeInOutRatio) ) / easeInOutRatio;
  34176. vec3 vColor1 = getColor();
  34177. vColor = mix(vColor,vColor1,easeProgress);
  34178. }
  34179. #else
  34180. vColor = getColor();
  34181. #endif
  34182. //-------------------
  34183. #ifdef attenuated_opacity
  34184. //zoom不会改变z 所以这并不是用在分屏时候的
  34185. //vOpacity = uOpacity * exp(-length(-mvPosition.xyz) / 1000.0); // e为底的指数函数 opacityAttenuation = 1000
  34186. vOpacity = uOpacity * exp(gl_Position.z/50.0);
  34187. vOpacity = clamp(vOpacity, 0.001, 1.0);
  34188. /*if(filtered_by_normal){//垂直朝相机时降低透明度
  34189. vOpacity *= 0.2;
  34190. vOpacity = clamp(vOpacity, 0.0001, 0.1);
  34191. } */
  34192. #else
  34193. vOpacity = uOpacity;
  34194. /*if(filtered_by_normal){//垂直朝相机时降低透明度
  34195. /*if(filtered_by_normal){//垂直朝相机时降低透明度
  34196. vOpacity *= 0.3;
  34197. vOpacity = clamp(vOpacity, 0.0001, 0.1);
  34198. }*/
  34199. vOpacity *= max(0.1, (1.0 - normalZ));
  34200. #endif
  34201. // POINT SIZE
  34202. float pointSize = getPointSize();
  34203. gl_PointSize = pointSize;
  34204. vPointSize = pointSize;
  34205. // only for "replacing" approaches
  34206. // if(getLOD() != uLevel){
  34207. // gl_Position = vec4(10.0, 10.0, 10.0, 1.0);
  34208. // }
  34209. #if defined hq_depth_pass
  34210. float originalDepth = gl_Position.w;
  34211. float adjustedDepth = originalDepth + 2.0 * vRadius;
  34212. float adjust = adjustedDepth / originalDepth;
  34213. mvPosition.xyz = mvPosition.xyz * adjust;
  34214. gl_Position = projectionMatrix * mvPosition;
  34215. #endif
  34216. // CLIPPING
  34217. doClipping();
  34218. #if defined(num_clipspheres) && num_clipspheres > 0
  34219. for(int i = 0; i < num_clipspheres; i++){
  34220. vec4 sphereLocal = uClipSpheres[i] * mvPosition;
  34221. float distance = length(sphereLocal.xyz);
  34222. if(distance < 1.0){
  34223. float w = distance;
  34224. vec3 cGradient = texture2D(gradient, vec2(w, 1.0 - w)).rgb;
  34225. vColor = cGradient;
  34226. //vColor = cGradient * 0.7 + vColor * 0.3;
  34227. }
  34228. }
  34229. #endif
  34230. #if defined(num_shadowmaps) && num_shadowmaps > 0
  34231. const float sm_near = 0.1;
  34232. const float sm_far = 10000.0;
  34233. for(int i = 0; i < num_shadowmaps; i++){
  34234. vec3 viewPos = (uShadowWorldView[i] * vec4(position, 1.0)).xyz;
  34235. float distanceToLight = abs(viewPos.z);
  34236. vec4 projPos = uShadowProj[i] * uShadowWorldView[i] * vec4(position, 1);
  34237. vec3 nc = projPos.xyz / projPos.w;
  34238. float u = nc.x * 0.5 + 0.5;
  34239. float v = nc.y * 0.5 + 0.5;
  34240. vec2 sampleStep = vec2(1.0 / (2.0*1024.0), 1.0 / (2.0*1024.0)) * 1.5;
  34241. vec2 sampleLocations[9];
  34242. sampleLocations[0] = vec2(0.0, 0.0);
  34243. sampleLocations[1] = sampleStep;
  34244. sampleLocations[2] = -sampleStep;
  34245. sampleLocations[3] = vec2(sampleStep.x, -sampleStep.y);
  34246. sampleLocations[4] = vec2(-sampleStep.x, sampleStep.y);
  34247. sampleLocations[5] = vec2(0.0, sampleStep.y);
  34248. sampleLocations[6] = vec2(0.0, -sampleStep.y);
  34249. sampleLocations[7] = vec2(sampleStep.x, 0.0);
  34250. sampleLocations[8] = vec2(-sampleStep.x, 0.0);
  34251. float visibleSamples = 0.0;
  34252. float numSamples = 0.0;
  34253. float bias = vRadius * 2.0;
  34254. for(int j = 0; j < 9; j++){
  34255. vec4 depthMapValue = texture2D(uShadowMap[i], vec2(u, v) + sampleLocations[j]);
  34256. float linearDepthFromSM = depthMapValue.x + bias;
  34257. float linearDepthFromViewer = distanceToLight;
  34258. if(linearDepthFromSM > linearDepthFromViewer){
  34259. visibleSamples += 1.0;
  34260. }
  34261. numSamples += 1.0;
  34262. }
  34263. float visibility = visibleSamples / numSamples;
  34264. if(u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0 || nc.x < -1.0 || nc.x > 1.0 || nc.y < -1.0 || nc.y > 1.0 || nc.z < -1.0 || nc.z > 1.0){
  34265. //vColor = vec3(0.0, 0.0, 0.2);
  34266. }else{
  34267. //vColor = vec3(1.0, 1.0, 1.0) * visibility + vec3(1.0, 1.0, 1.0) * vec3(0.5, 0.0, 0.0) * (1.0 - visibility);
  34268. vColor = vColor * visibility + vColor * uShadowColor * (1.0 - visibility);
  34269. }
  34270. }
  34271. #endif
  34272. }
  34273. `;
  34274. Shaders["pointcloud.fs"] = `
  34275. #if defined paraboloid_point_shape
  34276. #extension GL_EXT_frag_depth : enable
  34277. #endif
  34278. #define PI 3.141592653589793
  34279. precision highp float;
  34280. precision highp int;
  34281. /*
  34282. #if defined(usePanoMap)
  34283. uniform samplerCube pano0Map; //随便设置一个samplerCube去使用都会让点云消失
  34284. uniform samplerCube pano1Map;
  34285. uniform float progress;
  34286. uniform float easeInOutRatio;
  34287. uniform vec3 pano0Position;
  34288. uniform mat4 pano0Matrix;
  34289. uniform vec3 pano1Position;
  34290. uniform mat4 pano1Matrix;
  34291. varying vec3 vWorldPosition0;
  34292. varying vec3 vWorldPosition1;
  34293. #endif
  34294. */
  34295. //------------
  34296. uniform mat4 viewMatrix;
  34297. uniform mat4 uViewInv;
  34298. uniform mat4 uProjInv;
  34299. uniform vec3 cameraPosition;
  34300. uniform mat4 projectionMatrix;
  34301. //uniform float uOpacity;
  34302. varying float vOpacity; //add
  34303. uniform float blendHardness;
  34304. uniform float blendDepthSupplement;
  34305. uniform float fov;
  34306. uniform float uSpacing;
  34307. uniform float near;
  34308. uniform float far;
  34309. uniform float uPCIndex;
  34310. uniform float uScreenWidth;
  34311. uniform float uScreenHeight;
  34312. varying vec3 vColor;
  34313. varying float vLogDepth;
  34314. varying vec3 vViewPosition;
  34315. varying float vRadius;
  34316. varying float vPointSize;
  34317. varying vec3 vPosition;
  34318. float specularStrength = 1.0;
  34319. vec2 getSamplerCoord( vec3 direction )
  34320. {
  34321. direction = normalize(direction);
  34322. float tx=atan(direction.x,-direction.y)/(PI*2.0)+0.5;
  34323. float ty=acos(direction.z)/PI;
  34324. return vec2(tx,ty);
  34325. }
  34326. void main() {
  34327. vec3 color = vColor;
  34328. /*#if defined(usePanoMap) //加 经测试,即使全部写在fragment里也是无论pointsize多大都是一个点一个颜色,所以干脆写在vectex里
  34329. vec4 colorFromPano0=textureCube(pano0Map,vWorldPosition0.xyz);
  34330. vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1.xyz);
  34331. color = mix(colorFromPano0,colorFromPano1,progress).xyz;
  34332. //float easeInOutRatio = 0.0; //缓冲,渐变点云到贴图的颜色
  34333. if(progress < easeInOutRatio){
  34334. float easeProgress = (easeInOutRatio - progress) / easeInOutRatio;
  34335. color = mix(color,vColor,easeProgress);
  34336. }else if(progress > 1.0 - easeInOutRatio){
  34337. float easeProgress = (progress - (1.0 - easeInOutRatio) ) / easeInOutRatio;
  34338. color = mix(color,vColor,easeProgress);
  34339. }
  34340. #else
  34341. color = vColor;
  34342. #endif*/
  34343. float depth = gl_FragCoord.z;
  34344. #if defined(circle_point_shape) || defined(paraboloid_point_shape)
  34345. float u = 2.0 * gl_PointCoord.x - 1.0;
  34346. float v = 2.0 * gl_PointCoord.y - 1.0;
  34347. #endif
  34348. #if defined(circle_point_shape)
  34349. float cc = u*u + v*v;
  34350. if(cc > 1.0){
  34351. discard;
  34352. }
  34353. #endif
  34354. #if defined color_type_indices //pick point recognize
  34355. gl_FragColor = vec4(color, uPCIndex / 255.0); //uPCIndex : node Index
  34356. #else
  34357. gl_FragColor = vec4(color, vOpacity);
  34358. #endif
  34359. #if defined paraboloid_point_shape
  34360. float wi = 0.0 - ( u*u + v*v);
  34361. vec4 pos = vec4(vViewPosition, 1.0);
  34362. pos.z += wi * vRadius;
  34363. float linearDepth = -pos.z;
  34364. pos = projectionMatrix * pos;
  34365. pos = pos / pos.w;
  34366. float expDepth = pos.z;
  34367. depth = (pos.z + 1.0) / 2.0;
  34368. gl_FragDepthEXT = depth;
  34369. #if defined(color_type_depth)
  34370. color.r = linearDepth;
  34371. color.g = expDepth;
  34372. #endif
  34373. #if defined(use_edl)
  34374. gl_FragColor.a = log2(linearDepth);
  34375. #endif
  34376. #else
  34377. #if defined(use_edl)
  34378. gl_FragColor.a = vLogDepth;
  34379. #endif
  34380. #endif
  34381. #if defined(weighted_splats)
  34382. float distance = 2.0 * length(gl_PointCoord.xy - 0.5);
  34383. float weight = max(0.0, 1.0 - distance);
  34384. weight = pow(weight, 1.5);
  34385. gl_FragColor.a = weight;
  34386. gl_FragColor.xyz = gl_FragColor.xyz * weight;
  34387. #endif
  34388. //gl_FragColor = vec4(0.0, 0.7, 0.0, 1.0);
  34389. }
  34390. `;
  34391. Shaders["pointcloud_sm.vs"] = `
  34392. precision mediump float;
  34393. precision mediump int;
  34394. attribute vec3 position;
  34395. attribute vec3 color;
  34396. uniform mat4 modelMatrix;
  34397. uniform mat4 modelViewMatrix;
  34398. uniform mat4 projectionMatrix;
  34399. uniform mat4 viewMatrix;
  34400. uniform float uScreenWidth;
  34401. uniform float uScreenHeight;
  34402. uniform float near;
  34403. uniform float far;
  34404. uniform float uSpacing;
  34405. uniform float uOctreeSize;
  34406. uniform float uLevel;
  34407. uniform float uVNStart;
  34408. uniform sampler2D visibleNodes;
  34409. varying float vLinearDepth;
  34410. varying vec3 vColor;
  34411. #define PI 3.141592653589793
  34412. // ---------------------
  34413. // OCTREE
  34414. // ---------------------
  34415. #if defined(adaptive_point_size)
  34416. /**
  34417. * number of 1-bits up to inclusive index position
  34418. * number is treated as if it were an integer in the range 0-255
  34419. *
  34420. */
  34421. float numberOfOnes(float number, float index){
  34422. float tmp = mod(number, pow(2.0, index + 1.0));
  34423. float numOnes = 0.0;
  34424. for(float i = 0.0; i < 8.0; i++){
  34425. if(mod(tmp, 2.0) != 0.0){
  34426. numOnes++;
  34427. }
  34428. tmp = floor(tmp / 2.0);
  34429. }
  34430. return numOnes;
  34431. }
  34432. /**
  34433. * checks whether the bit at index is 1
  34434. * number is treated as if it were an integer in the range 0-255
  34435. *
  34436. */
  34437. bool isBitSet(float number, float index){
  34438. return mod(floor(number / pow(2.0, index)), 2.0) != 0.0;
  34439. }
  34440. /**
  34441. * find the LOD at the point position
  34442. */
  34443. float getLOD(){
  34444. vec3 offset = vec3(0.0, 0.0, 0.0);
  34445. float iOffset = uVNStart;
  34446. float depth = uLevel;
  34447. for(float i = 0.0; i <= 30.0; i++){
  34448. float nodeSizeAtLevel = uOctreeSize / pow(2.0, i + uLevel + 0.0);
  34449. vec3 index3d = (position-offset) / nodeSizeAtLevel;
  34450. index3d = floor(index3d + 0.5);
  34451. float index = 4.0 * index3d.x + 2.0 * index3d.y + index3d.z;
  34452. vec4 value = texture2D(visibleNodes, vec2(iOffset / 2048.0, 0.0));
  34453. float mask = value.r * 255.0;
  34454. if(isBitSet(mask, index)){
  34455. // there are more visible child nodes at this position
  34456. iOffset = iOffset + value.g * 255.0 * 256.0 + value.b * 255.0 + numberOfOnes(mask, index - 1.0);
  34457. depth++;
  34458. }else{
  34459. // no more visible child nodes at this position
  34460. return depth;
  34461. }
  34462. offset = offset + (vec3(1.0, 1.0, 1.0) * nodeSizeAtLevel * 0.5) * index3d;
  34463. }
  34464. return depth;
  34465. }
  34466. #endif
  34467. float getPointSize(){
  34468. float pointSize = 1.0;
  34469. float slope = tan(fov / 2.0);
  34470. float projFactor = -0.5 * uScreenHeight / (slope * vViewPosition.z);
  34471. float r = uOctreeSpacing * 1.5;
  34472. vRadius = r;
  34473. #if defined fixed_point_size
  34474. pointSize = size;
  34475. #elif defined attenuated_point_size
  34476. if(uUseOrthographicCamera){
  34477. pointSize = size;
  34478. }else{
  34479. pointSize = pointSize * projFactor;
  34480. }
  34481. #elif defined adaptive_point_size
  34482. if(uUseOrthographicCamera) {
  34483. float worldSpaceSize = 1.5 * size * r / getPointSizeAttenuation();
  34484. pointSize = (worldSpaceSize / uOrthoWidth) * uScreenWidth;
  34485. } else {
  34486. float worldSpaceSize = 1.5 * size * r / getPointSizeAttenuation();
  34487. pointSize = worldSpaceSize * projFactor;
  34488. }
  34489. #endif
  34490. pointSize = max(minSize, pointSize);
  34491. pointSize = min(maxSize, pointSize);
  34492. vRadius = pointSize / projFactor;
  34493. return pointSize;
  34494. }
  34495. void main() {
  34496. vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
  34497. vLinearDepth = gl_Position.w;
  34498. float pointSize = getPointSize();
  34499. gl_PointSize = pointSize;
  34500. }
  34501. `;
  34502. Shaders["pointcloud_sm.fs"] = `
  34503. precision mediump float;
  34504. precision mediump int;
  34505. varying vec3 vColor;
  34506. varying float vLinearDepth;
  34507. void main() {
  34508. //gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  34509. //gl_FragColor = vec4(vColor, 1.0);
  34510. //gl_FragColor = vec4(vLinearDepth, pow(vLinearDepth, 2.0), 0.0, 1.0);
  34511. gl_FragColor = vec4(vLinearDepth, vLinearDepth / 30.0, vLinearDepth / 30.0, 1.0);
  34512. }
  34513. `;
  34514. Shaders["normalize.vs"] = `
  34515. precision mediump float;
  34516. precision mediump int;
  34517. attribute vec3 position;
  34518. attribute vec2 uv;
  34519. uniform mat4 projectionMatrix;
  34520. uniform mat4 modelViewMatrix;
  34521. varying vec2 vUv;
  34522. void main() {
  34523. vUv = uv;
  34524. gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
  34525. }`;
  34526. Shaders["normalize.fs"] = `
  34527. #extension GL_EXT_frag_depth : enable
  34528. precision mediump float;
  34529. precision mediump int;
  34530. uniform sampler2D uWeightMap;
  34531. uniform sampler2D uDepthMap;
  34532. varying vec2 vUv;
  34533. void main() {
  34534. float depth = texture2D(uDepthMap, vUv).r;
  34535. if(depth >= 1.0){
  34536. discard;
  34537. }
  34538. gl_FragColor = vec4(depth, 1.0, 0.0, 1.0);
  34539. vec4 color = texture2D(uWeightMap, vUv);
  34540. color = color / color.w;
  34541. gl_FragColor = vec4(color.xyz, 1.0);
  34542. gl_FragDepthEXT = depth;
  34543. }`;
  34544. Shaders["normalize_and_edl.fs"] = `
  34545. #extension GL_EXT_frag_depth : enable
  34546. //
  34547. // adapted from the EDL shader code from Christian Boucheny in cloud compare:
  34548. // https://github.com/cloudcompare/trunk/tree/master/plugins/qEDL/shaders/EDL
  34549. //
  34550. precision mediump float;
  34551. precision mediump int;
  34552. uniform sampler2D uWeightMap;
  34553. uniform sampler2D uEDLMap;
  34554. uniform sampler2D uDepthMap;
  34555. uniform float screenWidth;
  34556. uniform float screenHeight;
  34557. uniform vec2 neighbours[NEIGHBOUR_COUNT];
  34558. uniform float edlStrength;
  34559. uniform float radius;
  34560. varying vec2 vUv;
  34561. float response(float depth){
  34562. vec2 uvRadius = radius / vec2(screenWidth, screenHeight);
  34563. float sum = 0.0;
  34564. for(int i = 0; i < NEIGHBOUR_COUNT; i++){
  34565. vec2 uvNeighbor = vUv + uvRadius * neighbours[i];
  34566. float neighbourDepth = texture2D(uEDLMap, uvNeighbor).a;
  34567. if(neighbourDepth != 0.0){
  34568. if(depth == 0.0){
  34569. sum += 100.0;
  34570. }else{
  34571. sum += max(0.0, depth - neighbourDepth);
  34572. }
  34573. }
  34574. }
  34575. return sum / float(NEIGHBOUR_COUNT);
  34576. }
  34577. void main() {
  34578. float edlDepth = texture2D(uEDLMap, vUv).a;
  34579. float res = response(edlDepth);
  34580. float shade = exp(-res * 300.0 * edlStrength);
  34581. float depth = texture2D(uDepthMap, vUv).r;
  34582. if(depth >= 1.0 && res == 0.0){
  34583. discard;
  34584. }
  34585. vec4 color = texture2D(uWeightMap, vUv);
  34586. color = color / color.w;
  34587. color = color * shade;
  34588. gl_FragColor = vec4(color.xyz, 1.0);
  34589. gl_FragDepthEXT = depth;
  34590. }`;
  34591. Shaders["edl.vs"] = `
  34592. precision mediump float;
  34593. precision mediump int;
  34594. attribute vec3 position;
  34595. attribute vec2 uv;
  34596. uniform mat4 projectionMatrix;
  34597. uniform mat4 modelViewMatrix;
  34598. varying vec2 vUv;
  34599. void main() {
  34600. vUv = uv;
  34601. vec4 mvPosition = modelViewMatrix * vec4(position,1.0);
  34602. gl_Position = projectionMatrix * mvPosition;
  34603. }`;
  34604. Shaders["edl.fs"] = `
  34605. #extension GL_EXT_frag_depth : enable
  34606. //
  34607. // adapted from the EDL shader code from Christian Boucheny in cloud compare:
  34608. // https://github.com/cloudcompare/trunk/tree/master/plugins/qEDL/shaders/EDL
  34609. //
  34610. precision mediump float;
  34611. precision mediump int;
  34612. //uniform float screenWidth;
  34613. //uniform float screenHeight;
  34614. uniform vec2 resolution;
  34615. uniform vec2 neighbours[NEIGHBOUR_COUNT];
  34616. uniform float edlStrength;
  34617. uniform float radius;
  34618. uniform float opacity;
  34619. //uniform float uNear;
  34620. //uniform float uFar;
  34621. uniform mat4 uProj;
  34622. uniform sampler2D uEDLColor;
  34623. uniform sampler2D uEDLDepth;
  34624. varying vec2 vUv;
  34625. uniform int useEDL;
  34626. float response(float depth){
  34627. vec2 uvRadius = radius / resolution; //vec2(screenWidth, screenHeight);
  34628. float sum = 0.0;
  34629. for(int i = 0; i < NEIGHBOUR_COUNT; i++){
  34630. vec2 uvNeighbor = vUv + uvRadius * neighbours[i];
  34631. //获取周围八个格子的值
  34632. float neighbourDepth = texture2D(uEDLColor, uvNeighbor).a;
  34633. neighbourDepth = (neighbourDepth == 1.0) ? 0.0 : neighbourDepth;
  34634. if(neighbourDepth != 0.0){
  34635. //if(depth == 0.0){
  34636. // sum += 100.0;
  34637. //}else{
  34638. sum += max(0.0, depth - neighbourDepth); //获取差值
  34639. //}
  34640. }
  34641. }
  34642. return sum / float(NEIGHBOUR_COUNT);
  34643. }
  34644. void main(){
  34645. vec4 cEDL = texture2D(uEDLColor, vUv);
  34646. float depth = cEDL.a;
  34647. depth = (depth == 1.0) ? 0.0 : depth;
  34648. if(depth == 0.0){ //去掉这句就能在无点云像素的地方渲染outline,但会遮住其他mesh
  34649. discard;
  34650. }
  34651. if(useEDL == 1){
  34652. float res = response(depth);
  34653. //if(depth == 0.0 && res == 0.0){ //test
  34654. // discard;
  34655. //}
  34656. float shade = exp(-res * 300.0 * edlStrength); //自然常数e为底的指数函数
  34657. gl_FragColor = vec4(cEDL.rgb * shade, opacity);
  34658. //const vec3 outlineColor = vec3(1.0,0.0,0.0);//test -outline
  34659. //gl_FragColor = vec4(mix(cEDL.rgb, outlineColor, -res), opacity );
  34660. }else{//加 不改颜色的情况
  34661. gl_FragColor = vec4(cEDL.rgb, opacity);
  34662. }
  34663. { // write regular hyperbolic depth values to depth buffer 修改深度
  34664. float dl = pow(2.0, depth);
  34665. vec4 dp = uProj * vec4(0.0, 0.0, -dl, 1.0);
  34666. float pz = dp.z / dp.w;
  34667. float fragDepth = (pz + 1.0) / 2.0;
  34668. gl_FragDepthEXT = fragDepth;
  34669. }
  34670. }
  34671. `;
  34672. Shaders["blur.vs"] = `
  34673. varying vec2 vUv;
  34674. void main() {
  34675. vUv = uv;
  34676. gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
  34677. }`;
  34678. Shaders["blur.fs"] = `
  34679. uniform mat4 projectionMatrix;
  34680. uniform float screenWidth;
  34681. uniform float screenHeight;
  34682. uniform float near;
  34683. uniform float far;
  34684. uniform sampler2D map;
  34685. varying vec2 vUv;
  34686. void main() {
  34687. float dx = 1.0 / screenWidth;
  34688. float dy = 1.0 / screenHeight;
  34689. vec3 color = vec3(0.0, 0.0, 0.0);
  34690. color += texture2D(map, vUv + vec2(-dx, -dy)).rgb;
  34691. color += texture2D(map, vUv + vec2( 0, -dy)).rgb;
  34692. color += texture2D(map, vUv + vec2(+dx, -dy)).rgb;
  34693. color += texture2D(map, vUv + vec2(-dx, 0)).rgb;
  34694. color += texture2D(map, vUv + vec2( 0, 0)).rgb;
  34695. color += texture2D(map, vUv + vec2(+dx, 0)).rgb;
  34696. color += texture2D(map, vUv + vec2(-dx, dy)).rgb;
  34697. color += texture2D(map, vUv + vec2( 0, dy)).rgb;
  34698. color += texture2D(map, vUv + vec2(+dx, dy)).rgb;
  34699. color = color / 9.0;
  34700. gl_FragColor = vec4(color, 1.0);
  34701. }`;
  34702. Shaders["depthBasic.vs"] = `
  34703. varying vec2 vUv;
  34704. void main() {
  34705. vUv = uv;
  34706. gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  34707. }
  34708. `;
  34709. Shaders["depthBasic.fs"] = `varying vec2 vUv;
  34710. uniform float opacity;
  34711. uniform vec3 baseColor;
  34712. uniform vec3 backColor;
  34713. uniform float occlusionDistance;
  34714. uniform float clipDistance;
  34715. uniform float maxClipFactor;
  34716. #if defined use_map
  34717. uniform sampler2D map;
  34718. #endif
  34719. #if defined(GL_EXT_frag_depth) && defined(useDepth)
  34720. //似乎通过gl.getExtension('EXT_frag_depth')得到的GL_EXT_frag_depth
  34721. uniform sampler2D depthTexture;
  34722. uniform float nearPlane;
  34723. uniform float farPlane;
  34724. uniform vec2 resolution;
  34725. uniform vec2 viewportOffset; // viewportOffset 范围从0-整个画布的像素
  34726. float convertToLinear(float zValue)
  34727. {
  34728. float z = zValue * 2.0 - 1.0;
  34729. return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane));
  34730. }
  34731. #endif
  34732. void main() {
  34733. vec4 color = vec4(baseColor, opacity);
  34734. #if defined(GL_EXT_frag_depth) && defined(useDepth)
  34735. // mixFactor and clipFactor define the color mixing proportion between the states of
  34736. // full visibility and occluded visibility
  34737. // and
  34738. // full visibility and total invisibility
  34739. float mixFactor = 0.0;
  34740. float clipFactor = 0.0;
  34741. // The linear depth value of the current fragment
  34742. float fragDepth = convertToLinear(gl_FragCoord.z);
  34743. // The coordinates of the current fragment in the depth texture
  34744. vec2 depthTxtCoords = vec2(gl_FragCoord.x-viewportOffset.x, gl_FragCoord.y - viewportOffset.y) / resolution;
  34745. // The linear depth value of the pixel occupied by this fragment in the depth buffer
  34746. float textureDepth = convertToLinear(texture2D(depthTexture, depthTxtCoords).r);
  34747. // The difference between the two depths
  34748. float delta = fragDepth - textureDepth;
  34749. if (delta > 0.0)//差距
  34750. {
  34751. // occlusionDistance and clipDistance define the width of the respective zones and
  34752. // mixFactor and clipFactor express the interpolation between the two colors depending on the position
  34753. // of the current fragment withing those zones.
  34754. mixFactor = clamp(delta / occlusionDistance, 0.0, 1.0);
  34755. clipFactor = clamp(delta / clipDistance, 0.0, maxClipFactor);
  34756. }
  34757. // If the fragment is totally transparent, don't bother drawing it
  34758. if (clipFactor == 1.0)
  34759. {
  34760. discard;
  34761. }else{
  34762. #if defined use_map
  34763. color = texture2D(map, vUv) * color;
  34764. #endif
  34765. color = vec4(mix(color.rgb, backColor, mixFactor), color.a * (1.0 - clipFactor));
  34766. }
  34767. #else
  34768. #if defined use_map
  34769. color = texture2D(map, vUv) * color;
  34770. #endif
  34771. #endif
  34772. gl_FragColor = color;
  34773. }
  34774. `;
  34775. Shaders["copyCubeMap.vs"] = `varying vec3 vWorldPos;
  34776. vec3 transformAxis( vec3 direction ) //navvis->4dkk
  34777. {
  34778. float y = direction.y;
  34779. direction.y = direction.z;
  34780. direction.z = -y;
  34781. return direction;
  34782. }
  34783. void main() {
  34784. vWorldPos = vec3(-position.x, -position.y, position.z);
  34785. //vWorldPos = transformAxis(vWorldPos);
  34786. gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  34787. }
  34788. `;
  34789. Shaders["copyCubeMap.fs"] = `varying vec3 vWorldPos;
  34790. uniform float alpha;
  34791. uniform samplerCube tDiffuse;
  34792. void main() {
  34793. vec4 texColor = textureCube(tDiffuse, vWorldPos);
  34794. gl_FragColor = vec4(texColor.rgb, texColor.a * alpha);
  34795. }
  34796. `;
  34797. Shaders["basicTextured.vs"] = `varying vec2 vUv;
  34798. void main() {
  34799. vUv = uv;
  34800. gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  34801. }
  34802. `;
  34803. Shaders["basicTextured.fs"] = `varying vec2 vUv;
  34804. uniform float alpha;
  34805. uniform sampler2D tDiffuse;
  34806. void main() {
  34807. vec4 texColor = texture2D(tDiffuse, vUv);
  34808. gl_FragColor = vec4(texColor.rgb, texColor.a * alpha);
  34809. }
  34810. `;
  34811. let ftCanvas = document.createElement('canvas');
  34812. const Features = (function () {
  34813. let gl = ftCanvas.getContext('webgl') || ftCanvas.getContext('experimental-webgl');
  34814. if (gl === null){
  34815. return null;
  34816. }
  34817. // -- code taken from THREE.WebGLRenderer --
  34818. let _vertexShaderPrecisionHighpFloat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT);
  34819. let _vertexShaderPrecisionMediumpFloat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT);
  34820. // Unused: let _vertexShaderPrecisionLowpFloat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.LOW_FLOAT);
  34821. let _fragmentShaderPrecisionHighpFloat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
  34822. let _fragmentShaderPrecisionMediumpFloat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);
  34823. // Unused: let _fragmentShaderPrecisionLowpFloat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.LOW_FLOAT);
  34824. let highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
  34825. let mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
  34826. // -----------------------------------------
  34827. let precision;
  34828. if (highpAvailable) {
  34829. precision = 'highp';
  34830. } else if (mediumpAvailable) {
  34831. precision = 'mediump';
  34832. } else {
  34833. precision = 'lowp';
  34834. }
  34835. return {
  34836. SHADER_INTERPOLATION: {
  34837. isSupported: function () {
  34838. let supported = true;
  34839. supported = supported && gl.getExtension('EXT_frag_depth');
  34840. supported = supported && gl.getParameter(gl.MAX_VARYING_VECTORS) >= 8;
  34841. return supported;
  34842. }
  34843. },
  34844. SHADER_SPLATS: {
  34845. isSupported: function () {
  34846. let supported = true;
  34847. supported = supported && gl.getExtension('EXT_frag_depth');
  34848. supported = supported && gl.getExtension('OES_texture_float');
  34849. supported = supported && gl.getParameter(gl.MAX_VARYING_VECTORS) >= 8;
  34850. return supported;
  34851. }
  34852. },
  34853. SHADER_EDL: {
  34854. isSupported: function () {
  34855. let supported = true;
  34856. supported = supported && gl.getExtension('EXT_frag_depth');
  34857. supported = supported && gl.getExtension('OES_texture_float');
  34858. supported = supported && gl.getParameter(gl.MAX_VARYING_VECTORS) >= 8;
  34859. //supported = supported || (gl instanceof WebGL2RenderingContext);
  34860. return supported;
  34861. }
  34862. },
  34863. //add:
  34864. EXT_DEPTH:{
  34865. isSupported: function () {
  34866. if(browser.detectIOS()){
  34867. let {major,minor,patch} = browser.iosVersion();
  34868. if(major == 15 && minor == 4 && patch == 1){
  34869. console.warn('检测到是ios15.4.1, 关闭EXT_frag_depth');//该版本ext_depth有问题,导致clear错乱。没有解决办法先关闭。
  34870. return false
  34871. }
  34872. }
  34873. return gl.getExtension('EXT_frag_depth'); //shader中的GL_EXT_frag_depth需要判断一下detectIOS吗。。
  34874. }
  34875. },
  34876. //WEBGL2: {
  34877. // isSupported: function(){
  34878. // return gl instanceof WebGL2RenderingContext;
  34879. // }
  34880. //},
  34881. precision: precision
  34882. };
  34883. }());
  34884. class DepthBasicMaterial extends ShaderMaterial{
  34885. constructor(o={}){
  34886. let {width, height} = viewer.renderer.getSize(new Vector2$1());
  34887. let uniforms = {
  34888. resolution: { type: 'v2', value: new Vector2$1(width, height ) },
  34889. viewportOffset: { type: 'v2', value: new Vector2$1(0, 0 ) }, //left, top
  34890. nearPlane: { type: 'f', value: 0.1 },
  34891. farPlane: { type: 'f', value: 10000 },
  34892. depthTexture: { type: 't', value: null },
  34893. opacity: { type: 'f', value: 1 },
  34894. map: { type: 't', value: o.map },
  34895. baseColor: {type:'v3', value: o.color ? new Color(o.color) : new Color("#ffffff")},
  34896. backColor: {type:'v3', value: o.backColor ? new Color(o.backColor) : new Color("#ddd")},
  34897. clipDistance : { type: 'f', value:o.clipDistance || 4}, //消失距离
  34898. occlusionDistance : { type: 'f', value: o.occlusionDistance || 1 }, //变为backColor距离
  34899. maxClipFactor : { type: 'f', value: o.maxClipFactor || 1 }, //0-1
  34900. };
  34901. let defines = {};
  34902. let useDepth = o.useDepth && Features.EXT_DEPTH.isSupported() && Potree.settings.matUseDepth;
  34903. if(useDepth )defines.useDepth = '';
  34904. if(o.map)defines.use_map = '';
  34905. super({
  34906. uniforms,
  34907. vertexShader: Shaders['depthBasic.vs'],
  34908. fragmentShader: Shaders['depthBasic.fs'],
  34909. depthWrite: !1,
  34910. depthTest: !1,
  34911. transparent: o.transparent == void 0 ? true : o.transparent,
  34912. side: o.side || 0 /* THREE.DoubleSide */,
  34913. defines,
  34914. });
  34915. if(o.opacity != void 0){
  34916. this.opacity = o.opacity;
  34917. }
  34918. if(useDepth) this.useDepth_ = true;
  34919. let setSize = (e)=>{//如果出现横条状的异常,往往是viewportOffset出错
  34920. let viewport = e.viewport;
  34921. let viewportOffset = viewport.offset || new Vector2$1();
  34922. this.uniforms.resolution.value.copy(viewport.resolution2);
  34923. this.uniforms.viewportOffset.value.copy(viewportOffset);
  34924. //console.log('depth '+viewportOffset.toArray())
  34925. };
  34926. let viewport = viewer.mainViewport;
  34927. setSize( {viewport} );
  34928. viewer.addEventListener('resize',(e)=>{
  34929. if(!e.viewport || e.viewport.camera.isPerspectiveCamera){//地图不需要
  34930. setSize(e);
  34931. //console.log(this.name + viewportOffset.toArray())
  34932. }
  34933. });
  34934. if(this.useDepth){
  34935. /* viewer.addEventListener('camera_changed', (e)=>{
  34936. if(e.viewport.name != 'mapViewport') this.updateDepthParams(e)
  34937. }) */
  34938. viewer.addEventListener("render.begin", (e)=>{//before render 如果有大于两个viewport的话,不同viewport用不同的depthTex
  34939. if(e.viewport.camera.isPerspectiveCamera) this.updateDepthParams(e);
  34940. });
  34941. this.updateDepthParams();
  34942. }
  34943. //点云变化时要一直触发updateDepthParams??
  34944. //viewer.once("render.pass.end",this.updateDepthParams.bind(this))
  34945. }
  34946. updateDepthParams(e={}){//主要用于点云遮住mesh
  34947. if(this.useDepth){
  34948. var viewport = e.viewport || viewer.mainViewport;
  34949. var camera = viewport.camera;
  34950. /* if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.depthTex){
  34951. this.uniforms.depthTexture.value = viewer.images360.currentPano.depthTex
  34952. }else{ */
  34953. this.uniforms.depthTexture.value = viewer.getPRenderer().getRtEDL(viewport).depthTexture; //其实只赋值一次就行
  34954. //}
  34955. this.uniforms.nearPlane.value = camera.near;
  34956. this.uniforms.farPlane.value = camera.far;
  34957. }
  34958. }
  34959. set map(map){
  34960. this.uniforms.map.value = map;
  34961. }
  34962. get useDepth(){
  34963. return this.useDepth_
  34964. }
  34965. set useDepth(value){//如果不支持 EXT_DEPTH 的话会失效
  34966. if(this.useDepth_ != value){
  34967. if(value && Features.EXT_DEPTH.isSupported()){
  34968. this.defines.useDepth = '';
  34969. this.updateDepthParams();
  34970. }else {
  34971. delete this.defines.useDepth;
  34972. }
  34973. this.useDepth_ = value;
  34974. this.needsUpdate = true;
  34975. }
  34976. }
  34977. get opacity(){
  34978. return this.uniforms.opacity.value
  34979. }
  34980. set opacity(o){
  34981. this.uniforms && (this.uniforms.opacity.value = o);
  34982. }
  34983. /* dispose(){
  34984. super.dispose()
  34985. viewer.depthBasic
  34986. } */
  34987. }
  34988. const geo = new PlaneBufferGeometry(1,1);
  34989. class Sprite$1 extends Mesh{
  34990. constructor(options){
  34991. super(geo, options.mat || new DepthBasicMaterial({map:options.map, useDepth:options.useDepth}));
  34992. this.root = options.root || this;
  34993. this.renderOrder = options.renderOrder != void 0 ? options.renderOrder : 4;
  34994. this.sizeInfo = options.sizeInfo;
  34995. this.dontFixOrient = options.dontFixOrient;
  34996. this.root.matrixAutoUpdate = false;
  34997. this.matrixMap = new Map();
  34998. this.name = options.name || 'sprite';
  34999. this.useViewport = null;
  35000. this.viewports = options.viewports;//指定更新的viewports
  35001. this.visible_ = true;
  35002. let update = (e)=>{
  35003. this.update(e);
  35004. };
  35005. viewer.mapViewer && viewer.mapViewer.addEventListener("camera_changed", update);
  35006. viewer.addEventListener("camera_changed", update);
  35007. /* if(viewer.viewports.length == 1){//直接更新。如果有多个不在这更新,在"render.begin"
  35008. this.update(e)
  35009. } */
  35010. let applyMatrix = (e)=>{
  35011. this.applyMatrix(e);
  35012. };
  35013. viewer.addEventListener("raycaster", applyMatrix); //before render
  35014. viewer.addEventListener("render.begin", applyMatrix); //before render //magnifier时要禁止吗
  35015. this.addEventListener('dispose', ()=>{
  35016. viewer.mapViewer && viewer.mapViewer.removeEventListener("camera_changed", update);
  35017. viewer.removeEventListener("camera_changed", update);
  35018. viewer.removeEventListener("raycaster", applyMatrix); //before render
  35019. viewer.removeEventListener("render.begin", applyMatrix);
  35020. this.dispose();
  35021. });
  35022. }
  35023. set visible(v){
  35024. this.visible_ = v;
  35025. if(v){
  35026. this.update();
  35027. }
  35028. }
  35029. get visible(){
  35030. return this.visible_
  35031. }
  35032. update(e){
  35033. if(!e){
  35034. (this.viewports || viewer.viewports).forEach(view=>{
  35035. this.update({viewport:view});
  35036. });
  35037. return;
  35038. }
  35039. if(!this.visible || !this.root)return
  35040. if(this.viewports && !this.viewports.includes(e.viewport) )return
  35041. if(e.viewport.name == 'magnifier')return
  35042. let camera = e.viewport.camera;
  35043. //rotation
  35044. this.dontFixOrient || this.root.quaternion.copy(camera.quaternion);
  35045. //scale
  35046. var info = this.sizeInfo;
  35047. if(info){
  35048. this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
  35049. this.root.updateMatrixWorld(true);
  35050. var scale;
  35051. if(info.restricMeshScale){//仅限制最大或最小的话,不判断像素大小,直接限制mesh的scale
  35052. var dis = camera.position.distanceTo(this.getWorldPosition(new Vector3()));
  35053. if(dis < info.nearBound){
  35054. scale = info.scale * dis / info.nearBound;
  35055. }else {
  35056. scale = info.scale;
  35057. }
  35058. }else {
  35059. scale = math.getScaleForConstantSize($.extend(info,{//规定下最小最大像素
  35060. camera , position:this.getWorldPosition(new Vector3()) ,
  35061. resolution: e.viewport.resolution//2
  35062. }));
  35063. }
  35064. if(!isNaN(scale)){
  35065. this.root.scale.set(scale, scale, scale);
  35066. }
  35067. }
  35068. this.root.updateMatrix();
  35069. this.root.updateMatrixWorld(true);
  35070. this.matrixMap.set(e.viewport, this.root.matrix.clone());
  35071. this.useViewport = e.viewport;
  35072. }
  35073. applyMatrix(e){
  35074. if(!e)e = {viewport:viewer.mainViewport};//随便写一个viewport
  35075. if(e.viewport.name == 'magnifier')return
  35076. if(this.viewports && !this.viewports.includes(e.viewport) )return
  35077. if(!this.visible || !this.root)return
  35078. var matrix = this.matrixMap.get(e.viewport);
  35079. if(!matrix){
  35080. this.update(e);
  35081. matrix = this.matrixMap.get(e.viewport);
  35082. }
  35083. if(e.viewport == this.useViewport){
  35084. return
  35085. }
  35086. this.useViewport = e.viewport;
  35087. this.root.matrix.copy(matrix);
  35088. this.root.updateMatrixWorld(true);
  35089. //console.log(this.root.name + e.viewport.name + " : "+this.root.matrixWorld.elements)
  35090. }
  35091. setUniforms(name,value){
  35092. this.material.setUniforms(name,value);
  35093. }
  35094. dispose(){
  35095. this.removeAllListeners();
  35096. this.parent && this.parent.remove(this);
  35097. }
  35098. }
  35099. //可能还是要用html写,因为要加按钮和图片
  35100. class TextSprite extends Object3D{
  35101. constructor( options={}){
  35102. super();
  35103. let map = new Texture();
  35104. map.minFilter = LinearFilter;
  35105. map.magFilter = LinearFilter;
  35106. this.sprite = new Sprite$1({
  35107. sizeInfo:options.sizeInfo,
  35108. renderOrder:options.renderOrder,
  35109. useDepth: options.useDepth,
  35110. map,
  35111. root: this ,
  35112. dontFixOrient: options.dontFixOrient
  35113. });
  35114. this.add(this.sprite);
  35115. this.rectBorderThick = options.rectBorderThick || 0;
  35116. this.textBorderThick = options.textBorderThick || 0;
  35117. this.fontface = 'Arial';
  35118. this.fontsize = options.fontsize || 16;
  35119. this.textBorderColor = options.textBorderColor || { r: 0, g: 0, b: 0, a: 0.0 };
  35120. this.backgroundColor = options.backgroundColor || { r: 255, g: 255, b: 255, a: 1.0 };
  35121. this.textColor = options.textColor || {r: 0, g: 0, b: 0, a: 1.0};
  35122. this.borderColor = options.borderColor || { r: 0, g: 0, b: 0, a: 0.0 };
  35123. this.borderRadius = options.borderRadius || 6;
  35124. if(options.text != void 0)this.setText(options.text);
  35125. this.name = options.name;
  35126. //this.setText(text);
  35127. this.addEventListener('dispose', this.dispose.bind(this));
  35128. }
  35129. setText(text){
  35130. if (this.text !== text){
  35131. this.text = text + '';
  35132. this.updateTexture();
  35133. }
  35134. }
  35135. setTextColor(color){
  35136. this.textColor = color;
  35137. this.updateTexture();
  35138. }
  35139. setBorderColor(color){
  35140. this.borderColor = color;
  35141. this.updateTexture();
  35142. }
  35143. setBackgroundColor(color){
  35144. this.backgroundColor = color;
  35145. this.updateTexture();
  35146. }
  35147. setPos(pos){
  35148. this.position.copy(pos);
  35149. this.sprite.update();
  35150. }
  35151. update(){
  35152. this.sprite.update();
  35153. }
  35154. setVisible(v){
  35155. this.visible = v;
  35156. }
  35157. setUniforms(name,value){
  35158. this.sprite.setUniforms(name,value);
  35159. }
  35160. updateTexture(){
  35161. let canvas = document.createElement('canvas');
  35162. let context = canvas.getContext('2d');
  35163. context.font = 'Bold ' + this.fontsize + 'px ' + this.fontface;
  35164. context["font-weight"] = 100; //语法与 CSS font 属性相同。
  35165. // get size data (height depends only on font size)
  35166. //this.text = '啊啊啊啊啊啊fag'
  35167. let metrics = context.measureText(this.text );
  35168. let textWidth = metrics.width;
  35169. let margin = new Vector2$1(this.fontsize, this.fontsize*0.4);
  35170. let spriteWidth = 2 * margin.x + textWidth + 2 * this.rectBorderThick;
  35171. let spriteHeight = 2 * margin.y + this.fontsize + 2 * this.rectBorderThick;
  35172. context.canvas.width = spriteWidth;
  35173. context.canvas.height = spriteHeight;
  35174. context.font = 'Bold ' + this.fontsize + 'px ' + this.fontface;
  35175. let diff = 2;//针对英文大部分在baseLine之上所以降低一点(metrics.fontBoundingBoxAscent - metrics.fontBoundingBoxDescent) / 2
  35176. context.textBaseline = "middle";
  35177. // border color
  35178. context.strokeStyle = 'rgba(' + this.borderColor.r + ',' + this.borderColor.g + ',' +
  35179. this.borderColor.b + ',' + this.borderColor.a + ')';
  35180. context.lineWidth = this.rectBorderThick;
  35181. // background color
  35182. context.fillStyle = 'rgba(' + this.backgroundColor.r + ',' + this.backgroundColor.g + ',' +
  35183. this.backgroundColor.b + ',' + this.backgroundColor.a + ')';
  35184. this.roundRect(context, this.rectBorderThick / 2, this.rectBorderThick / 2,
  35185. spriteWidth - this.rectBorderThick, spriteHeight - this.rectBorderThick, this.borderRadius);
  35186. // text color
  35187. if(this.textBorderThick){
  35188. context.strokeStyle = 'rgba(' + this.textBorderColor.r + ',' + this.textBorderColor.g + ',' +
  35189. this.textBorderColor.b + ',' + this.textBorderColor.a + ')';
  35190. context.lineWidth = this.textBorderThick;
  35191. context.strokeText(this.text , this.rectBorderThick + margin.x,spriteHeight/2 + diff );
  35192. }
  35193. context.fillStyle = 'rgba(' + this.textColor.r + ',' + this.textColor.g + ',' +
  35194. this.textColor.b + ',' + this.textColor.a + ')';
  35195. context.fillText(this.text , this.rectBorderThick + margin.x, spriteHeight/2 + diff );//x,y
  35196. let texture = new Texture(canvas);
  35197. texture.minFilter = LinearFilter;
  35198. texture.magFilter = LinearFilter;
  35199. texture.needsUpdate = true;
  35200. //this.material.needsUpdate = true;
  35201. if(this.sprite.material.map){
  35202. this.sprite.material.map.dispose();
  35203. }
  35204. this.sprite.material.map = texture;
  35205. this.sprite.scale.set(spriteWidth * 0.01, spriteHeight * 0.01, 1.0);
  35206. }
  35207. roundRect(ctx, x, y, w, h, r){
  35208. ctx.beginPath();
  35209. ctx.moveTo(x + r, y);
  35210. ctx.lineTo(x + w - r, y);
  35211. ctx.arcTo(x + w, y, x + w, y + r, r );//圆弧。前四个参数同quadraticCurveTo
  35212. //ctx.quadraticCurveTo(x + w, y, x + w, y + r); //二次贝塞尔曲线需要两个点。第一个点是用于二次贝塞尔计算中的控制点,第二个点是曲线的结束点。
  35213. ctx.lineTo(x + w, y + h - r);
  35214. ctx.arcTo(x + w, y + h, x + w - r, y + h, r );
  35215. ctx.lineTo(x + r, y + h);
  35216. ctx.arcTo(x, y + h, x, y + h - r, r );
  35217. ctx.lineTo(x, y + r);
  35218. ctx.arcTo(x, y, x + r, y, r );
  35219. ctx.closePath();
  35220. ctx.fill();
  35221. ctx.stroke();
  35222. }
  35223. dispose(){
  35224. this.sprite.material.uniforms.map.value.dispose();
  35225. this.parent && this.parent.remove(this);
  35226. this.sprite.dispatchEvent({type:'dispose'});
  35227. this.removeAllListeners();
  35228. }
  35229. }
  35230. class Volume extends Object3D {
  35231. constructor (args = {}) {
  35232. super();
  35233. if(this.constructor.name === "Volume"){
  35234. console.warn("Can't create object of class Volume directly. Use classes BoxVolume or SphereVolume instead.");
  35235. }
  35236. //console.log(this);
  35237. //console.log(this.constructor);
  35238. //console.log(this.constructor.name);
  35239. this._clip = args.clip || false;
  35240. this._visible = true;
  35241. this._modifiable = args.modifiable || true;
  35242. { // event listeners
  35243. this.addEventListener('select', e => {});
  35244. this.addEventListener('deselect', e => {});
  35245. }
  35246. }
  35247. get visible(){
  35248. return this._visible;
  35249. }
  35250. set visible(value){
  35251. if(this._visible !== value){
  35252. this._visible = value;
  35253. this.dispatchEvent({type: "visibility_changed", object: this});
  35254. }
  35255. }
  35256. getVolume () {
  35257. console.warn("override this in subclass");
  35258. }
  35259. update () {
  35260. };
  35261. raycast (raycaster, intersects) {
  35262. }
  35263. get clip () {
  35264. return this._clip;
  35265. }
  35266. set clip (value) {
  35267. if(this._clip !== value){
  35268. this._clip = value;
  35269. this.update();
  35270. this.dispatchEvent({
  35271. type: "clip_changed",
  35272. object: this
  35273. });
  35274. }
  35275. }
  35276. get modifieable () {
  35277. return this._modifiable;
  35278. }
  35279. set modifieable (value) {
  35280. this._modifiable = value;
  35281. this.update();
  35282. }
  35283. };
  35284. class BoxVolume extends Volume{
  35285. constructor(args = {}){
  35286. super(args);
  35287. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  35288. this.name = 'box_' + this.constructor.counter;
  35289. let boxGeometry = new BoxGeometry(1, 1, 1);
  35290. boxGeometry.computeBoundingBox();
  35291. let boxFrameGeometry = new Geometry();
  35292. {
  35293. let Vector3$1 = Vector3;
  35294. boxFrameGeometry.vertices.push(
  35295. // bottom
  35296. new Vector3$1(-0.5, -0.5, 0.5),
  35297. new Vector3$1(0.5, -0.5, 0.5),
  35298. new Vector3$1(0.5, -0.5, 0.5),
  35299. new Vector3$1(0.5, -0.5, -0.5),
  35300. new Vector3$1(0.5, -0.5, -0.5),
  35301. new Vector3$1(-0.5, -0.5, -0.5),
  35302. new Vector3$1(-0.5, -0.5, -0.5),
  35303. new Vector3$1(-0.5, -0.5, 0.5),
  35304. // top
  35305. new Vector3$1(-0.5, 0.5, 0.5),
  35306. new Vector3$1(0.5, 0.5, 0.5),
  35307. new Vector3$1(0.5, 0.5, 0.5),
  35308. new Vector3$1(0.5, 0.5, -0.5),
  35309. new Vector3$1(0.5, 0.5, -0.5),
  35310. new Vector3$1(-0.5, 0.5, -0.5),
  35311. new Vector3$1(-0.5, 0.5, -0.5),
  35312. new Vector3$1(-0.5, 0.5, 0.5),
  35313. // sides
  35314. new Vector3$1(-0.5, -0.5, 0.5),
  35315. new Vector3$1(-0.5, 0.5, 0.5),
  35316. new Vector3$1(0.5, -0.5, 0.5),
  35317. new Vector3$1(0.5, 0.5, 0.5),
  35318. new Vector3$1(0.5, -0.5, -0.5),
  35319. new Vector3$1(0.5, 0.5, -0.5),
  35320. new Vector3$1(-0.5, -0.5, -0.5),
  35321. new Vector3$1(-0.5, 0.5, -0.5),
  35322. );
  35323. }
  35324. this.material = new MeshBasicMaterial({
  35325. color: 0x00ff00,
  35326. transparent: true,
  35327. opacity: 0.3,
  35328. depthTest: true,
  35329. depthWrite: false});
  35330. this.box = new Mesh(boxGeometry, this.material);
  35331. this.box.geometry.computeBoundingBox();
  35332. this.boundingBox = this.box.geometry.boundingBox;
  35333. this.add(this.box);
  35334. this.frame = new LineSegments(boxFrameGeometry, new LineBasicMaterial({color: 0x000000}));
  35335. // this.frame.mode = THREE.Lines;
  35336. this.add(this.frame);
  35337. viewer.setObjectLayers(this, 'volume' );
  35338. this.update();
  35339. }
  35340. update(){
  35341. this.boundingBox = this.box.geometry.boundingBox;
  35342. this.boundingSphere = this.boundingBox.getBoundingSphere(new Sphere());
  35343. if (this._clip) {
  35344. this.box.visible = false;
  35345. } else {
  35346. this.box.visible = true;
  35347. }
  35348. }
  35349. raycast (raycaster, intersects) {
  35350. let is = [];
  35351. this.box.raycast(raycaster, is);
  35352. if (is.length > 0) {
  35353. let I = is[0];
  35354. intersects.push({
  35355. distance: I.distance,
  35356. object: this,
  35357. point: I.point.clone()
  35358. });
  35359. }
  35360. }
  35361. getVolume(){
  35362. return Math.abs(this.scale.x * this.scale.y * this.scale.z);
  35363. }
  35364. };
  35365. class SphereVolume extends Volume{
  35366. constructor(args = {}){
  35367. super(args);
  35368. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  35369. this.name = 'sphere_' + this.constructor.counter;
  35370. let sphereGeometry = new SphereGeometry(1, 32, 32);
  35371. sphereGeometry.computeBoundingBox();
  35372. this.material = new MeshBasicMaterial({
  35373. color: 0x00ff00,
  35374. transparent: true,
  35375. opacity: 0.3,
  35376. depthTest: true,
  35377. depthWrite: false});
  35378. this.sphere = new Mesh(sphereGeometry, this.material);
  35379. this.sphere.visible = false;
  35380. this.sphere.geometry.computeBoundingBox();
  35381. this.boundingBox = this.sphere.geometry.boundingBox;
  35382. this.add(this.sphere);
  35383. let frameGeometry = new Geometry();
  35384. {
  35385. let steps = 64;
  35386. let uSegments = 8;
  35387. let vSegments = 5;
  35388. let r = 1;
  35389. for(let uSegment = 0; uSegment < uSegments; uSegment++){
  35390. let alpha = (uSegment / uSegments) * Math.PI * 2;
  35391. let dirx = Math.cos(alpha);
  35392. let diry = Math.sin(alpha);
  35393. for(let i = 0; i <= steps; i++){
  35394. let v = (i / steps) * Math.PI * 2;
  35395. let vNext = v + 2 * Math.PI / steps;
  35396. let height = Math.sin(v);
  35397. let xyAmount = Math.cos(v);
  35398. let heightNext = Math.sin(vNext);
  35399. let xyAmountNext = Math.cos(vNext);
  35400. let vertex = new Vector3(dirx * xyAmount, diry * xyAmount, height);
  35401. frameGeometry.vertices.push(vertex);
  35402. let vertexNext = new Vector3(dirx * xyAmountNext, diry * xyAmountNext, heightNext);
  35403. frameGeometry.vertices.push(vertexNext);
  35404. }
  35405. }
  35406. // creates rings at poles, just because it's easier to implement
  35407. for(let vSegment = 0; vSegment <= vSegments + 1; vSegment++){
  35408. //let height = (vSegment / (vSegments + 1)) * 2 - 1; // -1 to 1
  35409. let uh = (vSegment / (vSegments + 1)); // -1 to 1
  35410. uh = (1 - uh) * (-Math.PI / 2) + uh *(Math.PI / 2);
  35411. let height = Math.sin(uh);
  35412. console.log(uh, height);
  35413. for(let i = 0; i <= steps; i++){
  35414. let u = (i / steps) * Math.PI * 2;
  35415. let uNext = u + 2 * Math.PI / steps;
  35416. let dirx = Math.cos(u);
  35417. let diry = Math.sin(u);
  35418. let dirxNext = Math.cos(uNext);
  35419. let diryNext = Math.sin(uNext);
  35420. let xyAmount = Math.sqrt(1 - height * height);
  35421. let vertex = new Vector3(dirx * xyAmount, diry * xyAmount, height);
  35422. frameGeometry.vertices.push(vertex);
  35423. let vertexNext = new Vector3(dirxNext * xyAmount, diryNext * xyAmount, height);
  35424. frameGeometry.vertices.push(vertexNext);
  35425. }
  35426. }
  35427. }
  35428. this.frame = new LineSegments(frameGeometry, new LineBasicMaterial({color: 0x000000}));
  35429. this.add(this.frame);
  35430. let frameMaterial = new MeshBasicMaterial({wireframe: true, color: 0x000000});
  35431. this.frame = new Mesh(sphereGeometry, frameMaterial);
  35432. //this.add(this.frame);
  35433. //this.frame = new THREE.LineSegments(boxFrameGeometry, new THREE.LineBasicMaterial({color: 0x000000}));
  35434. // this.frame.mode = THREE.Lines;
  35435. //this.add(this.frame);
  35436. this.update();
  35437. }
  35438. update(){
  35439. this.boundingBox = this.sphere.geometry.boundingBox;
  35440. this.boundingSphere = this.boundingBox.getBoundingSphere(new Sphere());
  35441. }
  35442. raycast (raycaster, intersects) {
  35443. let is = [];
  35444. this.sphere.raycast(raycaster, is);
  35445. if (is.length > 0) {
  35446. let I = is[0];
  35447. intersects.push({
  35448. distance: I.distance,
  35449. object: this,
  35450. point: I.point.clone()
  35451. });
  35452. }
  35453. }
  35454. // see https://en.wikipedia.org/wiki/Ellipsoid#Volume
  35455. getVolume(){
  35456. return (4 / 3) * Math.PI * this.scale.x * this.scale.y * this.scale.z;
  35457. }
  35458. };
  35459. class Profile extends Object3D{
  35460. constructor () {
  35461. super();
  35462. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  35463. this.name = 'Profile_' + this.constructor.counter;
  35464. this.points = [];
  35465. this.spheres = [];
  35466. this.edges = [];
  35467. this.boxes = [];
  35468. this.width = 1;
  35469. this.height = 20;
  35470. this._modifiable = true;
  35471. this.sphereGeometry = new SphereGeometry(0.4, 10, 10);
  35472. this.color = new Color(0xff0000);
  35473. this.lineColor = new Color(0xff0000);
  35474. }
  35475. createSphereMaterial () {
  35476. let sphereMaterial = new MeshLambertMaterial({
  35477. //shading: THREE.SmoothShading,
  35478. color: 0xff0000,
  35479. depthTest: false,
  35480. depthWrite: false}
  35481. );
  35482. return sphereMaterial;
  35483. };
  35484. getSegments () {
  35485. let segments = [];
  35486. for (let i = 0; i < this.points.length - 1; i++) {
  35487. let start = this.points[i].clone();
  35488. let end = this.points[i + 1].clone();
  35489. segments.push({start: start, end: end});
  35490. }
  35491. return segments;
  35492. }
  35493. getSegmentMatrices () {
  35494. let segments = this.getSegments();
  35495. let matrices = [];
  35496. for (let segment of segments) {
  35497. let {start, end} = segment;
  35498. let box = new Object3D();
  35499. let length;
  35500. if(window.axisYup){
  35501. length = start.clone().setY(0).distanceTo(end.clone().setY(0));
  35502. box.scale.set(length, 10000, this.width); //???
  35503. }else {
  35504. length = start.clone().setZ(0).distanceTo(end.clone().setZ(0));
  35505. box.scale.set(length, 10000, this.width);
  35506. box.up.set(0, 0, 1);
  35507. }
  35508. let center = new Vector3().addVectors(start, end).multiplyScalar(0.5);
  35509. let diff = new Vector3().subVectors(end, start);
  35510. let target = new Vector3(diff.y, -diff.x, 0);
  35511. box.position.set(0, 0, 0);
  35512. box.lookAt(target);
  35513. box.position.copy(center);
  35514. box.updateMatrixWorld();
  35515. matrices.push(box.matrixWorld);
  35516. }
  35517. return matrices;
  35518. }
  35519. addMarker (point) {
  35520. this.points.push(point);
  35521. let sphere = new Mesh(this.sphereGeometry, this.createSphereMaterial());
  35522. this.add(sphere);
  35523. this.spheres.push(sphere);
  35524. // edges & boxes
  35525. if (this.points.length > 1) {
  35526. let lineGeometry = new Geometry();
  35527. lineGeometry.vertices.push(new Vector3(), new Vector3());
  35528. lineGeometry.colors.push(this.lineColor, this.lineColor, this.lineColor);
  35529. let lineMaterial = new LineBasicMaterial({
  35530. vertexColors: VertexColors,
  35531. lineWidth: 2,
  35532. transparent: true,
  35533. opacity: 0.4
  35534. });
  35535. lineMaterial.depthTest = false;
  35536. let edge = new Line(lineGeometry, lineMaterial);
  35537. edge.visible = false;
  35538. this.add(edge);
  35539. this.edges.push(edge);
  35540. let boxGeometry = new BoxGeometry(1, 1, 1);
  35541. let boxMaterial = new MeshBasicMaterial({color: 0xff0000, transparent: true, opacity: 0.2});
  35542. let box = new Mesh(boxGeometry, boxMaterial);
  35543. box.visible = false;
  35544. this.add(box);
  35545. this.boxes.push(box);
  35546. }
  35547. { // event listeners
  35548. let drag = (e) => {
  35549. let I = Utils.getMousePointCloudIntersection(
  35550. e.drag.end,
  35551. e.viewer.scene.getActiveCamera(),
  35552. e.viewer,
  35553. e.viewer.scene.pointclouds);
  35554. if (I) {
  35555. let i = this.spheres.indexOf(e.drag.object);
  35556. if (i !== -1) {
  35557. this.setPosition(i, I.location);
  35558. //this.dispatchEvent({
  35559. // 'type': 'marker_moved',
  35560. // 'profile': this,
  35561. // 'index': i
  35562. //});
  35563. }
  35564. }
  35565. };
  35566. let drop = e => {
  35567. let i = this.spheres.indexOf(e.drag.object);
  35568. if (i !== -1) {
  35569. this.dispatchEvent({
  35570. 'type': 'marker_dropped',
  35571. 'profile': this,
  35572. 'index': i
  35573. });
  35574. }
  35575. };
  35576. let mouseover = (e) => e.object.material.emissive.setHex(0x888888);
  35577. let mouseleave = (e) => e.object.material.emissive.setHex(0x000000);
  35578. sphere.addEventListener('drag', drag);
  35579. sphere.addEventListener('drop', drop);
  35580. sphere.addEventListener('mouseover', mouseover);
  35581. sphere.addEventListener('mouseleave', mouseleave);
  35582. }
  35583. let event = {
  35584. type: 'marker_added',
  35585. profile: this,
  35586. sphere: sphere
  35587. };
  35588. this.dispatchEvent(event);
  35589. this.setPosition(this.points.length - 1, point);
  35590. }
  35591. removeMarker (index) {
  35592. this.points.splice(index, 1);
  35593. this.remove(this.spheres[index]);
  35594. let edgeIndex = (index === 0) ? 0 : (index - 1);
  35595. this.remove(this.edges[edgeIndex]);
  35596. this.edges.splice(edgeIndex, 1);
  35597. this.remove(this.boxes[edgeIndex]);
  35598. this.boxes.splice(edgeIndex, 1);
  35599. this.spheres.splice(index, 1);
  35600. this.update();
  35601. this.dispatchEvent({
  35602. 'type': 'marker_removed',
  35603. 'profile': this
  35604. });
  35605. }
  35606. setPosition (index, position) {
  35607. let point = this.points[index];
  35608. point.copy(position);
  35609. let event = {
  35610. type: 'marker_moved',
  35611. profile: this,
  35612. index: index,
  35613. position: point.clone()
  35614. };
  35615. this.dispatchEvent(event);
  35616. this.update();
  35617. }
  35618. setWidth (width) {
  35619. this.width = width;
  35620. let event = {
  35621. type: 'width_changed',
  35622. profile: this,
  35623. width: width
  35624. };
  35625. this.dispatchEvent(event);
  35626. this.update();
  35627. }
  35628. getWidth () {
  35629. return this.width;
  35630. }
  35631. update () {
  35632. if (this.points.length === 0) {
  35633. return;
  35634. } else if (this.points.length === 1) {
  35635. let point = this.points[0];
  35636. this.spheres[0].position.copy(point);
  35637. return;
  35638. }
  35639. let min = this.points[0].clone();
  35640. let max = this.points[0].clone();
  35641. let centroid = new Vector3();
  35642. let lastIndex = this.points.length - 1;
  35643. for (let i = 0; i <= lastIndex; i++) {
  35644. let point = this.points[i];
  35645. let sphere = this.spheres[i];
  35646. let leftIndex = (i === 0) ? lastIndex : i - 1;
  35647. // let rightIndex = (i === lastIndex) ? 0 : i + 1;
  35648. let leftVertex = this.points[leftIndex];
  35649. // let rightVertex = this.points[rightIndex];
  35650. let leftEdge = this.edges[leftIndex];
  35651. let rightEdge = this.edges[i];
  35652. let leftBox = this.boxes[leftIndex];
  35653. // rightBox = this.boxes[i];
  35654. // let leftEdgeLength = point.distanceTo(leftVertex);
  35655. // let rightEdgeLength = point.distanceTo(rightVertex);
  35656. // let leftEdgeCenter = new THREE.Vector3().addVectors(leftVertex, point).multiplyScalar(0.5);
  35657. // let rightEdgeCenter = new THREE.Vector3().addVectors(point, rightVertex).multiplyScalar(0.5);
  35658. sphere.position.copy(point);
  35659. if (this._modifiable) {
  35660. sphere.visible = true;
  35661. } else {
  35662. sphere.visible = false;
  35663. }
  35664. if (leftEdge) {
  35665. leftEdge.geometry.vertices[1].copy(point);
  35666. leftEdge.geometry.verticesNeedUpdate = true;
  35667. leftEdge.geometry.computeBoundingSphere();
  35668. }
  35669. if (rightEdge) {
  35670. rightEdge.geometry.vertices[0].copy(point);
  35671. rightEdge.geometry.verticesNeedUpdate = true;
  35672. rightEdge.geometry.computeBoundingSphere();
  35673. }
  35674. if (leftBox) {
  35675. let start = leftVertex;
  35676. let end = point;
  35677. let length;
  35678. if(window.axisYup){
  35679. length = start.clone().setY(0).distanceTo(end.clone().setY(0));
  35680. }else {
  35681. length = start.clone().setZ(0).distanceTo(end.clone().setZ(0));
  35682. leftBox.up.set(0, 0, 1);
  35683. }
  35684. leftBox.scale.set(length, 1000000, this.width);
  35685. let center = new Vector3().addVectors(start, end).multiplyScalar(0.5);
  35686. let diff = new Vector3().subVectors(end, start);
  35687. let target = new Vector3(diff.y, -diff.x, 0);
  35688. leftBox.position.set(0, 0, 0);
  35689. leftBox.lookAt(target);
  35690. leftBox.position.copy(center);
  35691. }
  35692. centroid.add(point);
  35693. min.min(point);
  35694. max.max(point);
  35695. }
  35696. centroid.multiplyScalar(1 / this.points.length);
  35697. for (let i = 0; i < this.boxes.length; i++) {
  35698. let box = this.boxes[i];
  35699. box.position.z = min.z + (max.z - min.z) / 2;
  35700. }
  35701. }
  35702. raycast (raycaster, intersects) {
  35703. for (let i = 0; i < this.points.length; i++) {
  35704. let sphere = this.spheres[i];
  35705. sphere.raycast(raycaster, intersects);
  35706. }
  35707. // recalculate distances because they are not necessarely correct
  35708. // for scaled objects.
  35709. // see https://github.com/mrdoob/three.js/issues/5827
  35710. // TODO: remove this once the bug has been fixed
  35711. for (let i = 0; i < intersects.length; i++) {
  35712. let I = intersects[i];
  35713. I.distance = raycaster.ray.origin.distanceTo(I.point);
  35714. }
  35715. intersects.sort(function (a, b) { return a.distance - b.distance; });
  35716. };
  35717. get modifiable () {
  35718. return this._modifiable;
  35719. }
  35720. set modifiable (value) {
  35721. this._modifiable = value;
  35722. this.update();
  35723. }
  35724. }
  35725. class Label extends EventDispatcher{
  35726. constructor(o={}){
  35727. super();
  35728. this.position = o.pos;
  35729. this.text = o.text || '';
  35730. this.elem = $('<div class="hide"><a></a></div>');
  35731. o.className && this.elem.addClass(o.className);
  35732. this.elem.find('a').html(this.text);
  35733. $("#potree_labels").append(this.elem);
  35734. this.pos2d = new Vector3;
  35735. this.dom = o.dom || viewer.renderArea;
  35736. this.camera = o.camera || viewer.scene.getActiveCamera();
  35737. let update = (e)=>{
  35738. this.update(e);
  35739. };
  35740. viewer.addEventListener('camera_changed', update);
  35741. this.addEventListener('dispose', ()=>{
  35742. viewer.removeEventListener('camera_changed', update);
  35743. this.dispose();
  35744. });
  35745. }
  35746. update(){
  35747. if(!this.position || this.elem.hasClass('unvisible'))return
  35748. var p = Utils.getPos2d(this.position,this.camera,this.dom, viewer.mainViewport);
  35749. if(!p.trueSide){
  35750. this.elem.addClass("hide"); return;
  35751. }
  35752. this.elem.css({
  35753. left: p.pos.x +'px',
  35754. top: p.pos.y +'px'
  35755. });
  35756. this.elem.removeClass("hide");
  35757. this.pos2d = p.vector;
  35758. }
  35759. setVisible(visi){
  35760. if(!visi){
  35761. this.elem.addClass("unvisible");
  35762. }else {
  35763. this.elem.removeClass("unvisible");
  35764. this.update();
  35765. }
  35766. }
  35767. setText(text){
  35768. this.text = text || '';
  35769. this.elem.find('a').html(this.text);
  35770. }
  35771. setPos(pos){
  35772. this.position = pos;
  35773. }
  35774. dispose(){
  35775. this.elem.remove();
  35776. this.removeAllListeners();
  35777. }
  35778. }
  35779. const _box$4 = new Box3();
  35780. const _vector$d = new Vector3();
  35781. class LineSegmentsGeometry extends InstancedBufferGeometry {
  35782. constructor() {
  35783. super();
  35784. this.isLineSegmentsGeometry = true;
  35785. this.type = 'LineSegmentsGeometry';
  35786. const positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
  35787. const uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ];
  35788. const index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
  35789. this.setIndex( index );
  35790. this.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
  35791. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  35792. }
  35793. applyMatrix4( matrix ) {
  35794. const start = this.attributes.instanceStart;
  35795. const end = this.attributes.instanceEnd;
  35796. if ( start !== undefined ) {
  35797. start.applyMatrix4( matrix );
  35798. end.applyMatrix4( matrix );
  35799. start.needsUpdate = true;
  35800. }
  35801. if ( this.boundingBox !== null ) {
  35802. this.computeBoundingBox();
  35803. }
  35804. if ( this.boundingSphere !== null ) {
  35805. this.computeBoundingSphere();
  35806. }
  35807. return this;
  35808. }
  35809. setPositions( array ) {
  35810. let lineSegments;
  35811. if ( array instanceof Float32Array ) {
  35812. lineSegments = array;
  35813. } else if ( Array.isArray( array ) ) {
  35814. lineSegments = new Float32Array( array );
  35815. }
  35816. const instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz
  35817. this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
  35818. this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
  35819. //
  35820. this.computeBoundingBox();
  35821. this.computeBoundingSphere();
  35822. return this;
  35823. }
  35824. setColors( array ) {
  35825. let colors;
  35826. if ( array instanceof Float32Array ) {
  35827. colors = array;
  35828. } else if ( Array.isArray( array ) ) {
  35829. colors = new Float32Array( array );
  35830. }
  35831. const instanceColorBuffer = new InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb
  35832. this.setAttribute( 'instanceColorStart', new InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb
  35833. this.setAttribute( 'instanceColorEnd', new InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb
  35834. return this;
  35835. }
  35836. fromWireframeGeometry( geometry ) {
  35837. this.setPositions( geometry.attributes.position.array );
  35838. return this;
  35839. }
  35840. fromEdgesGeometry( geometry ) {
  35841. this.setPositions( geometry.attributes.position.array );
  35842. return this;
  35843. }
  35844. fromMesh( mesh ) {
  35845. this.fromWireframeGeometry( new WireframeGeometry( mesh.geometry ) );
  35846. // set colors, maybe
  35847. return this;
  35848. }
  35849. fromLineSegments( lineSegments ) {
  35850. const geometry = lineSegments.geometry;
  35851. this.setPositions( geometry.attributes.position.array ); // assumes non-indexed
  35852. // set colors, maybe
  35853. return this;
  35854. }
  35855. computeBoundingBox() {
  35856. if ( this.boundingBox === null ) {
  35857. this.boundingBox = new Box3();
  35858. }
  35859. const start = this.attributes.instanceStart;
  35860. const end = this.attributes.instanceEnd;
  35861. if ( start !== undefined && end !== undefined ) {
  35862. this.boundingBox.setFromBufferAttribute( start );
  35863. _box$4.setFromBufferAttribute( end );
  35864. this.boundingBox.union( _box$4 );
  35865. }
  35866. }
  35867. computeBoundingSphere() {
  35868. if ( this.boundingSphere === null ) {
  35869. this.boundingSphere = new Sphere();
  35870. }
  35871. if ( this.boundingBox === null ) {
  35872. this.computeBoundingBox();
  35873. }
  35874. const start = this.attributes.instanceStart;
  35875. const end = this.attributes.instanceEnd;
  35876. if ( start !== undefined && end !== undefined ) {
  35877. const center = this.boundingSphere.center;
  35878. this.boundingBox.getCenter( center );
  35879. let maxRadiusSq = 0;
  35880. for ( let i = 0, il = start.count; i < il; i ++ ) {
  35881. _vector$d.fromBufferAttribute( start, i );
  35882. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$d ) );
  35883. _vector$d.fromBufferAttribute( end, i );
  35884. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$d ) );
  35885. }
  35886. this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
  35887. if ( isNaN( this.boundingSphere.radius ) ) {
  35888. console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this );
  35889. }
  35890. }
  35891. }
  35892. toJSON() {
  35893. // todo
  35894. }
  35895. applyMatrix( matrix ) {
  35896. console.warn( 'THREE.LineSegmentsGeometry: applyMatrix() has been renamed to applyMatrix4().' );
  35897. return this.applyMatrix4( matrix );
  35898. }
  35899. }
  35900. /**
  35901. * parameters = {
  35902. * color: <hex>,
  35903. * lineWidth: <float>,
  35904. * dashed: <boolean>,
  35905. * dashScale: <float>,
  35906. * dashSize: <float>,
  35907. * dashOffset: <float>,
  35908. * gapSize: <float>,
  35909. * resolution: <Vector2>, // to be set by renderer
  35910. * }
  35911. */
  35912. UniformsLib.line = {
  35913. /*
  35914. worldUnits: { value: 1 },
  35915. lineWidth: { value: 1 },
  35916. resolution: { value: new Vector2( 1, 1 ) },
  35917. dashOffset: { value: 0 },
  35918. dashScale: { value: 1 },
  35919. dashSize: { value: 1 },
  35920. gapSize: { value: 1 } // todo FIX - maybe change to totalSize
  35921. */
  35922. worldUnits: { value: 1 },
  35923. lineWidth: { value: 1 },
  35924. resolution: { value: new Vector2$1( 1, 1 ) },
  35925. viewportOffset: { value: new Vector2$1(0, 0 ) }, //left, top
  35926. dashScale: { value: 1 },
  35927. dashSize: { value: 1 },
  35928. dashOffset: { value: 0 },
  35929. gapSize: { value: 1 },
  35930. opacity: { value: 1 },
  35931. backColor: {type:'v3', value: new Color("#ddd")},
  35932. clipDistance : { type: 'f', value: 4}, //消失距离
  35933. occlusionDistance : { type: 'f', value: 1 }, //变为backColor距离
  35934. maxClipFactor : { type: 'f', value: 1 }, //0-1
  35935. depthTexture:{ value: null },
  35936. nearPlane:{value: 0.1},
  35937. farPlane:{value: 100000},
  35938. };
  35939. ShaderLib[ 'line' ] = {
  35940. uniforms: UniformsUtils.merge( [
  35941. UniformsLib.common,
  35942. UniformsLib.fog,
  35943. UniformsLib.line
  35944. ] ),
  35945. vertexShader:
  35946. /* glsl */`
  35947. #include <common>
  35948. #include <color_pars_vertex>
  35949. #include <fog_pars_vertex>
  35950. #include <logdepthbuf_pars_vertex>
  35951. #include <clipping_planes_pars_vertex>
  35952. uniform float lineWidth;
  35953. uniform vec2 resolution;
  35954. attribute vec3 instanceStart;
  35955. attribute vec3 instanceEnd;
  35956. attribute vec3 instanceColorStart;
  35957. attribute vec3 instanceColorEnd;
  35958. #ifdef WORLD_UNITS
  35959. varying vec4 worldPos;
  35960. varying vec3 worldStart;
  35961. varying vec3 worldEnd;
  35962. #ifdef USE_DASH
  35963. varying vec2 vUv;
  35964. #endif
  35965. #else
  35966. varying vec2 vUv;
  35967. #endif
  35968. #ifdef USE_DASH
  35969. uniform float dashScale;
  35970. attribute float instanceDistanceStart;
  35971. attribute float instanceDistanceEnd;
  35972. varying float vLineDistance;
  35973. #endif
  35974. void trimSegment( const in vec4 start, inout vec4 end ) {
  35975. // trim end segment so it terminates between the camera plane and the near plane
  35976. // conservative estimate of the near plane
  35977. float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
  35978. float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
  35979. float nearEstimate = - 0.5 * b / a;
  35980. float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
  35981. end.xyz = mix( start.xyz, end.xyz, alpha );
  35982. }
  35983. void main() {
  35984. #ifdef USE_COLOR
  35985. vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
  35986. #endif
  35987. #ifdef USE_DASH
  35988. vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
  35989. vUv = uv;
  35990. #endif
  35991. float aspect = resolution.x / resolution.y;
  35992. // camera space
  35993. vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
  35994. vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
  35995. #ifdef WORLD_UNITS
  35996. worldStart = start.xyz;
  35997. worldEnd = end.xyz;
  35998. #else
  35999. vUv = uv;
  36000. #endif
  36001. // special case for perspective projection, and segments that terminate either in, or behind, the camera plane
  36002. // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
  36003. // but we need to perform ndc-space calculations in the shader, so we must address this issue directly
  36004. // perhaps there is a more elegant solution -- WestLangley
  36005. bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
  36006. if ( perspective ) {
  36007. if ( start.z < 0.0 && end.z >= 0.0 ) {
  36008. trimSegment( start, end );
  36009. } else if ( end.z < 0.0 && start.z >= 0.0 ) {
  36010. trimSegment( end, start );
  36011. }
  36012. }
  36013. // clip space
  36014. vec4 clipStart = projectionMatrix * start;
  36015. vec4 clipEnd = projectionMatrix * end;
  36016. // ndc space
  36017. vec3 ndcStart = clipStart.xyz / clipStart.w;
  36018. vec3 ndcEnd = clipEnd.xyz / clipEnd.w;
  36019. // direction
  36020. vec2 dir = ndcEnd.xy - ndcStart.xy;
  36021. // account for clip-space aspect ratio
  36022. dir.x *= aspect;
  36023. dir = normalize( dir );
  36024. #ifdef WORLD_UNITS
  36025. // get the offset direction as perpendicular to the view vector
  36026. vec3 worldDir = normalize( end.xyz - start.xyz );
  36027. vec3 offset;
  36028. if ( position.y < 0.5 ) {
  36029. offset = normalize( cross( start.xyz, worldDir ) );
  36030. } else {
  36031. offset = normalize( cross( end.xyz, worldDir ) );
  36032. }
  36033. // sign flip
  36034. if ( position.x < 0.0 ) offset *= - 1.0;
  36035. float forwardOffset = dot( worldDir, vec3( 0.0, 0.0, 1.0 ) );
  36036. // don't extend the line if we're rendering dashes because we
  36037. // won't be rendering the endcaps
  36038. #ifndef USE_DASH
  36039. // extend the line bounds to encompass endcaps
  36040. start.xyz += - worldDir * lineWidth * 0.5;
  36041. end.xyz += worldDir * lineWidth * 0.5;
  36042. // shift the position of the quad so it hugs the forward edge of the line
  36043. offset.xy -= dir * forwardOffset;
  36044. offset.z += 0.5;
  36045. #endif
  36046. // endcaps
  36047. if ( position.y > 1.0 || position.y < 0.0 ) {
  36048. offset.xy += dir * 2.0 * forwardOffset;
  36049. }
  36050. // adjust for lineWidth
  36051. offset *= lineWidth * 0.5;
  36052. // set the world position
  36053. worldPos = ( position.y < 0.5 ) ? start : end;
  36054. worldPos.xyz += offset;
  36055. // project the worldpos
  36056. vec4 clip = projectionMatrix * worldPos;
  36057. // shift the depth of the projected points so the line
  36058. // segments overlap neatly
  36059. vec3 clipPose = ( position.y < 0.5 ) ? ndcStart : ndcEnd;
  36060. clip.z = clipPose.z * clip.w;
  36061. #else
  36062. vec2 offset = vec2( dir.y, - dir.x );
  36063. // undo aspect ratio adjustment
  36064. dir.x /= aspect;
  36065. offset.x /= aspect;
  36066. // sign flip
  36067. if ( position.x < 0.0 ) offset *= - 1.0;
  36068. // endcaps
  36069. if ( position.y < 0.0 ) {
  36070. offset += - dir;
  36071. } else if ( position.y > 1.0 ) {
  36072. offset += dir;
  36073. }
  36074. // adjust for lineWidth
  36075. offset *= lineWidth;
  36076. // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
  36077. offset /= resolution.y;
  36078. // select end
  36079. vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
  36080. // back to clip space
  36081. offset *= clip.w;
  36082. clip.xy += offset;
  36083. #endif
  36084. gl_Position = clip;
  36085. vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation
  36086. #include <logdepthbuf_vertex>
  36087. #include <clipping_planes_vertex>
  36088. #include <fog_vertex>
  36089. }
  36090. `,
  36091. fragmentShader:
  36092. /* glsl */`
  36093. uniform vec3 diffuse;
  36094. uniform float opacity;
  36095. uniform float lineWidth;
  36096. uniform vec3 backColor;
  36097. uniform float occlusionDistance;
  36098. uniform float clipDistance;
  36099. uniform float maxClipFactor;
  36100. #ifdef USE_DASH
  36101. uniform float dashOffset;
  36102. uniform float dashSize;
  36103. uniform float gapSize;
  36104. #endif
  36105. //加
  36106. #if defined(GL_EXT_frag_depth) && defined(useDepth)
  36107. uniform sampler2D depthTexture;
  36108. uniform float nearPlane;
  36109. uniform float farPlane;
  36110. uniform vec2 resolution;
  36111. uniform vec2 viewportOffset;
  36112. #endif
  36113. varying float vLineDistance;
  36114. #ifdef WORLD_UNITS
  36115. varying vec4 worldPos;
  36116. varying vec3 worldStart;
  36117. varying vec3 worldEnd;
  36118. #ifdef USE_DASH
  36119. varying vec2 vUv;
  36120. #endif
  36121. #else
  36122. varying vec2 vUv;
  36123. #endif
  36124. #include <common>
  36125. #include <color_pars_fragment>
  36126. #include <fog_pars_fragment>
  36127. #include <logdepthbuf_pars_fragment>
  36128. #include <clipping_planes_pars_fragment>
  36129. #if defined(GL_EXT_frag_depth) && defined(useDepth)
  36130. float convertToLinear(float zValue)
  36131. {
  36132. float z = zValue * 2.0 - 1.0;
  36133. return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane));
  36134. }
  36135. #endif
  36136. vec2 closestLineToLine(vec3 p1, vec3 p2, vec3 p3, vec3 p4) {
  36137. float mua;
  36138. float mub;
  36139. vec3 p13 = p1 - p3;
  36140. vec3 p43 = p4 - p3;
  36141. vec3 p21 = p2 - p1;
  36142. float d1343 = dot( p13, p43 );
  36143. float d4321 = dot( p43, p21 );
  36144. float d1321 = dot( p13, p21 );
  36145. float d4343 = dot( p43, p43 );
  36146. float d2121 = dot( p21, p21 );
  36147. float denom = d2121 * d4343 - d4321 * d4321;
  36148. float numer = d1343 * d4321 - d1321 * d4343;
  36149. mua = numer / denom;
  36150. mua = clamp( mua, 0.0, 1.0 );
  36151. mub = ( d1343 + d4321 * ( mua ) ) / d4343;
  36152. mub = clamp( mub, 0.0, 1.0 );
  36153. return vec2( mua, mub );
  36154. }
  36155. void main() {
  36156. #include <clipping_planes_fragment>
  36157. /*#ifdef USE_DASH
  36158. if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
  36159. if ( mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize ) discard; // todo - FIX
  36160. #endif*/
  36161. #ifdef USE_DASH
  36162. if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
  36163. bool unvisible = mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize;
  36164. //加
  36165. #ifdef DASH_with_depth
  36166. #else
  36167. if (unvisible) discard; // todo - FIX
  36168. #endif
  36169. #endif
  36170. float alpha = opacity;
  36171. #ifdef WORLD_UNITS
  36172. // Find the closest points on the view ray and the line segment
  36173. vec3 rayEnd = normalize( worldPos.xyz ) * 1e5;
  36174. vec3 lineDir = worldEnd - worldStart;
  36175. vec2 params = closestLineToLine( worldStart, worldEnd, vec3( 0.0, 0.0, 0.0 ), rayEnd );
  36176. vec3 p1 = worldStart + lineDir * params.x;
  36177. vec3 p2 = rayEnd * params.y;
  36178. vec3 delta = p1 - p2;
  36179. float len = length( delta );
  36180. float norm = len / lineWidth;
  36181. #ifndef USE_DASH
  36182. #ifdef USE_ALPHA_TO_COVERAGE
  36183. float dnorm = fwidth( norm );
  36184. alpha = 1.0 - smoothstep( 0.5 - dnorm, 0.5 + dnorm, norm );
  36185. #else
  36186. if ( norm > 0.5 ) {
  36187. discard;
  36188. }
  36189. #endif
  36190. #endif
  36191. #else
  36192. #ifdef USE_ALPHA_TO_COVERAGE
  36193. // artifacts appear on some hardware if a derivative is taken within a conditional
  36194. float a = vUv.x;
  36195. float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
  36196. float len2 = a * a + b * b;
  36197. float dlen = fwidth( len2 );
  36198. if ( abs( vUv.y ) > 1.0 ) {
  36199. alpha = 1.0 - smoothstep( 1.0 - dlen, 1.0 + dlen, len2 );
  36200. }
  36201. #else
  36202. if ( abs( vUv.y ) > 1.0 ) {
  36203. float a = vUv.x;
  36204. float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
  36205. float len2 = a * a + b * b;
  36206. if ( len2 > 1.0 ) discard;
  36207. }
  36208. #endif
  36209. #endif
  36210. vec4 diffuseColor = vec4( diffuse, alpha );
  36211. //加
  36212. #if defined(GL_EXT_frag_depth) && defined(useDepth)
  36213. float mixFactor = 0.0;
  36214. float clipFactor = 0.0;
  36215. float fragDepth = convertToLinear(gl_FragCoord.z);
  36216. vec2 depthTxtCoords = vec2(gl_FragCoord.x - viewportOffset.x, gl_FragCoord.y - viewportOffset.y) / resolution;
  36217. float textureDepth = convertToLinear(texture2D(depthTexture, depthTxtCoords).r);
  36218. float delta = fragDepth - textureDepth;
  36219. if (delta > 0.0)
  36220. {
  36221. mixFactor = clamp(delta / occlusionDistance, 0.0, 1.0);
  36222. clipFactor = clamp(delta / clipDistance, 0.0, maxClipFactor);
  36223. }
  36224. if (clipFactor == 1.0)
  36225. {
  36226. discard;
  36227. }
  36228. vec4 backColor_ = vec4(backColor, opacity); //vec4(0.8,0.8,0.8, 0.8*opacity);
  36229. #ifdef DASH_with_depth
  36230. // 只在被遮住的部分显示虚线, 所以若同时是虚线不可见部分和被遮住时, a为0
  36231. if(unvisible) backColor_.a = 0.0;
  36232. #endif
  36233. //vec4 diffuseColor = vec4(mix(diffuse, backColor_, mixFactor), opacity*(1.0 - clipFactor));
  36234. diffuseColor = mix(diffuseColor, backColor_ , mixFactor);
  36235. diffuseColor.a *= (1.0 - clipFactor);
  36236. #endif
  36237. #include <logdepthbuf_fragment>
  36238. #include <color_fragment>
  36239. //gl_FragColor = vec4( diffuseColor.rgb, alpha );
  36240. gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );
  36241. #include <tonemapping_fragment>
  36242. #include <encodings_fragment>
  36243. #include <fog_fragment>
  36244. #include <premultiplied_alpha_fragment>
  36245. }
  36246. `
  36247. };
  36248. class LineMaterial extends ShaderMaterial {
  36249. constructor( parameters ) {
  36250. super( {
  36251. type: 'LineMaterial',
  36252. uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
  36253. vertexShader: ShaderLib[ 'line' ].vertexShader,
  36254. fragmentShader: ShaderLib[ 'line' ].fragmentShader,
  36255. clipping: true // required for clipping support
  36256. } );
  36257. this.isLineMaterial = true;
  36258. this.lineWidth_ = 0;
  36259. this.supportExtDepth = parameters.supportExtDepth;
  36260. this.depthTestWhenPick = false; //pick时是否识别点云等
  36261. if(parameters.color){
  36262. this.color = new Color(parameters.color);
  36263. }
  36264. if(parameters.backColor){
  36265. this.uniforms.backColor.value = new Color(parameters.backColor);
  36266. }
  36267. if(parameters.clipDistance){
  36268. this.uniforms.clipDistance.value = parameters.clipDistance;
  36269. }
  36270. if(parameters.occlusionDistance){
  36271. this.uniforms.occlusionDistance.value = parameters.occlusionDistance;
  36272. }
  36273. if(parameters.maxClipFactor){
  36274. this.uniforms.maxClipFactor.value = parameters.maxClipFactor;
  36275. }
  36276. Object.defineProperties( this, {
  36277. color: {
  36278. enumerable: true,
  36279. get: function () {
  36280. return this.uniforms.diffuse.value;
  36281. },
  36282. set: function ( value ) {
  36283. this.uniforms.diffuse.value = value;
  36284. }
  36285. },
  36286. worldUnits: {
  36287. enumerable: true,
  36288. get: function () {
  36289. return 'WORLD_UNITS' in this.defines;
  36290. },
  36291. set: function ( value ) {
  36292. if ( value === true ) {
  36293. this.defines.WORLD_UNITS = '';
  36294. } else {
  36295. delete this.defines.WORLD_UNITS;
  36296. }
  36297. }
  36298. },
  36299. lineWidth: {
  36300. enumerable: true,
  36301. get: function () {
  36302. return this.lineWidth_;//this.uniforms.lineWidth.value;
  36303. },
  36304. set: function ( value ) {
  36305. this.uniforms.lineWidth.value = value * window.devicePixelRatio;
  36306. this.lineWidth_ = value;
  36307. }
  36308. },
  36309. dashed: {
  36310. enumerable: true,
  36311. get: function () {
  36312. return Boolean( 'USE_DASH' in this.defines );
  36313. },
  36314. set( value ) {
  36315. if ( Boolean( value ) !== Boolean( 'USE_DASH' in this.defines ) ) {
  36316. this.needsUpdate = true;
  36317. }
  36318. if ( value === true ) {
  36319. this.defines.USE_DASH = '';
  36320. } else {
  36321. delete this.defines.USE_DASH;
  36322. }
  36323. }
  36324. },
  36325. dashScale: {
  36326. enumerable: true,
  36327. get: function () {
  36328. return this.uniforms.dashScale.value;
  36329. },
  36330. set: function ( value ) {
  36331. this.uniforms.dashScale.value = value;
  36332. }
  36333. },
  36334. dashSize: {
  36335. enumerable: true,
  36336. get: function () {
  36337. return this.uniforms.dashSize.value;
  36338. },
  36339. set: function ( value ) {
  36340. this.uniforms.dashSize.value = value;
  36341. }
  36342. },
  36343. dashOffset: {
  36344. enumerable: true,
  36345. get: function () {
  36346. return this.uniforms.dashOffset.value;
  36347. },
  36348. set: function ( value ) {
  36349. this.uniforms.dashOffset.value = value;
  36350. }
  36351. },
  36352. gapSize: {
  36353. enumerable: true,
  36354. get: function () {
  36355. return this.uniforms.gapSize.value;
  36356. },
  36357. set: function ( value ) {
  36358. this.uniforms.gapSize.value = value;
  36359. }
  36360. },
  36361. opacity: {
  36362. enumerable: true,
  36363. get: function () {
  36364. return this.uniforms.opacity.value;
  36365. },
  36366. set: function ( value ) {
  36367. this.uniforms.opacity.value = value;
  36368. }
  36369. },
  36370. resolution: {
  36371. enumerable: true,
  36372. get: function () {
  36373. return this.uniforms.resolution.value;
  36374. },
  36375. set: function ( value ) {
  36376. this.uniforms.resolution.value.copy( value );
  36377. }
  36378. },
  36379. alphaToCoverage: {
  36380. enumerable: true,
  36381. get: function () {
  36382. return Boolean( 'USE_ALPHA_TO_COVERAGE' in this.defines );
  36383. },
  36384. set: function ( value ) {
  36385. if ( Boolean( value ) !== Boolean( 'USE_ALPHA_TO_COVERAGE' in this.defines ) ) {
  36386. this.needsUpdate = true;
  36387. }
  36388. if ( value === true ) {
  36389. this.defines.USE_ALPHA_TO_COVERAGE = '';
  36390. this.extensions.derivatives = true;
  36391. } else {
  36392. delete this.defines.USE_ALPHA_TO_COVERAGE;
  36393. this.extensions.derivatives = false;
  36394. }
  36395. }
  36396. }
  36397. ,
  36398. useDepth:{//add
  36399. enumerable: true,
  36400. get: function () {
  36401. return 'useDepth' in this.defines
  36402. },
  36403. set: function ( value ) {
  36404. value = value && !!this.supportExtDepth;
  36405. if(value != this.useDepth){
  36406. if(value){
  36407. this.defines.useDepth = '';
  36408. this.updateDepthParams();
  36409. }else {
  36410. delete this.defines.useDepth;
  36411. }
  36412. this.needsUpdate = true;
  36413. }
  36414. }
  36415. },
  36416. dashWithDepth:{//add
  36417. enumerable: true,
  36418. get: function () {
  36419. return 'DASH_with_depth' in this.defines
  36420. },
  36421. set: function ( value ) {
  36422. value = value && !!this.supportExtDepth;
  36423. if(value != this.dashWithDepth){
  36424. if(value){
  36425. this.defines.DASH_with_depth = '';
  36426. }else {
  36427. delete this.defines.DASH_with_depth;
  36428. }
  36429. this.needsUpdate = true;
  36430. }
  36431. }
  36432. },
  36433. } );
  36434. this.setValues( parameters );
  36435. let setSize = (e)=>{
  36436. let viewport = e.viewport;
  36437. let viewportOffset = viewport.offset || new Vector2$1();
  36438. this.uniforms.resolution.value.copy(viewport.resolution2);
  36439. this.uniforms.viewportOffset.value.copy(viewportOffset);
  36440. this.lineWidth = this.lineWidth_;
  36441. };
  36442. let viewport = viewer.mainViewport;
  36443. setSize({viewport});
  36444. viewer.addEventListener('resize',(e)=>{
  36445. setSize(e);
  36446. });
  36447. if(this.supportExtDepth){
  36448. //add
  36449. this.updateDepthParams();
  36450. /* viewer.addEventListener('camera_changed', (e)=>{
  36451. if(e.viewport.name != 'mapViewport') this.updateDepthParams(e)
  36452. }) */
  36453. viewer.addEventListener("render.begin", (e)=>{//before render 如果有大于两个viewport的话,不同viewport用不同的depthTex
  36454. if(e.viewport.camera.isPerspectiveCamera) this.updateDepthParams(e);
  36455. });
  36456. }
  36457. }
  36458. updateDepthParams(e={}){
  36459. if(this.useDepth){
  36460. var viewport = e.viewport || viewer.mainViewport;
  36461. var camera = viewport.camera;
  36462. this.uniforms.depthTexture.value = viewer.getPRenderer().getRtEDL(viewport).depthTexture; //viewer.getPRenderer().rtEDL.depthTexture
  36463. this.uniforms.nearPlane.value = camera.near; //似乎因为这个所以对OrthographicCamera 无效
  36464. this.uniforms.farPlane.value = camera.far;
  36465. }
  36466. }
  36467. }
  36468. const _start$2 = new Vector3();
  36469. const _end$2 = new Vector3();
  36470. const _start4 = new Vector4();
  36471. const _end4 = new Vector4();
  36472. const _ssOrigin = new Vector4();
  36473. const _ssOrigin3 = new Vector3();
  36474. const _mvMatrix = new Matrix4();
  36475. const _line = new Line3();
  36476. const _closestPoint = new Vector3();
  36477. const _box$5 = new Box3();
  36478. const _sphere$4 = new Sphere();
  36479. const _clipToWorldVector = new Vector4();
  36480. let _ray$3, _instanceStart, _instanceEnd, _lineWidth;
  36481. // Returns the margin required to expand by in world space given the distance from the camera,
  36482. // line width, resolution, and camera projection
  36483. function getWorldSpaceHalfWidth( camera, distance, resolution ) {
  36484. // transform into clip space, adjust the x and y values by the pixel width offset, then
  36485. // transform back into world space to get world offset. Note clip space is [-1, 1] so full
  36486. // width does not need to be halved.
  36487. _clipToWorldVector.set( 0, 0, - distance, 1.0 ).applyMatrix4( camera.projectionMatrix );
  36488. _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
  36489. _clipToWorldVector.x = _lineWidth / resolution.width;
  36490. _clipToWorldVector.y = _lineWidth / resolution.height;
  36491. _clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
  36492. _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
  36493. return Math.abs( Math.max( _clipToWorldVector.x, _clipToWorldVector.y ) );
  36494. }
  36495. function raycastWorldUnits( lineSegments, intersects ) {
  36496. for ( let i = 0, l = _instanceStart.count; i < l; i ++ ) {
  36497. _line.start.fromBufferAttribute( _instanceStart, i );
  36498. _line.end.fromBufferAttribute( _instanceEnd, i );
  36499. const pointOnLine = new Vector3();
  36500. const point = new Vector3();
  36501. _ray$3.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
  36502. const isInside = point.distanceTo( pointOnLine ) < _lineWidth * 0.5;
  36503. if ( isInside ) {
  36504. intersects.push( {
  36505. point,
  36506. pointOnLine,
  36507. distance: _ray$3.origin.distanceTo( point ),
  36508. object: lineSegments,
  36509. face: null,
  36510. faceIndex: i,
  36511. uv: null,
  36512. uv2: null,
  36513. } );
  36514. }
  36515. }
  36516. }
  36517. function raycastScreenSpace( lineSegments, camera, intersects ) {
  36518. const projectionMatrix = camera.projectionMatrix;
  36519. const material = lineSegments.material;
  36520. const resolution = material.resolution;
  36521. const matrixWorld = lineSegments.matrixWorld;
  36522. const geometry = lineSegments.geometry;
  36523. const instanceStart = geometry.attributes.instanceStart;
  36524. const instanceEnd = geometry.attributes.instanceEnd;
  36525. const near = - camera.near;
  36526. //
  36527. // pick a point 1 unit out along the ray to avoid the ray origin
  36528. // sitting at the camera origin which will cause "w" to be 0 when
  36529. // applying the projection matrix.
  36530. _ray$3.at( 1, _ssOrigin );
  36531. // ndc space [ - 1.0, 1.0 ]
  36532. _ssOrigin.w = 1;
  36533. _ssOrigin.applyMatrix4( camera.matrixWorldInverse );
  36534. _ssOrigin.applyMatrix4( projectionMatrix );
  36535. _ssOrigin.multiplyScalar( 1 / _ssOrigin.w );
  36536. // screen space
  36537. _ssOrigin.x *= resolution.x / 2;
  36538. _ssOrigin.y *= resolution.y / 2;
  36539. _ssOrigin.z = 0;
  36540. _ssOrigin3.copy( _ssOrigin );
  36541. _mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
  36542. for ( let i = 0, l = instanceStart.count; i < l; i ++ ) {
  36543. _start4.fromBufferAttribute( instanceStart, i );
  36544. _end4.fromBufferAttribute( instanceEnd, i );
  36545. _start4.w = 1;
  36546. _end4.w = 1;
  36547. // camera space
  36548. _start4.applyMatrix4( _mvMatrix );
  36549. _end4.applyMatrix4( _mvMatrix );
  36550. // skip the segment if it's entirely behind the camera
  36551. const isBehindCameraNear = _start4.z > near && _end4.z > near;
  36552. if ( isBehindCameraNear ) {
  36553. continue;
  36554. }
  36555. // trim the segment if it extends behind camera near
  36556. if ( _start4.z > near ) {
  36557. const deltaDist = _start4.z - _end4.z;
  36558. const t = ( _start4.z - near ) / deltaDist;
  36559. _start4.lerp( _end4, t );
  36560. } else if ( _end4.z > near ) {
  36561. const deltaDist = _end4.z - _start4.z;
  36562. const t = ( _end4.z - near ) / deltaDist;
  36563. _end4.lerp( _start4, t );
  36564. }
  36565. // clip space
  36566. _start4.applyMatrix4( projectionMatrix );
  36567. _end4.applyMatrix4( projectionMatrix );
  36568. // ndc space [ - 1.0, 1.0 ]
  36569. _start4.multiplyScalar( 1 / _start4.w );
  36570. _end4.multiplyScalar( 1 / _end4.w );
  36571. // screen space
  36572. _start4.x *= resolution.x / 2;
  36573. _start4.y *= resolution.y / 2;
  36574. _end4.x *= resolution.x / 2;
  36575. _end4.y *= resolution.y / 2;
  36576. // create 2d segment
  36577. _line.start.copy( _start4 );
  36578. _line.start.z = 0;
  36579. _line.end.copy( _end4 );
  36580. _line.end.z = 0;
  36581. // get closest point on ray to segment
  36582. const param = _line.closestPointToPointParameter( _ssOrigin3, true );
  36583. _line.at( param, _closestPoint );
  36584. // check if the intersection point is within clip space
  36585. const zPos = MathUtils.lerp( _start4.z, _end4.z, param );
  36586. const isInClipSpace = zPos >= - 1 && zPos <= 1;
  36587. const isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5;
  36588. if ( isInClipSpace && isInside ) {
  36589. _line.start.fromBufferAttribute( instanceStart, i );
  36590. _line.end.fromBufferAttribute( instanceEnd, i );
  36591. _line.start.applyMatrix4( matrixWorld );
  36592. _line.end.applyMatrix4( matrixWorld );
  36593. const pointOnLine = new Vector3();
  36594. const point = new Vector3();
  36595. _ray$3.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
  36596. intersects.push( {
  36597. point: point,
  36598. pointOnLine: pointOnLine,
  36599. distance: _ray$3.origin.distanceTo( point ),
  36600. object: lineSegments,
  36601. face: null,
  36602. faceIndex: i,
  36603. uv: null,
  36604. uv2: null,
  36605. } );
  36606. }
  36607. }
  36608. }
  36609. class LineSegments2 extends Mesh {
  36610. constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
  36611. super( geometry, material );
  36612. this.isLineSegments2 = true;
  36613. this.type = 'LineSegments2';
  36614. }
  36615. // for backwards-compatibility, but could be a method of LineSegmentsGeometry...
  36616. computeLineDistances() {
  36617. const geometry = this.geometry;
  36618. const instanceStart = geometry.attributes.instanceStart;
  36619. const instanceEnd = geometry.attributes.instanceEnd;
  36620. const lineDistances = new Float32Array( 2 * instanceStart.count );
  36621. for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
  36622. _start$2.fromBufferAttribute( instanceStart, i );
  36623. _end$2.fromBufferAttribute( instanceEnd, i );
  36624. lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
  36625. lineDistances[ j + 1 ] = lineDistances[ j ] + _start$2.distanceTo( _end$2 );
  36626. }
  36627. const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1
  36628. geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
  36629. geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1
  36630. return this;
  36631. }
  36632. raycast( raycaster, intersects ) {
  36633. const worldUnits = this.material.worldUnits;
  36634. const camera = raycaster.camera;
  36635. if ( camera === null && ! worldUnits ) {
  36636. console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false.' );
  36637. }
  36638. const threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0;
  36639. _ray$3 = raycaster.ray;
  36640. const matrixWorld = this.matrixWorld;
  36641. const geometry = this.geometry;
  36642. const material = this.material;
  36643. _lineWidth = material.lineWidth + threshold;
  36644. _instanceStart = geometry.attributes.instanceStart;
  36645. _instanceEnd = geometry.attributes.instanceEnd;
  36646. // check if we intersect the sphere bounds
  36647. if ( geometry.boundingSphere === null ) {
  36648. geometry.computeBoundingSphere();
  36649. }
  36650. _sphere$4.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
  36651. // increase the sphere bounds by the worst case line screen space width
  36652. let sphereMargin;
  36653. if ( worldUnits ) {
  36654. sphereMargin = _lineWidth * 0.5;
  36655. } else {
  36656. const distanceToSphere = Math.max( camera.near, _sphere$4.distanceToPoint( _ray$3.origin ) );
  36657. sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere, material.resolution );
  36658. }
  36659. _sphere$4.radius += sphereMargin;
  36660. if ( _ray$3.intersectsSphere( _sphere$4 ) === false ) {
  36661. return;
  36662. }
  36663. // check if we intersect the box bounds
  36664. if ( geometry.boundingBox === null ) {
  36665. geometry.computeBoundingBox();
  36666. }
  36667. _box$5.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
  36668. // increase the box bounds by the worst case line width
  36669. let boxMargin;
  36670. if ( worldUnits ) {
  36671. boxMargin = _lineWidth * 0.5;
  36672. } else {
  36673. const distanceToBox = Math.max( camera.near, _box$5.distanceToPoint( _ray$3.origin ) );
  36674. boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, material.resolution );
  36675. }
  36676. _box$5.expandByScalar( boxMargin );
  36677. if ( _ray$3.intersectsBox( _box$5 ) === false ) {
  36678. return;
  36679. }
  36680. if ( worldUnits ) {
  36681. raycastWorldUnits( this, intersects );
  36682. } else {
  36683. raycastScreenSpace( this, camera, intersects );
  36684. }
  36685. }
  36686. }
  36687. class LineGeometry extends LineSegmentsGeometry {
  36688. constructor() {
  36689. super();
  36690. this.isLineGeometry = true;
  36691. this.type = 'LineGeometry';
  36692. }
  36693. setPositions( array ) {
  36694. // converts [ x1, y1, z1, x2, y2, z2, ... ] to pairs format
  36695. const length = array.length - 3;
  36696. const points = new Float32Array( 2 * length );
  36697. for ( let i = 0; i < length; i += 3 ) {
  36698. points[ 2 * i ] = array[ i ];
  36699. points[ 2 * i + 1 ] = array[ i + 1 ];
  36700. points[ 2 * i + 2 ] = array[ i + 2 ];
  36701. points[ 2 * i + 3 ] = array[ i + 3 ];
  36702. points[ 2 * i + 4 ] = array[ i + 4 ];
  36703. points[ 2 * i + 5 ] = array[ i + 5 ];
  36704. }
  36705. super.setPositions( points );
  36706. return this;
  36707. }
  36708. setColors( array ) {
  36709. // converts [ r1, g1, b1, r2, g2, b2, ... ] to pairs format
  36710. const length = array.length - 3;
  36711. const colors = new Float32Array( 2 * length );
  36712. for ( let i = 0; i < length; i += 3 ) {
  36713. colors[ 2 * i ] = array[ i ];
  36714. colors[ 2 * i + 1 ] = array[ i + 1 ];
  36715. colors[ 2 * i + 2 ] = array[ i + 2 ];
  36716. colors[ 2 * i + 3 ] = array[ i + 3 ];
  36717. colors[ 2 * i + 4 ] = array[ i + 4 ];
  36718. colors[ 2 * i + 5 ] = array[ i + 5 ];
  36719. }
  36720. super.setColors( colors );
  36721. return this;
  36722. }
  36723. fromLine( line ) {
  36724. const geometry = line.geometry;
  36725. this.setPositions( geometry.attributes.position.array ); // assumes non-indexed
  36726. // set colors, maybe
  36727. return this;
  36728. }
  36729. }
  36730. class Line2 extends LineSegments2 {
  36731. constructor( geometry = new LineGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
  36732. super( geometry, material );
  36733. this.isLine2 = true;
  36734. this.type = 'Line2';
  36735. }
  36736. }
  36737. var defaultColor = new Color(1,1,1);//config.applicationName == "zhiHouse" ? Colors.zhiBlue : Colors.lightGreen;
  36738. var LineDraw = {
  36739. createLine: function (posArr, o={}) {
  36740. //多段普通线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序)
  36741. var mat;
  36742. if(o.mat){
  36743. mat = o.mat;
  36744. }else {
  36745. let prop = {
  36746. lineWidth: o.lineWidth || 1,
  36747. //windows无效。 似乎mac/ios上粗细有效 ?
  36748. color: o.color || defaultColor,
  36749. transparent: o.dontAlwaysSeen ? false : true,
  36750. depthTest: o.dontAlwaysSeen ? true : false,
  36751. };
  36752. if(o.deshed ){
  36753. prop.dashSize = o.dashSize || 0.1,
  36754. prop.gapSize = o.gapSize || 0.1;
  36755. }
  36756. mat = new THREE$1[o.deshed ? "LineDashedMaterial" : "LineBasicMaterial"](prop);
  36757. }
  36758. var line = new LineSegments(new BufferGeometry, mat);
  36759. line.renderOrder = o.renderOrder || 4;
  36760. this.moveLine(line, posArr);
  36761. return line;
  36762. },
  36763. moveLine: function (line, posArr) {
  36764. if(posArr.length == 0)return
  36765. let position = [];
  36766. posArr.forEach(e=>position.push(e.x,e.y,e.z));
  36767. line.geometry.setAttribute('position', new Float32BufferAttribute(/* new Float32Array( */position/* ) */, 3));
  36768. line.geometry.attributes.position.needsUpdate = true;
  36769. line.geometry.computeBoundingSphere();
  36770. if(line.material instanceof LineDashedMaterial){
  36771. line.computeLineDistances();
  36772. //line.geometry.attributes.lineDistance.needsUpdate = true;
  36773. line.geometry.verticesNeedUpdate = true; //没用
  36774. }
  36775. }
  36776. ,
  36777. createFatLineMat : function(o){
  36778. var supportExtDepth = !!Features.EXT_DEPTH.isSupported();
  36779. let params = $.extend({}, {
  36780. //默认
  36781. lineWidth : 5,
  36782. color:0xffffff,
  36783. transparent : true, depthWrite:true, depthTest:true,
  36784. dashSize : 0.1, gapSize:0.1,
  36785. }, o, {
  36786. //修正覆盖:
  36787. dashed: o.dashWithDepth ? supportExtDepth && !!o.dashed : !!o.dashed ,
  36788. dashWithDepth:!!o.dashWithDepth,//只在被遮住的部分显示虚线
  36789. useDepth: Potree.settings.matUseDepth && !!o.useDepth,
  36790. supportExtDepth,
  36791. });
  36792. var mat = new LineMaterial(params);
  36793. //if(o.dashed)(mat.defines.USE_DASH = "")
  36794. return mat;
  36795. },
  36796. /*
  36797. 创建可以改变粗细的线。
  36798. */
  36799. createFatLine : function(posArr, o){
  36800. var geometry = new LineGeometry();
  36801. geometry.setColors( o.color || [1,1,1]);
  36802. var matLine = o.material || this.createFatLineMat(o);
  36803. var line = new Line2( geometry, matLine );
  36804. //line.computeLineDistances();
  36805. line.scale.set( 1, 1, 1 );
  36806. line.renderOrder = 2;
  36807. this.moveFatLine(line, posArr);
  36808. return line;
  36809. },
  36810. moveFatLine: function(line, posArr){
  36811. var geometry = line.geometry;
  36812. var positions = [];
  36813. posArr.forEach(e=>{positions.push(...e.toArray());});
  36814. if(positions.length > 0){
  36815. if(!geometry){
  36816. geometry = line.geometry = new LineGeometry();
  36817. }
  36818. if(geometry.attributes.instanceEnd && geometry.attributes.instanceEnd.data.array.length != positions.length){//positions个数改变会有部分显示不出来,所以重建
  36819. geometry.dispose();
  36820. geometry = new LineGeometry();
  36821. line.geometry = geometry;
  36822. }
  36823. geometry.setPositions( positions );
  36824. if(line.material.defines.USE_DASH != void 0){
  36825. //line.geometry.verticesNeedUpdate = true; //没用
  36826. line.geometry.computeBoundingSphere(); //for raycaster
  36827. line.computeLineDistances();
  36828. }
  36829. }else {
  36830. geometry.dispose();
  36831. line.geometry = new LineGeometry();
  36832. }
  36833. },
  36834. updateLine: function(line, posArr){
  36835. if(line instanceof Line2){
  36836. LineDraw.moveFatLine(line,posArr);
  36837. }else {
  36838. LineDraw.moveLine(line,posArr);
  36839. }
  36840. },
  36841. /*
  36842. 为line创建用于检测鼠标的透明mesh,实际是个1-2段圆台。
  36843. 由于近大远小的原因,假设没有透视畸变、创建的是等粗的圆柱的话, 所看到的线上每个位置的粗细应该和距离成反比。所以将圆柱改为根据距离线性渐变其截面半径的圆台,在最近点(相机到线的垂足)最细。如果最近点在线段上,则分成两段圆台,否则一段。
  36844. */
  36845. createBoldLine:function(points, o){
  36846. o = o || {};
  36847. var cylinder = o && o.cylinder;
  36848. var CD = points[1].clone().sub(points[0]);
  36849. var rotate = function(){//根据端点旋转好模型
  36850. cylinder.lastVector = CD;//记录本次的端点向量
  36851. var AB = new Vector3(0,-1,0);
  36852. var axisVec = AB.clone().cross(CD).normalize(); //得到垂直于它们的向量,也就是旋转轴
  36853. var rotationAngle = AB.angleTo(CD);
  36854. cylinder.quaternion.setFromAxisAngle( axisVec, rotationAngle );
  36855. };
  36856. if(o && o.type == "init"){
  36857. cylinder = new Mesh();
  36858. cylinder.material = o.mat;
  36859. if(CD.length() == 0)return cylinder;
  36860. rotate();
  36861. }
  36862. if(CD.length() == 0)return cylinder;
  36863. if(o.type != "update"){
  36864. var CDcenter = points[0].clone().add(points[1]).multiplyScalar(.5);
  36865. cylinder.position.copy(CDcenter);
  36866. if(!cylinder.lastVector || o.type == "moveAndRotate")rotate();
  36867. else if(cylinder.lastVector && CD.angleTo(cylinder.lastVector)>0) rotate();//线方向改了or线反向了 重新旋转一下模型
  36868. if(config.isEdit && !objects.mainDesign.editing )return cylinder;//节省初始加载时间?
  36869. }
  36870. //为了保证线段任何地方的可检测点击范围看起来一样大,更新圆台的结构(但是在镜头边缘会比中心看起来大)
  36871. var height = points[0].distanceTo(points[1]);
  36872. var standPos = o && o.standPos || objects.player.position;
  36873. var k = config.isMobile ? 20 : 40;
  36874. var dis1 = points[0].distanceTo(standPos);
  36875. var dis2 = points[1].distanceTo(standPos);
  36876. var foot = math.getFootPoint(standPos, points[0], points[1]);//垂足
  36877. if(o.constantBold || objects.player.mode != "panorama"){
  36878. var width = 0.1;//0.08;
  36879. var pts = [new Vector2$1(width ,height/2),new Vector2$1(width ,-height/2)];
  36880. }else if(foot.clone().sub(points[0]).dot( foot.clone().sub(points[1]) ) > 0){//foot不在线段上
  36881. var pts = [new Vector2$1(dis1 / k,height/2),new Vector2$1(dis2 / k,-height/2)];
  36882. }else {//在线段上的话,要在垂足这加一个节点,因它距离站位最近,而两端较远
  36883. var dis3 = foot.distanceTo(standPos);
  36884. var len = foot.distanceTo(points[0]);
  36885. var pts = [new Vector2$1(dis1 / k,height/2), new Vector2$1(dis3 / k,height/2-len), new Vector2$1(dis2 / k,-height/2)];
  36886. }
  36887. cylinder.geometry && cylinder.geometry.dispose();//若不删除会占用内存
  36888. cylinder.geometry = new LatheBufferGeometry( pts, 4/* Math.min(dis1,dis2)<10?4:3 */ );
  36889. cylinder.renderOrder = 2;
  36890. return cylinder;
  36891. },
  36892. updateBoldLine:function(cylinder, points, type, standPos, constantBold){
  36893. this.createBoldLine(points,{type:type, cylinder : cylinder, standPos:standPos, constantBold}); //type:move:平移 会改长短 , type:update根据距离和角度更新 不改长短
  36894. },
  36895. };
  36896. var MeshDraw = {
  36897. getShape:function(points, holes){
  36898. var shape = new Shape();
  36899. shape.moveTo( points[0].x, points[0].y );
  36900. for(var i=1,len=points.length; i<len; i++){
  36901. shape.lineTo(points[i].x, points[i].y );
  36902. }
  36903. /* var holePath = new THREE.Path()
  36904. .moveTo( 20, 10 )
  36905. .absarc( 10, 10, 10, 0, Math.PI * 2, true )
  36906. arcShape.holes.push( holePath );
  36907. */
  36908. if(holes){//挖空
  36909. holes.forEach((points)=>{
  36910. var holePath = new Path();
  36911. holePath.moveTo( points[0].x, points[0].y );
  36912. for(var i=1,len=points.length; i<len; i++){
  36913. holePath.lineTo(points[i].x, points[i].y );
  36914. }
  36915. shape.holes.push( holePath );
  36916. });
  36917. }
  36918. return shape
  36919. },
  36920. getShapeGeo: function(points, holes){//获取任意形状(多边形或弧形)的形状面 //quadraticCurveTo() 这是弧形的含函数
  36921. var geometry = new ShapeBufferGeometry( this.getShape(points, holes) ); //ShapeGeometry
  36922. /* var matrix = new THREE.Matrix4();//将竖直的面变为水平
  36923. matrix.set(//z = y
  36924. 1, 0, 0, 0,
  36925. 0, 0, 0, 0,
  36926. 0, 1, 0, 0,
  36927. 0, 0, 0, 1
  36928. )
  36929. geometry.applyMatrix(matrix) */
  36930. //geometry.computeVertexNormals();//对于光照需要的是点法线
  36931. return geometry;
  36932. },
  36933. getExtrudeGeo: function(points, holes, options={}){//获得挤出棱柱,可以选择传递height,或者extrudePath
  36934. var shape = this.getShape(points, holes); //points是横截面 [vector2,...]
  36935. if(options.extrudePath ){// 路径 :[vector3,...]
  36936. var length = extrudePath.reduce((total, currentValue, currentIndex, arr)=>{
  36937. if(currentIndex == 0)return 0
  36938. return total + currentValue.distanceTo(arr[currentIndex-1]);
  36939. },0);
  36940. options.extrudePath = new CatmullRomCurve3(extrudePath, options.closed , 'catmullrom' /* 'centripetal' */ , options.tension);
  36941. }
  36942. var extrudeSettings = $.extend(options,{
  36943. steps: options.steps != void 0 ? options.steps : ( options.extrudePath ? Math.round(length/0.3) : 1),
  36944. bevelEnabled: false, //不加的话,height为0时会有圆弧高度
  36945. //depth
  36946. });
  36947. var geometry = new ExtrudeBufferGeometry( shape, extrudeSettings );
  36948. return geometry;
  36949. },
  36950. getUnPosPlaneGeo : function(){//获取还没有赋值位置的plane geometry
  36951. var e = new Uint16Array([0, 1, 2, 0, 2, 3])
  36952. // , t = new Float32Array([-.5, -.5, 0, .5, -.5, 0, .5, .5, 0, -.5, .5, 0])
  36953. , i = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1])
  36954. , g = new BufferGeometry;
  36955. g.setIndex(new BufferAttribute(e, 1)),
  36956. //g.addAttribute("position", new n.BufferAttribute(t, 3)),
  36957. g.setAttribute("uv", new BufferAttribute(i, 2));
  36958. return function(){
  36959. return g
  36960. }
  36961. }(),
  36962. getPlaneGeo : function(A,B,C,D){
  36963. var geo = this.getUnPosPlaneGeo().clone();
  36964. var pos = [
  36965. A.x, A.y, A.z,
  36966. B.x, B.y, B.z,
  36967. C.x, C.y, C.z,
  36968. D.x, D.y, D.z
  36969. ];
  36970. //geo.addAttribute("position", new THREE.BufferAttribute(pos, 3))
  36971. geo.setAttribute('position', new Float32BufferAttribute(pos, 3));
  36972. geo.computeVertexNormals();
  36973. geo.computeBoundingSphere(); //for raycaster
  36974. return geo;
  36975. },
  36976. drawPlane : function(A,B,C,D, material){
  36977. var wall = new Mesh(this.getPlaneGeo(A,B,C,D), material);
  36978. return wall;
  36979. },
  36980. movePlane: function(mesh, A,B,C,D){
  36981. var pos = new Float32Array([
  36982. A.x, A.y, A.z,
  36983. B.x, B.y, B.z,
  36984. C.x, C.y, C.z,
  36985. D.x, D.y, D.z
  36986. ]);
  36987. mesh.geometry.addAttribute("position", new BufferAttribute(pos, 3));
  36988. mesh.geometry.computeBoundingSphere();//for checkIntersect
  36989. }
  36990. ,
  36991. createGeometry:function(posArr, faceArr, uvArr, normalArr ){//创建复杂mesh. faceArr:[[0,1,2],[0,2,3]]
  36992. let geo = new BufferGeometry;
  36993. let positions = [];
  36994. posArr.forEach(p=>positions.push(p.x,p.y,p.z));
  36995. geo.setAttribute('position', new Float32BufferAttribute(positions, 3));
  36996. if(faceArr){
  36997. let indice = [];
  36998. faceArr.forEach(f=>indice.push(...f));
  36999. geo.setIndex(indice); // auto set Uint16BufferAttribute or Uint32BufferAttribute
  37000. }
  37001. if(uvArr){
  37002. let uvs = [];
  37003. uvArr.forEach(uv=>uvs.push(uv.x,uv.y));
  37004. geo.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
  37005. }
  37006. if(normalArr){
  37007. let normals = [];
  37008. normalArr.forEach(n=>normals.push(n.x,n.y,n.z));
  37009. geo.setAttribute("normal", new Float32BufferAttribute(normals, 3));
  37010. }
  37011. /*
  37012. geo.computeVertexNormals()
  37013. geo.computeBoundingSphere() //for raycaster
  37014. */
  37015. return geo
  37016. },
  37017. updateGeometry:function(geo, posArr, faceArr, uvArr, normalArr ){//创建复杂mesh. faceArr:[[0,1,2],[0,2,3]]
  37018. let positions = [];
  37019. posArr.forEach(p=>positions.push(p.x,p.y,p.z));
  37020. geo.setAttribute('position', new Float32BufferAttribute(positions, 3));
  37021. geo.attributes.position.needsUpdate = true;
  37022. if(faceArr){
  37023. let indice = [];
  37024. faceArr.forEach(f=>indice.push(...f));
  37025. geo.setIndex(indice); // auto set Uint16BufferAttribute or Uint32BufferAttribute
  37026. }
  37027. if(uvArr){
  37028. let uvs = [];
  37029. uvArr.forEach(uv=>uvs.push(uv.x,uv.y));
  37030. geo.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
  37031. }
  37032. if(normalArr){
  37033. let normals = [];
  37034. normalArr.forEach(n=>normals.push(n.x,n.y,n.z));
  37035. geo.setAttribute("normal", new Float32BufferAttribute(normals, 3));
  37036. }
  37037. /*
  37038. geo.computeVertexNormals()
  37039. */
  37040. geo.computeBoundingSphere(); //for raycaster and visi
  37041. return geo
  37042. }
  37043. };
  37044. const verticalLine = new Line3();
  37045. //控制点和边的合集。具有可以拖拽修改的功能,拖拽时能防止线相交。
  37046. class ctrlPolygon extends Object3D {
  37047. constructor (type, prop) {
  37048. super();
  37049. this.type = type;
  37050. this.maxMarkers = Number.MAX_SAFE_INTEGER;
  37051. this.transformData(prop);
  37052. for(let i in prop){
  37053. this[i] = prop[i];
  37054. }
  37055. if(this.closed && this.dimension == '2d'){
  37056. this.areaPlane = this.createAreaPlane();
  37057. this.add(this.areaPlane);
  37058. }
  37059. //数据--刚开始一定是空的
  37060. this.points = [];
  37061. //mesh 不一定有
  37062. this.markers = [];
  37063. this.edges = [];
  37064. this.center;
  37065. }
  37066. initData(prop){
  37067. //开始加数据
  37068. if(prop.points){
  37069. for(const p of prop.points){
  37070. const pos = new Vector3().copy(p);
  37071. this.addMarker({point:pos});
  37072. }
  37073. if(this.datasetId != void 0){//初始化位置
  37074. if(this.dataset_points){
  37075. this.dataset_points = this.dataset_points.map(e=>{
  37076. return e && new Vector3().copy(e)
  37077. });
  37078. this.transformByPointcloud(); //根据dataset_points生成points
  37079. }
  37080. }else {
  37081. if(prop.dataset_points && prop.dataset_points.some(e=>e != void 0)){
  37082. console.error('存在测量线的datasetId为空而dataset_points有值,请检查并删除:'+this.sid);//存在过的bug,原因未知,可能是后台处理dataset时替换的错误:http://192.168.0.21/index.php?m=bug&f=view&bugID=23601
  37083. console.log(this);
  37084. }
  37085. }
  37086. this.getFacePlane();
  37087. this.getPoint2dInfo(this.points);
  37088. this.update({ifUpdateMarkers:true});
  37089. //this.dragChange(new THREE.Vector3().copy(prop.points[prop.points.length-1]), prop.points.length-1);
  37090. this.setSelected(false );
  37091. this.markers.forEach(marker=>{marker.dispatchEvent('addHoverEvent'); });
  37092. return true
  37093. }
  37094. }
  37095. addMarker(o={}){
  37096. var index = o.index == void 0 ? this.points.length : o.index; //要当第几个
  37097. this.points = [...this.points.slice(0,index), o.point, ...this.points.slice(index,this.points.length)];
  37098. //this.points.push(o.point);
  37099. if(o.marker){
  37100. this.add(o.marker);
  37101. this.markers = [...this.markers.slice(0,index), o.marker, ...this.markers.slice(index,this.markers.length)];
  37102. this.updateMarker(o.marker, o.point);
  37103. o.marker.addEventListener('drag', this.dragMarker.bind(this));
  37104. o.marker.addEventListener('drop', this.dropMarker.bind(this));
  37105. let addHoverEvent = (e)=>{
  37106. let mouseover = (e) => {
  37107. this.setMarkerSelected(e.object, 'hover', 'single');
  37108. viewer.dispatchEvent({
  37109. type : "CursorChange", action : "add", name:"markerMove"
  37110. });
  37111. };
  37112. let mouseleave = (e) => {
  37113. this.setMarkerSelected(e.object, 'unhover', 'single');
  37114. viewer.dispatchEvent({
  37115. type : "CursorChange", action : "remove", name:"markerMove"
  37116. });
  37117. };
  37118. o.marker.addEventListener('mouseover', mouseover);
  37119. o.marker.addEventListener('mouseleave', mouseleave);
  37120. o.marker.removeEventListener('addHoverEvent',addHoverEvent);
  37121. };
  37122. o.marker.addEventListener('addHoverEvent',addHoverEvent);//当非isNew时才添加事件
  37123. if(!this.isNew){
  37124. o.marker.dispatchEvent('addHoverEvent');
  37125. }
  37126. }
  37127. if(o.edge){
  37128. this.add(o.edge);
  37129. this.edges = [...this.edges.slice(0,index), o.edge, ...this.edges.slice(index,this.edges.length)];
  37130. }
  37131. }
  37132. dragMarker(e){
  37133. var I, atMap;
  37134. if(e.hoverViewport != e.drag.dragViewport){//不能使用e.dragViewport,要使用drag中的,因为drag中存储的要一直继承下来,不因mouseup了而改变。
  37135. viewer.dispatchEvent({
  37136. type : "CursorChange", action : "add", name:"polygon_AtWrongPlace"
  37137. });
  37138. return
  37139. }
  37140. viewer.dispatchEvent({
  37141. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  37142. });
  37143. atMap = e.drag.dragViewport.name == 'mapViewport';
  37144. if(atMap && this.unableDragAtMap){
  37145. e.drag.object = null; //取消拖拽
  37146. return
  37147. }
  37148. e.drag.object.isDragging = true;
  37149. I = e.intersect && (e.intersect.orthoIntersect || e.intersect.location);
  37150. //记录数据集
  37151. //在三维中脱离点云(在map中拉到周围都没有点云的地方)的顶点,无法拖拽怎么办
  37152. if (I) {
  37153. let i = this.markers.indexOf(e.drag.object);
  37154. if (i !== -1) {
  37155. this.dragChange(I.clone(), i, atMap);
  37156. /* if(this.points_datasets){
  37157. if(e.intersectPoint.pointcloud) this.points_datasets[i] = e.intersectPoint.pointcloud.dataset_id
  37158. else this.points_datasets[i] = null
  37159. } */
  37160. if(this.points_datasets){
  37161. if(e.intersect.pointcloud) this.points_datasets[i] = e.intersect.pointcloud.dataset_id;
  37162. else if(e.intersect.object) this.points_datasets[i] = e.intersect.object.dataset_id;
  37163. else this.points_datasets[i] = null;
  37164. }
  37165. }
  37166. this.editStateChange(true);
  37167. return true
  37168. }
  37169. };
  37170. dragChange(intersectPos, i, atMap){
  37171. let len = this.markers.length;
  37172. let oldPoint = this.points[i];
  37173. if(atMap){
  37174. intersectPos.setZ(oldPoint.z); //在地图上拖拽,不改变其高度。
  37175. }
  37176. let location = intersectPos.clone();
  37177. if(this.faceDirection && this.maxMarkers == 2 && len == 2){//add 固定方向的点不直接拖拽
  37178. var p1 = this.markers[0].position;
  37179. if(this.faceDirection == 'horizontal'){
  37180. var projectPos = location.clone().setZ(p1.z);
  37181. }else {
  37182. var projectPos = p1.clone().setZ(location.z);
  37183. }
  37184. //var p2 = p1.clone().add(this.direction)
  37185. //var projectPos = math.getFootPoint(location, p1, p2)
  37186. LineDraw.updateLine(this.guideLine, [location, projectPos]);
  37187. location = projectPos;
  37188. this.guideLine.visible = true;
  37189. }else if( len > 1){
  37190. var points = this.points.map(e=>e.clone());
  37191. points[i].copy(location); //算normal需要提前确认point
  37192. //若为定义了面朝向的矩形
  37193. if(this.faceDirection == 'horizontal'){
  37194. if(len == 2){
  37195. location.setZ(points[0].z);
  37196. }
  37197. if(!this.facePlane){//一个点就能确定面
  37198. this.facePlane = new Plane().setFromNormalAndCoplanarPoint( new Vector3(0,0,1), this.points[0] );
  37199. }
  37200. }else if(this.faceDirection == 'vertical'){//当有两个点时, 有两个方向的可能
  37201. if(len == 2){
  37202. if(this.isRect){
  37203. let vec = points[0].clone().sub(location);
  37204. if(Math.sqrt(vec.x*vec.x+vec.y*vec.y) > Math.abs(vec.z) ){//水平(高度差小于水平距离时)
  37205. location.setZ(points[0].z);
  37206. //this.cannotConfirmNormal = false;//能确定面为水平方向
  37207. }else {//垂直 (当两点一样时也属于这种)
  37208. location.setX(points[0].x);
  37209. location.setY(points[0].y);
  37210. //this.cannotConfirmNormal = true; //不能确定面,因第三点可绕着纵轴线自由移动
  37211. }
  37212. }
  37213. }else {
  37214. {//判断cannotConfirmNormal. 如果前几段都在竖直线上,就不能固定出面方向。
  37215. this.cannotConfirmNormal = true;
  37216. let max = this.isRect ? 1 : len-2;
  37217. for(let i=0;i<max;i++){
  37218. let p1 = points[i].clone();
  37219. let p2 = points[i+1].clone();
  37220. let vec = p1.sub(p2);
  37221. if(vec.x != 0 || vec.y != 0){
  37222. this.cannotConfirmNormal = false;
  37223. break;
  37224. }
  37225. }
  37226. }
  37227. if(!this.facePlane || this.cannotConfirmNormal){//三个点且为水平方向时,计算面
  37228. var points_ = points.map(e=>new Vector2$1(e.x,e.y));
  37229. var points2 = getDifferentPoint(points_, 2);
  37230. if(points2){
  37231. let normal = math.getNormal2d({p1:points2[0], p2:points2[1]});
  37232. normal = new Vector3(normal.x, normal.y, 0);
  37233. this.facePlane = new Plane().setFromNormalAndCoplanarPoint( normal, this.points[0] );
  37234. }
  37235. }
  37236. }
  37237. }
  37238. if(len > 2){//area
  37239. if(!this.faceDirection){
  37240. if(len == 3 || this.isRect) this.cannotConfirmNormal = true; //当第三个点固定后(有四个点时)才能固定面
  37241. if(!this.facePlane || this.cannotConfirmNormal){
  37242. var points3 = getDifferentPoint(points, 3);//只有找到三个不同的点算拥有面和area
  37243. if(points3){
  37244. this.facePlane = new Plane().setFromCoplanarPoints(...points3 );
  37245. }
  37246. }
  37247. }
  37248. if( this.facePlane && !this.cannotConfirmNormal ){//之后加的点一定要在面上
  37249. if(atMap){
  37250. //地图上用垂直线,得到和面的交点。
  37251. verticalLine.set(location.clone().setZ(100000), location.clone().setZ(-100000));//确保长度范围覆盖所有测量面
  37252. location = this.facePlane.intersectLine(verticalLine, new Vector3() );
  37253. if(!location) return;
  37254. }else {
  37255. location = this.facePlane.projectPoint(intersectPos, new Vector3() );
  37256. }
  37257. }
  37258. points[i].copy(location);//再copy确认一次
  37259. if(this.isRect){ //是矩形 (即使没有faceDirection也能执行)
  37260. //根据前两个点计算当前和下一个点
  37261. var p1 = points[(i-2+len)%len];
  37262. var p2 = points[(i-1+len)%len];
  37263. if(p1.equals(p2)){//意外情况:重复点两次 ( bug点,改了好多遍)
  37264. if(this.faceDirection == 'vertical'){
  37265. p2.add(new Vector3(0,0,0.0001));
  37266. }else {
  37267. p2.add(new Vector3(0,0.0001,0));
  37268. }
  37269. }
  37270. //p3 : location
  37271. var foot = math.getFootPoint(location, p1, p2);//p2 修改p2到垂足的位置
  37272. var vec = foot.clone().sub(location);
  37273. var p4 = p1.clone().sub(vec);
  37274. points[(i-1+len)%len].copy(foot);
  37275. points[(i+1)%len].copy(p4);
  37276. this.setPosition((i-1+len)%len, foot);//p2
  37277. this.setPosition((i+1)%len, p4);
  37278. }
  37279. /* let points2d;
  37280. if(this.facePlane){
  37281. var originPoint0 = points[0].clone()
  37282. var qua = math.getQuaBetween2Vector(this.facePlane.normal, new THREE.Vector3(0,0,1), new THREE.Vector3(0,0,1));
  37283. points2d = points.map(e=>e.clone().applyQuaternion(qua))
  37284. } */
  37285. this.getPoint2dInfo(points);
  37286. var isIntersectSelf = !this.isRect && len > 3 && this.intersectSelf(this.point2dInfo.points2d);//检测相交
  37287. if(isIntersectSelf){
  37288. //not-allowed
  37289. viewer.dispatchEvent({
  37290. type : "CursorChange", action : "add", name:"polygon_isIntersectSelf"
  37291. });
  37292. this.isIntersectSelf = true;
  37293. return
  37294. }else {
  37295. this.isIntersectSelf = false;
  37296. viewer.dispatchEvent({
  37297. type : "CursorChange", action : "remove", name:"polygon_isIntersectSelf"
  37298. });
  37299. /* this.facePlane && (this.point2dInfo = {
  37300. originPoint0 ,
  37301. points2d,
  37302. quaInverse : qua.clone().invert()
  37303. }) */
  37304. }
  37305. }
  37306. var showGuideLine = len>1 && (this.faceDirection || len > 3);
  37307. if(showGuideLine && this.guideLine){
  37308. LineDraw.updateLine(this.guideLine, [intersectPos, location]);
  37309. this.guideLine.visible = true;
  37310. }
  37311. //console.log(this.points.map(e=>e.toArray()))
  37312. }
  37313. if(this.restrictArea){
  37314. let holes = this.restrictArea.holes.concat(this.restrictArea.parentHoles);
  37315. let holesPoints = holes.filter(e=>e!=this && e.points.length>2).map(e=>e.points);
  37316. if(!math.isPointInArea(this.restrictArea.points, holesPoints, location)){
  37317. viewer.dispatchEvent({
  37318. type : "CursorChange", action : "add", name:"polygon_AtWrongPlace"
  37319. });
  37320. this.isAtWrongPlace = true;
  37321. return
  37322. }
  37323. //就不处理相交线了。 有个缺点:floor上的hole可以限制room,但hole不受room限制,会导致room的marker被框在hole里而动不了。只能去调整hole了
  37324. }
  37325. viewer.dispatchEvent({
  37326. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  37327. });
  37328. this.isAtWrongPlace = false;
  37329. this.setPosition(i, location);
  37330. this.update();
  37331. this.dispatchEvent({type:'dragChange', index:i});
  37332. }
  37333. dropMarker(e){
  37334. //console.log('dropMarker')
  37335. if (this.isNew && e.pressDistance>Potree.config.clickMaxDragDis){//拖拽的话返回
  37336. return this.continueDrag(null,e)
  37337. }
  37338. if(e.isTouch){
  37339. if(e.hoverViewport != viewer.mainViewport && this.unableDragAtMap){
  37340. viewer.dispatchEvent({type:'reticule_forbit', v:true});
  37341. //console.log('reticule_forbit',true)
  37342. return this.continueDrag(null,e)
  37343. }else {
  37344. viewer.dispatchEvent({type:'reticule_forbit', v:false});
  37345. //console.log('reticule_forbit',false)
  37346. }
  37347. this.dragMarker(e); //触屏时必须先更新下点
  37348. }
  37349. if (e.button != MOUSE.RIGHT && (//右键click的话继续执行,因为会停止
  37350. this.isIntersectSelf && this.isNew //有线相交了
  37351. || this.isAtWrongPlace && this.isNew
  37352. || !e.isAtDomElement && this.isNew//如果是刚添加时在其他dom点击, 不要响应
  37353. || e.hoverViewport != viewer.mainViewport && this.unableDragAtMap //垂直的测量线不允许在地图上放点
  37354. || !getDifferentPoint(this.points, this.points.length) //不允许和之前的点相同
  37355. )
  37356. ){
  37357. return this.continueDrag(null,e)
  37358. }
  37359. //console.log('drop marker' )
  37360. let i = this.markers.indexOf(e.drag.object);
  37361. if (i !== -1) {
  37362. this.dispatchEvent({
  37363. 'type': 'marker_dropped',
  37364. 'index': i
  37365. });
  37366. if(this.markers.length>2 && this.facePlane)this.cannotConfirmNormal = false;
  37367. this.guideLine &&(this.guideLine.visible = false);
  37368. }
  37369. this.setMarkerSelected(e.drag.object, 'unhover', 'single');
  37370. this.editStateChange(false);
  37371. e.drag.endDragFun && e.drag.endDragFun(e);// addmarker
  37372. if(this.changeCallBack)this.changeCallBack();
  37373. return true
  37374. };
  37375. getFacePlane(){//最普通一种get方法,根据顶点。且假设所有点已经共面,且不重合
  37376. if(this.points.length<3) return
  37377. this.facePlane = new Plane().setFromCoplanarPoints(...this.points.slice(0,3) );
  37378. }
  37379. getPoint2dInfo(points){ //在更新areaplane之前必须更新过point2dInfo
  37380. if(this.facePlane){
  37381. var originPoint0 = points[0].clone();
  37382. var qua = math.getQuaBetween2Vector(this.facePlane.normal, new Vector3(0,0,1), new Vector3(0,0,1));
  37383. let points2d = points.map(e=>e.clone().applyQuaternion(qua));
  37384. this.point2dInfo = {
  37385. originPoint0 ,
  37386. points2d,
  37387. quaInverse : qua.clone().invert()
  37388. };
  37389. }
  37390. }
  37391. setPosition (index, position) {//拖拽后设置位置
  37392. let point = this.points[index];
  37393. point.copy(position);
  37394. if(this.datasetId){
  37395. this.dataset_points[index] = Potree.Utils.datasetPosTransform({toDataset:true, datasetId:this.datasetId, position:point.clone()});
  37396. }
  37397. let marker = this.markers[index];
  37398. this.updateMarker(marker, point);
  37399. }
  37400. updateMarker(marker, pos){
  37401. marker.position.copy(pos);
  37402. marker.update();
  37403. }
  37404. intersectSelf(points2d){//add
  37405. var len = points2d.length;
  37406. for(var i=0;i<len;i++){
  37407. for(var j=i+2;j<len;j++){
  37408. if(Math.abs(j-len-i)<2)continue;//不和邻边比
  37409. var p1 = points2d[i];
  37410. var p2 = points2d[i+1];
  37411. var p3 = points2d[j];
  37412. var p4 = points2d[(j+1)%len];
  37413. if(p1.equals(p2) || p3.equals(p4) || p1.equals(p3) || p2.equals(p3) || p1.equals(p4) || p2.equals(p4))continue
  37414. var line1 = [p1,p2];
  37415. var line2 = [p3,p4];
  37416. var intersect = math.isLineIntersect(line1, line2, false, 0.001);
  37417. if(intersect){
  37418. return true
  37419. break
  37420. }
  37421. }
  37422. }
  37423. }
  37424. removeMarker (index) {
  37425. this.points.splice(index, 1);
  37426. const marker = this.markers[index];
  37427. //this.remove(marker);
  37428. this.markers.splice(index, 1);
  37429. marker.dispatchEvent({type:'dispose'});
  37430. let edgeIndex = index; //(index === 0) ? 0 : (index - 1);
  37431. const edge = this.edges[edgeIndex];
  37432. if(edge){
  37433. this.remove(edge);
  37434. this.edges.splice(edgeIndex, 1);
  37435. edge.dispatchEvent({type:'dispose'});
  37436. }
  37437. this.point2dInfo && this.point2dInfo.points2d.splice(index, 1); //add
  37438. this.dispatchEvent({type:'removeMarker',index,marker});
  37439. }
  37440. createAreaPlane(mat){
  37441. var geometry = new Geometry();
  37442. var mesh = new Mesh(geometry, mat);
  37443. return mesh
  37444. }
  37445. updateAreaPlane(){
  37446. if(!this.point2dInfo)return
  37447. this.areaPlane.geometry.dispose();
  37448. if(this.points.length>2){
  37449. this.areaPlane.geometry = MeshDraw.getShapeGeo(this.point2dInfo.points2d);
  37450. var center = math.getCenterOfGravityPoint(this.point2dInfo.points2d); //重心
  37451. var firstPos = this.point2dInfo.points2d[0].clone();
  37452. firstPos.z = 0; //因为shape只读取了xy,所以位移下, 再算出最终位置,得到差距
  37453. firstPos.applyQuaternion(this.point2dInfo.quaInverse);
  37454. var vec = this.point2dInfo.originPoint0.clone().sub(firstPos);
  37455. center = new Vector3(center.x, center.y, 0);
  37456. center.applyQuaternion(this.point2dInfo.quaInverse);
  37457. this.areaPlane.quaternion.copy(this.point2dInfo.quaInverse);
  37458. this.areaPlane.position.copy(vec);
  37459. center.add(vec);
  37460. this.center = center;
  37461. }else {
  37462. this.areaPlane.geometry = new Geometry();
  37463. }
  37464. }
  37465. update(options={}){
  37466. if(this.points.length === 0){
  37467. return;
  37468. }
  37469. let lastIndex = this.points.length - 1;
  37470. for (let index = 0; index <= lastIndex; index++) {
  37471. let nextIndex = (index + 1 > lastIndex) ? 0 : index + 1;
  37472. let previousIndex = (index === 0) ? lastIndex : index - 1;
  37473. let point = this.points[index];
  37474. let nextPoint = this.points[nextIndex];
  37475. let previousPoint = this.points[previousIndex];
  37476. if(options.ifUpdateMarkers){
  37477. this.updateMarker(this.markers[index], point);
  37478. }
  37479. { // edges
  37480. let edge = this.edges[index];
  37481. if(edge){
  37482. LineDraw.updateLine(edge, [point, nextPoint]);
  37483. //edge.visible = index < lastIndex || this.isRect || (this.closed && !this.isNew);
  37484. }
  37485. }
  37486. }
  37487. if(this.areaPlane){
  37488. this.updateAreaPlane();
  37489. }
  37490. //this.dispatchEvent({type:'update'})
  37491. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed'); //暂时先这么都通知
  37492. }
  37493. dispose(){//add
  37494. this.parent.remove(this);
  37495. this.markers.concat(this.edges).forEach(e=>e.dispatchEvent({type:'dispose'}));
  37496. }
  37497. reDraw(restMarkerCount=0){//重新开始画
  37498. let pointCount = this.points.length - restMarkerCount; // restMarkerCount为需要留下的marker数量
  37499. while(pointCount > 0){
  37500. this.removeMarker(--pointCount);
  37501. }
  37502. this.point2dInfo = null;
  37503. this.facePlane = null;
  37504. }
  37505. setMarkerSelected(){}
  37506. editStateChange(state){
  37507. if(!state){
  37508. viewer.dispatchEvent({
  37509. type : "CursorChange", action : "remove", name:"polygon_isIntersectSelf"
  37510. });
  37511. viewer.dispatchEvent({
  37512. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  37513. });
  37514. viewer.dispatchEvent({type:'reticule_forbit', v:false});
  37515. this.markers.forEach(e=>e.isDragging = false );
  37516. }
  37517. }
  37518. transformData(){}
  37519. setSelected(){}
  37520. continueDrag(marker, e){
  37521. let object = marker || e.drag.object;
  37522. object.isDragging = true;
  37523. var timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
  37524. if(this.parent && object.isDragging){
  37525. //console.log('continueDrag')
  37526. viewer.inputHandler.startDragging( object ,
  37527. {endDragFun: e.drag.endDragFun, notPressMouse:e.drag.notPressMouse, dragViewport:e.drag.dragViewport}
  37528. );
  37529. }
  37530. },1);
  37531. return timer
  37532. }
  37533. }
  37534. function getDifferentPoint(points, count){//for facePlane
  37535. var result = [];
  37536. for(let i=0;i<points.length;i++){
  37537. var p = points[i];
  37538. if(result.find(e=>e.equals(p)))continue;
  37539. else result.push(p);
  37540. if(result.length == count)break
  37541. }
  37542. if(result.length == count)return result
  37543. }
  37544. let texLoader = new TextureLoader();
  37545. let defaultColor$1 = new Color(config$1.measure.default.color);
  37546. let highlightColor = new Color(config$1.measure.highlight.color);
  37547. let color = new Color(config$1.measure.color);
  37548. let textColor = new Color(config$1.measure.textColor);
  37549. var markerMats;
  37550. var lineMats;
  37551. var planeMats;
  37552. const lineDepthInfo = {
  37553. clipDistance : 4,//消失距离
  37554. occlusionDistance: 1,//变为backColor距离
  37555. };
  37556. const LabelDepthInfo = {
  37557. clipDistance : 6,//消失距离
  37558. occlusionDistance: 2,//变为backColor距离
  37559. };
  37560. /* const LabelDepthInfo = {
  37561. clipDistance : 0.1,//消失距离
  37562. occlusionDistance: 0.1,//变为backColor距离
  37563. } */
  37564. const markerSizeInfo = {
  37565. minSize : 25 , maxSize : 65, nearBound : 0.2, farBound : 4,
  37566. };
  37567. const labelSizeInfo = {width2d:200};
  37568. const mainLabelProp = {
  37569. backgroundColor: {r: defaultColor$1.r*255, g: defaultColor$1.g*255, b: defaultColor$1.b*255, a:config$1.measure.default.opacity},
  37570. textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
  37571. fontsize:16,
  37572. useDepth : true ,
  37573. renderOrder : 5
  37574. };
  37575. const subLabelProp = {
  37576. backgroundColor: {r: 255, g: 255, b: 255, a:1},
  37577. textColor: {r: 0, g: 0, b:0, a: 1.0},
  37578. fontsize:14,
  37579. renderOrder : 4
  37580. };
  37581. const angle = MathUtils.degToRad(5);//显示水平垂直辅助线的最小角度
  37582. const guideShowMinAngle = {min: angle, max: Math.PI/2 - angle};
  37583. class Measure extends ctrlPolygon{
  37584. constructor (prop) {
  37585. prop.dimension = '2d';
  37586. super('measure',prop);
  37587. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  37588. this.name = this.measureType + this.constructor.counter; //'Measure_' + this.constructor.counter;
  37589. this.markerLabels = [];
  37590. this.edgeLabels = [];
  37591. this.angleLabels = [];
  37592. this.coordinateLabels = [];
  37593. this.area = {value:0,string:''};
  37594. if(this.closed/* this.showArea */){
  37595. this.areaLabel = this.createAreaLabel();
  37596. this.add(this.areaLabel);
  37597. }
  37598. //add:
  37599. if(this.maxMarkers > 2 || this.faceDirection){
  37600. this.createGuideLine();
  37601. }
  37602. if(this.measureType == 'Distance'){
  37603. this.createHorVerGuideLine();
  37604. }
  37605. this.selectStates = {};
  37606. this.setUnitSystem(prop.unit || viewer.unitConvert.UnitService.defaultSystem);
  37607. viewer.setObjectLayers(this, 'measure' );
  37608. //addMarkers:
  37609. this.initData(prop);
  37610. this.points_datasets || (this.points_datasets = []); //存每个点是哪个数据集
  37611. this.addEventListener('marker_dropped',(e)=>{
  37612. this.updateDatasetBelong();
  37613. });
  37614. this.addEventListener('isVisible', ()=>{
  37615. viewer.mapViewer && viewer.mapViewer.dispatchEvent({type:'content_changed'});
  37616. });
  37617. }
  37618. initData(prop){
  37619. let makeIt = super.initData(prop);
  37620. if(makeIt){
  37621. this.edges.forEach(edge=>{edge.dispatchEvent('addHoverEvent'); });
  37622. }
  37623. }
  37624. updateDatasetBelong(){//更新所属数据集
  37625. let old = this.datasetId;
  37626. let maxCount = {id:null,count:0};
  37627. let datasets = {};
  37628. this.points_datasets.forEach(e=>{
  37629. if(e == void 0)return
  37630. if(datasets[e]){
  37631. datasets[e] ++;
  37632. }else {
  37633. datasets[e] = 1;
  37634. }
  37635. });
  37636. for(let i in datasets) {
  37637. if(datasets[i]>maxCount.count){
  37638. maxCount = {id:i, count:datasets[i]};
  37639. }
  37640. }
  37641. this.datasetId = maxCount.count > 0 ? maxCount.id : null;
  37642. if(this.datasetId != old){
  37643. this.dispatchEvent({type:'changeDatasetId'});
  37644. if(this.datasetId == void 0){
  37645. this.dataset_points = null; //可能为空或[null,null...]
  37646. }else {
  37647. this.dataset_points = this.points.map(e=>{
  37648. return Potree.Utils.datasetPosTransform({toDataset:true,datasetId:this.datasetId, position:e.clone()})
  37649. });
  37650. }
  37651. }
  37652. }
  37653. transformByPointcloud(){//每次移动点云 or 加载测量线时要获取一下当前position
  37654. if(this.datasetId == void 0)return
  37655. this.points = this.dataset_points.map(e=>{
  37656. return Potree.Utils.datasetPosTransform({fromDataset:true, datasetId:this.datasetId, position:e.clone()})
  37657. });
  37658. this.getPoint2dInfo(this.points);
  37659. this.update({ifUpdateMarkers:true});
  37660. this.setSelected(false);//隐藏edgelabel
  37661. }
  37662. update(options={}) {
  37663. super.update(options);
  37664. if(this.showCoordinates && this.points.length>0){
  37665. let position = this.points[0];
  37666. this.markers[0].position.copy(position);
  37667. { // coordinate labels
  37668. let coordinateLabel = this.coordinateLabels[0];
  37669. let lonlat = viewer.transform.lonlatToLocal.inverse(position.toArray());
  37670. let EPSG4550 = viewer.transform.lonlatTo4550.forward(lonlat);
  37671. let pos = [
  37672. position.toArray(),
  37673. lonlat,
  37674. EPSG4550
  37675. ];
  37676. //let msg = position.toArray().map(p => Utils.addCommas(p.toFixed(2))).join(" / ");
  37677. let msg = pos.map(a=>
  37678. a.map(p => Utils.addCommas(p.toFixed(10))).join(", ")
  37679. ).join("<br>");
  37680. coordinateLabel.setText(msg);
  37681. coordinateLabel.setPos(position);
  37682. coordinateLabel.setVisible(true);//this.showCoordinates;
  37683. }
  37684. return
  37685. }
  37686. let setEdgeLabel = (label,p1,p2,distance)=>{//设置label位置和字
  37687. let center = new Vector3().addVectors(p1,p2).multiplyScalar(0.5);
  37688. label.setPos(center);
  37689. distance = distance == void 0 ? p1.distanceTo(p2) : distance;
  37690. var text = viewer.unitConvert.convert(distance, 'distance', void 0, this.unitSystem, 0.1 , true);//distance要传0.1 这个factor
  37691. label.setText(text);
  37692. return distance
  37693. };
  37694. let lastIndex = this.points.length - 1;
  37695. for (let index = 0; index <= lastIndex; index++) {
  37696. let nextIndex = (index + 1 > lastIndex) ? 0 : index + 1;
  37697. let previousIndex = (index === 0) ? lastIndex : index - 1;
  37698. let point = this.points[index];
  37699. let nextPoint = this.points[nextIndex];
  37700. let previousPoint = this.points[previousIndex];
  37701. if(this.showDistances){ // edge labels
  37702. let edgeLabel = this.edgeLabels[index];
  37703. let distance = point.distanceTo(nextPoint);
  37704. edgeLabel.shouldVisi = (index < lastIndex || this.isRect || this.closed && !this.isNew /* && this.points.length > 2 */) && distance>0;
  37705. /* this.closed || */edgeLabel.setVisible(edgeLabel.shouldVisi);
  37706. if(edgeLabel.visible){
  37707. setEdgeLabel(edgeLabel,point,nextPoint,distance);
  37708. }
  37709. }
  37710. }
  37711. if(this.measureType == 'Distance' && this.points.length>1){//设置水平垂直辅助线
  37712. var pTop, pBtm;
  37713. if(this.points[0].z > this.points[1].z ){
  37714. pTop = this.points[0];
  37715. pBtm = this.points[1];
  37716. }else {
  37717. pTop = this.points[1];
  37718. pBtm = this.points[0];
  37719. }
  37720. let projectPos = new Vector3(pTop.x, pTop.y, pBtm.z);//两条guideline的交点
  37721. {//倾斜角度太小的时候不显示
  37722. let tan = pTop.distanceTo(projectPos) / pBtm.distanceTo(projectPos);
  37723. let angle = Math.atan(tan);
  37724. this.shouldShowHorVerGuide = angle > guideShowMinAngle.min && angle < guideShowMinAngle.max;
  37725. }
  37726. LineDraw.updateLine(this.verGuideEdge, [pTop, projectPos]);
  37727. LineDraw.updateLine(this.horGuideEdge, [pBtm, projectPos]);
  37728. setEdgeLabel(this.verEdgeLabel,pTop,projectPos);
  37729. setEdgeLabel(this.horEdgeLabel,pBtm,projectPos);
  37730. this.verGuideEdge.visible = this.horGuideEdge.visible = this.shouldShowHorVerGuide;
  37731. this.verEdgeLabel.visible = this.horEdgeLabel.visible = this.shouldShowHorVerGuide;
  37732. }
  37733. if(this.showArea && this.point2dInfo){ // update area
  37734. /* if(this.points.length>2){
  37735. this.area = {value:0};
  37736. this.areaLabel.setVisible(false)
  37737. }else{ */
  37738. let area = Math.abs(math.getArea(this.point2dInfo.points2d));//this.getArea();
  37739. let msg = viewer.unitConvert.convert(area, 'area', void 0, this.unitSystem/* , 0.1 */ );
  37740. this.area = {value:area, string:msg};
  37741. this.areaLabel.setPos(this.center);
  37742. this.areaLabel.setText(msg);
  37743. this.areaLabel.setVisible(true);
  37744. //}
  37745. }
  37746. };
  37747. addMarker (o={}) {
  37748. let marker = new Sprite$1({mat:this.getMarkerMaterial('default'), sizeInfo: markerSizeInfo, name:"measure_point"} );
  37749. viewer.setObjectLayers(marker, 'measure' );
  37750. marker.renderOrder = 3;
  37751. marker.markerSelectStates = {};
  37752. marker.addEventListener('startDragging',(e)=>{
  37753. if(e.drag.dragViewport.name == 'MainView')viewer.inputHandler.dispatchEvent( {type: 'isMeasuring',v:true, cause:'startDragging'});
  37754. });
  37755. marker.addEventListener('drop',(e)=>{
  37756. viewer.inputHandler.dispatchEvent({type: 'isMeasuring', v:false, cause:'stopDragging'} );
  37757. });
  37758. let edge;
  37759. { // edges
  37760. edge = LineDraw.createFatLine( [ ],{material:this.getLineMat('edgeDefault')} );
  37761. viewer.setObjectLayers(edge, 'measure' );
  37762. let addHoverEvent = ()=>{ //当非isNew时才添加事件
  37763. let mouseover = (e) => {this.setSelected(true, 'edge');};
  37764. let mouseleave = (e) => {this.setSelected(false, 'edge');};
  37765. edge.addEventListener('mouseover', mouseover);
  37766. edge.addEventListener('mouseleave', mouseleave);
  37767. edge.removeEventListener('addHoverEvent', addHoverEvent);
  37768. };
  37769. edge.addEventListener('addHoverEvent', addHoverEvent);
  37770. }
  37771. super.addMarker({point:o.point, marker:marker, edge});
  37772. if(this.showEdges){ // edge labels
  37773. const edgeLabel = this.createEdgeLabel('edgeLabel', !this.closed);
  37774. this.edgeLabels.push(edgeLabel);
  37775. }
  37776. if(this.showCoordinates){ // coordinate labels
  37777. let coordinateLabel = new Label({
  37778. className:'measure_pointPos',
  37779. camera: viewer.scene.getActiveCamera()
  37780. });
  37781. coordinateLabel.setVisible(false);
  37782. this.coordinateLabels.push(coordinateLabel);
  37783. }
  37784. let event = {
  37785. type: 'marker_added',
  37786. measurement: this,
  37787. marker: marker
  37788. };
  37789. this.dispatchEvent(event);
  37790. //this.setMarker(this.points.length - 1, point);
  37791. this.update();//更新一下倒数第二条线
  37792. return marker;//add
  37793. };
  37794. editStateChange(state){ //主要针对edgeLabels显示切换,编辑时显示
  37795. super.editStateChange(state);
  37796. if(!state){
  37797. this.editStateTimer = setTimeout(()=>{
  37798. if(!this.isEditing){
  37799. this.dispatchEvent({type:'editStateChange',state:false});
  37800. this.setEdgesDisplay(false);
  37801. }
  37802. },100);
  37803. }else {
  37804. if(!this.isEditing){
  37805. this.dispatchEvent({type:'editStateChange',state:true});
  37806. this.setEdgesDisplay(true);
  37807. clearTimeout(this.editStateTimer);
  37808. }
  37809. }
  37810. this.isEditing = state;
  37811. }
  37812. setMarkerSelected(marker, state, hoverObject){
  37813. //console.warn(marker.id , state, hoverObject)
  37814. marker.markerSelectStates[hoverObject] = state;
  37815. let absoluteState = false;
  37816. for(var i in marker.markerSelectStates){
  37817. if(marker.markerSelectStates[i] == 'hover'){
  37818. absoluteState = true; break;
  37819. }
  37820. }
  37821. if(absoluteState){
  37822. marker.material = this.getMarkerMaterial('select');
  37823. }else {
  37824. marker.material = this.getMarkerMaterial('default');
  37825. }
  37826. marker.selected = absoluteState;
  37827. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed');
  37828. }
  37829. setEdgesDisplay(state, ignoreGuideLine){
  37830. this.closed && this.edgeLabels.forEach(e=>e.setVisible(!!(state && e.shouldVisi)) );
  37831. if(!ignoreGuideLine && this.measureType == 'Distance'){
  37832. this.horEdgeLabel.visible = this.verEdgeLabel.visible = this.horGuideEdge.visible = this.verGuideEdge.visible = !!(state && this.shouldShowHorVerGuide);
  37833. }
  37834. }
  37835. setSelected(state, hoverObject){//add
  37836. hoverObject && (this.selectStates[hoverObject] = state);
  37837. let absoluteState = false;
  37838. for(var i in this.selectStates){
  37839. if(this.selectStates[i]){
  37840. absoluteState = true; break;
  37841. }
  37842. }
  37843. if(absoluteState){
  37844. this.markers.forEach(e=>this.setMarkerSelected(e, 'hover', 'selectAll' ) );
  37845. this.edges.forEach(e=>e.material = this.getLineMat('edgeSelect') );
  37846. this.areaPlane && (this.areaPlane.material = planeMats.selected);
  37847. //this.areaLabel && this.areaLabel.elem.addClass('highLight')
  37848. //this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight') )
  37849. this.setEdgesDisplay(true, hoverObject=="screenshot");
  37850. this.areaLabel && setLabelHightState(this.areaLabel, true);
  37851. this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, true) );
  37852. }else {
  37853. this.markers.forEach(e=>this.setMarkerSelected(e, 'unhover', 'selectAll' ));
  37854. this.edges.forEach(e=>e.material = this.getLineMat('edgeDefault') );
  37855. this.areaPlane && (this.areaPlane.material = planeMats.default);
  37856. this.setEdgesDisplay(false, hoverObject=="screenshot");
  37857. //this.areaLabel && this.areaLabel.elem.removeClass('highLight')
  37858. //this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight') )
  37859. this.areaLabel && setLabelHightState(this.areaLabel, false);
  37860. this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, false) );
  37861. }
  37862. this.selected = absoluteState;
  37863. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed');
  37864. if(hoverObject != 'byList'){
  37865. this.bus && this.bus.emit('highlight', this.selected);//列表高亮
  37866. }
  37867. }
  37868. removeMarker(index ){
  37869. super.removeMarker(index);
  37870. this.points_datasets.splice(index, 1);
  37871. this.dataset_points && this.dataset_points.splice(index, 1);
  37872. this.coordinateLabels.splice(index, 1);
  37873. let edgeIndex = index;//(index === 0) ? 0 : (index - 1);
  37874. if(this.edgeLabels[edgeIndex]){
  37875. this.edgeLabels[edgeIndex].dispose();
  37876. this.edgeLabels.splice(edgeIndex, 1);
  37877. }
  37878. this.update();
  37879. this.dispatchEvent({type: 'marker_removed', measurement: this});
  37880. }
  37881. setPosition(index, position) {
  37882. super.setPosition(index, position);
  37883. let event = {
  37884. type: 'marker_moved',
  37885. measure: this,
  37886. index: index,
  37887. position: position.clone()
  37888. };
  37889. this.dispatchEvent(event);
  37890. }
  37891. dispose(){//add
  37892. var labels = this.edgeLabels.concat(this.coordinateLabels);
  37893. this.areaLabel && labels.push(this.areaLabel);
  37894. labels.forEach(e=>e.dispatchEvent({type:'dispose'}));
  37895. super.dispose();
  37896. }
  37897. getTotalDistance () {
  37898. if (this.points.length === 0) {
  37899. return 0;
  37900. }
  37901. let distance = 0;
  37902. for (let i = 1; i < this.points.length; i++) {
  37903. let prev = this.points[i - 1];
  37904. let curr = this.points[i];
  37905. let d = prev.distanceTo(curr);
  37906. distance += d;
  37907. }
  37908. if (this.closed && this.points.length > 1) {
  37909. let first = this.points[0];
  37910. let last = this.points[this.points.length - 1];
  37911. let d = last.distanceTo(first);
  37912. distance += d;
  37913. }
  37914. return distance;
  37915. }
  37916. getAngleBetweenLines (cornerPoint, point1, point2) {
  37917. let v1 = new Vector3().subVectors(point1, cornerPoint);
  37918. let v2 = new Vector3().subVectors(point2, cornerPoint);
  37919. // avoid the error printed by threejs if denominator is 0
  37920. const denominator = Math.sqrt( v1.lengthSq() * v2.lengthSq() );
  37921. if(denominator === 0){
  37922. return 0;
  37923. }else {
  37924. return v1.angleTo(v2);
  37925. }
  37926. };
  37927. getAngle (index) {
  37928. if (this.points.length < 3 || index >= this.points.length) {
  37929. return 0;
  37930. }
  37931. let previous = (index === 0) ? this.points[this.points.length - 1] : this.points[index - 1];
  37932. let point = this.points[index];
  37933. let next = this.points[(index + 1) % (this.points.length)];
  37934. return this.getAngleBetweenLines(point, previous, next);
  37935. }
  37936. getCenter(/* update */){
  37937. if(this.points.length>=3){
  37938. return this.center.clone()
  37939. }else if(this.points.length == 2){
  37940. return this.points[0].clone().add((this.points[1])).multiplyScalar(0.5)
  37941. }else return this.points[0].clone()
  37942. }
  37943. // updateAzimuth(){
  37944. // // if(this.points.length !== 2){
  37945. // // return;
  37946. // // }
  37947. // // const azimuth = this.azimuth;
  37948. // // const [p0, p1] = this.points;
  37949. // // const r = p0.distanceTo(p1);
  37950. // }
  37951. createGuideLine(){//add 辅助线
  37952. var guideLine = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} );
  37953. guideLine.visible = false;
  37954. this.guideLine = guideLine;
  37955. this.add(guideLine);
  37956. }
  37957. createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
  37958. var verGuideEdge = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} );
  37959. verGuideEdge.visible = false;
  37960. this.verGuideEdge = verGuideEdge;
  37961. var horGuideEdge = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} );
  37962. horGuideEdge.visible = false;
  37963. this.horGuideEdge = horGuideEdge;
  37964. this.add(this.verGuideEdge);
  37965. this.add(this.horGuideEdge);
  37966. //label:
  37967. this.verEdgeLabel = this.createEdgeLabel('verGuideEdge');
  37968. this.horEdgeLabel = this.createEdgeLabel('horGuideEdge');
  37969. }
  37970. createEdgeLabel(name, hasHoverEvent){
  37971. const edgeLabel = new TextSprite(
  37972. $.extend(hasHoverEvent ? mainLabelProp : subLabelProp,{sizeInfo: labelSizeInfo, name:name||'edgeLabel'})
  37973. );
  37974. if(hasHoverEvent){
  37975. edgeLabel.addEventListener('mouseover',()=>{
  37976. this.setSelected(true, 'edgeLabel');
  37977. });
  37978. edgeLabel.addEventListener('mouseleave',()=>{
  37979. this.setSelected(false, 'edgeLabel');
  37980. });
  37981. edgeLabel.addEventListener('click',()=>{
  37982. viewer.focusOnObject(this, 'measure');
  37983. });
  37984. }
  37985. edgeLabel.visible = false;
  37986. edgeLabel.sprite.material.depthTestWhenPick = true;
  37987. viewer.setObjectLayers(edgeLabel, 'measure' );
  37988. this.add(edgeLabel);
  37989. return edgeLabel
  37990. }
  37991. createAreaLabel(){
  37992. /* const areaLabel = new Label({
  37993. className:'measure_area',
  37994. })
  37995. areaLabel.elem.on('mouseover',()=>{
  37996. this.setSelected(true, 'areaLabel')
  37997. })
  37998. areaLabel.elem.on('mouseout',()=>{
  37999. this.setSelected(false, 'areaLabel')
  38000. }) */
  38001. const areaLabel = new TextSprite(
  38002. $.extend(mainLabelProp,{sizeInfo: labelSizeInfo, name:'areaLabel_'} )
  38003. );
  38004. areaLabel.addEventListener('mouseover',()=>{
  38005. this.setSelected(true, 'areaLabel');
  38006. });
  38007. areaLabel.addEventListener('mouseleave',()=>{
  38008. this.setSelected(false, 'areaLabel');
  38009. });
  38010. areaLabel.addEventListener('click',()=>{
  38011. viewer.focusOnObject(this, 'measure');
  38012. });
  38013. viewer.setObjectLayers(areaLabel, 'measure' );
  38014. areaLabel.visible = false;
  38015. return areaLabel;
  38016. }
  38017. getMarkerMaterial(type) {
  38018. if(!markerMats){
  38019. markerMats = {
  38020. default: new DepthBasicMaterial($.extend({},lineDepthInfo,{
  38021. transparent: !0,
  38022. opacity: 1,
  38023. map: texLoader.load(Potree.resourcePath+'/textures/pic_point_s32.png' ),
  38024. useDepth:true
  38025. })),
  38026. select: new MeshBasicMaterial({
  38027. transparent: !0,
  38028. opacity: 1,
  38029. depthTest:false,
  38030. map: texLoader.load(Potree.resourcePath+'/textures/pic_point32.png'/* , null, null, { antialias: false } */),
  38031. }),
  38032. };
  38033. Measure.markerMats = markerMats;
  38034. }
  38035. return markerMats[type]
  38036. }
  38037. getLineMat(type) {
  38038. if(!Measure.lineMats){
  38039. Measure.lineMats = {
  38040. edgeDefault: LineDraw.createFatLineMat({
  38041. color: config$1.measure.default.color,
  38042. lineWidth: config$1.measure.lineWidth,
  38043. useDepth :true,
  38044. dashWithDepth :true, // 只在被遮住的部分显示虚线,因为实线容易挡住label
  38045. dashed :true,
  38046. dashSize : 0.04,
  38047. gapSize: 0.04,
  38048. transparent: true,
  38049. opacity: config$1.measure.default.opacity,
  38050. depthTestWhenPick:true,
  38051. }),
  38052. edgeSelect: LineDraw.createFatLineMat({
  38053. color: config$1.measure.highlight.color,//'#f0ff00',
  38054. dashSize: 0.5,
  38055. gapSize: 0.2,
  38056. lineWidth: config$1.measure.lineWidth ,
  38057. transparent: true,
  38058. opacity: config$1.measure.highlight.opacity
  38059. }),
  38060. guide: LineDraw.createFatLineMat({
  38061. color:config$1.measure.guide.color,
  38062. dashSize: 0.1,
  38063. gapSize: 0.02,
  38064. dashed: true,
  38065. lineWidth: config$1.measure.lineWidth
  38066. })
  38067. };
  38068. }
  38069. return Measure.lineMats[type]
  38070. }
  38071. createAreaPlane(){
  38072. planeMats || (planeMats = {
  38073. default: new DepthBasicMaterial( $.extend({},LabelDepthInfo,{
  38074. color:color,
  38075. side:DoubleSide,
  38076. opacity:0.2,
  38077. transparent:true,
  38078. useDepth:true
  38079. })),
  38080. selected: new MeshBasicMaterial({
  38081. color: color ,
  38082. side:DoubleSide,
  38083. opacity:0.3,
  38084. transparent:true,
  38085. })
  38086. },Measure.planeMats = planeMats);
  38087. return super.createAreaPlane(planeMats.default)
  38088. }
  38089. raycast (raycaster, intersects) {
  38090. for (let i = 0; i < this.points.length; i++) {
  38091. let marker = this.markers[i];
  38092. marker.raycast(raycaster, intersects);
  38093. }
  38094. // recalculate distances because they are not necessarely correct
  38095. // for scaled objects.
  38096. // see https://github.com/mrdoob/three.js/issues/5827
  38097. // TODO: remove this once the bug has been fixed
  38098. for (let i = 0; i < intersects.length; i++) {
  38099. let I = intersects[i];
  38100. I.distance = raycaster.ray.origin.distanceTo(I.point);
  38101. }
  38102. intersects.sort(function (a, b) { return a.distance - b.distance; });
  38103. };
  38104. transformData(prop){
  38105. if(prop.measureType == 'Point'){
  38106. prop.showCoordinates = true,
  38107. prop.closed = true,
  38108. prop.maxMarkers = 1,
  38109. prop.minMarkers = 1;
  38110. }else if(prop.measureType == 'Distance'){
  38111. prop.showDistances = true,
  38112. prop.closed = false,
  38113. prop.showEdges = true,
  38114. prop.maxMarkers = 2,
  38115. prop.minMarkers = 2;
  38116. }else if(prop.measureType == 'Ver Distance'){
  38117. prop.showDistances = true,
  38118. prop.closed = false,
  38119. prop.showEdges = true,
  38120. prop.maxMarkers = 2,
  38121. prop.minMarkers = 2,
  38122. prop.faceDirection = "vertical";
  38123. prop.unableDragAtMap = true;
  38124. }else if(prop.measureType == 'Hor Distance'){
  38125. prop.showDistances = true,
  38126. prop.closed = false,
  38127. prop.showEdges = true,
  38128. prop.maxMarkers = 2,
  38129. prop.minMarkers = 2,
  38130. prop.faceDirection = "horizontal";
  38131. }else if(prop.measureType == 'Area'){
  38132. prop.showDistances = true,
  38133. prop.showArea = true,
  38134. prop.showEdges = true,
  38135. prop.closed = true,
  38136. prop.minMarkers = 3;
  38137. }else if(prop.measureType == 'Hor Area'){
  38138. prop.showDistances = true,
  38139. prop.showArea = true,
  38140. prop.showEdges = true,
  38141. prop.closed = true,
  38142. prop.minMarkers = 3;
  38143. prop.faceDirection = "horizontal";
  38144. }else if(prop.measureType == 'Ver Area'){
  38145. prop.showDistances = true,
  38146. prop.showArea = true,
  38147. prop.showEdges = true,
  38148. prop.closed = true,
  38149. prop.minMarkers = 3;
  38150. prop.faceDirection = "vertical";
  38151. prop.unableDragAtMap = true;
  38152. }else if(prop.measureType == 'Rect Area'){
  38153. prop.showDistances = true,
  38154. prop.showArea = true,
  38155. prop.showEdges = true,
  38156. prop.closed = true,
  38157. prop.minMarkers = 4;
  38158. prop.maxMarkers = 4;
  38159. }else if(prop.measureType == 'Hor Rect Area'){
  38160. prop.showDistances = true,
  38161. prop.showArea = true,
  38162. prop.showEdges = true,
  38163. prop.closed = true,
  38164. prop.minMarkers = 4;
  38165. prop.maxMarkers = 4;
  38166. prop.isRect = true;
  38167. prop.faceDirection = "horizontal";
  38168. }else if(prop.measureType == 'Ver Rect Area'){
  38169. prop.showDistances = true,
  38170. prop.showArea = true,
  38171. prop.showEdges = true,
  38172. prop.closed = true,
  38173. prop.minMarkers = 4;
  38174. prop.maxMarkers = 4;
  38175. prop.isRect = true;
  38176. prop.faceDirection = "vertical";
  38177. prop.unableDragAtMap = true;
  38178. }
  38179. }
  38180. setUnitSystem(unitSystem){
  38181. //console.log(this.name +':' +this.unitSystem)
  38182. if(unitSystem != this.unitSystem){
  38183. if(unitSystem == "metric"){
  38184. }else if(unitSystem == 'imperial'){
  38185. }
  38186. this.unitSystem = unitSystem;
  38187. this.update();
  38188. }
  38189. }
  38190. reDraw(restMarkerCount=0){//重新开始画
  38191. super.reDraw(restMarkerCount);
  38192. if(this.measureType == 'Distance'){
  38193. this.shouldShowHorVerGuide = false;
  38194. this.setEdgesDisplay(false);
  38195. }
  38196. if(this.showArea){
  38197. this.area = {value:0};
  38198. this.areaLabel && this.areaLabel.setVisible(false);
  38199. }
  38200. viewer.inputHandler.dispatchEvent( {type:'isMeasuring', v:true, cause:'reDraw'} );
  38201. }
  38202. /* get showCoordinates () {
  38203. return this._showCoordinates;
  38204. }
  38205. set showCoordinates (value) {
  38206. this._showCoordinates = value;
  38207. this.update();
  38208. }
  38209. get showAngles () {
  38210. return this._showAngles;
  38211. }
  38212. set showAngles (value) {
  38213. this._showAngles = value;
  38214. this.update();
  38215. }
  38216. get showCircle () {
  38217. return this._showCircle;
  38218. }
  38219. set showCircle (value) {
  38220. this._showCircle = value;
  38221. this.update();
  38222. }
  38223. get showAzimuth(){
  38224. return this._showAzimuth;
  38225. }
  38226. set showAzimuth(value){
  38227. this._showAzimuth = value;
  38228. this.update();
  38229. }
  38230. get showEdges () {
  38231. return this._showEdges;
  38232. }
  38233. set showEdges (value) {
  38234. this._showEdges = value;
  38235. this.update();
  38236. }
  38237. get showHeight () {
  38238. return this._showHeight;
  38239. }
  38240. set showHeight (value) {
  38241. this._showHeight = value;
  38242. this.update();
  38243. }
  38244. get showArea () {
  38245. return this._showArea;
  38246. }
  38247. set showArea (value) {
  38248. this._showArea = value;
  38249. this.update();
  38250. }
  38251. get closed () {
  38252. return this._closed;
  38253. }
  38254. set closed (value) {
  38255. this._closed = value;
  38256. this.update();
  38257. }
  38258. get showDistances () {
  38259. return this._showDistances;
  38260. }
  38261. set showDistances (value) {
  38262. this._showDistances = value;
  38263. this.update();
  38264. } */
  38265. }
  38266. function setLabelHightState(label, state){
  38267. if(state){
  38268. label.backgroundColor = {r: highlightColor.r*255, g: highlightColor.g*255, b: highlightColor.b*255, a:config$1.measure.highlight.opacity},
  38269. label.backgroundColor.a = config$1.measure.highlight.opacity;
  38270. label.sprite.material.useDepth = false;
  38271. }else {
  38272. label.backgroundColor = mainLabelProp.backgroundColor;
  38273. label.backgroundColor.a = config$1.measure.default.opacity;
  38274. label.sprite.material.useDepth = true;
  38275. }
  38276. label.updateTexture();
  38277. //label.sprite.material.needsUpdate = true
  38278. }
  38279. function createCircleRadiusLabel(){
  38280. const circleRadiusLabel = new TextSprite("");
  38281. circleRadiusLabel.setTextColor({r: 140, g: 250, b: 140, a: 1.0});
  38282. circleRadiusLabel.setBorderColor({r: 0, g: 0, b: 0, a: 1.0});
  38283. circleRadiusLabel.setBackgroundColor({r: 0, g: 0, b: 0, a: 1.0});
  38284. circleRadiusLabel.fontsize = 16;
  38285. circleRadiusLabel.material.depthTest = false;
  38286. circleRadiusLabel.material.opacity = 1;
  38287. circleRadiusLabel.visible = false;
  38288. return circleRadiusLabel;
  38289. }
  38290. function createCircleRadiusLine(){
  38291. /* const lineGeometry = new LineGeometry();
  38292. lineGeometry.setPositions([
  38293. 0, 0, 0,
  38294. 0, 0, 0,
  38295. ]);
  38296. const lineMaterial = new LineMaterial({
  38297. color: 0xff0000,
  38298. lineWidth: 2,
  38299. resolution: new THREE.Vector2(1000, 1000),
  38300. gapSize: 1,
  38301. dashed: true,
  38302. });
  38303. lineMaterial.depthTest = false;
  38304. const circleRadiusLine = new Line2(lineGeometry, lineMaterial);*/
  38305. var circleRadiusLine = LineDraw.createFatLine([ ],{
  38306. color:0xff0000,
  38307. dashSize: 0.5,
  38308. gapSize: 0.2,
  38309. lineWidth: config$1.measure.lineWidth
  38310. });
  38311. circleRadiusLine.visible = false;
  38312. return circleRadiusLine;
  38313. }
  38314. function createCircleLine(){
  38315. const coordinates = [];
  38316. let n = 128;
  38317. for(let i = 0; i <= n; i++){
  38318. let u0 = 2 * Math.PI * (i / n);
  38319. let u1 = 2 * Math.PI * (i + 1) / n;
  38320. let p0 = new Vector3(
  38321. Math.cos(u0),
  38322. Math.sin(u0),
  38323. 0
  38324. );
  38325. let p1 = new Vector3(
  38326. Math.cos(u1),
  38327. Math.sin(u1),
  38328. 0
  38329. );
  38330. coordinates.push(
  38331. p0,
  38332. p1
  38333. );
  38334. }
  38335. /* const geometry = new LineGeometry();
  38336. geometry.setPositions(coordinates);
  38337. const material = new LineMaterial({
  38338. color: 0xff0000,
  38339. dashSize: 5,
  38340. gapSize: 2,
  38341. lineWidth: 2,
  38342. resolution: new THREE.Vector2(1000, 1000),
  38343. });
  38344. material.depthTest = false;
  38345. const circleLine = new Line2(geometry, material);
  38346. circleLine.visible = false;
  38347. circleLine.computeLineDistances();*/
  38348. var circleLine = LineDraw.createFatLine(coordinates,{
  38349. color: 0xff0000,
  38350. dashSize: 0.5,
  38351. gapSize: 0.2,
  38352. lineWidth: config$1.measure.lineWidth
  38353. });
  38354. return circleLine;
  38355. }
  38356. /* function createCircleCenter(){
  38357. const sg = new THREE.markerGeometry(1, 32, 32);
  38358. const sm = new THREE.MeshNormalMaterial();
  38359. const circleCenter = new THREE.Mesh(sg, sm);
  38360. circleCenter.visible = false;
  38361. return circleCenter;
  38362. } */
  38363. function createLine(){
  38364. const line = LineDraw.createFatLine([ ],{
  38365. color: 0xff0000,
  38366. dashSize: 0.5,
  38367. gapSize: 0.2,
  38368. lineWidth: config$1.measure.lineWidth
  38369. });
  38370. return line;
  38371. }
  38372. function createCircle(){
  38373. const coordinates = [];
  38374. let n = 128;
  38375. for(let i = 0; i <= n; i++){
  38376. let u0 = 2 * Math.PI * (i / n);
  38377. let u1 = 2 * Math.PI * (i + 1) / n;
  38378. let p0 = new Vector3(
  38379. Math.cos(u0),
  38380. Math.sin(u0),
  38381. 0
  38382. );
  38383. let p1 = new Vector3(
  38384. Math.cos(u1),
  38385. Math.sin(u1),
  38386. 0
  38387. );
  38388. coordinates.push(
  38389. p0,
  38390. p1
  38391. );
  38392. }
  38393. var line = LineDraw.createFatLine(coordinates,{
  38394. color: 0xff0000,
  38395. dashSize: 0.5,
  38396. gapSize: 0.2,
  38397. lineWidth: config$1.measure.lineWidth
  38398. });
  38399. return line;
  38400. }
  38401. /* function createAzimuth(){
  38402. const azimuth = {
  38403. label: null,
  38404. center: null,
  38405. target: null,
  38406. north: null,
  38407. centerToNorth: null,
  38408. centerToTarget: null,
  38409. centerToTargetground: null,
  38410. targetgroundToTarget: null,
  38411. circle: null,
  38412. node: null,
  38413. };
  38414. const sg = new THREE.markerGeometry(1, 32, 32);
  38415. const sm = new THREE.MeshNormalMaterial();
  38416. {
  38417. const label = new TextSprite("");
  38418. label.setTextColor({r: 140, g: 250, b: 140, a: 1.0});
  38419. label.setBorderColor({r: 0, g: 0, b: 0, a: 1.0});
  38420. label.setBackgroundColor({r: 0, g: 0, b: 0, a: 1.0});
  38421. label.fontsize = 16;
  38422. label.material.depthTest = false;
  38423. label.material.opacity = 1;
  38424. azimuth.label = label;
  38425. }
  38426. azimuth.center = new THREE.Mesh(sg, sm);
  38427. azimuth.target = new THREE.Mesh(sg, sm);
  38428. azimuth.north = new THREE.Mesh(sg, sm);
  38429. azimuth.centerToNorth = createLine();
  38430. azimuth.centerToTarget = createLine();
  38431. azimuth.centerToTargetground = createLine();
  38432. azimuth.targetgroundToTarget = createLine();
  38433. azimuth.circle = createCircle();
  38434. azimuth.node = new THREE.Object3D();
  38435. azimuth.node.add(
  38436. azimuth.centerToNorth,
  38437. azimuth.centerToTarget,
  38438. azimuth.centerToTargetground,
  38439. azimuth.targetgroundToTarget,
  38440. azimuth.circle,
  38441. azimuth.label,
  38442. azimuth.center,
  38443. azimuth.target,
  38444. azimuth.north,
  38445. );
  38446. return azimuth;
  38447. } */
  38448. /*
  38449. */
  38450. class PolygonClipVolume extends Object3D{
  38451. constructor(camera){
  38452. super();
  38453. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  38454. this.name = "polygon_clip_volume_" + this.constructor.counter;
  38455. this.camera = camera.clone();
  38456. this.camera.rotation.set(...camera.rotation.toArray()); // [r85] workaround because camera.clone() doesn't work on rotation
  38457. this.camera.rotation.order = camera.rotation.order;
  38458. this.camera.updateMatrixWorld();
  38459. this.camera.updateProjectionMatrix();
  38460. this.camera.matrixWorldInverse.copy(this.camera.matrixWorld).invert();
  38461. this.viewMatrix = this.camera.matrixWorldInverse.clone();
  38462. this.projMatrix = this.camera.projectionMatrix.clone();
  38463. // projected markers
  38464. this.markers = [];
  38465. this.initialized = false;
  38466. }
  38467. addMarker() {
  38468. let marker = new Mesh();
  38469. let cancel;
  38470. let drag = e => {
  38471. let size = e.viewer.renderer.getSize(new Vector2$1());
  38472. let projectedPos = new Vector3(
  38473. 2.0 * (e.drag.end.x / size.width) - 1.0,
  38474. -2.0 * (e.drag.end.y / size.height) + 1.0,
  38475. 0
  38476. );
  38477. marker.position.copy(projectedPos);
  38478. };
  38479. let drop = e => {
  38480. cancel();
  38481. };
  38482. cancel = e => {
  38483. marker.removeEventListener("drag", drag);
  38484. marker.removeEventListener("drop", drop);
  38485. };
  38486. marker.addEventListener("drag", drag);
  38487. marker.addEventListener("drop", drop);
  38488. this.markers.push(marker);
  38489. }
  38490. removeLastMarker() {
  38491. if(this.markers.length > 0) {
  38492. this.markers.splice(this.markers.length - 1, 1);
  38493. }
  38494. }
  38495. };
  38496. class Utils {
  38497. static async loadShapefileFeatures (file, callback) {
  38498. let features = [];
  38499. let handleFinish = () => {
  38500. callback(features);
  38501. };
  38502. let source = await shapefile.open(file);
  38503. while(true){
  38504. let result = await source.read();
  38505. if (result.done) {
  38506. handleFinish();
  38507. break;
  38508. }
  38509. if (result.value && result.value.type === 'Feature' && result.value.geometry !== undefined) {
  38510. features.push(result.value);
  38511. }
  38512. }
  38513. }
  38514. static toString (value) {
  38515. if (value.x != null) {
  38516. return value.x.toFixed(2) + ', ' + value.y.toFixed(2) + ', ' + value.z.toFixed(2);
  38517. } else {
  38518. return '' + value + '';
  38519. }
  38520. }
  38521. static normalizeURL (url) {
  38522. let u = new URL(url);
  38523. return u.protocol + '//' + u.hostname + u.pathname.replace(/\/+/g, '/');
  38524. };
  38525. static pathExists (url) {
  38526. let req = XHRFactory.createXMLHttpRequest();
  38527. req.open('GET', url, false);
  38528. req.send(null);
  38529. if (req.status !== 200) {
  38530. return false;
  38531. }
  38532. return true;
  38533. };
  38534. static debugSphere(parent, position, scale, color){
  38535. let geometry = new SphereGeometry(1, 8, 8);
  38536. let material;
  38537. if(color !== undefined){
  38538. material = new MeshBasicMaterial({color: color});
  38539. }else {
  38540. material = new MeshNormalMaterial();
  38541. }
  38542. let sphere = new Mesh(geometry, material);
  38543. sphere.position.copy(position);
  38544. sphere.scale.set(scale, scale, scale);
  38545. parent.add(sphere);
  38546. return sphere;
  38547. }
  38548. static debugLine(parent, start, end, color){
  38549. let material = new LineBasicMaterial({ color: color });
  38550. let geometry = new Geometry();
  38551. const p1 = new Vector3(0, 0, 0);
  38552. const p2 = end.clone().sub(start);
  38553. geometry.vertices.push(p1, p2);
  38554. let tl = new Line( geometry, material );
  38555. tl.position.copy(start);
  38556. parent.add(tl);
  38557. let line = {
  38558. node: tl,
  38559. set: (start, end) => {
  38560. geometry.vertices[0].copy(start);
  38561. geometry.vertices[1].copy(end);
  38562. geometry.verticesNeedUpdate = true;
  38563. },
  38564. };
  38565. return line;
  38566. }
  38567. static debugCircle(parent, center, radius, normal, color){
  38568. let material = new LineBasicMaterial({ color: color });
  38569. let geometry = new Geometry();
  38570. let n = 32;
  38571. for(let i = 0; i <= n; i++){
  38572. let u0 = 2 * Math.PI * (i / n);
  38573. let u1 = 2 * Math.PI * (i + 1) / n;
  38574. let p0 = new Vector3(
  38575. Math.cos(u0),
  38576. Math.sin(u0),
  38577. 0
  38578. );
  38579. let p1 = new Vector3(
  38580. Math.cos(u1),
  38581. Math.sin(u1),
  38582. 0
  38583. );
  38584. geometry.vertices.push(p0, p1);
  38585. }
  38586. let tl = new Line( geometry, material );
  38587. tl.position.copy(center);
  38588. tl.scale.set(radius, radius, radius);
  38589. parent.add(tl);
  38590. }
  38591. static debugBox(parent, box, transform = new Matrix4(), color = 0xFFFF00){
  38592. let vertices = [
  38593. [box.min.x, box.min.y, box.min.z],
  38594. [box.min.x, box.min.y, box.max.z],
  38595. [box.min.x, box.max.y, box.min.z],
  38596. [box.min.x, box.max.y, box.max.z],
  38597. [box.max.x, box.min.y, box.min.z],
  38598. [box.max.x, box.min.y, box.max.z],
  38599. [box.max.x, box.max.y, box.min.z],
  38600. [box.max.x, box.max.y, box.max.z],
  38601. ].map(v => new Vector3(...v));
  38602. let edges = [
  38603. [0, 4], [4, 5], [5, 1], [1, 0],
  38604. [2, 6], [6, 7], [7, 3], [3, 2],
  38605. [0, 2], [4, 6], [5, 7], [1, 3]
  38606. ];
  38607. let center = box.getCenter(new Vector3());
  38608. let centroids = [
  38609. {position: [box.min.x, center.y, center.z], color: 0xFF0000},
  38610. {position: [box.max.x, center.y, center.z], color: 0x880000},
  38611. {position: [center.x, box.min.y, center.z], color: 0x00FF00},
  38612. {position: [center.x, box.max.y, center.z], color: 0x008800},
  38613. {position: [center.x, center.y, box.min.z], color: 0x0000FF},
  38614. {position: [center.x, center.y, box.max.z], color: 0x000088},
  38615. ];
  38616. for(let vertex of vertices){
  38617. let pos = vertex.clone().applyMatrix4(transform);
  38618. Utils.debugSphere(parent, pos, 0.1, 0xFF0000);
  38619. }
  38620. for(let edge of edges){
  38621. let start = vertices[edge[0]].clone().applyMatrix4(transform);
  38622. let end = vertices[edge[1]].clone().applyMatrix4(transform);
  38623. Utils.debugLine(parent, start, end, color);
  38624. }
  38625. for(let centroid of centroids){
  38626. let pos = new Vector3(...centroid.position).applyMatrix4(transform);
  38627. Utils.debugSphere(parent, pos, 0.1, centroid.color);
  38628. }
  38629. }
  38630. static debugPlane(parent, plane, size = 1, color = 0x0000FF){
  38631. let planehelper = new PlaneHelper(plane, size, color);
  38632. parent.add(planehelper);
  38633. }
  38634. /**
  38635. * adapted from mhluska at https://github.com/mrdoob/three.js/issues/1561
  38636. */
  38637. static computeTransformedBoundingBox (box, transform) {
  38638. let vertices = [
  38639. new Vector3(box.min.x, box.min.y, box.min.z).applyMatrix4(transform),
  38640. new Vector3(box.min.x, box.min.y, box.min.z).applyMatrix4(transform),
  38641. new Vector3(box.max.x, box.min.y, box.min.z).applyMatrix4(transform),
  38642. new Vector3(box.min.x, box.max.y, box.min.z).applyMatrix4(transform),
  38643. new Vector3(box.min.x, box.min.y, box.max.z).applyMatrix4(transform),
  38644. new Vector3(box.min.x, box.max.y, box.max.z).applyMatrix4(transform),
  38645. new Vector3(box.max.x, box.max.y, box.min.z).applyMatrix4(transform),
  38646. new Vector3(box.max.x, box.min.y, box.max.z).applyMatrix4(transform),
  38647. new Vector3(box.max.x, box.max.y, box.max.z).applyMatrix4(transform)
  38648. ];
  38649. let boundingBox = new Box3();
  38650. boundingBox.setFromPoints(vertices);
  38651. return boundingBox;
  38652. };
  38653. /**
  38654. * add separators to large numbers
  38655. *
  38656. * @param nStr
  38657. * @returns
  38658. */
  38659. static addCommas (nStr) {
  38660. nStr += '';
  38661. let x = nStr.split('.');
  38662. let x1 = x[0];
  38663. let x2 = x.length > 1 ? '.' + x[1] : '';
  38664. let rgx = /(\d+)(\d{3})/;
  38665. while (rgx.test(x1)) {
  38666. x1 = x1.replace(rgx, '$1' + ',' + '$2');
  38667. }
  38668. return x1 + x2;
  38669. };
  38670. static removeCommas (str) {
  38671. return str.replace(/,/g, '');
  38672. }
  38673. /**
  38674. * create worker from a string
  38675. *
  38676. * code from http://stackoverflow.com/questions/10343913/how-to-create-a-web-worker-from-a-string
  38677. */
  38678. static createWorker (code) {
  38679. let blob = new Blob([code], {type: 'application/javascript'});
  38680. let worker = new Worker(URL.createObjectURL(blob));
  38681. return worker;
  38682. };
  38683. static moveTo(scene, endPosition, endTarget){
  38684. let view = scene.view;
  38685. let camera = scene.getActiveCamera();
  38686. let animationDuration = 500;
  38687. let easing = TWEEN.Easing.Quartic.Out;
  38688. { // animate camera position
  38689. let tween = new TWEEN.Tween(view.position).to(endPosition, animationDuration);
  38690. tween.easing(easing);
  38691. tween.start();
  38692. }
  38693. { // animate camera target
  38694. let camTargetDistance = camera.position.distanceTo(endTarget);
  38695. let target = new Vector3().addVectors(
  38696. camera.position,
  38697. camera.getWorldDirection(new Vector3()).clone().multiplyScalar(camTargetDistance)
  38698. );
  38699. let tween = new TWEEN.Tween(target).to(endTarget, animationDuration);
  38700. tween.easing(easing);
  38701. tween.onUpdate(() => {
  38702. view.lookAt(target);
  38703. });
  38704. tween.onComplete(() => {
  38705. view.lookAt(target);
  38706. });
  38707. tween.start();
  38708. }
  38709. }
  38710. static loadSkybox (path) {
  38711. let parent = new Object3D("skybox_root");
  38712. let camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
  38713. if(!window.axisYup) camera.up.set(0, 0, 1);
  38714. let scene = new Scene();
  38715. let format = '.jpg';
  38716. let urls = [
  38717. path + 'px' + format, path + 'nx' + format,
  38718. path + 'py' + format, path + 'ny' + format,
  38719. path + 'pz' + format, path + 'nz' + format
  38720. ];
  38721. let materialArray = [];
  38722. {
  38723. for (let i = 0; i < 6; i++) {
  38724. let material = new MeshBasicMaterial({
  38725. map: null,
  38726. side: BackSide,
  38727. depthTest: false,
  38728. depthWrite: false,
  38729. color: 0x424556
  38730. });
  38731. materialArray.push(material);
  38732. let loader = new TextureLoader();
  38733. loader.load(urls[i],
  38734. function loaded (texture) {
  38735. material.map = texture;
  38736. material.needsUpdate = true;
  38737. material.color.setHex(0xffffff);
  38738. }, function progress (xhr) {
  38739. // console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
  38740. }, function error (xhr) {
  38741. console.log('An error happened', xhr);
  38742. }
  38743. );
  38744. }
  38745. }
  38746. let skyGeometry = new BoxGeometry(700, 700, 700);
  38747. let skybox = new Mesh(skyGeometry, materialArray);
  38748. scene.add(skybox);
  38749. scene.traverse(n => n.frustumCulled = false);
  38750. // z up
  38751. scene.rotation.x = Math.PI / 2;
  38752. parent.children.push(camera);
  38753. camera.parent = parent;
  38754. return {camera, scene, parent};
  38755. };
  38756. static createGrid (width, length, spacing, color) {
  38757. let material = new LineBasicMaterial({
  38758. color: color || 0x888888
  38759. });
  38760. let geometry = new Geometry();
  38761. for (let i = 0; i <= length; i++) {
  38762. geometry.vertices.push(new Vector3(-(spacing * width) / 2, i * spacing - (spacing * length) / 2, 0));
  38763. geometry.vertices.push(new Vector3(+(spacing * width) / 2, i * spacing - (spacing * length) / 2, 0));
  38764. }
  38765. for (let i = 0; i <= width; i++) {
  38766. geometry.vertices.push(new Vector3(i * spacing - (spacing * width) / 2, -(spacing * length) / 2, 0));
  38767. geometry.vertices.push(new Vector3(i * spacing - (spacing * width) / 2, +(spacing * length) / 2, 0));
  38768. }
  38769. let line = new LineSegments(geometry, material, LinePieces);
  38770. line.receiveShadow = true;
  38771. return line;
  38772. }
  38773. static createBackgroundTexture (width, height) {
  38774. function gauss (x, y) {
  38775. return (1 / (2 * Math.PI)) * Math.exp(-(x * x + y * y) / 2);
  38776. };
  38777. // map.magFilter = THREE.NearestFilter;
  38778. let size = width * height;
  38779. let data = new Uint8Array(3 * size);
  38780. let chroma = [1, 1.5, 1.7];
  38781. let max = gauss(0, 0);
  38782. for (let x = 0; x < width; x++) {
  38783. for (let y = 0; y < height; y++) {
  38784. let u = 2 * (x / width) - 1;
  38785. let v = 2 * (y / height) - 1;
  38786. let i = x + width * y;
  38787. let d = gauss(2 * u, 2 * v) / max;
  38788. let r = (Math.random() + Math.random() + Math.random()) / 3;
  38789. r = (d * 0.5 + 0.5) * r * 0.03;
  38790. r = r * 0.4;
  38791. // d = Math.pow(d, 0.6);
  38792. data[3 * i + 0] = 255 * (d / 15 + 0.05 + r) * chroma[0];
  38793. data[3 * i + 1] = 255 * (d / 15 + 0.05 + r) * chroma[1];
  38794. data[3 * i + 2] = 255 * (d / 15 + 0.05 + r) * chroma[2];
  38795. }
  38796. }
  38797. let texture = new DataTexture(data, width, height, RGBFormat);
  38798. texture.needsUpdate = true;
  38799. return texture;
  38800. }
  38801. static getMousePointCloudIntersection (viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
  38802. if(!pointclouds)return
  38803. let renderer = viewer.renderer;
  38804. if(viewport){ //转换到类似整个画面时
  38805. /*let mouseInViewport = Utils.convertNDCToScreenPosition(pointer, null, viewport.resolution.x, viewport.resolution.y)
  38806. pickParams.x = mouseInViewport.x //mouse.x / viewport.width;
  38807. pickParams.y = mouseInViewport.y //renderer.domElement.clientHeight - mouse.y / viewport.height; */
  38808. pickParams.x = mouse.x;
  38809. pickParams.y = viewport.resolution.y - mouse.y;
  38810. }else {
  38811. pickParams.x = mouse.x;
  38812. pickParams.y = renderer.domElement.clientHeight - mouse.y;
  38813. }
  38814. //console.log('getMousePointCloudIntersection')
  38815. /* if(!raycaster){
  38816. raycaster = new THREE.Raycaster();
  38817. raycaster.setFromCamera(pointer, camera);
  38818. } */
  38819. let raycaster = new Raycaster();
  38820. raycaster.setFromCamera(pointer, camera);
  38821. let ray = raycaster.ray;
  38822. let selectedPointcloud = null;
  38823. let closestDistance = Infinity;
  38824. let closestIntersection = null;
  38825. let closestPoint = null;
  38826. let density;
  38827. let sizeType;
  38828. let size = new Map();
  38829. if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){ //测量或全景模式提高精准度
  38830. density = Potree.settings.pointDensity;
  38831. Potree.settings.pointDensity = 'magnifier';
  38832. pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
  38833. size.set(e, e.temp.pointSize);
  38834. sizeType = e.material.pointSizeType;
  38835. e.material.pointSizeType = Potree.config.material.pointSizeType;
  38836. e.changePointSize(Potree.config.material.realPointSize*2, true);//更改点云大小到能铺满为止,否则容易识别不到
  38837. });
  38838. Potree.updatePointClouds(pointclouds, camera, viewport.resolution );
  38839. }else {
  38840. if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){
  38841. viewport.beforeRender && viewport.beforeRender();
  38842. Potree.updatePointClouds(pointclouds, camera, viewport.resolution ); //不加这句的话hover久了会不准 因node是错的
  38843. //但依旧需要camera真的移动到那个位置才能加载出点云
  38844. }
  38845. }
  38846. let allPointclouds = [];
  38847. for(let pointcloud of pointclouds){
  38848. let point = pointcloud.pick(viewer, viewport, camera, ray, pickParams );
  38849. if(!point){
  38850. continue;
  38851. }
  38852. allPointclouds.push(pointcloud);
  38853. let distance = camera.position.distanceTo(point.position);
  38854. if (distance < closestDistance) {
  38855. closestDistance = distance;
  38856. selectedPointcloud = pointcloud;
  38857. closestIntersection = point.position;
  38858. closestPoint = point;
  38859. }
  38860. }
  38861. if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){
  38862. Potree.settings.pointDensity = density;
  38863. pointclouds.forEach(e=>{
  38864. e.material.pointSizeType = sizeType;
  38865. e.changePointSize(size.get(e));
  38866. });
  38867. }else {
  38868. /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
  38869. viewport.afterRender && viewport.afterRender()
  38870. } */
  38871. }
  38872. if (selectedPointcloud) {
  38873. return {
  38874. location: closestIntersection,
  38875. distance: closestDistance,
  38876. pointcloud: selectedPointcloud,
  38877. pointclouds: allPointclouds, //add
  38878. point: closestPoint
  38879. };
  38880. } else {
  38881. return null;
  38882. }
  38883. }
  38884. static renderTargetToDataUrl(renderTarget, width, height, renderer, compressRatio = 0.7){
  38885. let pixelCount = width * height;
  38886. let buffer = new Uint8Array(4 * pixelCount);
  38887. renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
  38888. var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio);
  38889. return dataUrl
  38890. }
  38891. static pixelsArrayToDataUrl(pixels, width, height, compressRatio = 0.7) {
  38892. let canvas = document.createElement('canvas');
  38893. canvas.width = width;
  38894. canvas.height = height;
  38895. let context = canvas.getContext('2d');
  38896. pixels = new pixels.constructor(pixels);
  38897. /* for (let i = 0; i < pixels.length; i++) {
  38898. pixels[i * 4 + 3] = 255;
  38899. } */
  38900. // flip vertically
  38901. let bytesPerLine = width * 4;
  38902. for(let i = 0; i < parseInt(height / 2); i++){
  38903. let j = height - i - 1;
  38904. let lineI = pixels.slice(i * bytesPerLine, i * bytesPerLine + bytesPerLine);
  38905. let lineJ = pixels.slice(j * bytesPerLine, j * bytesPerLine + bytesPerLine);
  38906. pixels.set(lineJ, i * bytesPerLine);
  38907. pixels.set(lineI, j * bytesPerLine);
  38908. }
  38909. let imageData = context.createImageData(width, height);
  38910. imageData.data.set(pixels);
  38911. context.putImageData(imageData, 0, 0);
  38912. let dataURL = canvas.toDataURL(compressRatio);
  38913. return dataURL;
  38914. }
  38915. static removeListeners(dispatcher, type){
  38916. if (dispatcher._listeners === undefined) {
  38917. return;
  38918. }
  38919. if (dispatcher._listeners[ type ]) {
  38920. delete dispatcher._listeners[ type ];
  38921. }
  38922. }
  38923. /* static mouseToRay(mouse, camera, width, height){
  38924. let normalizedMouse = {
  38925. x: (mouse.x / width) * 2 - 1,
  38926. y: -(mouse.y / height) * 2 + 1
  38927. };
  38928. let vector = new THREE.Vector3(normalizedMouse.x, normalizedMouse.y, 0.5);
  38929. let origin = camera.position.clone();
  38930. vector.unproject(camera);
  38931. let direction = new THREE.Vector3().subVectors(vector, origin).normalize();
  38932. let ray = new THREE.Ray(origin, direction);
  38933. return ray;
  38934. } */
  38935. static mouseToRay(pointer, camera ){
  38936. let vector = new Vector3(pointer.x, pointer.y, 1);
  38937. let origin = new Vector3(pointer.x, pointer.y, -1); //不能用camera.position,在orbitCamera时不准
  38938. vector.unproject(camera);
  38939. origin.unproject(camera);
  38940. let direction = new Vector3().subVectors(vector, origin).normalize();
  38941. let ray = new Ray(origin, direction);
  38942. return ray;
  38943. }
  38944. static getPos2d(point, camera, dom, viewport){//获取一个三维坐标对应屏幕中的二维坐标
  38945. var pos;
  38946. if(math.closeTo(camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
  38947. pos = new Vector3(0,0,1.5); //1.5是为了不可见
  38948. }else {
  38949. pos = point.clone().project(camera); //比之前hotspot的计算方式写得简单 project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
  38950. }
  38951. var x,y,left,top;
  38952. x = (pos.x + 1) / 2 * dom.clientWidth * viewport.width;
  38953. y = (1 - (pos.y + 1) / 2) * dom.clientHeight * viewport.height;
  38954. left = viewport.left * dom.clientWidth;
  38955. top = (1- viewport.bottom - viewport.height) * dom.clientHeight;
  38956. var inSight = pos.x <= 1 && pos.x >= -1 //是否在屏幕中
  38957. && pos.x <= 1 && pos.y >= -1;
  38958. return {
  38959. pos: new Vector2$1(left+x,top+y) ,// 屏幕像素坐标
  38960. vector: pos, //(范围 -1 ~ 1)
  38961. trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点 参见Tag.update
  38962. inSight : inSight, //在屏幕范围内可见,
  38963. posInViewport: new Vector2$1(x,y)
  38964. };
  38965. }
  38966. static projectedRadius(radius, camera, distance, screenWidth, screenHeight){
  38967. if(camera instanceof OrthographicCamera){
  38968. return Utils.projectedRadiusOrtho(radius, camera.projectionMatrix, screenWidth, screenHeight);
  38969. }else if(camera instanceof PerspectiveCamera){
  38970. return Utils.projectedRadiusPerspective(radius, camera.fov * Math.PI / 180, distance, screenHeight);
  38971. }else {
  38972. throw new Error("invalid parameters");
  38973. }
  38974. }
  38975. static projectedRadiusPerspective(radius, fov, distance, screenHeight) {
  38976. let projFactor = (1 / Math.tan(fov / 2)) / distance;
  38977. projFactor = projFactor * screenHeight / 2;
  38978. return radius * projFactor;
  38979. }
  38980. static projectedRadiusOrtho(radius, proj, screenWidth, screenHeight) {
  38981. let p1 = new Vector4(0);
  38982. let p2 = new Vector4(radius);
  38983. p1.applyMatrix4(proj);
  38984. p2.applyMatrix4(proj);
  38985. p1 = new Vector3(p1.x, p1.y, p1.z);
  38986. p2 = new Vector3(p2.x, p2.y, p2.z);
  38987. p1.x = (p1.x + 1.0) * 0.5 * screenWidth;
  38988. p1.y = (p1.y + 1.0) * 0.5 * screenHeight;
  38989. p2.x = (p2.x + 1.0) * 0.5 * screenWidth;
  38990. p2.y = (p2.y + 1.0) * 0.5 * screenHeight;
  38991. return p1.distanceTo(p2);
  38992. }
  38993. static topView(camera, node){
  38994. camera.position.set(0, 1, 0);
  38995. camera.rotation.set(-Math.PI / 2, 0, 0);
  38996. camera.zoomTo(node, 1);
  38997. }
  38998. static frontView (camera, node) {
  38999. camera.position.set(0, 0, 1);
  39000. camera.rotation.set(0, 0, 0);
  39001. camera.zoomTo(node, 1);
  39002. }
  39003. static leftView (camera, node) {
  39004. camera.position.set(-1, 0, 0);
  39005. camera.rotation.set(0, -Math.PI / 2, 0);
  39006. camera.zoomTo(node, 1);
  39007. }
  39008. static rightView (camera, node) {
  39009. camera.position.set(1, 0, 0);
  39010. camera.rotation.set(0, Math.PI / 2, 0);
  39011. camera.zoomTo(node, 1);
  39012. }
  39013. static findClosestGpsTime(target, viewer){
  39014. const start = performance.now();
  39015. const nodes = [];
  39016. for(const pc of viewer.scene.pointclouds){
  39017. nodes.push(pc.root);
  39018. for(const child of pc.root.children){
  39019. if(child){
  39020. nodes.push(child);
  39021. }
  39022. }
  39023. }
  39024. let closestNode = null;
  39025. let closestIndex = Infinity;
  39026. let closestDistance = Infinity;
  39027. let closestValue = 0;
  39028. for(const node of nodes){
  39029. const isOkay = node.geometryNode != null
  39030. && node.geometryNode.geometry != null
  39031. && node.sceneNode != null;
  39032. if(!isOkay){
  39033. continue;
  39034. }
  39035. let geometry = node.geometryNode.geometry;
  39036. let gpsTime = geometry.attributes["gps-time"];
  39037. let range = gpsTime.potree.range;
  39038. for(let i = 0; i < gpsTime.array.length; i++){
  39039. let value = gpsTime.array[i];
  39040. value = value * (range[1] - range[0]) + range[0];
  39041. const distance = Math.abs(target - value);
  39042. if(distance < closestDistance){
  39043. closestIndex = i;
  39044. closestDistance = distance;
  39045. closestValue = value;
  39046. closestNode = node;
  39047. //console.log("found a closer one: " + value);
  39048. }
  39049. }
  39050. }
  39051. const geometry = closestNode.geometryNode.geometry;
  39052. const position = new Vector3(
  39053. geometry.attributes.position.array[3 * closestIndex + 0],
  39054. geometry.attributes.position.array[3 * closestIndex + 1],
  39055. geometry.attributes.position.array[3 * closestIndex + 2],
  39056. );
  39057. position.applyMatrix4(closestNode.sceneNode.matrixWorld);
  39058. const end = performance.now();
  39059. const duration = (end - start);
  39060. console.log(`duration: ${duration.toFixed(3)}ms`);
  39061. return {
  39062. node: closestNode,
  39063. index: closestIndex,
  39064. position: position,
  39065. };
  39066. }
  39067. /**
  39068. *
  39069. * 0: no intersection
  39070. * 1: intersection
  39071. * 2: fully inside
  39072. */
  39073. static frustumSphereIntersection (frustum, sphere) {
  39074. let planes = frustum.planes;
  39075. let center = sphere.center;
  39076. let negRadius = -sphere.radius;
  39077. let minDistance = Number.MAX_VALUE;
  39078. for (let i = 0; i < 6; i++) {
  39079. let distance = planes[ i ].distanceToPoint(center);
  39080. if (distance < negRadius) {
  39081. return 0;
  39082. }
  39083. minDistance = Math.min(minDistance, distance);
  39084. }
  39085. return (minDistance >= sphere.radius) ? 2 : 1;
  39086. }
  39087. // code taken from three.js
  39088. // ImageUtils - generateDataTexture()
  39089. static generateDataTexture (width, height, color) {
  39090. let size = width * height;
  39091. let data = new Uint8Array(4 * width * height);
  39092. let r = Math.floor(color.r * 255);
  39093. let g = Math.floor(color.g * 255);
  39094. let b = Math.floor(color.b * 255);
  39095. for (let i = 0; i < size; i++) {
  39096. data[ i * 3 ] = r;
  39097. data[ i * 3 + 1 ] = g;
  39098. data[ i * 3 + 2 ] = b;
  39099. }
  39100. let texture = new DataTexture(data, width, height, RGBAFormat);
  39101. texture.needsUpdate = true;
  39102. texture.magFilter = NearestFilter;
  39103. return texture;
  39104. }
  39105. // from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
  39106. static getParameterByName (name) {
  39107. name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
  39108. let regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
  39109. let results = regex.exec(document.location.search);
  39110. return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, ' '));
  39111. }
  39112. static setParameter (name, value) {
  39113. // value = encodeURIComponent(value);
  39114. name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
  39115. let regex = new RegExp('([\\?&])(' + name + '=([^&#]*))');
  39116. let results = regex.exec(document.location.search);
  39117. let url = window.location.href;
  39118. if (results === null) {
  39119. if (window.location.search.length === 0) {
  39120. url = url + '?';
  39121. } else {
  39122. url = url + '&';
  39123. }
  39124. url = url + name + '=' + value;
  39125. } else {
  39126. let newValue = name + '=' + value;
  39127. url = url.replace(results[2], newValue);
  39128. }
  39129. window.history.replaceState({}, '', url);
  39130. }
  39131. static createChildAABB(aabb, index){
  39132. let min = aabb.min.clone();
  39133. let max = aabb.max.clone();
  39134. let size = new Vector3().subVectors(max, min);
  39135. if ((index & 0b0001) > 0) {
  39136. min.z += size.z / 2;
  39137. } else {
  39138. max.z -= size.z / 2;
  39139. }
  39140. if ((index & 0b0010) > 0) {
  39141. min.y += size.y / 2;
  39142. } else {
  39143. max.y -= size.y / 2;
  39144. }
  39145. if ((index & 0b0100) > 0) {
  39146. min.x += size.x / 2;
  39147. } else {
  39148. max.x -= size.x / 2;
  39149. }
  39150. return new Box3(min, max);
  39151. }
  39152. // see https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
  39153. static clipboardCopy(text){
  39154. let textArea = document.createElement("textarea");
  39155. textArea.style.position = 'fixed';
  39156. textArea.style.top = 0;
  39157. textArea.style.left = 0;
  39158. textArea.style.width = '2em';
  39159. textArea.style.height = '2em';
  39160. textArea.style.padding = 0;
  39161. textArea.style.border = 'none';
  39162. textArea.style.outline = 'none';
  39163. textArea.style.boxShadow = 'none';
  39164. textArea.style.background = 'transparent';
  39165. textArea.value = text;
  39166. document.body.appendChild(textArea);
  39167. textArea.select();
  39168. try {
  39169. let success = document.execCommand('copy');
  39170. if(success){
  39171. console.log("copied text to clipboard");
  39172. }else {
  39173. console.log("copy to clipboard failed");
  39174. }
  39175. } catch (err) {
  39176. console.log("error while trying to copy to clipboard");
  39177. }
  39178. document.body.removeChild(textArea);
  39179. }
  39180. static getMeasurementIcon(measurement){
  39181. if (measurement instanceof Measure) {
  39182. if (measurement.showDistances && !measurement.showArea && !measurement.showAngles) {
  39183. return `${Potree.resourcePath}/icons/distance.svg`;
  39184. } else if (measurement.showDistances && measurement.showArea && !measurement.showAngles) {
  39185. return `${Potree.resourcePath}/icons/area.svg`;
  39186. } else if (measurement.maxMarkers === 1) {
  39187. return `${Potree.resourcePath}/icons/point.svg`;
  39188. } else if (!measurement.showDistances && !measurement.showArea && measurement.showAngles) {
  39189. return `${Potree.resourcePath}/icons/angle.png`;
  39190. } else if (measurement.showHeight) {
  39191. return `${Potree.resourcePath}/icons/height.svg`;
  39192. } else {
  39193. return `${Potree.resourcePath}/icons/distance.svg`;
  39194. }
  39195. } else if (measurement instanceof Profile) {
  39196. return `${Potree.resourcePath}/icons/profile.svg`;
  39197. } else if (measurement instanceof Volume) {
  39198. return `${Potree.resourcePath}/icons/volume.svg`;
  39199. } else if (measurement instanceof PolygonClipVolume) {
  39200. return `${Potree.resourcePath}/icons/clip-polygon.svg`;
  39201. }
  39202. }
  39203. static lineToLineIntersection(P0, P1, P2, P3){
  39204. const P = [P0, P1, P2, P3];
  39205. const d = (m, n, o, p) => {
  39206. let result =
  39207. (P[m].x - P[n].x) * (P[o].x - P[p].x)
  39208. + (P[m].y - P[n].y) * (P[o].y - P[p].y)
  39209. + (P[m].z - P[n].z) * (P[o].z - P[p].z);
  39210. return result;
  39211. };
  39212. const mua = (d(0, 2, 3, 2) * d(3, 2, 1, 0) - d(0, 2, 1, 0) * d(3, 2, 3, 2))
  39213. /**-----------------------------------------------------------------**/ /
  39214. (d(1, 0, 1, 0) * d(3, 2, 3, 2) - d(3, 2, 1, 0) * d(3, 2, 1, 0));
  39215. const mub = (d(0, 2, 3, 2) + mua * d(3, 2, 1, 0))
  39216. /**--------------------------------------**/ /
  39217. d(3, 2, 3, 2);
  39218. const P01 = P1.clone().sub(P0);
  39219. const P23 = P3.clone().sub(P2);
  39220. const Pa = P0.clone().add(P01.multiplyScalar(mua));
  39221. const Pb = P2.clone().add(P23.multiplyScalar(mub));
  39222. const center = Pa.clone().add(Pb).multiplyScalar(0.5);
  39223. return center;
  39224. }
  39225. static computeCircleCenter(A, B, C){
  39226. const AB = B.clone().sub(A);
  39227. const AC = C.clone().sub(A);
  39228. const N = AC.clone().cross(AB).normalize();
  39229. const ab_dir = AB.clone().cross(N).normalize();
  39230. const ac_dir = AC.clone().cross(N).normalize();
  39231. const ab_origin = A.clone().add(B).multiplyScalar(0.5);
  39232. const ac_origin = A.clone().add(C).multiplyScalar(0.5);
  39233. const P0 = ab_origin;
  39234. const P1 = ab_origin.clone().add(ab_dir);
  39235. const P2 = ac_origin;
  39236. const P3 = ac_origin.clone().add(ac_dir);
  39237. const center = Utils.lineToLineIntersection(P0, P1, P2, P3);
  39238. return center;
  39239. // Potree.Utils.debugLine(viewer.scene.scene, P0, P1, 0x00ff00);
  39240. // Potree.Utils.debugLine(viewer.scene.scene, P2, P3, 0x0000ff);
  39241. // Potree.Utils.debugSphere(viewer.scene.scene, center, 0.03, 0xff00ff);
  39242. // const radius = center.distanceTo(A);
  39243. // Potree.Utils.debugCircle(viewer.scene.scene, center, radius, new THREE.Vector3(0, 0, 1), 0xff00ff);
  39244. }
  39245. static getNorthVec(p1, distance, projection){
  39246. if(projection){
  39247. // if there is a projection, transform coordinates to WGS84
  39248. // and compute angle to north there
  39249. proj4.defs("pointcloud", projection);
  39250. const transform = proj4("pointcloud", "WGS84");
  39251. const llP1 = transform.forward(p1.toArray());
  39252. let llP2 = transform.forward([p1.x, p1.y + distance]);
  39253. const polarRadius = Math.sqrt((llP2[0] - llP1[0]) ** 2 + (llP2[1] - llP1[1]) ** 2);
  39254. llP2 = [llP1[0], llP1[1] + polarRadius];
  39255. const northVec = transform.inverse(llP2);
  39256. return new Vector3(...northVec, p1.z).sub(p1);
  39257. }else {
  39258. // if there is no projection, assume [0, 1, 0] as north direction
  39259. const vec = new Vector3(0, 1, 0).multiplyScalar(distance);
  39260. return vec;
  39261. }
  39262. }
  39263. static computeAzimuth(p1, p2, projection){
  39264. let azimuth = 0;
  39265. if(projection){
  39266. // if there is a projection, transform coordinates to WGS84
  39267. // and compute angle to north there
  39268. let transform;
  39269. if (projection.includes('EPSG')) {
  39270. transform = proj4(projection, "WGS84");
  39271. } else {
  39272. proj4.defs("pointcloud", projection);
  39273. transform = proj4("pointcloud", "WGS84");
  39274. }
  39275. const llP1 = transform.forward(p1.toArray());
  39276. const llP2 = transform.forward(p2.toArray());
  39277. const dir = [
  39278. llP2[0] - llP1[0],
  39279. llP2[1] - llP1[1],
  39280. ];
  39281. azimuth = Math.atan2(dir[1], dir[0]) - Math.PI / 2;
  39282. }else {
  39283. // if there is no projection, assume [0, 1, 0] as north direction
  39284. const dir = [p2.x - p1.x, p2.y - p1.y];
  39285. azimuth = Math.atan2(dir[1], dir[0]) - Math.PI / 2;
  39286. }
  39287. // make clockwise
  39288. azimuth = -azimuth;
  39289. return azimuth;
  39290. }
  39291. static async loadScript(url){
  39292. return new Promise( resolve => {
  39293. const element = document.getElementById(url);
  39294. if(element){
  39295. resolve();
  39296. }else {
  39297. const script = document.createElement("script");
  39298. script.id = url;
  39299. script.onload = () => {
  39300. resolve();
  39301. };
  39302. script.src = url;
  39303. document.body.appendChild(script);
  39304. }
  39305. });
  39306. }
  39307. static createSvgGradient(scheme){
  39308. // this is what we are creating:
  39309. //
  39310. //<svg width="1em" height="3em" xmlns="http://www.w3.org/2000/svg">
  39311. // <defs>
  39312. // <linearGradient id="gradientID" gradientTransform="rotate(90)">
  39313. // <stop offset="0%" stop-color="rgb(93, 78, 162)" />
  39314. // ...
  39315. // <stop offset="100%" stop-color="rgb(157, 0, 65)" />
  39316. // </linearGradient>
  39317. // </defs>
  39318. //
  39319. // <rect width="100%" height="100%" fill="url('#myGradient')" stroke="black" stroke-width="0.1em"/>
  39320. //</svg>
  39321. const gradientId = `${Math.random()}_${Date.now()}`;
  39322. const svgn = "http://www.w3.org/2000/svg";
  39323. const svg = document.createElementNS(svgn, "svg");
  39324. svg.setAttributeNS(null, "width", "2em");
  39325. svg.setAttributeNS(null, "height", "3em");
  39326. { // <defs>
  39327. const defs = document.createElementNS(svgn, "defs");
  39328. const linearGradient = document.createElementNS(svgn, "linearGradient");
  39329. linearGradient.setAttributeNS(null, "id", gradientId);
  39330. linearGradient.setAttributeNS(null, "gradientTransform", "rotate(90)");
  39331. for(let i = scheme.length - 1; i >= 0; i--){
  39332. const stopVal = scheme[i];
  39333. const percent = parseInt(100 - stopVal[0] * 100);
  39334. const [r, g, b] = stopVal[1].toArray().map(v => parseInt(v * 255));
  39335. const stop = document.createElementNS(svgn, "stop");
  39336. stop.setAttributeNS(null, "offset", `${percent}%`);
  39337. stop.setAttributeNS(null, "stop-color", `rgb(${r}, ${g}, ${b})`);
  39338. linearGradient.appendChild(stop);
  39339. }
  39340. defs.appendChild(linearGradient);
  39341. svg.appendChild(defs);
  39342. }
  39343. const rect = document.createElementNS(svgn, "rect");
  39344. rect.setAttributeNS(null, "width", `100%`);
  39345. rect.setAttributeNS(null, "height", `100%`);
  39346. rect.setAttributeNS(null, "fill", `url("#${gradientId}")`);
  39347. rect.setAttributeNS(null, "stroke", `black`);
  39348. rect.setAttributeNS(null, "stroke-width", `0.1em`);
  39349. svg.appendChild(rect);
  39350. return svg;
  39351. }
  39352. static async waitAny(promises){
  39353. return new Promise( (resolve) => {
  39354. promises.map( promise => {
  39355. promise.then( () => {
  39356. resolve();
  39357. });
  39358. });
  39359. });
  39360. }
  39361. }
  39362. Utils.screenPass = new function () {
  39363. this.screenScene = new Scene();
  39364. this.screenQuad = new Mesh(new PlaneBufferGeometry(2, 2, 1));
  39365. this.screenQuad.material.depthTest = true;
  39366. this.screenQuad.material.depthWrite = true;
  39367. this.screenQuad.material.transparent = true;
  39368. this.screenScene.add(this.screenQuad);
  39369. this.camera = new Camera();
  39370. this.render = function (renderer, material, target) {
  39371. this.screenQuad.material = material;
  39372. if (typeof target === 'undefined') {
  39373. renderer.render(this.screenScene, this.camera);
  39374. } else {
  39375. renderer.setRenderTarget(target);
  39376. renderer.render(this.screenScene, this.camera);
  39377. }
  39378. };
  39379. }();
  39380. //add
  39381. Utils.computePointcloudsBound = function(pointclouds){
  39382. var boundingBox = new Box3();
  39383. pointclouds.forEach(pointcloud=>{
  39384. pointcloud.updateBound();
  39385. boundingBox.union(pointcloud.bound);
  39386. });
  39387. var boundSize = boundingBox.getSize(new Vector3);
  39388. var center = boundingBox.getCenter(new Vector3);
  39389. return {boundSize, center, boundingBox}
  39390. };
  39391. Utils.convertScreenPositionToNDC = function(pointer, mouse, width, height) {
  39392. return pointer = pointer || new Vector2$1,
  39393. pointer.x = mouse.x / width * 2 - 1,
  39394. pointer.y = 2 * -(mouse.y / height) + 1,
  39395. pointer
  39396. };
  39397. Utils.convertNDCToScreenPosition = function(pointer, mouse, width, height) {
  39398. return mouse = mouse || new Vector2$1,
  39399. mouse.x = Math.round((pointer.x + 1 ) / 2 * width),
  39400. mouse.y = Math.round(-(pointer.y - 1 ) / 2 * height),
  39401. mouse
  39402. };
  39403. Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera为Ortho型时 屏幕点1 到 屏幕点2 的三维距离
  39404. let cameraViewWidth = camera.right / camera.zoom;
  39405. let cameraViewHeight = camera.top / camera.zoom;
  39406. let moveVec = new Vector3;
  39407. moveVec.set( pointerDelta.x * cameraViewWidth , pointerDelta.y * cameraViewHeight , 0).applyQuaternion(camera.quaternion);
  39408. return moveVec
  39409. };
  39410. Utils.VectorFactory = {
  39411. fromArray : function(t) {
  39412. if (t) {
  39413. if (t.length < 2 || t.length > 3)
  39414. console.error("Wrong number of ordinates for a point!");
  39415. return 3 === t.length ? (new Vector3).fromArray(t) : (new Vector2$1).fromArray(t)
  39416. }
  39417. },
  39418. fromArray3 : function(t) {
  39419. if (t) {
  39420. if (3 !== t.length)
  39421. console.error("Wrong number of ordinates for a point!");
  39422. return (new Vector3).fromArray(t)
  39423. }
  39424. },
  39425. fromArray2 : function(t) {
  39426. if (t) {
  39427. if (2 !== t.length)
  39428. console.error("Wrong number of ordinates for a point!");
  39429. return (new Vector2$1).fromArray(t)
  39430. }
  39431. },
  39432. toString : function(t) {
  39433. return t.x.toFixed(8) + "," + t.y.toFixed(8) + "," + t.z.toFixed(3)
  39434. }
  39435. };
  39436. Utils.QuaternionFactory = {
  39437. rot90 : (new Quaternion).setFromAxisAngle(new Vector3(0,0,1), MathUtils.degToRad(-90)),
  39438. fromArray : function(t) {
  39439. if (t) {
  39440. if (4 !== t.length)
  39441. console.error("Wrong number of ordinates for a quaternion!");
  39442. return new Quaternion(t[1],t[2],t[3],t[0]).multiply(this.rot90)
  39443. }
  39444. }
  39445. ,
  39446. toArray : function(t) {
  39447. if (t) {
  39448. var e = t.clone().multiply(a).toArray();
  39449. return [e[3], e[0], e[1], e[2]]
  39450. }
  39451. }
  39452. ,
  39453. fromLonLat : function(t) {
  39454. if (t)
  39455. return (new Quaternion).setFromEuler(new Euler(t.lon,t.lat,0))
  39456. }
  39457. ,
  39458. toLonLat : function(t) {
  39459. if (t) {
  39460. var e = (new Euler).setFromQuaternion(t);
  39461. return {
  39462. lon: e.x,
  39463. lat: e.y
  39464. }
  39465. }
  39466. }
  39467. };
  39468. Utils.datasetPosTransform = function(o={}){
  39469. let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId);
  39470. let tranMatrix;
  39471. if(pointcloud){
  39472. if(Potree.settings.editType == 'merge'){
  39473. tranMatrix = o.fromDataset ? pointcloud.matrixWorld : new Matrix4().copy(pointcloud.matrixWorld).invert();
  39474. }else {
  39475. tranMatrix = o.fromDataset ? pointcloud.transformMatrix : pointcloud.transformInvMatrix;
  39476. }
  39477. }else {
  39478. if(Potree.settings.intersectOnObjs){
  39479. let object = viewer.objs.children.find(e=>e.dataset_id == o.datasetId);
  39480. if(object){
  39481. tranMatrix = o.fromDataset ? object.matrixWorld : new Matrix4().copy(object.matrixWorld).invert();
  39482. }
  39483. }
  39484. }
  39485. if(tranMatrix){
  39486. return (new Vector3).copy(o.position).applyMatrix4(tranMatrix)
  39487. }else {
  39488. if(o.datasetId != void 0){
  39489. console.error(`datasetPosTransform找不到datasetId为${o.datasetId}的数据集,请检查(热点?测量线?)数据`);
  39490. //很可能是旧的热点,需要删除
  39491. }
  39492. }
  39493. };
  39494. Utils.datasetRotTransform = function(o={}){
  39495. let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId);
  39496. if(pointcloud){
  39497. var matrix, newMatrix, result;
  39498. if(o.rotation){
  39499. matrix = new Matrix4().makeRotationFromEuler(o.rotation);
  39500. }else if(o.quaternion){
  39501. matrix = new Matrix4().makeRotationFromQuaternion(o.quaternion);
  39502. }else if(o.matrix){
  39503. matrix = o.matrix.clone();
  39504. }else {
  39505. return
  39506. }
  39507. let rotateMatrix = o.fromDataset ? pointcloud.rotateMatrix : pointcloud.rotateInvMatrix;
  39508. newMatrix = new Matrix4().multiplyMatrices(rotateMatrix, matrix );
  39509. if(o.getRotation){
  39510. result = new Euler().setFromRotationMatrix(newMatrix);
  39511. }else if(o.getQuaternion){
  39512. result = new Quaternion().setFromRotationMatrix(newMatrix);
  39513. }else if(o.getMatrix){
  39514. result = newMatrix;
  39515. }
  39516. return result
  39517. }
  39518. };
  39519. Utils.isInsideFrustum = function(bounding, camera){// boundingBox在视野范围内有可见部分
  39520. let frustumMatrix = new Matrix4;
  39521. frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
  39522. let frustum = new Frustum();
  39523. frustum.setFromProjectionMatrix(frustumMatrix);
  39524. if(bounding instanceof Sphere){
  39525. return frustum.intersectsSphere(bounding)
  39526. }else {
  39527. return frustum.intersectsBox(bounding)
  39528. }
  39529. };
  39530. Utils.isInsideBox = function(object, boxMatrixInverse){//object可以是点或者bounding, box原为1*1*1,但可能形变
  39531. let frustum = new Frustum();
  39532. frustum.setFromProjectionMatrix(boxMatrixInverse);
  39533. if(object instanceof Box3){
  39534. return frustum.intersectsSphere(object)
  39535. }else if(object instanceof Array){//点合集,先求Sphere setFromPoints
  39536. let sphere = new Sphere();
  39537. sphere.setFromPoints(object);
  39538. return this.isInsideBox(sphere, boxMatrixInverse)
  39539. }else if(object instanceof Sphere){
  39540. return frustum.intersectsSphere(object)
  39541. }else if(object instanceof Vector3){
  39542. return frustum.containsPoint(object)
  39543. }
  39544. /* containsPoint: ƒ containsPoint( point )
  39545. intersectsBox: ƒ intersectsBox( box )
  39546. intersectsObject: ƒ intersectsObject( object )//geo
  39547. intersectsSphere: ƒ intersectsSphere( sphere )
  39548. intersectsSprite: ƒ intersectsSprite( sprite )
  39549. */
  39550. };
  39551. Utils.getIntersect = function (camera, meshes, pointer, raycaster) {
  39552. //获取鼠标和meshes交点
  39553. camera.updateMatrixWorld();
  39554. if(!raycaster){//getMouseIntersect
  39555. raycaster = new Raycaster();
  39556. var origin = new Vector3(pointer.x, pointer.y, -1).unproject(camera),
  39557. end = new Vector3(pointer.x, pointer.y, 1).unproject(camera);
  39558. var dir = end.sub(origin).normalize();
  39559. raycaster.set(origin, dir);
  39560. }
  39561. meshes.forEach(e=>{
  39562. raycaster.layers.enable(math.getBaseLog(e.layers.mask,2));
  39563. });
  39564. var n = raycaster.intersectObjects(meshes);
  39565. if (0 === n.length) return null
  39566. return n[0]
  39567. };
  39568. var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
  39569. /* {
  39570. let obj = JSON.parse(localStorage.getItem('setting'))
  39571. for(let i in obj){
  39572. console.log(i + ': ' + obj[i])
  39573. }
  39574. }
  39575. */
  39576. Potree.settings.number = number || 't-o5YMR13';// 't-iksBApb'// 写在viewer前
  39577. Potree.fileServer = fileServer;
  39578. webSite && (Potree.settings.webSite = webSite);
  39579. let viewer = new Potree.Viewer(dom , mapDom);
  39580. let Alignment = viewer.modules.Alignment;
  39581. //let pointDensity = config.pointDensity.middle
  39582. viewer.setEDLEnabled(false);
  39583. viewer.setFOV(config$1.view.fov);
  39584. //viewer.setPointBudget(pointDensity.pointBudget);
  39585. viewer.loadSettingsFromURL();
  39586. if(!Potree.settings.isOfficial){
  39587. viewer.loadGUI(() => {
  39588. viewer.setLanguage('en');
  39589. //$("#menu_appearance").next().show();
  39590. $("#menu_tools").next().show();
  39591. $("#menu_scene").next().show();
  39592. $("#siteModel").show();
  39593. //$("#alignment").show();
  39594. viewer.toggleSidebar();
  39595. });
  39596. Potree.settings.sizeFitToLevel = true;//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
  39597. }
  39598. Potree.loadDatasetsCallback = function(data, ifReload){
  39599. if(!data || data.length == 0)return console.error('getDataSet加载的数据为空')
  39600. Potree.datasetData = data;
  39601. viewer.transform = null;
  39602. var datasetLength = data.length;
  39603. var pointcloudLoaded = 0;
  39604. var panosLoaded = 0;
  39605. var pointcloudLoadDone = function(){//点云cloud.js加载完毕后
  39606. viewer.updateModelBound();
  39607. let {boundSize, center} = viewer.bound;
  39608. Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12);
  39609. if(!Potree.settings.isOfficial){
  39610. Potree.loadMapEntity('all'); //加载floorplan
  39611. }
  39612. if(!ifReload){
  39613. viewer.scene.view.setView({
  39614. position: center.clone().add(new Vector3(10,5,10)),
  39615. target: center
  39616. });
  39617. viewer.dispatchEvent({type:'loadPointCloudDone'});
  39618. if(!Potree.settings.UserPointDensity){
  39619. Potree.settings.UserPointDensity = 'high';//'middle'
  39620. }
  39621. Potree.Log('loadPointCloudDone 点云加载完毕', null, 10);
  39622. }
  39623. };
  39624. var panosLoadDone = function(){
  39625. viewer.images360.loadDone();
  39626. viewer.scene.add360Images(viewer.images360);
  39627. viewer.mapViewer.addListener(viewer.images360);
  39628. {//初始位置
  39629. var urlFirstView = false;
  39630. var panoId = browser.urlHasValue('pano',true);
  39631. if(panoId !== ''){
  39632. var pos;
  39633. var pano = viewer.images360.panos.find(e=>e.id==panoId);
  39634. if(pano){
  39635. viewer.images360.focusPano({
  39636. pano,
  39637. duration:0,
  39638. callback:()=>{/* Potree.settings.displayMode = 'showPanos' */}
  39639. });
  39640. }
  39641. }else {//考虑到多数据集距离很远,或者像隧道那种场景,要使视野范围内一定能看到点云,最好初始点设置在漫游点上
  39642. let {boundSize, center} = viewer.bound;
  39643. let pano = viewer.images360.findNearestPano(center);
  39644. /* pano && viewer.scene.view.setView({
  39645. position: pano.position.clone().add(new THREE.Vector3(10,10,10)),
  39646. target: pano.position
  39647. }) */
  39648. pano && viewer.images360.flyToPano({
  39649. pano, duration:0,
  39650. target : viewer.images360.bound.center
  39651. });
  39652. }
  39653. }
  39654. viewer.addVideo();//addFire()
  39655. console.log('allLoaded');
  39656. viewer.dispatchEvent('allLoaded');
  39657. };
  39658. var transformPointcloud = (pointcloud, dataset)=>{
  39659. var locationLonLat = dataset.location.slice(0,2);
  39660. //当只有一个dataset时,无论如何transform 点云和漫游点都能对应上。
  39661. var location = viewer.transform.lonlatToLocal.forward(locationLonLat); //transform.inverse()
  39662. //初始化位置
  39663. viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud);
  39664. //dataset.orientation = 0
  39665. Alignment.rotate(pointcloud, null, dataset.orientation);
  39666. Alignment.translate(pointcloud, new Vector3(location[0], location[1], dataset.location[2]));
  39667. pointcloud.updateMatrixWorld();
  39668. Potree.Log(`点云${pointcloud.dataset_id}旋转值:${pointcloud.orientationUser}, 位置${math.toPrecision(pointcloud.translateUser.toArray(),3)}, 经纬度 ${locationLonLat}, spacing ${pointcloud.material.spacing}`, null, 17 );
  39669. //-------------------
  39670. //viewer.mapView.showSources(false);
  39671. };
  39672. if(!Potree.settings.originDatasetId)Potree.settings.originDatasetId = data[0].id;
  39673. var originDataset = data.find(e=>e.id == Potree.settings.originDatasetId);
  39674. {//拿初始数据集作为基准。它的位置是000
  39675. var locationLonLat = originDataset.location.slice(0,2);
  39676. proj4.defs("NAVVIS:TMERC", "+proj=tmerc +ellps=WGS84 +lon_0=" + locationLonLat[0].toPrecision(15) + " +lat_0=" + locationLonLat[1].toPrecision(15));
  39677. proj4.defs("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
  39678. let transform1 = proj4("WGS84", "NAVVIS:TMERC"); //这个ok TMERC是展开的平面投影
  39679. let transform2 = proj4("+proj=tmerc +lat_0=0 +lon_0=123 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs;");
  39680. viewer.transform = {
  39681. lonlatToLocal : transform1,
  39682. lonlatTo4550 : transform2 // 转大地坐标EPSG:4550
  39683. };
  39684. viewer.mapViewer && viewer.mapViewer.mapLayer.maps[0].updateProjection();
  39685. }
  39686. data.forEach((dataset,index)=>{
  39687. if(!ifReload){
  39688. var datasetCode = dataset.sceneCode || dataset.name; //对应4dkk的场景码
  39689. var cloudPath = `${Potree.settings.urls.prefix}/${Potree.settings.webSite}/${datasetCode}/data/${datasetCode}/webcloud/cloud.js`;
  39690. var timeStamp = dataset.createTime ? dataset.createTime.replace(/[^0-9]/ig,'') : ''; //每重算一次后缀随createTime更新一次
  39691. //console.warn(dataset.name, 'timeStamp', timeStamp)
  39692. Potree.loadPointCloud(cloudPath, dataset.name ,datasetCode, timeStamp, e => {
  39693. let scene = viewer.scene;
  39694. let pointcloud = e.pointcloud;
  39695. let config = Potree.config.material;
  39696. let material = pointcloud.material;
  39697. pointcloud.hasDepthTex = Potree.settings.useDepthTex && (!!dataset.has_depth || Potree.settings.isLocalhost && Potree.settings.number == 'SS-t-7DUfWAUZ3V'); //test
  39698. material.minSize = config.minSize;
  39699. material.maxSize = config.maxSize;
  39700. material.pointSizeType = config.pointSizeType; //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
  39701. pointcloud.changePointSize(config.realPointSize); //material.size = config.pointSize;
  39702. pointcloud.changePointOpacity(1);
  39703. material.shape = Potree.PointShape.SQUARE;
  39704. pointcloud.color = pointcloud.material.color = dataset.color;
  39705. pointcloud.dataset_id = dataset.id;//供漫游点找到属于的dataset点云
  39706. pointcloud.timeStamp = timeStamp;
  39707. transformPointcloud(pointcloud,dataset);
  39708. scene.addPointCloud(pointcloud);
  39709. pointcloudLoaded ++;
  39710. if(pointcloudLoaded == datasetLength)pointcloudLoadDone();
  39711. Potree.loadPanos(dataset.id, (data) => {
  39712. //console.log('loadPanos',dataset.sceneCode, dataset.id, data)
  39713. viewer.images360.addPanoData(data, dataset.id );
  39714. panosLoaded ++;
  39715. if(panosLoaded == datasetLength){
  39716. panosLoadDone();
  39717. }
  39718. });
  39719. });
  39720. }else {
  39721. let pointcloud = viewer.scene.pointclouds.find(p => p.dataset_id == dataset.id);
  39722. if(!pointcloud){
  39723. Potree.Log('数据集id变了,自动使用第一个','#500');
  39724. pointcloud = viewer.scene.pointclouds[0];
  39725. }
  39726. //先归零
  39727. Alignment.translate(pointcloud, pointcloud.translateUser.clone().negate());
  39728. Alignment.rotate(pointcloud, null, - pointcloud.orientationUser);
  39729. transformPointcloud(pointcloud, dataset);
  39730. }
  39731. });
  39732. if(ifReload){
  39733. //loadDone()
  39734. }
  39735. };
  39736. Potree.loadDatasets(Potree.loadDatasetsCallback);
  39737. window.testTransform = function(locationLonLat, location1, location2){
  39738. proj4.defs("NAVVIS:test", "+proj=tmerc +ellps=WGS84 +lon_0=" + locationLonLat[0].toPrecision(15) + " +lat_0=" + locationLonLat[1].toPrecision(15));
  39739. let transform = proj4("WGS84", "NAVVIS:test"); //这个ok navvis里也是这两种转换 见proj4Factory
  39740. if(location1){//经纬度
  39741. return transform.forward(location1)
  39742. }else {
  39743. return transform.inverse(location2)
  39744. }
  39745. };
  39746. window.THREE = THREE$1;
  39747. window.buttonFunction = function(){
  39748. viewer.scene.pointclouds.forEach(e=>e.predictNodeMaxLevel());
  39749. /*
  39750. viewer.startScreenshot({type:'measure', measurement:viewer.scene.measurements[0]})
  39751. viewer.modules.RouteGuider.routeStart = new THREE.Vector3(0,0,-1.3)
  39752. viewer.modules.RouteGuider.routeEnd = new THREE.Vector3(-10,0,-1.3)
  39753. */
  39754. };
  39755. if(Potree.settings.isLocalhost){
  39756. let before = {};
  39757. viewer.inputHandler.addEventListener('keydown',e=>{ //测试的代码
  39758. if(e.event.key == 't'){
  39759. viewer.images360.cube.visible = true;
  39760. viewer.images360.cube.material.wireframe = true;
  39761. }else if(e.event.key == 'y'){
  39762. viewer.images360.cube.material.wireframe = false;
  39763. viewer.images360.cube.visible = Potree.settings.displayMode == 'showPanos';
  39764. }
  39765. });
  39766. }
  39767. };
  39768. //=======================================================================
  39769. /*
  39770. 漫游点编辑
  39771. */
  39772. //=======================================================================
  39773. var panoEditStart = function(dom, number, fileServer, webSite){
  39774. Potree.settings.editType = 'pano';
  39775. Potree.settings.number = number;
  39776. Potree.settings.unableNavigate = true;
  39777. let viewer = new Potree.Viewer(dom);
  39778. let Alignment = viewer.modules.Alignment;
  39779. viewer.setEDLEnabled(false);
  39780. viewer.setFOV(config$1.view.fov);
  39781. viewer.loadSettingsFromURL();
  39782. let datasetLoaded = 0;
  39783. if(!Potree.settings.isOfficial){
  39784. viewer.loadGUI(() => {
  39785. viewer.setLanguage('en');
  39786. $("#menu_tools").next().show();
  39787. $("#panos").show();
  39788. $("#alignment").show();
  39789. viewer.toggleSidebar();
  39790. });
  39791. Potree.settings.sizeFitToLevel = true;
  39792. }
  39793. var pointcloudLoadDone = function( ){//所有点云cloud.js加载完毕后
  39794. viewer.scene.pointclouds.forEach(c=>{
  39795. transformPointcloud(c);
  39796. });
  39797. viewer.images360.loadDone();
  39798. viewer.scene.add360Images(viewer.images360);
  39799. viewer.updateModelBound();
  39800. let {boundSize, center} = viewer.bound;
  39801. Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12);
  39802. viewer.scene.view.setView({
  39803. position: center.clone().add(new Vector3(10,5,10)),
  39804. target: center
  39805. });
  39806. viewer.dispatchEvent({type:'loadPointCloudDone'});
  39807. if(!Potree.settings.UserPointDensity){
  39808. Potree.settings.UserPointDensity = 'panoEdit';//'middle'
  39809. }
  39810. Potree.Log('loadPointCloudDone 点云加载完毕', null, 10);
  39811. viewer.dispatchEvent('allLoaded');
  39812. };
  39813. var transformPointcloud = (pointcloud )=>{ //初始化位置
  39814. viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud);
  39815. let orientation = pointcloud.panos[0].dataRotation.z;
  39816. let location = pointcloud.panos[0].dataPosition.clone().negate();
  39817. Alignment.rotate(pointcloud, null, orientation );
  39818. Alignment.translate(pointcloud, location );
  39819. pointcloud.updateMatrixWorld();
  39820. };
  39821. let loadPanosDone = Potree.loadPanosDone = (datasetId, panoData)=>{ //一个数据集获取到它的panos后
  39822. Potree.settings.datasetsPanos[datasetId] = {panoData, panos:[]};
  39823. console.log('panoData', datasetId, panoData);
  39824. let panoCount = panoData.length;
  39825. let pointcloudLoaded = 0;
  39826. let datasetsCount = Object.keys(Potree.settings.datasetsPanos).length;
  39827. panoData.forEach((pano, index)=>{
  39828. //let cloudPath = `${Potree.scriptPath}/data/panoEdit/uuidcloud/${pano.uuid}/cloud.js`
  39829. let cloudPath = `https://laser-oss.4dkankan.com/testdata/${Potree.settings.number}/data/bundle_${Potree.settings.number}/building/uuidcloud/${pano.uuid}/cloud.js`;
  39830. let name = datasetId + '-'+pano.uuid;
  39831. let timeStamp = 0;
  39832. pano.index = index; //注意:index不等于uuid,因为有的uuid缺失。但是visibles中存的是下标!
  39833. Potree.loadPointCloud(cloudPath, name , name, timeStamp, e => { //开始加载点云
  39834. let scene = viewer.scene;
  39835. let pointcloud = e.pointcloud;
  39836. let config = Potree.config.material;
  39837. let material = pointcloud.material;
  39838. material.minSize = config.minSize;
  39839. material.maxSize = config.maxSize;
  39840. material.pointSizeType = /* 'ADAPTIVE'// */config.pointSizeType; //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
  39841. pointcloud.changePointSize( 0.2 /* config.realPointSize */ ); //material.size = config.pointSize;
  39842. pointcloud.changePointOpacity(1);
  39843. material.shape = Potree.PointShape.SQUARE;
  39844. pointcloud.color = config.pointColor;
  39845. pointcloud.dataset_id = datasetId; //多个点云指向一个datasetId
  39846. pointcloud.panoUuid = pano.uuid;
  39847. pointcloud.timeStamp = timeStamp;
  39848. //transformPointcloud(pointcloud, pano)
  39849. scene.addPointCloud(pointcloud);
  39850. pointcloudLoaded ++;
  39851. if(pointcloudLoaded == panoCount ){
  39852. datasetLoaded ++;
  39853. viewer.images360.addPanoData(panoData , datasetId );
  39854. if(datasetLoaded == datasetsCount){
  39855. pointcloudLoadDone();
  39856. }
  39857. }
  39858. });
  39859. });
  39860. };
  39861. if(!Potree.settings.isOfficial){
  39862. Potree.settings.datasetsPano = {'testDataset':null};
  39863. Potree.loadPanosInfo( data=>{loadPanosDone('testDataset', data.sweepLocations);} );
  39864. }
  39865. };
  39866. var mergeEditStart = function(dom){
  39867. Potree.settings.editType = 'merge';
  39868. Potree.settings.intersectOnObjs = true;
  39869. Potree.settings.boundAddObjs = true;
  39870. Potree.settings.unableNavigate = true;
  39871. let viewer = new Potree.Viewer(dom );
  39872. let Alignment = viewer.modules.Alignment;
  39873. viewer.setEDLEnabled(false);
  39874. viewer.setFOV(config$1.view.fov);
  39875. viewer.loadSettingsFromURL();
  39876. {
  39877. viewer.mainViewport.view.position.set(30,30,30);
  39878. viewer.mainViewport.view.lookAt(0,0,0);
  39879. viewer.updateModelBound();//init
  39880. //this.bound = new THREE.Box3(new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,1,1))
  39881. viewer.transformationTool.setModeEnable('scale',false);
  39882. viewer.ssaaRenderPass.sampleLevel = 1; // sampleLevel为1 的话,ground就不会变黑
  39883. viewer.inputHandler.fixSelection = true; //不通过点击屏幕而切换transfrom选中状态
  39884. }
  39885. Potree.settings.sizeFitToLevel = true;//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
  39886. Potree.loadPointCloudScene = function(sceneCode, done, onError){//对应4dkk的场景码
  39887. Potree.loadDatasets((data)=>{
  39888. var originDataset = data.find(e=>e.sceneCode == sceneCode);//只加载初始数据集
  39889. var cloudPath = `${Potree.settings.urls.prefix}/${Potree.settings.webSite}/${sceneCode}/data/${sceneCode}/webcloud/cloud.js`;
  39890. var timeStamp = originDataset.createTime ? originDataset.createTime.replace(/[^0-9]/ig,'') : ''; //每重算一次后缀随createTime更新一次
  39891. //console.warn(dataset.sceneName, 'timeStamp', timeStamp)
  39892. Potree.loadPointCloud(cloudPath, originDataset.sceneName , sceneCode, timeStamp, e => {
  39893. let scene = viewer.scene;
  39894. let pointcloud = e.pointcloud;
  39895. let config = Potree.config.material;
  39896. let material = pointcloud.material;
  39897. material.minSize = config.minSize;
  39898. material.maxSize = config.maxSize;
  39899. material.pointSizeType = config.pointSizeType; //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
  39900. pointcloud.changePointSize(config.realPointSize); //material.size = config.pointSize;
  39901. pointcloud.changePointOpacity(1);
  39902. material.shape = Potree.PointShape.SQUARE;
  39903. pointcloud.color = pointcloud.material.color = originDataset.color;
  39904. //pointcloud.dataset_id = originDataset.id;//供漫游点找到属于的dataset点云
  39905. pointcloud.timeStamp = timeStamp;
  39906. //transformPointcloud(pointcloud, originDataset)
  39907. scene.addPointCloud(pointcloud);
  39908. {
  39909. viewer.updateModelBound();
  39910. let {boundSize, center} = viewer.bound;
  39911. viewer.dispatchEvent({type:'loadPointCloudDone'});
  39912. if(!Potree.settings.UserPointDensity){
  39913. Potree.settings.UserPointDensity = 'high';//'middle'
  39914. }
  39915. Potree.Log('loadPointCloudDone 点云加载完毕', null, 10);
  39916. }
  39917. /* Potree.loadPanos(dataset.id, (data) => { //暂时不加载panos了,因为没有id
  39918. //console.log('loadPanos',dataset.sceneCode, dataset.id, data)
  39919. viewer.images360.addPanoData(data, dataset.id )
  39920. viewer.images360.loadDone()
  39921. viewer.scene.add360Images(viewer.images360); */
  39922. viewer.dispatchEvent('allLoaded');
  39923. done(pointcloud);
  39924. },onError);
  39925. }, sceneCode, onError);
  39926. };
  39927. let setMatrix = (pointcloud)=>{//为了漫游点变换,要算一下 类似setMatrix
  39928. /* pointcloud.transformMatrix = new THREE.Matrix4().multiplyMatrices(pointcloud.matrix, pointcloud.pos1MatrixInvert)//还原一点位移
  39929. pointcloud.transformInvMatrix.copy(pointcloud.transformMatrix).invert()
  39930. pointcloud.rotateMatrix = new THREE.Matrix4().makeRotationFromEuler(pointcloud.rotation);
  39931. pointcloud.rotateInvMatrix.copy(pointcloud.rotateMatrix).invert()
  39932. pointcloud.panos.forEach(e=>e.transformByPointcloud()) */
  39933. //pointcloud.updateBound()
  39934. //pointcloud.getPanosBound()
  39935. viewer.updateModelBound();
  39936. };
  39937. let moveModel = (e)=>{//根据鼠标移动的位置改变位置
  39938. let camera = viewer.mainViewport.camera;
  39939. var origin = new Vector3(e.pointer.x, e.pointer.y, -1).unproject(camera),
  39940. end = new Vector3(e.pointer.x, e.pointer.y, 1).unproject(camera);
  39941. var dir = end.sub(origin);
  39942. let planeZ = 0;
  39943. let r = (planeZ - origin.z)/dir.z;
  39944. let x = r * dir.x + origin.x;
  39945. let y = r * dir.y + origin.y;
  39946. //过后改为根据intersect的点来设置底部高度;这样的话,需要发送高度
  39947. /*let pos = new THREE.Vector3(x,y, planeZ )
  39948. modelEditing.updateMatrixWorld()
  39949. let boundCenter = modelEditing.boundingBox.getCenter(new THREE.Vector3).applyMatrix4(modelEditing.matrixWorld);
  39950. */
  39951. MergeEditor.moveBoundCenterTo(modelEditing,new Vector3(x,y, modelEditing.boundCenter.z)); //使模型中心的xy在鼠标所在位置
  39952. modelEditing.dispatchEvent("position_changed");
  39953. };
  39954. let cancelMove = ()=>{
  39955. modelEditing = null;
  39956. viewer.removeEventListener('global_mousemove', moveModel);
  39957. viewer.removeEventListener('global_click', confirmPos);
  39958. };
  39959. let confirmPos = ()=>{
  39960. MergeEditor.focusOn(modelEditing);
  39961. cancelMove();
  39962. return {stopContinue:true}
  39963. };
  39964. let modelType, modelEditing, MergeEditor = viewer.modules.MergeEditor;
  39965. Potree.addModel = function(prop, done, onProgress, onError){ //加载模型
  39966. let loadDone = (model)=>{
  39967. if(prop.isFirstLoad){
  39968. modelEditing = model;
  39969. MergeEditor.setModelBtmHeight(model, 0); //默认离地高度为0
  39970. viewer.addEventListener('global_mousemove', moveModel);
  39971. viewer.addEventListener('global_click', confirmPos, 3);
  39972. }else {
  39973. MergeEditor.setModelBtmHeight(model, prop.bottom || 0); //默认离地高度为0
  39974. modelEditing = null;
  39975. }
  39976. {//transform
  39977. let updateBound = ()=>{
  39978. model.updateMatrixWorld();
  39979. viewer.updateModelBound();
  39980. };
  39981. let maintainBtmZAndCenter = ()=>{
  39982. MergeEditor.maintainBoundXY(model);
  39983. MergeEditor.setModelBtmHeight(model);
  39984. updateBound();
  39985. model.dispatchEvent('transformChanged');
  39986. };
  39987. model.addEventListener('position_changed', ()=>{
  39988. updateBound();
  39989. MergeEditor.getBoundCenter(model);//更新boundcenter
  39990. MergeEditor.computeBtmHeight(model);
  39991. model.dispatchEvent('transformChanged');
  39992. });
  39993. model.addEventListener("orientation_changed", maintainBtmZAndCenter );
  39994. model.addEventListener("scale_changed", maintainBtmZAndCenter );
  39995. }
  39996. model.updateMatrixWorld();
  39997. viewer.updateModelBound();
  39998. MergeEditor.getBoundCenter(model); //初始化
  39999. done(model);
  40000. };
  40001. if(prop.type == 'laser'){
  40002. Potree.loadPointCloudScene(prop.url, (pointcloud)=>{
  40003. pointcloud.matrixAutoUpdate = true;
  40004. pointcloud.initialPosition = pointcloud.position.clone();
  40005. pointcloud.pos1MatrixInvert = new Matrix4().setPosition(pointcloud.initialPosition).invert();
  40006. /* let maintainBtmZ = ()=>{
  40007. MergeEditor.setModelBtmHeight(pointcloud)
  40008. updateMatrix()
  40009. }
  40010. let updateMatrix = ()=>{
  40011. setMatrix(pointcloud)
  40012. pointcloud.dispatchEvent('transformChanged')
  40013. }
  40014. pointcloud.addEventListener('position_changed', updateMatrix )
  40015. pointcloud.addEventListener("orientation_changed", maintainBtmZ )
  40016. pointcloud.addEventListener("scale_changed", maintainBtmZ ) */
  40017. loadDone(pointcloud);
  40018. /* pointcloud.addEventListener('select',(e)=>{
  40019. if(Potree.settings.displayMode == 'showPanos')return
  40020. console.log('select',e)
  40021. //viewer.setControls(viewer.orbitControls)
  40022. MergeEditor.focusOnSelect(pointcloud)
  40023. viewer.outlinePass.selectedObjects = [pointcloud]
  40024. return {stopContinue:true}
  40025. },1)
  40026. pointcloud.addEventListener('deselect',(e)=>{
  40027. console.log('deselect',e)
  40028. //viewer.setControls(viewer.fpControls)
  40029. viewer.outlinePass.selectedObjects = []
  40030. }) */
  40031. }, onError);
  40032. }else {
  40033. let callback = (object)=>{
  40034. //focusOnSelect(object, 1000)
  40035. object.isModel = true;
  40036. //object.dataset_id = Date.now() //暂时
  40037. object.traverse(e=>e.material && (e.material.transparent = true));
  40038. /* object.addEventListener('select',(e)=>{
  40039. if(Potree.settings.displayMode == 'showPanos')return
  40040. console.log('select',e)
  40041. MergeEditor.selectModel(object, true)
  40042. return {stopContinue:true}
  40043. },1)
  40044. object.addEventListener('deselect',(e)=>{
  40045. console.log('deselect',e)
  40046. MergeEditor.selectModel(object, false)
  40047. viewer.outlinePass.selectedObjects = []
  40048. }) */
  40049. object.addEventListener('click',(e)=>{
  40050. //只是为了能得到hoverElement识别才加这个侦听
  40051. });
  40052. /* let updateBound = ()=>{
  40053. object.updateMatrixWorld()
  40054. viewer.updateModelBound()
  40055. object.dispatchEvent('transformChanged')
  40056. }
  40057. let maintainBtmZ = ()=>{
  40058. MergeEditor.setModelBtmHeight(object)
  40059. updateBound()
  40060. }
  40061. object.addEventListener('position_changed', updateBound )
  40062. object.addEventListener("orientation_changed", maintainBtmZ )
  40063. object.addEventListener("scale_changed", maintainBtmZ ) */
  40064. loadDone(object);
  40065. };
  40066. let info = {
  40067. name: prop.type,
  40068. id: prop.id,
  40069. transform : {
  40070. position : prop.position,
  40071. rotation : new Euler().setFromVector3(prop.rotation),
  40072. scale: new Vector3(prop.scale,prop.scale,prop.scale),
  40073. }
  40074. };
  40075. if(prop.type == 'glb'){
  40076. info.glburl = prop.url;
  40077. }else {
  40078. info.objurl = prop.url;
  40079. info.mtlurl = prop.mtlurl;
  40080. }
  40081. viewer.loadModel(info , callback, onProgress, onError);
  40082. }
  40083. };
  40084. return {THREE: THREE$1}
  40085. };
  40086. /*
  40087. 坐标转换问题:
  40088. 由于控制点可以随便输入,所以本地和地理位置的转换也是可拉伸的。而navvis的转换是等比由中心展开,
  40089. 所以对比两种转化方式时误差较大。
  40090. 另外地理注册控制点是有参考数据集的,若参考数据集和我放置在0,0,0的数据集一致,就可直接使用,否则要转换。
  40091. */
  40092. class Action extends EventDispatcher {
  40093. constructor (args = {}) {
  40094. super();
  40095. this.icon = args.icon || '';
  40096. this.tooltip = args.tooltip;
  40097. if (args.onclick !== undefined) {
  40098. this.onclick = args.onclick;
  40099. }
  40100. }
  40101. onclick (event) {
  40102. }
  40103. pairWith (object) {
  40104. }
  40105. setIcon (newIcon) {
  40106. let oldIcon = this.icon;
  40107. if (newIcon === oldIcon) {
  40108. return;
  40109. }
  40110. this.icon = newIcon;
  40111. this.dispatchEvent({
  40112. type: 'icon_changed',
  40113. action: this,
  40114. icon: newIcon,
  40115. oldIcon: oldIcon
  40116. });
  40117. }
  40118. };
  40119. //Potree.Actions = {};
  40120. //
  40121. //Potree.Actions.ToggleAnnotationVisibility = class ToggleAnnotationVisibility extends Potree.Action {
  40122. // constructor (args = {}) {
  40123. // super(args);
  40124. //
  40125. // this.icon = Potree.resourcePath + '/icons/eye.svg';
  40126. // this.showIn = 'sidebar';
  40127. // this.tooltip = 'toggle visibility';
  40128. // }
  40129. //
  40130. // pairWith (annotation) {
  40131. // if (annotation.visible) {
  40132. // this.setIcon(Potree.resourcePath + '/icons/eye.svg');
  40133. // } else {
  40134. // this.setIcon(Potree.resourcePath + '/icons/eye_crossed.svg');
  40135. // }
  40136. //
  40137. // annotation.addEventListener('visibility_changed', e => {
  40138. // let annotation = e.annotation;
  40139. //
  40140. // if (annotation.visible) {
  40141. // this.setIcon(Potree.resourcePath + '/icons/eye.svg');
  40142. // } else {
  40143. // this.setIcon(Potree.resourcePath + '/icons/eye_crossed.svg');
  40144. // }
  40145. // });
  40146. // }
  40147. //
  40148. // onclick (event) {
  40149. // let annotation = event.annotation;
  40150. //
  40151. // annotation.visible = !annotation.visible;
  40152. //
  40153. // if (annotation.visible) {
  40154. // this.setIcon(Potree.resourcePath + '/icons/eye.svg');
  40155. // } else {
  40156. // this.setIcon(Potree.resourcePath + '/icons/eye_crossed.svg');
  40157. // }
  40158. // }
  40159. //};
  40160. class PathAnimation{
  40161. constructor(path, start, end, speed, callback){
  40162. this.path = path;
  40163. this.length = this.path.spline.getLength();
  40164. this.speed = speed;
  40165. this.callback = callback;
  40166. this.tween = null;
  40167. this.startPoint = Math.max(start, 0);
  40168. this.endPoint = Math.min(end, this.length);
  40169. this.t = 0.0;
  40170. }
  40171. start(resume = false){
  40172. if(this.tween){
  40173. this.tween.stop();
  40174. this.tween = null;
  40175. }
  40176. let tStart;
  40177. if(resume){
  40178. tStart = this.t;
  40179. }else {
  40180. tStart = this.startPoint / this.length;
  40181. }
  40182. let tEnd = this.endPoint / this.length;
  40183. let animationDuration = (tEnd - tStart) * this.length * 1000 / this.speed;
  40184. let progress = {t: tStart};
  40185. this.tween = new TWEEN.Tween(progress).to({t: tEnd}, animationDuration);
  40186. this.tween.easing(TWEEN.Easing.Linear.None);
  40187. this.tween.onUpdate((e) => {
  40188. this.t = progress.t;
  40189. this.callback(progress.t);
  40190. });
  40191. this.tween.onComplete(() => {
  40192. if(this.repeat){
  40193. this.start();
  40194. }
  40195. });
  40196. setTimeout(() => {
  40197. this.tween.start();
  40198. }, 0);
  40199. }
  40200. stop(){
  40201. if(!this.tween){
  40202. return;
  40203. }
  40204. this.tween.stop();
  40205. this.tween = null;
  40206. this.t = 0;
  40207. }
  40208. pause(){
  40209. if(!this.tween){
  40210. return;
  40211. }
  40212. this.tween.stop();
  40213. TWEEN.remove(this.tween);
  40214. this.tween = null;
  40215. }
  40216. resume(){
  40217. this.start(true);
  40218. }
  40219. getPoint(t){
  40220. return this.path.spline.getPoint(t);
  40221. }
  40222. }
  40223. class AnimationPath{
  40224. constructor (points = []) {
  40225. this.points = points;
  40226. this.spline = new CatmullRomCurve3(points);
  40227. //this.spline.reparametrizeByArcLength(1 / this.spline.getLength().total);
  40228. }
  40229. get (t) {
  40230. return this.spline.getPoint(t);
  40231. }
  40232. getLength () {
  40233. return this.spline.getLength();
  40234. }
  40235. animate (start, end, speed, callback) {
  40236. let animation = new PathAnimation(this, start, end, speed, callback);
  40237. animation.start();
  40238. return animation;
  40239. }
  40240. pause () {
  40241. if (this.tween) {
  40242. this.tween.stop();
  40243. }
  40244. }
  40245. resume () {
  40246. if (this.tween) {
  40247. this.tween.start();
  40248. }
  40249. }
  40250. getGeometry () {
  40251. let geometry = new Geometry();
  40252. let samples = 500;
  40253. let i = 0;
  40254. for (let u = 0; u <= 1; u += 1 / samples) {
  40255. let position = this.spline.getPoint(u);
  40256. geometry.vertices[i] = new Vector3(position.x, position.y, position.z);
  40257. i++;
  40258. }
  40259. if(this.closed){
  40260. let position = this.spline.getPoint(0);
  40261. geometry.vertices[i] = new Vector3(position.x, position.y, position.z);
  40262. }
  40263. return geometry;
  40264. }
  40265. get closed(){
  40266. return this.spline.closed;
  40267. }
  40268. set closed(value){
  40269. this.spline.closed = value;
  40270. }
  40271. }
  40272. class Annotation extends EventDispatcher {
  40273. constructor (args = {}) {
  40274. super();
  40275. this.scene = null;
  40276. this._title = args.title || 'No Title';
  40277. this._description = args.description || '';
  40278. this.offset = new Vector3();
  40279. this.uuid = MathUtils.generateUUID();
  40280. if (!args.position) {
  40281. this.position = null;
  40282. } else if (args.position.x != null) {
  40283. this.position = args.position;
  40284. } else {
  40285. this.position = new Vector3(...args.position);
  40286. }
  40287. this.cameraPosition = (args.cameraPosition instanceof Array)
  40288. ? new Vector3().fromArray(args.cameraPosition) : args.cameraPosition;
  40289. this.cameraTarget = (args.cameraTarget instanceof Array)
  40290. ? new Vector3().fromArray(args.cameraTarget) : args.cameraTarget;
  40291. if(!this.cameraTarget && this.position){//add
  40292. this.cameraTarget = this.position.clone();
  40293. }
  40294. this.radius = args.radius;
  40295. this.view = args.view || null;
  40296. this.keepOpen = false;
  40297. this.descriptionVisible = false;
  40298. this.showDescription = true;
  40299. this.actions = args.actions || [];
  40300. this.isHighlighted = false;
  40301. this._visible = true;
  40302. this.__visible = true;
  40303. this._display = true;
  40304. this._expand = false;
  40305. this.collapseThreshold = [args.collapseThreshold, 100].find(e => e !== undefined);
  40306. this.children = [];
  40307. this.parent = null;
  40308. this.boundingBox = new Box3();
  40309. let iconClose = exports.resourcePath + '/icons/close.svg';
  40310. this.domElement = $(`
  40311. <div class="annotation" oncontextmenu="return false;">
  40312. <div class="annotation-titlebar">
  40313. <span class="annotation-label"></span>
  40314. </div>
  40315. <div class="annotation-description">
  40316. <span class="annotation-description-close">
  40317. <img src="${iconClose}" width="16px">
  40318. </span>
  40319. <span class="annotation-description-content">${this._description}</span>
  40320. </div>
  40321. </div>
  40322. `);
  40323. this.elTitlebar = this.domElement.find('.annotation-titlebar');
  40324. this.elTitle = this.elTitlebar.find('.annotation-label');
  40325. this.elTitle.append(this._title);
  40326. this.elDescription = this.domElement.find('.annotation-description');
  40327. this.elDescriptionClose = this.elDescription.find('.annotation-description-close');
  40328. // this.elDescriptionContent = this.elDescription.find(".annotation-description-content");
  40329. this.clickTitle = () => {
  40330. //if(this.hasView()){
  40331. this.moveHere(this.scene.getActiveCamera());
  40332. //}
  40333. this.dispatchEvent({type: 'click', target: this});
  40334. viewer.renderer.domElement.focus();//add 使得方向键可用
  40335. };
  40336. this.elTitle.click(this.clickTitle);
  40337. this.actions = this.actions.map(a => {
  40338. if (a instanceof Action) {
  40339. return a;
  40340. } else {
  40341. return new Action(a);
  40342. }
  40343. });
  40344. for (let action of this.actions) {
  40345. action.pairWith(this);
  40346. }
  40347. let actions = this.actions.filter(
  40348. a => a.showIn === undefined || a.showIn.includes('scene'));
  40349. for (let action of actions) {
  40350. let elButton = $(`<img src="${action.icon}" class="annotation-action-icon">`);
  40351. this.elTitlebar.append(elButton);
  40352. elButton.click(() => action.onclick({annotation: this}));
  40353. }
  40354. this.elDescriptionClose.hover(
  40355. e => this.elDescriptionClose.css('opacity', '1'),
  40356. e => this.elDescriptionClose.css('opacity', '0.5')
  40357. );
  40358. this.elDescriptionClose.click(e => this.setHighlighted(false));
  40359. // this.elDescriptionContent.html(this._description);
  40360. this.domElement.mouseenter(e => this.setHighlighted(true));
  40361. this.domElement.mouseleave(e => this.setHighlighted(false));
  40362. this.domElement.on('touchstart', e => {
  40363. this.setHighlighted(!this.isHighlighted);
  40364. });
  40365. this.display = false;
  40366. //this.display = true;
  40367. }
  40368. installHandles(viewer){
  40369. if(this.handles !== undefined){
  40370. return;
  40371. }
  40372. let domElement = $(`
  40373. <div style="position: absolute; left: 300; top: 200; pointer-events: none">
  40374. <svg width="300" height="600">
  40375. <line x1="0" y1="0" x2="1200" y2="200" style="stroke: black; stroke-width:2" />
  40376. <circle cx="50" cy="50" r="4" stroke="black" stroke-width="2" fill="gray" />
  40377. <circle cx="150" cy="50" r="4" stroke="black" stroke-width="2" fill="gray" />
  40378. </svg>
  40379. </div>
  40380. `);
  40381. let svg = domElement.find("svg")[0];
  40382. let elLine = domElement.find("line")[0];
  40383. let elStart = domElement.find("circle")[0];
  40384. let elEnd = domElement.find("circle")[1];
  40385. let setCoordinates = (start, end) => {
  40386. elStart.setAttribute("cx", `${start.x}`);
  40387. elStart.setAttribute("cy", `${start.y}`);
  40388. elEnd.setAttribute("cx", `${end.x}`);
  40389. elEnd.setAttribute("cy", `${end.y}`);
  40390. elLine.setAttribute("x1", start.x);
  40391. elLine.setAttribute("y1", start.y);
  40392. elLine.setAttribute("x2", end.x);
  40393. elLine.setAttribute("y2", end.y);
  40394. let box = svg.getBBox();
  40395. svg.setAttribute("width", `${box.width}`);
  40396. svg.setAttribute("height", `${box.height}`);
  40397. svg.setAttribute("viewBox", `${box.x} ${box.y} ${box.width} ${box.height}`);
  40398. let ya = start.y - end.y;
  40399. let xa = start.x - end.x;
  40400. if(ya > 0){
  40401. start.y = start.y - ya;
  40402. }
  40403. if(xa > 0){
  40404. start.x = start.x - xa;
  40405. }
  40406. domElement.css("left", `${start.x}px`);
  40407. domElement.css("top", `${start.y}px`);
  40408. };
  40409. $(viewer.renderArea).append(domElement);
  40410. let annotationStartPos = this.position.clone();
  40411. let annotationStartOffset = this.offset.clone();
  40412. $(this.domElement).draggable({
  40413. start: (event, ui) => {
  40414. annotationStartPos = this.position.clone();
  40415. annotationStartOffset = this.offset.clone();
  40416. $(this.domElement).find(".annotation-titlebar").css("pointer-events", "none");
  40417. console.log($(this.domElement).find(".annotation-titlebar"));
  40418. },
  40419. stop: () => {
  40420. $(this.domElement).find(".annotation-titlebar").css("pointer-events", "");
  40421. },
  40422. drag: (event, ui ) => {
  40423. let renderAreaWidth = viewer.renderer.getSize(new Vector2$1()).width;
  40424. //let renderAreaHeight = viewer.renderer.getSize().height;
  40425. let diff = {
  40426. x: ui.originalPosition.left - ui.position.left,
  40427. y: ui.originalPosition.top - ui.position.top
  40428. };
  40429. let nDiff = {
  40430. x: -(diff.x / renderAreaWidth) * 2,
  40431. y: (diff.y / renderAreaWidth) * 2
  40432. };
  40433. let camera = viewer.scene.getActiveCamera();
  40434. let oldScreenPos = new Vector3()
  40435. .addVectors(annotationStartPos, annotationStartOffset)
  40436. .project(camera);
  40437. let newScreenPos = oldScreenPos.clone();
  40438. newScreenPos.x += nDiff.x;
  40439. newScreenPos.y += nDiff.y;
  40440. let newPos = newScreenPos.clone();
  40441. newPos.unproject(camera);
  40442. let newOffset = new Vector3().subVectors(newPos, this.position);
  40443. this.offset.copy(newOffset);
  40444. }
  40445. });
  40446. let updateCallback = () => {
  40447. let position = this.position;
  40448. let scene = viewer.scene;
  40449. const renderAreaSize = viewer.renderer.getSize(new Vector2$1());
  40450. let renderAreaWidth = renderAreaSize.width;
  40451. let renderAreaHeight = renderAreaSize.height;
  40452. let start = this.position.clone();
  40453. let end = new Vector3().addVectors(this.position, this.offset);
  40454. let toScreen = (position) => {
  40455. let camera = scene.getActiveCamera();
  40456. let screenPos = new Vector3();
  40457. let worldView = new Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
  40458. let ndc = new Vector4(position.x, position.y, position.z, 1.0).applyMatrix4(worldView);
  40459. // limit w to small positive value, in case position is behind the camera
  40460. ndc.w = Math.max(ndc.w, 0.1);
  40461. ndc.divideScalar(ndc.w);
  40462. screenPos.copy(ndc);
  40463. screenPos.x = renderAreaWidth * (screenPos.x + 1) / 2;
  40464. screenPos.y = renderAreaHeight * (1 - (screenPos.y + 1) / 2);
  40465. return screenPos;
  40466. };
  40467. start = toScreen(start);
  40468. end = toScreen(end);
  40469. setCoordinates(start, end);
  40470. };
  40471. viewer.addEventListener("update", updateCallback);
  40472. this.handles = {
  40473. domElement: domElement,
  40474. setCoordinates: setCoordinates,
  40475. updateCallback: updateCallback
  40476. };
  40477. }
  40478. removeHandles(viewer){
  40479. if(this.handles === undefined){
  40480. return;
  40481. }
  40482. //$(viewer.renderArea).remove(this.handles.domElement);
  40483. this.handles.domElement.remove();
  40484. viewer.removeEventListener("update", this.handles.updateCallback);
  40485. delete this.handles;
  40486. }
  40487. get visible () {
  40488. return this._visible;
  40489. }
  40490. set visible (value) {
  40491. if (this._visible === value) {
  40492. return;
  40493. }
  40494. this._visible = value;
  40495. //this.traverse(node => {
  40496. // node.display = value;
  40497. //});
  40498. this.dispatchEvent({
  40499. type: 'visibility_changed',
  40500. annotation: this
  40501. });
  40502. }
  40503. get display () {
  40504. return this._display;
  40505. }
  40506. set display (display) {
  40507. if (this._display === display) {
  40508. return;
  40509. }
  40510. this._display = display;
  40511. if (display) {
  40512. // this.domElement.fadeIn(200);
  40513. this.domElement.show();
  40514. } else {
  40515. // this.domElement.fadeOut(200);
  40516. this.domElement.hide();
  40517. }
  40518. }
  40519. get expand () {
  40520. return this._expand;
  40521. }
  40522. set expand (expand) {
  40523. if (this._expand === expand) {
  40524. return;
  40525. }
  40526. if (expand) {
  40527. this.display = false;
  40528. } else {
  40529. this.display = true;
  40530. this.traverseDescendants(node => {
  40531. node.display = false;
  40532. });
  40533. }
  40534. this._expand = expand;
  40535. }
  40536. get title () {
  40537. return this._title;
  40538. }
  40539. set title (title) {
  40540. if (this._title === title) {
  40541. return;
  40542. }
  40543. this._title = title;
  40544. this.elTitle.empty();
  40545. this.elTitle.append(this._title);
  40546. this.dispatchEvent({
  40547. type: "annotation_changed",
  40548. annotation: this,
  40549. });
  40550. }
  40551. get description () {
  40552. return this._description;
  40553. }
  40554. set description (description) {
  40555. if (this._description === description) {
  40556. return;
  40557. }
  40558. this._description = description;
  40559. const elDescriptionContent = this.elDescription.find(".annotation-description-content");
  40560. elDescriptionContent.empty();
  40561. elDescriptionContent.append(this._description);
  40562. this.dispatchEvent({
  40563. type: "annotation_changed",
  40564. annotation: this,
  40565. });
  40566. }
  40567. add (annotation) {
  40568. if (!this.children.includes(annotation)) {
  40569. this.children.push(annotation);
  40570. annotation.parent = this;
  40571. let descendants = [];
  40572. annotation.traverse(a => { descendants.push(a); });
  40573. for (let descendant of descendants) {
  40574. let c = this;
  40575. while (c !== null) {
  40576. c.dispatchEvent({
  40577. 'type': 'annotation_added',
  40578. 'annotation': descendant
  40579. });
  40580. c = c.parent;
  40581. }
  40582. }
  40583. }
  40584. }
  40585. level () {
  40586. if (this.parent === null) {
  40587. return 0;
  40588. } else {
  40589. return this.parent.level() + 1;
  40590. }
  40591. }
  40592. hasChild(annotation) {
  40593. return this.children.includes(annotation);
  40594. }
  40595. remove (annotation) {
  40596. if (this.hasChild(annotation)) {
  40597. annotation.removeAllChildren();
  40598. annotation.dispose();
  40599. this.children = this.children.filter(e => e !== annotation);
  40600. annotation.parent = null;
  40601. }
  40602. }
  40603. removeAllChildren() {
  40604. this.children.forEach((child) => {
  40605. if (child.children.length > 0) {
  40606. child.removeAllChildren();
  40607. }
  40608. this.remove(child);
  40609. });
  40610. }
  40611. updateBounds () {
  40612. let box = new Box3();
  40613. if (this.position) {
  40614. box.expandByPoint(this.position);
  40615. }
  40616. for (let child of this.children) {
  40617. child.updateBounds();
  40618. box.union(child.boundingBox);
  40619. }
  40620. this.boundingBox.copy(box);
  40621. }
  40622. traverse (handler) {
  40623. let expand = handler(this);
  40624. if (expand === undefined || expand === true) {
  40625. for (let child of this.children) {
  40626. child.traverse(handler);
  40627. }
  40628. }
  40629. }
  40630. traverseDescendants (handler) {
  40631. for (let child of this.children) {
  40632. child.traverse(handler);
  40633. }
  40634. }
  40635. flatten () {
  40636. let annotations = [];
  40637. this.traverse(annotation => {
  40638. annotations.push(annotation);
  40639. });
  40640. return annotations;
  40641. }
  40642. descendants () {
  40643. let annotations = [];
  40644. this.traverse(annotation => {
  40645. if (annotation !== this) {
  40646. annotations.push(annotation);
  40647. }
  40648. });
  40649. return annotations;
  40650. }
  40651. setHighlighted (highlighted) {
  40652. if (highlighted) {
  40653. this.domElement.css('opacity', '0.8');
  40654. this.elTitlebar.css('box-shadow', '0 0 5px #fff');
  40655. this.domElement.css('z-index', '1000');
  40656. if (this._description) {
  40657. this.descriptionVisible = true;
  40658. this.elDescription.fadeIn(200);
  40659. this.elDescription.css('position', 'relative');
  40660. }
  40661. } else {
  40662. this.domElement.css('opacity', '0.5');
  40663. this.elTitlebar.css('box-shadow', '');
  40664. this.domElement.css('z-index', '100');
  40665. this.descriptionVisible = false;
  40666. this.elDescription.css('display', 'none');
  40667. }
  40668. this.isHighlighted = highlighted;
  40669. }
  40670. hasView () {
  40671. let hasPosTargetView = this.cameraTarget.x != null;
  40672. hasPosTargetView = hasPosTargetView && this.cameraPosition.x != null;
  40673. let hasRadiusView = this.radius !== undefined;
  40674. let hasView = hasPosTargetView || hasRadiusView;
  40675. return hasView;
  40676. };
  40677. moveHere (camera) {
  40678. if (!this.hasView()) {
  40679. return;
  40680. }
  40681. let view = this.scene.view;
  40682. let animationDuration = 500;
  40683. let easing = TWEEN.Easing.Quartic.Out;
  40684. let endTarget;
  40685. if (this.cameraTarget) {
  40686. endTarget = this.cameraTarget;
  40687. } else if (this.position) {
  40688. endTarget = this.position;
  40689. } else {
  40690. endTarget = this.boundingBox.getCenter(new Vector3());
  40691. }
  40692. if (this.cameraPosition) {
  40693. let endPosition = this.cameraPosition;
  40694. Utils.moveTo(this.scene, endPosition, endTarget);
  40695. } else if (this.radius) {
  40696. let direction = view.direction;
  40697. let endPosition = endTarget.clone().add(direction.multiplyScalar(-this.radius));
  40698. let startRadius = view.radius;
  40699. let endRadius = this.radius;
  40700. { // animate camera position
  40701. let tween = new TWEEN.Tween(view.position).to(endPosition, animationDuration);
  40702. tween.easing(easing);
  40703. tween.start();
  40704. }
  40705. { // animate radius
  40706. let t = {x: 0};
  40707. let tween = new TWEEN.Tween(t)
  40708. .to({x: 1}, animationDuration)
  40709. .onUpdate(function () {
  40710. view.radius = this.x * endRadius + (1 - this.x) * startRadius;
  40711. });
  40712. tween.easing(easing);
  40713. tween.start();
  40714. }
  40715. }
  40716. };
  40717. dispose () {
  40718. if (this.domElement.parentElement) {
  40719. this.domElement.parentElement.removeChild(this.domElement);
  40720. }
  40721. };
  40722. toString () {
  40723. return 'Annotation: ' + this._title;
  40724. }
  40725. };
  40726. class EnumItem{
  40727. constructor(object){
  40728. for(let key of Object.keys(object)){
  40729. this[key] = object[key];
  40730. }
  40731. }
  40732. inspect(){
  40733. return `Enum(${this.name}: ${this.value})`;
  40734. }
  40735. };
  40736. class Enum{//??????做什么用的
  40737. constructor(object){
  40738. this.object = object;
  40739. for(let key of Object.keys(object)){
  40740. let value = object[key];
  40741. if(typeof value === "object"){
  40742. value.name = key;
  40743. }else {
  40744. value = {name: key, value: value};
  40745. }
  40746. this[key] = new EnumItem(value);
  40747. }
  40748. }
  40749. fromValue(value){
  40750. for(let key of Object.keys(this.object)){
  40751. if(this[key].value === value){
  40752. return this[key];
  40753. }
  40754. }
  40755. throw new Error(`No enum for value: ${value}`);
  40756. }
  40757. };
  40758. const CameraMode = {
  40759. ORTHOGRAPHIC: 0,
  40760. PERSPECTIVE: 1,
  40761. VR: 2,
  40762. };
  40763. const ClipTask = {
  40764. NONE: 0,
  40765. HIGHLIGHT: 1,
  40766. SHOW_INSIDE: 2,
  40767. SHOW_OUTSIDE: 3
  40768. };
  40769. const ClipMethod = {
  40770. INSIDE_ANY: 0,
  40771. INSIDE_ALL: 1
  40772. };
  40773. const ElevationGradientRepeat = {
  40774. CLAMP: 0,
  40775. REPEAT: 1,
  40776. MIRRORED_REPEAT: 2,
  40777. };
  40778. const Buttons = {// MouseEvent.buttons
  40779. //buttons,设置按下了鼠标哪些键,是一个3个比特位的二进制值,默认为0。1表示按下主键(通常是左键),2表示按下次要键(通常是右键),4表示按下辅助键(通常是中间的键)。
  40780. NONE:0,//add
  40781. LEFT: 0b0001,
  40782. RIGHT: 0b0010,
  40783. MIDDLE: 0b0100
  40784. };
  40785. /* 如果访问的是button, 用THREE.MOUSE来判断:
  40786. button,设置按下了哪一个鼠标按键,默认为0。-1表示没有按键,0表示按下主键(通常是左键),1表示按下辅助键(通常是中间的键),2表示按下次要键(通常是右键)
  40787. */
  40788. const PointSizeType = {
  40789. FIXED: 0,
  40790. ATTENUATED: 1,
  40791. ADAPTIVE: 2
  40792. };
  40793. const PointShape = {
  40794. SQUARE: 0,
  40795. CIRCLE: 1,
  40796. PARABOLOID: 2
  40797. };
  40798. const TreeType = {
  40799. OCTREE: 0,
  40800. KDTREE: 1
  40801. };
  40802. const LengthUnits = {
  40803. METER: {code: 'm', unitspermeter: 1.0},
  40804. FEET: {code: 'ft', unitspermeter: 3.28084},
  40805. INCH: {code: '\u2033', unitspermeter: 39.3701}
  40806. };
  40807. /////////// add //////////////////////////////////
  40808. var GLCubeFaces$1 = {
  40809. GL_TEXTURE_CUBE_MAP_POSITIVE_X: 0,
  40810. GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1,
  40811. GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 2,
  40812. GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 3,
  40813. GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4,
  40814. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 5
  40815. };
  40816. var PanoSizeClass = {
  40817. BASE: 1,
  40818. STANDARD: 2,
  40819. HIGH: 3,
  40820. ULTRAHIGH: 4
  40821. };
  40822. var PanoRendererEvents = {
  40823. PanoRenderComplete: "panorama.render.complete",
  40824. TileRenderFailure: "panorama.tile.render.failed",
  40825. TileRenderSuccess: "panorama.tile.render.success",
  40826. TileUploadAttempted: "panorama.tile.upload.attempted",
  40827. UploadAttemptedForAllTiles: "panorama.upload.attempted.all.tiles",
  40828. ZoomLevelRenderStarted: "panorama.zoom.render.started"
  40829. };
  40830. var SceneRendererEvents = {
  40831. ContextCreated: "scene-renderer-context-created",
  40832. AfterRender: "after-render",
  40833. MemoryUsageUpdated: "scene-renderer-memory-usage-updated"
  40834. };
  40835. var TileDownloaderEvents = {
  40836. TileDownloadSuccess: "tiledownloader.download.success",
  40837. TileDownloadFailure: "tiledownloader.download.failure",
  40838. PanoDownloadComplete: "tiledownloader.pano.download.complete"
  40839. };
  40840. var Vectors = {
  40841. UP: new Vector3(0,1,0),
  40842. DOWN: new Vector3(0,-1,0),
  40843. LEFT: new Vector3(-1,0,0),
  40844. RIGHT: new Vector3(1,0,0),
  40845. FORWARD: new Vector3(0,0,-1),
  40846. BACK: new Vector3(0,0,1)
  40847. };
  40848. var Vectors2 = {};
  40849. for(var i in Vectors){
  40850. Vectors2[i] = math.convertVector.YupToZup(Vectors[i]);
  40851. }
  40852. var DownloadStatus = Object.freeze({
  40853. None: 0,
  40854. Queued: 1,
  40855. ForceQueued: 2,
  40856. Downloading: 3,
  40857. Downloaded: 4,
  40858. DownloadFailed: 5
  40859. });
  40860. var ModelManagerEvents = {
  40861. ModelAdded: "model-added",
  40862. ActiveModelChanged: "active-model-changed"
  40863. };
  40864. var PanoramaEvents = {
  40865. Enter: 'panorama.enter',
  40866. Exit: 'panorama.exit',
  40867. LoadComplete: "panorama.load.complete",
  40868. LoadFailed: "panorama.load.failed",
  40869. TileLoaded: "panorama.tile.loaded",
  40870. VideoRendered: "panorama.video.rendered"
  40871. };
  40872. /**
  40873. * @author mrdoob / http://mrdoob.com/ https://github.com/mrdoob/eventdispatcher.js
  40874. *
  40875. * with slight modifications by mschuetz, http://potree.org
  40876. *
  40877. */
  40878. // The MIT License
  40879. //
  40880. // Copyright (c) 2011 Mr.doob
  40881. //
  40882. // Permission is hereby granted, free of charge, to any person obtaining a copy
  40883. // of this software and associated documentation files (the "Software"), to deal
  40884. // in the Software without restriction, including without limitation the rights
  40885. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  40886. // copies of the Software, and to permit persons to whom the Software is
  40887. // furnished to do so, subject to the following conditions:
  40888. //
  40889. // The above copyright notice and this permission notice shall be included in
  40890. // all copies or substantial portions of the Software.
  40891. //
  40892. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  40893. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  40894. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  40895. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  40896. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  40897. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  40898. // THE SOFTWARE.
  40899. class EventDispatcher$1{
  40900. constructor(){
  40901. this._listeners = {};
  40902. }
  40903. addEventListener(type, listener, importance=0 ){//add importance
  40904. const listeners = this._listeners;
  40905. if(listeners[type] === undefined){
  40906. listeners[type] = [];
  40907. }
  40908. if(listeners[type].indexOf(listener) === - 1){
  40909. listeners[type].push({ listener, importance});
  40910. listeners[type] = listeners[type].sort((e,a)=> a.importance - e.importance);//add
  40911. }
  40912. }
  40913. hasEventListener(type, listener){
  40914. const listeners = this._listeners;
  40915. return listeners[type] !== undefined && listeners[type].indexOf(listener) !== - 1;
  40916. }
  40917. removeEventListener(type, listener){
  40918. let listeners = this._listeners;
  40919. let listenerArray = listeners[type];
  40920. if (listenerArray !== undefined){
  40921. /* let index = listenerArray.indexOf(listener);
  40922. if(index !== - 1){
  40923. listenerArray.splice(index, 1);
  40924. } */
  40925. let item = listenerArray.find(e=>e.listener == listener);
  40926. item && listenerArray.splice(listenerArray.indexOf(item), 1);
  40927. }
  40928. }
  40929. removeEventListeners(type){
  40930. if(this._listeners[type] !== undefined){
  40931. delete this._listeners[type];
  40932. }
  40933. };
  40934. dispatchEvent(event){
  40935. if(typeof event == 'string'){//add
  40936. event = {type:event};
  40937. }
  40938. let listeners = this._listeners;
  40939. let listenerArray = listeners[event.type];
  40940. if ( listenerArray !== undefined ) {
  40941. event.target = this;
  40942. for(let {listener} of listenerArray.slice(0)){
  40943. let result = listener.call(this, event); //add stopContinue
  40944. if(result && result.stopContinue){
  40945. break
  40946. }
  40947. }
  40948. }
  40949. }
  40950. //add
  40951. /* emit(type){
  40952. this.dispatchEvent({type, arguments: Array.from(arguments).slice(1, arguments.length) })
  40953. }
  40954. on(type, fun){
  40955. this.addEventListener(type,(ev)=>{
  40956. fun.apply(this, ev.arguments)
  40957. })
  40958. }
  40959. off(type, fun){
  40960. this.removeEventListener(type,)
  40961. }
  40962. once(type, fun) {
  40963. function callback() {
  40964. this.removeEventListener(type, callback),
  40965. n || (n = !0, fun.apply(this, arguments))
  40966. }
  40967. var n = !1;
  40968. return callback.listener = fun,
  40969. this.on(type, callback),
  40970. this
  40971. } */
  40972. removeAllListeners(){
  40973. this._listeners = {};
  40974. }
  40975. }
  40976. const KeyCodes = {
  40977. LEFT: 37,
  40978. UP: 38,
  40979. RIGHT: 39,
  40980. BOTTOM: 40,
  40981. DELETE: 46,
  40982. BACKSPACE:8,
  40983. A: 'A'.charCodeAt(0),
  40984. S: 'S'.charCodeAt(0),
  40985. D: 'D'.charCodeAt(0),
  40986. W: 'W'.charCodeAt(0),
  40987. Q: 'Q'.charCodeAt(0),
  40988. E: 'E'.charCodeAt(0),
  40989. R: 'R'.charCodeAt(0),
  40990. F: 'F'.charCodeAt(0)
  40991. };
  40992. class LRUItem{
  40993. constructor(node){
  40994. this.previous = null;
  40995. this.next = null;
  40996. this.node = node;
  40997. }
  40998. }
  40999. /**
  41000. *
  41001. * @class A doubly-linked-list of the least recently used elements.
  41002. */
  41003. class LRU{
  41004. constructor(){
  41005. // the least recently used item
  41006. this.first = null;
  41007. // the most recently used item
  41008. this.last = null;
  41009. // a list of all items in the lru list
  41010. this.items = {};
  41011. this.elements = 0;
  41012. this.numPoints = 0;
  41013. }
  41014. size(){
  41015. return this.elements;
  41016. }
  41017. contains(node){
  41018. return this.items[node.id] == null;
  41019. }
  41020. touch(node){
  41021. if (!node.loaded) {
  41022. return;
  41023. }
  41024. let item;
  41025. if (this.items[node.id] == null) {
  41026. // add to list
  41027. item = new LRUItem(node);
  41028. item.previous = this.last;
  41029. this.last = item;
  41030. if (item.previous !== null) {
  41031. item.previous.next = item;
  41032. }
  41033. this.items[node.id] = item;
  41034. this.elements++;
  41035. if (this.first === null) {
  41036. this.first = item;
  41037. }
  41038. this.numPoints += node.numPoints;
  41039. } else {
  41040. // update in list
  41041. item = this.items[node.id];
  41042. if (item.previous === null) {
  41043. // handle touch on first element
  41044. if (item.next !== null) {
  41045. this.first = item.next;
  41046. this.first.previous = null;
  41047. item.previous = this.last;
  41048. item.next = null;
  41049. this.last = item;
  41050. item.previous.next = item;
  41051. }
  41052. } else if (item.next === null) {
  41053. // handle touch on last element
  41054. } else {
  41055. // handle touch on any other element
  41056. item.previous.next = item.next;
  41057. item.next.previous = item.previous;
  41058. item.previous = this.last;
  41059. item.next = null;
  41060. this.last = item;
  41061. item.previous.next = item;
  41062. }
  41063. }
  41064. }
  41065. remove(node){
  41066. let lruItem = this.items[node.id];
  41067. if (lruItem) {
  41068. if (this.elements === 1) {
  41069. this.first = null;
  41070. this.last = null;
  41071. } else {
  41072. if (!lruItem.previous) {
  41073. this.first = lruItem.next;
  41074. this.first.previous = null;
  41075. }
  41076. if (!lruItem.next) {
  41077. this.last = lruItem.previous;
  41078. this.last.next = null;
  41079. }
  41080. if (lruItem.previous && lruItem.next) {
  41081. lruItem.previous.next = lruItem.next;
  41082. lruItem.next.previous = lruItem.previous;
  41083. }
  41084. }
  41085. delete this.items[node.id];
  41086. this.elements--;
  41087. this.numPoints -= node.numPoints;
  41088. }
  41089. }
  41090. getLRUItem(){
  41091. if (this.first === null) {
  41092. return null;
  41093. }
  41094. let lru = this.first;
  41095. return lru.node;
  41096. }
  41097. toString(){
  41098. let string = '{ ';
  41099. let curr = this.first;
  41100. while (curr !== null) {
  41101. string += curr.node.id;
  41102. if (curr.next !== null) {
  41103. string += ', ';
  41104. }
  41105. curr = curr.next;
  41106. }
  41107. string += '}';
  41108. string += '(' + this.size() + ')';
  41109. return string;
  41110. }
  41111. freeMemory(){
  41112. if (this.elements <= 1) {
  41113. return;
  41114. }
  41115. /* while (this.numPoints > Potree.pointLoadLimit) {
  41116. let element = this.first;
  41117. let node = element.node;
  41118. this.disposeDescendants(node);
  41119. } */
  41120. //改成navvis的,使用pointBudget,否则四屏点云闪烁。
  41121. let max = /* this.pageVisible ? */viewer.viewports.length * 2 * Potree.pointBudget;// : 1000
  41122. for (; this.numPoints > max; ) {//要根据屏幕数量来增加pointBudget
  41123. var node = this.getLRUItem();
  41124. node && this.disposeSubtree(node);
  41125. }
  41126. }
  41127. disposeSubtree(t) {//add from navvis 25.js
  41128. var e = [t];
  41129. t.traverse((function(t) {
  41130. t.loaded && e.push(t);
  41131. }
  41132. ));
  41133. for (var n = 0, i = e; n < i.length; n++) {
  41134. var o = i[n];
  41135. o.dispose(),
  41136. this.remove(o);
  41137. }
  41138. }
  41139. disposeDescendants(node){
  41140. let stack = [];
  41141. stack.push(node);
  41142. while (stack.length > 0) {
  41143. let current = stack.pop();
  41144. // console.log(current);
  41145. current.dispose();
  41146. this.remove(current);
  41147. for (let key in current.children) {
  41148. if (current.children.hasOwnProperty(key)) {
  41149. let child = current.children[key];
  41150. if (child.loaded) {
  41151. stack.push(current.children[key]);
  41152. }
  41153. }
  41154. }
  41155. }
  41156. }
  41157. }
  41158. class PointCloudTreeNode extends EventDispatcher{
  41159. constructor(){
  41160. super();
  41161. this.needsTransformUpdate = true;
  41162. }
  41163. getChildren () {
  41164. throw new Error('override function');
  41165. }
  41166. getBoundingBox () {
  41167. throw new Error('override function');
  41168. }
  41169. isLoaded () {
  41170. throw new Error('override function');
  41171. }
  41172. isGeometryNode () {
  41173. throw new Error('override function');
  41174. }
  41175. isTreeNode () {
  41176. throw new Error('override function');
  41177. }
  41178. getLevel () {
  41179. throw new Error('override function');
  41180. }
  41181. getBoundingSphere () {
  41182. throw new Error('override function');
  41183. }
  41184. };
  41185. class PointCloudTree extends Object3D {
  41186. constructor () {
  41187. super();
  41188. //this.spriteGroup = new THREE.Object3D //add
  41189. }
  41190. initialized () {
  41191. return this.root !== null;
  41192. }
  41193. };
  41194. /**
  41195. * Some types of possible point attribute data formats
  41196. *
  41197. * @class
  41198. */
  41199. const PointAttributeTypes = {
  41200. DATA_TYPE_DOUBLE: {ordinal: 0, name: "double", size: 8},
  41201. DATA_TYPE_FLOAT: {ordinal: 1, name: "float", size: 4},
  41202. DATA_TYPE_INT8: {ordinal: 2, name: "int8", size: 1},
  41203. DATA_TYPE_UINT8: {ordinal: 3, name: "uint8", size: 1},
  41204. DATA_TYPE_INT16: {ordinal: 4, name: "int16", size: 2},
  41205. DATA_TYPE_UINT16: {ordinal: 5, name: "uint16", size: 2},
  41206. DATA_TYPE_INT32: {ordinal: 6, name: "int32", size: 4},
  41207. DATA_TYPE_UINT32: {ordinal: 7, name: "uint32", size: 4},
  41208. DATA_TYPE_INT64: {ordinal: 8, name: "int64", size: 8},
  41209. DATA_TYPE_UINT64: {ordinal: 9, name: "uint64", size: 8}
  41210. };
  41211. let i$1 = 0;
  41212. for (let obj in PointAttributeTypes) {
  41213. PointAttributeTypes[i$1] = PointAttributeTypes[obj];
  41214. i$1++;
  41215. }
  41216. class PointAttribute{
  41217. constructor(name, type, numElements){
  41218. this.name = name;
  41219. this.type = type;
  41220. this.numElements = numElements;
  41221. this.byteSize = this.numElements * this.type.size;
  41222. this.description = "";
  41223. this.range = [Infinity, -Infinity];
  41224. }
  41225. };
  41226. //add
  41227. const replacements = {
  41228. "COLOR_PACKED": "rgba",
  41229. "RGBA": "rgba",
  41230. "INTENSITY": "intensity",
  41231. "CLASSIFICATION": "classification",
  41232. "GPS_TIME": "gps-time",
  41233. };
  41234. const replaceOldNames = (old) => {
  41235. if(replacements[old]){
  41236. return replacements[old];
  41237. }else {
  41238. return old;
  41239. }
  41240. };
  41241. PointAttribute.POSITION_CARTESIAN = new PointAttribute(
  41242. "POSITION_CARTESIAN", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  41243. PointAttribute.RGBA_PACKED = new PointAttribute(
  41244. replaceOldNames("COLOR_PACKED"), PointAttributeTypes.DATA_TYPE_INT8, 4);
  41245. PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
  41246. PointAttribute.RGB_PACKED = new PointAttribute(
  41247. "COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 3);
  41248. PointAttribute.NORMAL_FLOATS = new PointAttribute(
  41249. "NORMAL_FLOATS", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  41250. PointAttribute.INTENSITY = new PointAttribute(
  41251. replaceOldNames("INTENSITY"), PointAttributeTypes.DATA_TYPE_UINT16, 1);
  41252. PointAttribute.CLASSIFICATION = new PointAttribute(
  41253. replaceOldNames("CLASSIFICATION"), PointAttributeTypes.DATA_TYPE_UINT8, 1);
  41254. PointAttribute.NORMAL_SPHEREMAPPED = new PointAttribute(
  41255. "NORMAL_SPHEREMAPPED", PointAttributeTypes.DATA_TYPE_UINT8, 2);
  41256. PointAttribute.NORMAL_OCT16 = new PointAttribute(
  41257. "NORMAL_OCT16", PointAttributeTypes.DATA_TYPE_UINT8, 2);
  41258. PointAttribute.NORMAL = new PointAttribute(
  41259. "NORMAL", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  41260. PointAttribute.RETURN_NUMBER = new PointAttribute(
  41261. "RETURN_NUMBER", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  41262. PointAttribute.NUMBER_OF_RETURNS = new PointAttribute(
  41263. "NUMBER_OF_RETURNS", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  41264. PointAttribute.SOURCE_ID = new PointAttribute(
  41265. "SOURCE_ID", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  41266. PointAttribute.INDICES = new PointAttribute(
  41267. "INDICES", PointAttributeTypes.DATA_TYPE_UINT32, 1);
  41268. PointAttribute.SPACING = new PointAttribute(
  41269. "SPACING", PointAttributeTypes.DATA_TYPE_FLOAT, 1);
  41270. PointAttribute.GPS_TIME = new PointAttribute(
  41271. replaceOldNames("GPS_TIME"), PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
  41272. class PointAttributes{
  41273. constructor(pointAttributes){
  41274. this.attributes = [];
  41275. this.byteSize = 0;
  41276. this.size = 0;
  41277. this.vectors = [];
  41278. if (pointAttributes != null) {
  41279. for (let i = 0; i < pointAttributes.length; i++) {
  41280. let pointAttributeName = pointAttributes[i];
  41281. let pointAttribute = PointAttribute[pointAttributeName];
  41282. this.attributes.push(pointAttribute);
  41283. this.byteSize += pointAttribute.byteSize;
  41284. this.size++;
  41285. }
  41286. }
  41287. }
  41288. add(pointAttribute){
  41289. this.attributes.push(pointAttribute);
  41290. this.byteSize += pointAttribute.byteSize;
  41291. this.size++;
  41292. };
  41293. addVector(vector){
  41294. this.vectors.push(vector);
  41295. }
  41296. hasNormals(){
  41297. for (let name in this.attributes) {
  41298. let pointAttribute = this.attributes[name];
  41299. if (
  41300. pointAttribute === PointAttribute.NORMAL_SPHEREMAPPED ||
  41301. pointAttribute === PointAttribute.NORMAL_FLOATS ||
  41302. pointAttribute === PointAttribute.NORMAL ||
  41303. pointAttribute === PointAttribute.NORMAL_OCT16) {
  41304. return true;
  41305. }
  41306. }
  41307. return false;
  41308. };
  41309. }
  41310. class U {
  41311. static toVector3(v, offset) {
  41312. return new Vector3().fromArray(v, offset || 0);
  41313. }
  41314. static toBox3(b) {
  41315. return new Box3(U.toVector3(b), U.toVector3(b, 3));
  41316. };
  41317. static findDim(schema, name) {
  41318. var dim = schema.find((dim) => dim.name == name);
  41319. if (!dim) throw new Error('Failed to find ' + name + ' in schema');
  41320. return dim;
  41321. }
  41322. static sphereFrom(b) {
  41323. return b.getBoundingSphere(new Sphere());
  41324. }
  41325. };
  41326. class PointCloudEptGeometry {
  41327. constructor(url, info) {
  41328. let version = info.version;
  41329. let schema = info.schema;
  41330. let bounds = info.bounds;
  41331. let boundsConforming = info.boundsConforming;
  41332. let xyz = [
  41333. U.findDim(schema, 'X'),
  41334. U.findDim(schema, 'Y'),
  41335. U.findDim(schema, 'Z')
  41336. ];
  41337. let scale = xyz.map((d) => d.scale || 1);
  41338. let offset = xyz.map((d) => d.offset || 0);
  41339. this.eptScale = U.toVector3(scale);
  41340. this.eptOffset = U.toVector3(offset);
  41341. this.url = url;
  41342. this.info = info;
  41343. this.type = 'ept';
  41344. this.schema = schema;
  41345. this.span = info.span || info.ticks;
  41346. this.boundingBox = U.toBox3(bounds);
  41347. this.tightBoundingBox = U.toBox3(boundsConforming);
  41348. this.offset = U.toVector3([0, 0, 0]);
  41349. this.boundingSphere = U.sphereFrom(this.boundingBox);
  41350. this.tightBoundingSphere = U.sphereFrom(this.tightBoundingBox);
  41351. this.version = new Potree.Version('1.7');
  41352. this.projection = null;
  41353. this.fallbackProjection = null;
  41354. if (info.srs && info.srs.horizontal) {
  41355. this.projection = info.srs.authority + ':' + info.srs.horizontal;
  41356. }
  41357. if (info.srs.wkt) {
  41358. if (!this.projection) this.projection = info.srs.wkt;
  41359. else this.fallbackProjection = info.srs.wkt;
  41360. }
  41361. {
  41362. // TODO [mschuetz]: named projections that proj4 can't handle seem to cause problems.
  41363. // remove them for now
  41364. try{
  41365. proj4(this.projection);
  41366. }catch(e){
  41367. this.projection = null;
  41368. }
  41369. }
  41370. {
  41371. const attributes = new PointAttributes();
  41372. attributes.add(PointAttribute.POSITION_CARTESIAN);
  41373. attributes.add(new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_UINT8, 4));
  41374. attributes.add(new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1));
  41375. attributes.add(new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  41376. attributes.add(new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1));
  41377. attributes.add(new PointAttribute("returnNumber", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  41378. attributes.add(new PointAttribute("number of returns", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  41379. attributes.add(new PointAttribute("return number", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  41380. attributes.add(new PointAttribute("source id", PointAttributeTypes.DATA_TYPE_UINT16, 1));
  41381. this.pointAttributes = attributes;
  41382. }
  41383. this.spacing =
  41384. (this.boundingBox.max.x - this.boundingBox.min.x) / this.span;
  41385. let hierarchyType = info.hierarchyType || 'json';
  41386. const dataType = info.dataType;
  41387. if (dataType == 'laszip') {
  41388. this.loader = new Potree.EptLaszipLoader();
  41389. }
  41390. else if (dataType == 'binary') {
  41391. this.loader = new Potree.EptBinaryLoader();
  41392. }
  41393. else if (dataType == 'zstandard') {
  41394. this.loader = new Potree.EptZstandardLoader();
  41395. }
  41396. else {
  41397. throw new Error('Could not read data type: ' + dataType);
  41398. }
  41399. }
  41400. };
  41401. class EptKey {
  41402. constructor(ept, b, d, x, y, z) {
  41403. this.ept = ept;
  41404. this.b = b;
  41405. this.d = d;
  41406. this.x = x || 0;
  41407. this.y = y || 0;
  41408. this.z = z || 0;
  41409. }
  41410. name() {
  41411. return this.d + '-' + this.x + '-' + this.y + '-' + this.z;
  41412. }
  41413. step(a, b, c) {
  41414. let min = this.b.min.clone();
  41415. let max = this.b.max.clone();
  41416. let dst = new Vector3().subVectors(max, min);
  41417. if (a) min.x += dst.x / 2;
  41418. else max.x -= dst.x / 2;
  41419. if (b) min.y += dst.y / 2;
  41420. else max.y -= dst.y / 2;
  41421. if (c) min.z += dst.z / 2;
  41422. else max.z -= dst.z / 2;
  41423. return new Potree.EptKey(
  41424. this.ept,
  41425. new Box3(min, max),
  41426. this.d + 1,
  41427. this.x * 2 + a,
  41428. this.y * 2 + b,
  41429. this.z * 2 + c);
  41430. }
  41431. children() {
  41432. var result = [];
  41433. for (var a = 0; a < 2; ++a) {
  41434. for (var b = 0; b < 2; ++b) {
  41435. for (var c = 0; c < 2; ++c) {
  41436. var add = this.step(a, b, c).name();
  41437. if (!result.includes(add)) result = result.concat(add);
  41438. }
  41439. }
  41440. }
  41441. return result;
  41442. }
  41443. }
  41444. class PointCloudEptGeometryNode extends PointCloudTreeNode {
  41445. constructor(ept, b, d, x, y, z) {
  41446. super();
  41447. this.ept = ept;
  41448. this.key = new Potree.EptKey(
  41449. this.ept,
  41450. b || this.ept.boundingBox,
  41451. d || 0,
  41452. x,
  41453. y,
  41454. z);
  41455. this.id = PointCloudEptGeometryNode.IDCount++;
  41456. this.geometry = null;
  41457. this.boundingBox = this.key.b;
  41458. this.tightBoundingBox = this.boundingBox;
  41459. this.spacing = this.ept.spacing / Math.pow(2, this.key.d);
  41460. this.boundingSphere = U.sphereFrom(this.boundingBox);
  41461. // These are set during hierarchy loading.
  41462. this.hasChildren = false;
  41463. this.children = { };
  41464. this.numPoints = -1;
  41465. this.level = this.key.d;
  41466. this.loaded = false;
  41467. this.loading = false;
  41468. this.oneTimeDisposeHandlers = [];
  41469. let k = this.key;
  41470. this.name = this.toPotreeName(k.d, k.x, k.y, k.z);
  41471. this.index = parseInt(this.name.charAt(this.name.length - 1));
  41472. }
  41473. isGeometryNode() { return true; }
  41474. getLevel() { return this.level; }
  41475. isTreeNode() { return false; }
  41476. isLoaded() { return this.loaded; }
  41477. getBoundingSphere() { return this.boundingSphere; }
  41478. getBoundingBox() { return this.boundingBox; }
  41479. url() { return this.ept.url + 'ept-data/' + this.filename(); }
  41480. getNumPoints() { return this.numPoints; }
  41481. filename() { return this.key.name(); }
  41482. getChildren() {
  41483. let children = [];
  41484. for (let i = 0; i < 8; i++) {
  41485. if (this.children[i]) {
  41486. children.push(this.children[i]);
  41487. }
  41488. }
  41489. return children;
  41490. }
  41491. addChild(child) {
  41492. this.children[child.index] = child;
  41493. child.parent = this;
  41494. }
  41495. load() {
  41496. if (this.loaded || this.loading) return;
  41497. if (Potree.numNodesLoading >= Potree.maxNodesLoading) return;
  41498. this.loading = true;
  41499. ++Potree.numNodesLoading;
  41500. if (this.numPoints == -1) this.loadHierarchy();
  41501. this.loadPoints();
  41502. }
  41503. loadPoints(){
  41504. this.ept.loader.load(this);
  41505. }
  41506. async loadHierarchy() {
  41507. let nodes = { };
  41508. nodes[this.filename()] = this;
  41509. this.hasChildren = false;
  41510. let eptHierarchyFile =
  41511. `${this.ept.url}ept-hierarchy/${this.filename()}.json`;
  41512. let response = await fetch(eptHierarchyFile);
  41513. let hier = await response.json();
  41514. // Since we want to traverse top-down, and 10 comes
  41515. // lexicographically before 9 (for example), do a deep sort.
  41516. var keys = Object.keys(hier).sort((a, b) => {
  41517. let [da, xa, ya, za] = a.split('-').map((n) => parseInt(n, 10));
  41518. let [db, xb, yb, zb] = b.split('-').map((n) => parseInt(n, 10));
  41519. if (da < db) return -1; if (da > db) return 1;
  41520. if (xa < xb) return -1; if (xa > xb) return 1;
  41521. if (ya < yb) return -1; if (ya > yb) return 1;
  41522. if (za < zb) return -1; if (za > zb) return 1;
  41523. return 0;
  41524. });
  41525. keys.forEach((v) => {
  41526. let [d, x, y, z] = v.split('-').map((n) => parseInt(n, 10));
  41527. let a = x & 1, b = y & 1, c = z & 1;
  41528. let parentName =
  41529. (d - 1) + '-' + (x >> 1) + '-' + (y >> 1) + '-' + (z >> 1);
  41530. let parentNode = nodes[parentName];
  41531. if (!parentNode) return;
  41532. parentNode.hasChildren = true;
  41533. let key = parentNode.key.step(a, b, c);
  41534. let node = new Potree.PointCloudEptGeometryNode(
  41535. this.ept,
  41536. key.b,
  41537. key.d,
  41538. key.x,
  41539. key.y,
  41540. key.z);
  41541. node.level = d;
  41542. node.numPoints = hier[v];
  41543. parentNode.addChild(node);
  41544. nodes[key.name()] = node;
  41545. });
  41546. }
  41547. doneLoading(bufferGeometry, tightBoundingBox, np, mean) {
  41548. bufferGeometry.boundingBox = this.boundingBox;
  41549. this.geometry = bufferGeometry;
  41550. this.tightBoundingBox = tightBoundingBox;
  41551. this.numPoints = np;
  41552. this.mean = mean;
  41553. this.loaded = true;
  41554. this.loading = false;
  41555. --Potree.numNodesLoading;
  41556. }
  41557. toPotreeName(d, x, y, z) {
  41558. var name = 'r';
  41559. for (var i = 0; i < d; ++i) {
  41560. var shift = d - i - 1;
  41561. var mask = 1 << shift;
  41562. var step = 0;
  41563. if (x & mask) step += 4;
  41564. if (y & mask) step += 2;
  41565. if (z & mask) step += 1;
  41566. name += step;
  41567. }
  41568. return name;
  41569. }
  41570. dispose() {
  41571. if (this.geometry && this.parent != null) {
  41572. this.geometry.dispose();
  41573. this.geometry = null;
  41574. this.loaded = false;
  41575. // this.dispatchEvent( { type: 'dispose' } );
  41576. for (let i = 0; i < this.oneTimeDisposeHandlers.length; i++) {
  41577. let handler = this.oneTimeDisposeHandlers[i];
  41578. handler();
  41579. }
  41580. this.oneTimeDisposeHandlers = [];
  41581. }
  41582. }
  41583. }
  41584. PointCloudEptGeometryNode.IDCount = 0;
  41585. class PointCloudOctreeGeometry extends EventDispatcher{
  41586. constructor(){
  41587. super();
  41588. this.url = null;
  41589. this.octreeDir = null;
  41590. this.spacing = 0;
  41591. this.boundingBox = null;
  41592. this.root = null;
  41593. this.nodes = null;
  41594. this.pointAttributes = null;
  41595. this.hierarchyStepSize = -1;
  41596. this.loader = null;
  41597. }
  41598. }
  41599. class PointCloudOctreeGeometryNode extends PointCloudTreeNode{
  41600. constructor(name, pcoGeometry, boundingBox){
  41601. super();
  41602. this.id = PointCloudOctreeGeometryNode.IDCount++;
  41603. this.name = name;
  41604. this.index = parseInt(name.charAt(name.length - 1));
  41605. this.pcoGeometry = pcoGeometry;
  41606. this.geometry = null;
  41607. this.boundingBox = boundingBox;
  41608. this.boundingSphere = boundingBox.getBoundingSphere(new Sphere());
  41609. this.children = {};
  41610. this.numPoints = 0;
  41611. this.level = null;
  41612. this.loaded = false;
  41613. this.oneTimeDisposeHandlers = [];
  41614. }
  41615. isGeometryNode(){
  41616. return true;
  41617. }
  41618. getLevel(){
  41619. return this.level;
  41620. }
  41621. isTreeNode(){
  41622. return false;
  41623. }
  41624. isLoaded(){
  41625. return this.loaded;
  41626. }
  41627. getBoundingSphere(){
  41628. return this.boundingSphere;
  41629. }
  41630. getBoundingBox(){
  41631. return this.boundingBox;
  41632. }
  41633. getChildren(){
  41634. let children = [];
  41635. for (let i = 0; i < 8; i++) {
  41636. if (this.children[i]) {
  41637. children.push(this.children[i]);
  41638. }
  41639. }
  41640. return children;
  41641. }
  41642. getBoundingBox(){
  41643. return this.boundingBox;
  41644. }
  41645. getURL(){
  41646. let url = '';
  41647. let version = this.pcoGeometry.loader.version;
  41648. if (version.equalOrHigher('1.5')) {
  41649. url = this.pcoGeometry.octreeDir + '/' + this.getHierarchyPath() + '/' + this.name;
  41650. } else if (version.equalOrHigher('1.4')) {
  41651. url = this.pcoGeometry.octreeDir + '/' + this.name;
  41652. } else if (version.upTo('1.3')) {
  41653. url = this.pcoGeometry.octreeDir + '/' + this.name;
  41654. }
  41655. return url;
  41656. }
  41657. getHierarchyPath(){
  41658. let path = 'r/';
  41659. let hierarchyStepSize = this.pcoGeometry.hierarchyStepSize;
  41660. let indices = this.name.substr(1);
  41661. let numParts = Math.floor(indices.length / hierarchyStepSize);
  41662. for (let i = 0; i < numParts; i++) {
  41663. path += indices.substr(i * hierarchyStepSize, hierarchyStepSize) + '/';
  41664. }
  41665. path = path.slice(0, -1);
  41666. return path;
  41667. }
  41668. addChild(child) {
  41669. this.children[child.index] = child;
  41670. child.parent = this;
  41671. }
  41672. load(){
  41673. if (this.loading === true || this.loaded === true || Potree.numNodesLoading >= Potree.maxNodesLoading) {
  41674. return;
  41675. }
  41676. this.loading = true;
  41677. Potree.numNodesLoading++;
  41678. if (this.pcoGeometry.loader.version.equalOrHigher('1.5')) {
  41679. if ((this.level % this.pcoGeometry.hierarchyStepSize) === 0 && this.hasChildren) {
  41680. this.loadHierachyThenPoints();
  41681. } else {
  41682. this.loadPoints();
  41683. }
  41684. } else {
  41685. this.loadPoints();
  41686. }
  41687. }
  41688. loadPoints(){
  41689. this.pcoGeometry.loader.load(this);
  41690. }
  41691. loadHierachyThenPoints(pointcloud){
  41692. let node = this;
  41693. // load hierarchy
  41694. let callback = function (node, hbuffer) {
  41695. let tStart = performance.now();
  41696. let view = new DataView(hbuffer);
  41697. let stack = [];
  41698. let children = view.getUint8(0);
  41699. let numPoints = view.getUint32(1, true);
  41700. node.numPoints = numPoints;
  41701. stack.push({children: children, numPoints: numPoints, name: node.name});
  41702. let decoded = [];
  41703. let offset = 5;
  41704. while (stack.length > 0) {
  41705. let snode = stack.shift();
  41706. let mask = 1;
  41707. for (let i = 0; i < 8; i++) {
  41708. if ((snode.children & mask) !== 0) {
  41709. let childName = snode.name + i;
  41710. let childChildren = view.getUint8(offset);
  41711. let childNumPoints = view.getUint32(offset + 1, true);
  41712. stack.push({children: childChildren, numPoints: childNumPoints, name: childName});
  41713. decoded.push({children: childChildren, numPoints: childNumPoints, name: childName});
  41714. offset += 5;
  41715. }
  41716. mask = mask * 2;
  41717. }
  41718. if (offset === hbuffer.byteLength) {
  41719. break;
  41720. }
  41721. }
  41722. // console.log(decoded);
  41723. let nodes = {};
  41724. nodes[node.name] = node;
  41725. let pco = node.pcoGeometry;
  41726. for (let i = 0; i < decoded.length; i++) {
  41727. let name = decoded[i].name;
  41728. let decodedNumPoints = decoded[i].numPoints;
  41729. let index = parseInt(name.charAt(name.length - 1));
  41730. let parentName = name.substring(0, name.length - 1);
  41731. let parentNode = nodes[parentName];
  41732. let level = name.length - 1;
  41733. pco.dispatchEvent({type:'updateNodeMaxLevel',level});//add
  41734. let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
  41735. let currentNode = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  41736. currentNode.level = level;
  41737. currentNode.numPoints = decodedNumPoints;
  41738. currentNode.hasChildren = decoded[i].children > 0;
  41739. currentNode.spacing = pco.spacing / Math.pow(2, level);
  41740. parentNode.addChild(currentNode);
  41741. nodes[name] = currentNode;
  41742. }
  41743. let duration = performance.now() - tStart;
  41744. if(duration > 5){
  41745. /* let msg = `duration: ${duration}ms, numNodes: ${decoded.length}`;
  41746. console.log(msg); */
  41747. }
  41748. node.loadPoints();
  41749. };
  41750. if ((node.level % node.pcoGeometry.hierarchyStepSize) === 0) {
  41751. // let hurl = node.pcoGeometry.octreeDir + "/../hierarchy/" + node.name + ".hrc";
  41752. let hurl = node.pcoGeometry.octreeDir + '/' + node.getHierarchyPath() + '/' + node.name + '.hrc';
  41753. hurl += '?m='+node.pcoGeometry.timeStamp; //add
  41754. let xhr = XHRFactory.createXMLHttpRequest();
  41755. xhr.open('GET', hurl, true);
  41756. xhr.responseType = 'arraybuffer';
  41757. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  41758. xhr.onreadystatechange = () => {
  41759. if (xhr.readyState === 4) {
  41760. if (xhr.status === 200 || xhr.status === 0) {
  41761. let hbuffer = xhr.response;
  41762. callback(node, hbuffer);
  41763. } else {
  41764. console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + hurl);
  41765. Potree.numNodesLoading--;
  41766. }
  41767. }
  41768. };
  41769. try {
  41770. xhr.send(null);
  41771. } catch (e) {
  41772. console.log('fehler beim laden der punktwolke: ' + e);
  41773. }
  41774. }
  41775. }
  41776. getNumPoints(){
  41777. return this.numPoints;
  41778. }
  41779. dispose(){
  41780. if (this.geometry && this.parent != null) {
  41781. this.geometry.dispose();
  41782. this.geometry = null;
  41783. this.loaded = false;
  41784. this.dispatchEvent( { type: 'dispose' } );
  41785. for (let i = 0; i < this.oneTimeDisposeHandlers.length; i++) {
  41786. let handler = this.oneTimeDisposeHandlers[i];
  41787. handler();
  41788. }
  41789. this.oneTimeDisposeHandlers = [];
  41790. }
  41791. }
  41792. traverse(t, e){//add from navvis 25.js
  41793. void 0 === e && (e = !0);
  41794. for (var n, i = e ? [this] : []; void 0 !== (n = i.pop()); ) {
  41795. t(n);
  41796. for (var o = 0, r = n.children; o < r.length; o++) {
  41797. var a = r[o];
  41798. null !== a && i.push(a);
  41799. }
  41800. }
  41801. }
  41802. }
  41803. PointCloudOctreeGeometryNode.IDCount = 0;
  41804. // -------------------------------------------
  41805. // to get a ready to use gradient array from a chroma.js gradient:
  41806. // http://gka.github.io/chroma.js/
  41807. // -------------------------------------------
  41808. //
  41809. // let stops = [];
  41810. // for(let i = 0; i <= 10; i++){
  41811. // let range = chroma.scale(['yellow', 'navy']).mode('lch').domain([10,0])(i)._rgb
  41812. // .slice(0, 3)
  41813. // .map(v => (v / 255).toFixed(4))
  41814. // .join(", ");
  41815. //
  41816. // let line = `[${i / 10}, new THREE.Color(${range})],`;
  41817. //
  41818. // stops.push(line);
  41819. // }
  41820. // stops.join("\n");
  41821. //
  41822. //
  41823. //
  41824. // -------------------------------------------
  41825. // to get a ready to use gradient array from matplotlib:
  41826. // -------------------------------------------
  41827. // import matplotlib.pyplot as plt
  41828. // import matplotlib.colors as colors
  41829. //
  41830. // norm = colors.Normalize(vmin=0,vmax=1)
  41831. // cmap = plt.cm.viridis
  41832. //
  41833. // for i in range(0,11):
  41834. // u = i / 10
  41835. // rgb = cmap(norm(u))[0:3]
  41836. // rgb = ["{0:.3f}".format(v) for v in rgb]
  41837. // rgb = "[" + str(u) + ", new THREE.Color(" + ", ".join(rgb) + ")],"
  41838. // print(rgb)
  41839. let Gradients = {
  41840. // From chroma spectral http://gka.github.io/chroma.js/
  41841. SPECTRAL: [
  41842. [0, new Color(0.3686, 0.3098, 0.6353)],
  41843. [0.1, new Color(0.1961, 0.5333, 0.7412)],
  41844. [0.2, new Color(0.4000, 0.7608, 0.6471)],
  41845. [0.3, new Color(0.6706, 0.8667, 0.6431)],
  41846. [0.4, new Color(0.9020, 0.9608, 0.5961)],
  41847. [0.5, new Color(1.0000, 1.0000, 0.7490)],
  41848. [0.6, new Color(0.9961, 0.8784, 0.5451)],
  41849. [0.7, new Color(0.9922, 0.6824, 0.3804)],
  41850. [0.8, new Color(0.9569, 0.4275, 0.2627)],
  41851. [0.9, new Color(0.8353, 0.2431, 0.3098)],
  41852. [1, new Color(0.6196, 0.0039, 0.2588)]
  41853. ],
  41854. PLASMA: [
  41855. [0.0, new Color(0.241, 0.015, 0.610)],
  41856. [0.1, new Color(0.387, 0.001, 0.654)],
  41857. [0.2, new Color(0.524, 0.025, 0.653)],
  41858. [0.3, new Color(0.651, 0.125, 0.596)],
  41859. [0.4, new Color(0.752, 0.227, 0.513)],
  41860. [0.5, new Color(0.837, 0.329, 0.431)],
  41861. [0.6, new Color(0.907, 0.435, 0.353)],
  41862. [0.7, new Color(0.963, 0.554, 0.272)],
  41863. [0.8, new Color(0.992, 0.681, 0.195)],
  41864. [0.9, new Color(0.987, 0.822, 0.144)],
  41865. [1.0, new Color(0.940, 0.975, 0.131)]
  41866. ],
  41867. YELLOW_GREEN: [
  41868. [0, new Color(0.1647, 0.2824, 0.3451)],
  41869. [0.1, new Color(0.1338, 0.3555, 0.4227)],
  41870. [0.2, new Color(0.0610, 0.4319, 0.4864)],
  41871. [0.3, new Color(0.0000, 0.5099, 0.5319)],
  41872. [0.4, new Color(0.0000, 0.5881, 0.5569)],
  41873. [0.5, new Color(0.1370, 0.6650, 0.5614)],
  41874. [0.6, new Color(0.2906, 0.7395, 0.5477)],
  41875. [0.7, new Color(0.4453, 0.8099, 0.5201)],
  41876. [0.8, new Color(0.6102, 0.8748, 0.4850)],
  41877. [0.9, new Color(0.7883, 0.9323, 0.4514)],
  41878. [1, new Color(0.9804, 0.9804, 0.4314)]
  41879. ],
  41880. VIRIDIS: [
  41881. [0.0, new Color(0.267, 0.005, 0.329)],
  41882. [0.1, new Color(0.283, 0.141, 0.458)],
  41883. [0.2, new Color(0.254, 0.265, 0.530)],
  41884. [0.3, new Color(0.207, 0.372, 0.553)],
  41885. [0.4, new Color(0.164, 0.471, 0.558)],
  41886. [0.5, new Color(0.128, 0.567, 0.551)],
  41887. [0.6, new Color(0.135, 0.659, 0.518)],
  41888. [0.7, new Color(0.267, 0.749, 0.441)],
  41889. [0.8, new Color(0.478, 0.821, 0.318)],
  41890. [0.9, new Color(0.741, 0.873, 0.150)],
  41891. [1.0, new Color(0.993, 0.906, 0.144)]
  41892. ],
  41893. INFERNO: [
  41894. [0.0, new Color(0.077, 0.042, 0.206)],
  41895. [0.1, new Color(0.225, 0.036, 0.388)],
  41896. [0.2, new Color(0.373, 0.074, 0.432)],
  41897. [0.3, new Color(0.522, 0.128, 0.420)],
  41898. [0.4, new Color(0.665, 0.182, 0.370)],
  41899. [0.5, new Color(0.797, 0.255, 0.287)],
  41900. [0.6, new Color(0.902, 0.364, 0.184)],
  41901. [0.7, new Color(0.969, 0.516, 0.063)],
  41902. [0.8, new Color(0.988, 0.683, 0.072)],
  41903. [0.9, new Color(0.961, 0.859, 0.298)],
  41904. [1.0, new Color(0.988, 0.998, 0.645)]
  41905. ],
  41906. GRAYSCALE: [
  41907. [0, new Color(0, 0, 0)],
  41908. [1, new Color(1, 1, 1)]
  41909. ],
  41910. // 16 samples of the TURBU color scheme
  41911. // values taken from: https://gist.github.com/mikhailov-work/ee72ba4191942acecc03fe6da94fc73f
  41912. // original file licensed under Apache-2.0
  41913. TURBO: [
  41914. [0.00, new Color(0.18995, 0.07176, 0.23217)],
  41915. [0.07, new Color(0.25107, 0.25237, 0.63374)],
  41916. [0.13, new Color(0.27628, 0.42118, 0.89123)],
  41917. [0.20, new Color(0.25862, 0.57958, 0.99876)],
  41918. [0.27, new Color(0.15844, 0.73551, 0.92305)],
  41919. [0.33, new Color(0.09267, 0.86554, 0.7623)],
  41920. [0.40, new Color(0.19659, 0.94901, 0.59466)],
  41921. [0.47, new Color(0.42778, 0.99419, 0.38575)],
  41922. [0.53, new Color(0.64362, 0.98999, 0.23356)],
  41923. [0.60, new Color(0.80473, 0.92452, 0.20459)],
  41924. [0.67, new Color(0.93301, 0.81236, 0.22667)],
  41925. [0.73, new Color(0.99314, 0.67408, 0.20348)],
  41926. [0.80, new Color(0.9836, 0.49291, 0.12849)],
  41927. [0.87, new Color(0.92105, 0.31489, 0.05475)],
  41928. [0.93, new Color(0.81608, 0.18462, 0.01809)],
  41929. [1.00, new Color(0.66449, 0.08436, 0.00424)],
  41930. ],
  41931. RAINBOW: [
  41932. [0, new Color(0.278, 0, 0.714)],
  41933. [1 / 6, new Color(0, 0, 1)],
  41934. [2 / 6, new Color(0, 1, 1)],
  41935. [3 / 6, new Color(0, 1, 0)],
  41936. [4 / 6, new Color(1, 1, 0)],
  41937. [5 / 6, new Color(1, 0.64, 0)],
  41938. [1, new Color(1, 0, 0)]
  41939. ],
  41940. CONTOUR: [
  41941. [0.00, new Color(0, 0, 0)],
  41942. [0.03, new Color(0, 0, 0)],
  41943. [0.04, new Color(1, 1, 1)],
  41944. [1.00, new Color(1, 1, 1)]
  41945. ],
  41946. };
  41947. const ClassificationScheme = {
  41948. DEFAULT: {
  41949. 0: { visible: true, name: 'never classified' , color: [0.5, 0.5, 0.5, 1.0] },
  41950. 1: { visible: true, name: 'unclassified' , color: [0.5, 0.5, 0.5, 1.0] },
  41951. 2: { visible: true, name: 'ground' , color: [0.63, 0.32, 0.18, 1.0] },
  41952. 3: { visible: true, name: 'low vegetation' , color: [0.0, 1.0, 0.0, 1.0] },
  41953. 4: { visible: true, name: 'medium vegetation' , color: [0.0, 0.8, 0.0, 1.0] },
  41954. 5: { visible: true, name: 'high vegetation' , color: [0.0, 0.6, 0.0, 1.0] },
  41955. 6: { visible: true, name: 'building' , color: [1.0, 0.66, 0.0, 1.0] },
  41956. 7: { visible: true, name: 'low point(noise)' , color: [1.0, 0.0, 1.0, 1.0] },
  41957. 8: { visible: true, name: 'key-point' , color: [1.0, 0.0, 0.0, 1.0] },
  41958. 9: { visible: true, name: 'water' , color: [0.0, 0.0, 1.0, 1.0] },
  41959. 12: { visible: true, name: 'overlap' , color: [1.0, 1.0, 0.0, 1.0] },
  41960. DEFAULT: { visible: true, name: 'default' , color: [0.3, 0.6, 0.6, 0.5] },
  41961. }
  41962. };
  41963. Object.defineProperty(ClassificationScheme, 'RANDOM', {
  41964. get: function() {
  41965. let scheme = {};
  41966. for(let i = 0; i <= 255; i++){
  41967. scheme[i] = new Vector4(Math.random(), Math.random(), Math.random());
  41968. }
  41969. scheme["DEFAULT"] = new Vector4(Math.random(), Math.random(), Math.random());
  41970. return scheme;
  41971. }
  41972. });
  41973. //
  41974. // how to calculate the radius of a projected sphere in screen space
  41975. // http://stackoverflow.com/questions/21648630/radius-of-projected-sphere-in-screen-space
  41976. // http://stackoverflow.com/questions/3717226/radius-of-projected-sphere
  41977. //
  41978. class PointCloudMaterial$1 extends RawShaderMaterial {
  41979. constructor (parameters = {}) {
  41980. super();
  41981. this.visibleNodesTexture = Utils.generateDataTexture(2048, 1, new Color(0xffffff));
  41982. this.visibleNodesTexture.minFilter = NearestFilter;
  41983. this.visibleNodesTexture.magFilter = NearestFilter;
  41984. let getValid = (a, b) => {
  41985. if(a !== undefined){
  41986. return a;
  41987. }else {
  41988. return b;
  41989. }
  41990. };
  41991. let pointSize = getValid(parameters.size, 1.0);
  41992. let minSize = getValid(parameters.minSize, 2.0);
  41993. let maxSize = getValid(parameters.maxSize, 1550.0);
  41994. let treeType = getValid(parameters.treeType, TreeType.OCTREE);
  41995. this._pointSizeType = PointSizeType.FIXED;
  41996. this._shape = PointShape.SQUARE;
  41997. this._useClipBox = false;
  41998. this.clipBoxes = [];
  41999. this.clipPolygons = [];
  42000. this._weighted = false;
  42001. this._gradient = Gradients.RAINBOW;//Gradients.SPECTRAL;//海拔贴图种类
  42002. this.gradientTexture = PointCloudMaterial$1.generateGradientTexture(this._gradient);
  42003. this._matcap = "matcap.jpg";
  42004. this.matcapTexture = Potree.PointCloudMaterial.generateMatcapTexture(this._matcap);
  42005. this.lights = false;
  42006. this.fog = false;
  42007. this._treeType = treeType;
  42008. this._useEDL = false;
  42009. this.defines = new Map();
  42010. this.ranges = new Map();
  42011. this._activeAttributeName = null;
  42012. this._defaultIntensityRangeChanged = false;
  42013. this._defaultElevationRangeChanged = false;
  42014. {
  42015. const [width, height] = [256, 1];
  42016. let data = new Uint8Array(width * 4);
  42017. let texture = new DataTexture(data, width, height, RGBAFormat);
  42018. texture.magFilter = NearestFilter;
  42019. texture.needsUpdate = true;
  42020. this.classificationTexture = texture;
  42021. }
  42022. this.attributes = {
  42023. position: { type: 'fv', value: [] },
  42024. color: { type: 'fv', value: [] },
  42025. normal: { type: 'fv', value: [] },
  42026. intensity: { type: 'f', value: [] },
  42027. classification: { type: 'f', value: [] },
  42028. returnNumber: { type: 'f', value: [] },
  42029. numberOfReturns: { type: 'f', value: [] },
  42030. pointSourceID: { type: 'f', value: [] },
  42031. indices: { type: 'fv', value: [] }
  42032. };
  42033. this.uniforms = {
  42034. level: { type: "f", value: 0.0 },
  42035. vnStart: { type: "f", value: 0.0 },
  42036. spacing: { type: "f", value: 1.0 },
  42037. blendHardness: { type: "f", value: 2.0 },
  42038. blendDepthSupplement: { type: "f", value: 0.0 },
  42039. fov: { type: "f", value: 1.0 },
  42040. /* screenWidth: { type: "f", value: 1.0 },
  42041. screenHeight: { type: "f", value: 1.0 }, */
  42042. resolution: { type: 'v2', value: new Vector2$1() },
  42043. near: { type: "f", value: 0.1 },
  42044. far: { type: "f", value: 1.0 },
  42045. uColor: { type: "c", value: new Color( 0xffffff ) },
  42046. uOpacity: { type: "f", value: 1.0 },
  42047. size: { type: "f", value: pointSize },
  42048. minSize: { type: "f", value: minSize },
  42049. maxSize: { type: "f", value: maxSize },
  42050. octreeSize: { type: "f", value: 0 },
  42051. bbSize: { type: "fv", value: [0, 0, 0] },
  42052. elevationRange: { type: "2fv", value: [0, 0] },
  42053. clipBoxCount: { type: "f", value: 0 },
  42054. //clipSphereCount: { type: "f", value: 0 },
  42055. clipPolygonCount: { type: "i", value: 0 },
  42056. clipBoxes: { type: "Matrix4fv", value: [] },
  42057. //clipSpheres: { type: "Matrix4fv", value: [] },
  42058. clipPolygons: { type: "3fv", value: [] },
  42059. clipPolygonVCount: { type: "iv", value: [] },
  42060. clipPolygonVP: { type: "Matrix4fv", value: [] },
  42061. visibleNodes: { type: "t", value: this.visibleNodesTexture },
  42062. pcIndex: { type: "f", value: 0 },
  42063. gradient: { type: "t", value: this.gradientTexture },
  42064. classificationLUT: { type: "t", value: this.classificationTexture },
  42065. uHQDepthMap: { type: "t", value: null },
  42066. toModel: { type: "Matrix4f", value: [] },
  42067. diffuse: { type: "fv", value: [1, 1, 1] },
  42068. transition: { type: "f", value: 0.5 },
  42069. intensityRange: { type: "fv", value: [Infinity, -Infinity] },
  42070. intensity_gbc: { type: "fv", value: [1, 0, 0]},
  42071. uRGB_gbc: { type: "fv", value: [1, 0, 0]},
  42072. // intensityGamma: { type: "f", value: 1 },
  42073. // intensityContrast: { type: "f", value: 0 },
  42074. // intensityBrightness:{ type: "f", value: 0 },
  42075. // rgbGamma: { type: "f", value: 1 },
  42076. // rgbContrast: { type: "f", value: 0 },
  42077. // rgbBrightness: { type: "f", value: 0 },
  42078. wRGB: { type: "f", value: 1 },
  42079. wIntensity: { type: "f", value: 0 },
  42080. wElevation: { type: "f", value: 0 },
  42081. wClassification: { type: "f", value: 0 },
  42082. wReturnNumber: { type: "f", value: 0 },
  42083. wSourceID: { type: "f", value: 0 },
  42084. useOrthographicCamera: { type: "b", value: false },
  42085. elevationGradientRepat: { type: "i", value: ElevationGradientRepeat.CLAMP },
  42086. clipTask: { type: "i", value: 1 },
  42087. clipMethod: { type: "i", value: 1 },
  42088. uShadowColor: { type: "3fv", value: [0, 0, 0] },
  42089. uExtraScale: { type: "f", value: 1},
  42090. uExtraOffset: { type: "f", value: 0},
  42091. uExtraRange: { type: "2fv", value: [0, 1] },
  42092. uExtraGammaBrightContr: { type: "3fv", value: [1, 0, 0] },
  42093. uFilterReturnNumberRange: { type: "fv", value: [0, 7]},
  42094. uFilterNumberOfReturnsRange: { type: "fv", value: [0, 7]},
  42095. uFilterGPSTimeClipRange: { type: "fv", value: [0, 7]},
  42096. uFilterPointSourceIDClipRange: { type: "fv", value: [0, 65535]},
  42097. matcapTextureUniform: { type: "t", value: this.matcapTexture },
  42098. backfaceCulling: { type: "b", value: false },
  42099. ////////////////add
  42100. //usePanoMap:{ type: "i", value: 0 },
  42101. progress: {
  42102. type: "f",
  42103. value: 0
  42104. },
  42105. easeInOutRatio:{
  42106. type: "f",
  42107. value: 0.3
  42108. },
  42109. pano0Map: {
  42110. type: "t",
  42111. value: null
  42112. },
  42113. pano0Position: {
  42114. type: "v3",
  42115. value: new Vector3
  42116. },
  42117. pano0Matrix: {
  42118. type: "m4",
  42119. value: new Matrix4
  42120. },
  42121. pano1Map: {
  42122. type: "t",
  42123. value: null
  42124. },
  42125. pano1Position: {
  42126. type: "v3",
  42127. value: new Vector3
  42128. },
  42129. pano1Matrix: {
  42130. type: "m4",
  42131. value: new Matrix4
  42132. },
  42133. };
  42134. this.classification = ClassificationScheme.DEFAULT;
  42135. this.defaultAttributeValues.normal = [0, 0, 0];
  42136. this.defaultAttributeValues.classification = [0, 0, 0];
  42137. this.defaultAttributeValues.indices = [0, 0, 0, 0];
  42138. this.vertexShader = Shaders['pointcloud.vs'];
  42139. this.fragmentShader = Shaders['pointcloud.fs'];
  42140. this.vertexColors = VertexColors;
  42141. this.updateShaderSource();
  42142. }
  42143. setDefine(key, value){
  42144. if(value !== undefined && value !== null){
  42145. if(this.defines.get(key) !== value){
  42146. this.defines.set(key, value);
  42147. this.updateShaderSource();
  42148. }
  42149. }else {
  42150. this.removeDefine(key);
  42151. }
  42152. }
  42153. removeDefine(key){
  42154. this.defines.delete(key);
  42155. }
  42156. updateShaderSource () {
  42157. let vs = Shaders['pointcloud.vs'];
  42158. let fs = Shaders['pointcloud.fs'];
  42159. let definesString = this.getDefines();
  42160. let vsVersionIndex = vs.indexOf("#version ");
  42161. let fsVersionIndex = fs.indexOf("#version ");
  42162. if(vsVersionIndex >= 0){
  42163. vs = vs.replace(/(#version .*)/, `$1\n${definesString}`);
  42164. }else {
  42165. vs = `${definesString}\n${vs}`;
  42166. }
  42167. if(fsVersionIndex >= 0){
  42168. fs = fs.replace(/(#version .*)/, `$1\n${definesString}`);
  42169. }else {
  42170. fs = `${definesString}\n${fs}`;
  42171. }
  42172. this.vertexShader = vs;
  42173. this.fragmentShader = fs;
  42174. if (this.opacity === 1.0 && !this.useFilterByNormal) {//add useFilterByNormal
  42175. this.blending = NoBlending;
  42176. this.transparent = false;
  42177. this.depthTest = true;
  42178. this.depthWrite = true;
  42179. this.depthFunc = LessEqualDepth;
  42180. } else if ( (this.opacity < 1.0 ||this.useFilterByNormal) && !this.useEDL) {//add useFilterByNormal
  42181. this.blending = AdditiveBlending;
  42182. this.transparent = true;
  42183. this.depthTest = false;
  42184. this.depthWrite = true;
  42185. this.depthFunc = AlwaysDepth;
  42186. }
  42187. if (this.weighted) {
  42188. this.blending = AdditiveBlending;
  42189. this.transparent = true;
  42190. this.depthTest = true;
  42191. this.depthWrite = false;
  42192. }
  42193. this.needsUpdate = true;
  42194. }
  42195. getDefines () {
  42196. let defines = [];
  42197. if (this.pointSizeType === PointSizeType.FIXED) {
  42198. defines.push('#define fixed_point_size');
  42199. } else if (this.pointSizeType === PointSizeType.ATTENUATED) {
  42200. defines.push('#define attenuated_point_size');
  42201. } else if (this.pointSizeType === PointSizeType.ADAPTIVE) {
  42202. defines.push('#define adaptive_point_size');
  42203. }
  42204. if(!Features.EXT_DEPTH.isSupported() && this.shape === PointShape.PARABOLOID){
  42205. this.shape = PointShape.SQUARE ;//强行替换
  42206. }
  42207. if (this.shape === PointShape.SQUARE) {
  42208. defines.push('#define square_point_shape');
  42209. } else if (this.shape === PointShape.CIRCLE) {
  42210. defines.push('#define circle_point_shape');
  42211. } else if (this.shape === PointShape.PARABOLOID) {
  42212. defines.push('#define paraboloid_point_shape');
  42213. }
  42214. //console.log('this.shape PARABOLOID', this.shape, this.shape === PointShape.PARABOLOID)
  42215. if (this._useEDL || this.fakeEDL) {
  42216. defines.push('#define use_edl');
  42217. }
  42218. if(this.activeAttributeName){
  42219. let attributeName = this.activeAttributeName.replace(/[^a-zA-Z0-9]/g, '_');
  42220. defines.push(`#define color_type_${attributeName}`);
  42221. }
  42222. if(this._treeType === TreeType.OCTREE){
  42223. defines.push('#define tree_type_octree');
  42224. }else if(this._treeType === TreeType.KDTREE){
  42225. defines.push('#define tree_type_kdtree');
  42226. }
  42227. if (this.weighted) {
  42228. defines.push('#define weighted_splats');
  42229. }
  42230. for(let [key, value] of this.defines){
  42231. defines.push(value);
  42232. }
  42233. return defines.join("\n");
  42234. }
  42235. setClipBoxes (clipBoxes) {
  42236. if (!clipBoxes) {
  42237. return;
  42238. }
  42239. let doUpdate = (this.clipBoxes.length !== clipBoxes.length) && (clipBoxes.length === 0 || this.clipBoxes.length === 0);
  42240. this.uniforms.clipBoxCount.value = this.clipBoxes.length;
  42241. this.clipBoxes = clipBoxes;
  42242. if (doUpdate) {
  42243. this.updateShaderSource();
  42244. }
  42245. this.uniforms.clipBoxes.value = new Float32Array(this.clipBoxes.length * 16);
  42246. for (let i = 0; i < this.clipBoxes.length; i++) {
  42247. let box = clipBoxes[i];
  42248. this.uniforms.clipBoxes.value.set(box.inverse.elements, 16 * i);
  42249. }
  42250. for (let i = 0; i < this.uniforms.clipBoxes.value.length; i++) {
  42251. if (Number.isNaN(this.uniforms.clipBoxes.value[i])) {
  42252. this.uniforms.clipBoxes.value[i] = Infinity;
  42253. }
  42254. }
  42255. }
  42256. setClipPolygons(clipPolygons, maxPolygonVertices) {
  42257. if(!clipPolygons){
  42258. return;
  42259. }
  42260. this.clipPolygons = clipPolygons;
  42261. let doUpdate = (this.clipPolygons.length !== clipPolygons.length);
  42262. if(doUpdate){
  42263. this.updateShaderSource();
  42264. }
  42265. }
  42266. get gradient(){
  42267. return this._gradient;
  42268. }
  42269. set gradient (value) {//海拔贴图
  42270. if (this._gradient !== value) {
  42271. this._gradient = value;
  42272. this.gradientTexture = PointCloudMaterial$1.generateGradientTexture(this._gradient);
  42273. this.uniforms.gradient.value = this.gradientTexture;
  42274. }
  42275. }
  42276. get matcap(){
  42277. return this._matcap;
  42278. }
  42279. set matcap (value) {
  42280. if (this._matcap !== value) {
  42281. this._matcap = value;
  42282. this.matcapTexture = Potree.PointCloudMaterial.generateMatcapTexture(this._matcap);
  42283. this.uniforms.matcapTextureUniform.value = this.matcapTexture;
  42284. }
  42285. }
  42286. get useOrthographicCamera() {
  42287. return this.uniforms.useOrthographicCamera.value;
  42288. }
  42289. set useOrthographicCamera(value) {
  42290. if(this.uniforms.useOrthographicCamera.value !== value){
  42291. this.uniforms.useOrthographicCamera.value = value;
  42292. }
  42293. }
  42294. get backfaceCulling() {
  42295. return this.uniforms.backfaceCulling.value;
  42296. }
  42297. set backfaceCulling(value) {
  42298. if(this.uniforms.backfaceCulling.value !== value){
  42299. this.uniforms.backfaceCulling.value = value;
  42300. this.dispatchEvent({type: 'backface_changed', target: this});
  42301. }
  42302. }
  42303. recomputeClassification () {
  42304. const classification = this.classification;
  42305. const data = this.classificationTexture.image.data;
  42306. let width = 256;
  42307. const black = [1, 1, 1, 1];
  42308. let valuesChanged = false;
  42309. for (let i = 0; i < width; i++) {
  42310. let color;
  42311. let visible = true;
  42312. if (classification[i]) {
  42313. color = classification[i].color;
  42314. visible = classification[i].visible;
  42315. } else if (classification[i % 32]) {
  42316. color = classification[i % 32].color;
  42317. visible = classification[i % 32].visible;
  42318. } else if(classification.DEFAULT) {
  42319. color = classification.DEFAULT.color;
  42320. visible = classification.DEFAULT.visible;
  42321. }else {
  42322. color = black;
  42323. }
  42324. const r = parseInt(255 * color[0]);
  42325. const g = parseInt(255 * color[1]);
  42326. const b = parseInt(255 * color[2]);
  42327. const a = visible ? parseInt(255 * color[3]) : 0;
  42328. if(data[4 * i + 0] !== r){
  42329. data[4 * i + 0] = r;
  42330. valuesChanged = true;
  42331. }
  42332. if(data[4 * i + 1] !== g){
  42333. data[4 * i + 1] = g;
  42334. valuesChanged = true;
  42335. }
  42336. if(data[4 * i + 2] !== b){
  42337. data[4 * i + 2] = b;
  42338. valuesChanged = true;
  42339. }
  42340. if(data[4 * i + 3] !== a){
  42341. data[4 * i + 3] = a;
  42342. valuesChanged = true;
  42343. }
  42344. }
  42345. if(valuesChanged){
  42346. this.classificationTexture.needsUpdate = true;
  42347. this.dispatchEvent({
  42348. type: 'material_property_changed',
  42349. target: this
  42350. });
  42351. }
  42352. }
  42353. get spacing () {
  42354. return this.uniforms.spacing.value;
  42355. }
  42356. set spacing (value) {
  42357. if (this.uniforms.spacing.value !== value) { // 即 uOctreeSpacing 来自cloud.js里
  42358. this.uniforms.spacing.value = value;
  42359. }
  42360. }
  42361. get useClipBox () {
  42362. return this._useClipBox;
  42363. }
  42364. set useClipBox (value) {
  42365. if (this._useClipBox !== value) {
  42366. this._useClipBox = value;
  42367. this.updateShaderSource();
  42368. }
  42369. }
  42370. get clipTask(){
  42371. return this.uniforms.clipTask.value;
  42372. }
  42373. set clipTask(mode){
  42374. this.uniforms.clipTask.value = mode;
  42375. }
  42376. get elevationGradientRepat(){
  42377. return this.uniforms.elevationGradientRepat.value;
  42378. }
  42379. set elevationGradientRepat(mode){
  42380. this.uniforms.elevationGradientRepat.value = mode;
  42381. }
  42382. get clipMethod(){
  42383. return this.uniforms.clipMethod.value;
  42384. }
  42385. set clipMethod(mode){
  42386. this.uniforms.clipMethod.value = mode;
  42387. }
  42388. get weighted(){
  42389. return this._weighted;
  42390. }
  42391. set weighted (value) {
  42392. if (this._weighted !== value) {
  42393. this._weighted = value;
  42394. this.updateShaderSource();
  42395. }
  42396. }
  42397. get fov () {
  42398. return this.uniforms.fov.value;
  42399. }
  42400. set fov (value) {
  42401. if (this.uniforms.fov.value !== value) {
  42402. this.uniforms.fov.value = value;
  42403. // this.updateShaderSource();
  42404. }
  42405. }
  42406. /* get screenWidth () {
  42407. return this.uniforms.screenWidth.value;
  42408. }
  42409. set screenWidth (value) {
  42410. if (this.uniforms.screenWidth.value !== value) {
  42411. this.uniforms.screenWidth.value = value;
  42412. // this.updateShaderSource();
  42413. }
  42414. }
  42415. get screenHeight () {
  42416. return this.uniforms.screenHeight.value;
  42417. }
  42418. set screenHeight (value) {
  42419. if (this.uniforms.screenHeight.value !== value) {
  42420. this.uniforms.screenHeight.value = value;
  42421. // this.updateShaderSource();
  42422. }
  42423. }*/
  42424. //add--------------
  42425. get resolution(){
  42426. return this.uniforms.resolution.value
  42427. }
  42428. set resolution(value){
  42429. this.uniforms.resolution.value.copy(value);
  42430. }
  42431. //--------------
  42432. get near () {
  42433. return this.uniforms.near.value;
  42434. }
  42435. set near (value) {
  42436. if (this.uniforms.near.value !== value) {
  42437. this.uniforms.near.value = value;
  42438. }
  42439. }
  42440. get far () {
  42441. return this.uniforms.far.value;
  42442. }
  42443. set far (value) {
  42444. if (this.uniforms.far.value !== value) {
  42445. this.uniforms.far.value = value;
  42446. }
  42447. }
  42448. get opacity(){
  42449. return this.uniforms.uOpacity.value;
  42450. }
  42451. set opacity (value) {
  42452. if (this.uniforms && this.uniforms.uOpacity) {
  42453. if (this.uniforms.uOpacity.value !== value) {
  42454. this.uniforms.uOpacity.value = value;
  42455. this.updateShaderSource();
  42456. this.dispatchEvent({
  42457. type: 'opacity_changed',
  42458. target: this
  42459. });
  42460. this.dispatchEvent({
  42461. type: 'material_property_changed',
  42462. target: this
  42463. });
  42464. }
  42465. }
  42466. }
  42467. get activeAttributeName(){
  42468. return this._activeAttributeName;
  42469. }
  42470. set activeAttributeName(value){
  42471. if (this._activeAttributeName !== value) {
  42472. this._activeAttributeName = value;
  42473. this.updateShaderSource();
  42474. this.dispatchEvent({
  42475. type: 'active_attribute_changed',
  42476. target: this
  42477. });
  42478. this.dispatchEvent({
  42479. type: 'material_property_changed',
  42480. target: this
  42481. });
  42482. }
  42483. }
  42484. get pointSizeType () {
  42485. return this._pointSizeType;
  42486. }
  42487. set pointSizeType (value) {
  42488. if(typeof value == 'string' )value = PointSizeType[value];
  42489. if (this._pointSizeType !== value) {
  42490. this._pointSizeType = value;
  42491. this.updateShaderSource(); //这句表明这个属性频繁更改会卡顿
  42492. this.dispatchEvent({
  42493. type: 'point_size_type_changed',
  42494. target: this
  42495. });
  42496. this.dispatchEvent({
  42497. type: 'material_property_changed',
  42498. target: this
  42499. });
  42500. }
  42501. }
  42502. get useEDL(){
  42503. return this._useEDL;
  42504. }
  42505. set useEDL (value) {
  42506. if (this._useEDL !== value) {
  42507. this._useEDL = value;
  42508. this.updateShaderSource();
  42509. }
  42510. }
  42511. get fakeEDL(){
  42512. return this._fakeEDL;
  42513. }
  42514. set fakeEDL (value) {//add
  42515. if (this._fakeEDL !== value) {
  42516. this._fakeEDL = value;
  42517. this.updateShaderSource();
  42518. }
  42519. }
  42520. get color () {
  42521. return this.uniforms.uColor.value;
  42522. }
  42523. set color (value) {//改
  42524. if(value == this.color_)return
  42525. let color = value;
  42526. //if (!this.uniforms.uColor.value.equals(value)) {
  42527. if(typeof value == 'string') {
  42528. var colorArr = Potree.config.colors[value];
  42529. if(!colorArr){
  42530. //console.warn('没找到该颜色值'+ value)
  42531. }else {
  42532. color = new Color().fromArray(colorArr).multiplyScalar(1/255);
  42533. }
  42534. }
  42535. this.uniforms.uColor.value.set(color);
  42536. //this.uniforms.uColor.value.copy(value);
  42537. this.dispatchEvent({
  42538. type: 'color_changed',
  42539. target: this
  42540. });
  42541. this.dispatchEvent({
  42542. type: 'material_property_changed',
  42543. target: this
  42544. });
  42545. //}
  42546. this.color_ = value; //记录下str
  42547. }
  42548. get shape () {
  42549. return this._shape;
  42550. }
  42551. set shape (value) {
  42552. if (this._shape !== value) {
  42553. this._shape = value;
  42554. this.updateShaderSource();
  42555. this.dispatchEvent({type: 'point_shape_changed', target: this});
  42556. this.dispatchEvent({
  42557. type: 'material_property_changed',
  42558. target: this
  42559. });
  42560. }
  42561. }
  42562. get treeType () {
  42563. return this._treeType;
  42564. }
  42565. set treeType (value) {
  42566. if (this._treeType !== value) {
  42567. this._treeType = value;
  42568. this.updateShaderSource();
  42569. }
  42570. }
  42571. get bbSize () {
  42572. return this.uniforms.bbSize.value;
  42573. }
  42574. set bbSize (value) {
  42575. this.uniforms.bbSize.value = value;
  42576. }
  42577. get size () {
  42578. return this.uniforms.size.value;
  42579. }
  42580. set size (value) {
  42581. if (this.uniforms.size.value !== value) {
  42582. this.uniforms.size.value = value;
  42583. this.dispatchEvent({
  42584. type: 'point_size_changed',
  42585. target: this
  42586. });
  42587. this.dispatchEvent({
  42588. type: 'material_property_changed',
  42589. target: this
  42590. });
  42591. }
  42592. }
  42593. get minSize(){
  42594. return this.uniforms.minSize.value;
  42595. }
  42596. set minSize(value){
  42597. if (this.uniforms.minSize.value !== value) {
  42598. this.uniforms.minSize.value = value;
  42599. this.dispatchEvent({
  42600. type: 'point_size_changed',
  42601. target: this
  42602. });
  42603. this.dispatchEvent({
  42604. type: 'material_property_changed',
  42605. target: this
  42606. });
  42607. }
  42608. }
  42609. get elevationRange () {
  42610. return this.uniforms.elevationRange.value;
  42611. }
  42612. set elevationRange (value) {
  42613. let changed = this.uniforms.elevationRange.value[0] !== value[0]
  42614. || this.uniforms.elevationRange.value[1] !== value[1];
  42615. if(changed){
  42616. this.uniforms.elevationRange.value = value;
  42617. this._defaultElevationRangeChanged = true;
  42618. this.dispatchEvent({
  42619. type: 'material_property_changed',
  42620. target: this
  42621. });
  42622. }
  42623. }
  42624. get heightMin () {
  42625. return this.uniforms.elevationRange.value[0];
  42626. }
  42627. set heightMin (value) {
  42628. this.elevationRange = [value, this.elevationRange[1]];
  42629. }
  42630. get heightMax () {
  42631. return this.uniforms.elevationRange.value[1];
  42632. }
  42633. set heightMax (value) {
  42634. this.elevationRange = [this.elevationRange[0], value];
  42635. }
  42636. get transition () {
  42637. return this.uniforms.transition.value;
  42638. }
  42639. set transition (value) {
  42640. this.uniforms.transition.value = value;
  42641. }
  42642. get intensityRange () {
  42643. return this.uniforms.intensityRange.value;
  42644. }
  42645. set intensityRange (value) {
  42646. if (!(value instanceof Array && value.length === 2)) {
  42647. return;
  42648. }
  42649. if (value[0] === this.uniforms.intensityRange.value[0] &&
  42650. value[1] === this.uniforms.intensityRange.value[1]) {
  42651. return;
  42652. }
  42653. this.uniforms.intensityRange.value = value;
  42654. this._defaultIntensityRangeChanged = true;
  42655. this.dispatchEvent({
  42656. type: 'material_property_changed',
  42657. target: this
  42658. });
  42659. }
  42660. get intensityGamma () {
  42661. return this.uniforms.intensity_gbc.value[0];
  42662. }
  42663. set intensityGamma (value) {
  42664. if (this.uniforms.intensity_gbc.value[0] !== value) {
  42665. this.uniforms.intensity_gbc.value[0] = value;
  42666. this.dispatchEvent({
  42667. type: 'material_property_changed',
  42668. target: this
  42669. });
  42670. }
  42671. }
  42672. get intensityContrast () {
  42673. return this.uniforms.intensity_gbc.value[2];
  42674. }
  42675. set intensityContrast (value) {
  42676. if (this.uniforms.intensity_gbc.value[2] !== value) {
  42677. this.uniforms.intensity_gbc.value[2] = value;
  42678. this.dispatchEvent({
  42679. type: 'material_property_changed',
  42680. target: this
  42681. });
  42682. }
  42683. }
  42684. get intensityBrightness () {
  42685. return this.uniforms.intensity_gbc.value[1];
  42686. }
  42687. set intensityBrightness (value) {
  42688. if (this.uniforms.intensity_gbc.value[1] !== value) {
  42689. this.uniforms.intensity_gbc.value[1] = value;
  42690. this.dispatchEvent({
  42691. type: 'material_property_changed',
  42692. target: this
  42693. });
  42694. }
  42695. }
  42696. get rgbGamma () {
  42697. return this.uniforms.uRGB_gbc.value[0];
  42698. }
  42699. set rgbGamma (value) {
  42700. if (this.uniforms.uRGB_gbc.value[0] !== value) {
  42701. this.uniforms.uRGB_gbc.value[0] = value;
  42702. this.dispatchEvent({
  42703. type: 'material_property_changed',
  42704. target: this
  42705. });
  42706. }
  42707. }
  42708. get rgbContrast () {
  42709. return this.uniforms.uRGB_gbc.value[2];
  42710. }
  42711. set rgbContrast (value) {
  42712. if (this.uniforms.uRGB_gbc.value[2] !== value) {
  42713. this.uniforms.uRGB_gbc.value[2] = value;
  42714. this.dispatchEvent({
  42715. type: 'material_property_changed',
  42716. target: this
  42717. });
  42718. }
  42719. }
  42720. get rgbBrightness () {
  42721. return this.uniforms.uRGB_gbc.value[1];
  42722. }
  42723. set rgbBrightness (value) {
  42724. if (this.uniforms.uRGB_gbc.value[1] !== value) {
  42725. this.uniforms.uRGB_gbc.value[1] = value;
  42726. this.dispatchEvent({
  42727. type: 'material_property_changed',
  42728. target: this
  42729. });
  42730. }
  42731. }
  42732. get extraGamma () {
  42733. return this.uniforms.uExtraGammaBrightContr.value[0];
  42734. }
  42735. set extraGamma (value) {
  42736. if (this.uniforms.uExtraGammaBrightContr.value[0] !== value) {
  42737. this.uniforms.uExtraGammaBrightContr.value[0] = value;
  42738. this.dispatchEvent({
  42739. type: 'material_property_changed',
  42740. target: this
  42741. });
  42742. }
  42743. }
  42744. get extraBrightness () {
  42745. return this.uniforms.uExtraGammaBrightContr.value[1];
  42746. }
  42747. set extraBrightness (value) {
  42748. if (this.uniforms.uExtraGammaBrightContr.value[1] !== value) {
  42749. this.uniforms.uExtraGammaBrightContr.value[1] = value;
  42750. this.dispatchEvent({
  42751. type: 'material_property_changed',
  42752. target: this
  42753. });
  42754. }
  42755. }
  42756. get extraContrast () {
  42757. return this.uniforms.uExtraGammaBrightContr.value[2];
  42758. }
  42759. set extraContrast (value) {
  42760. if (this.uniforms.uExtraGammaBrightContr.value[2] !== value) {
  42761. this.uniforms.uExtraGammaBrightContr.value[2] = value;
  42762. this.dispatchEvent({
  42763. type: 'material_property_changed',
  42764. target: this
  42765. });
  42766. }
  42767. }
  42768. getRange(attributeName){
  42769. return this.ranges.get(attributeName);
  42770. }
  42771. setRange(attributeName, newRange){
  42772. let rangeChanged = false;
  42773. let oldRange = this.ranges.get(attributeName);
  42774. if(oldRange != null && newRange != null){
  42775. rangeChanged = oldRange[0] !== newRange[0] || oldRange[1] !== newRange[1];
  42776. }else {
  42777. rangeChanged = true;
  42778. }
  42779. this.ranges.set(attributeName, newRange);
  42780. if(rangeChanged){
  42781. this.dispatchEvent({
  42782. type: 'material_property_changed',
  42783. target: this
  42784. });
  42785. }
  42786. }
  42787. get extraRange () {
  42788. return this.uniforms.uExtraRange.value;
  42789. }
  42790. set extraRange (value) {
  42791. if (!(value instanceof Array && value.length === 2)) {
  42792. return;
  42793. }
  42794. if (value[0] === this.uniforms.uExtraRange.value[0] &&
  42795. value[1] === this.uniforms.uExtraRange.value[1]) {
  42796. return;
  42797. }
  42798. this.uniforms.uExtraRange.value = value;
  42799. this._defaultExtraRangeChanged = true;
  42800. this.dispatchEvent({
  42801. type: 'material_property_changed',
  42802. target: this
  42803. });
  42804. }
  42805. get weightRGB () {
  42806. return this.uniforms.wRGB.value;
  42807. }
  42808. set weightRGB (value) {
  42809. if(this.uniforms.wRGB.value !== value){
  42810. this.uniforms.wRGB.value = value;
  42811. this.dispatchEvent({
  42812. type: 'material_property_changed',
  42813. target: this
  42814. });
  42815. }
  42816. }
  42817. get weightIntensity () {
  42818. return this.uniforms.wIntensity.value;
  42819. }
  42820. set weightIntensity (value) {
  42821. if(this.uniforms.wIntensity.value !== value){
  42822. this.uniforms.wIntensity.value = value;
  42823. this.dispatchEvent({
  42824. type: 'material_property_changed',
  42825. target: this
  42826. });
  42827. }
  42828. }
  42829. get weightElevation () {
  42830. return this.uniforms.wElevation.value;
  42831. }
  42832. set weightElevation (value) {
  42833. if(this.uniforms.wElevation.value !== value){
  42834. this.uniforms.wElevation.value = value;
  42835. this.dispatchEvent({
  42836. type: 'material_property_changed',
  42837. target: this
  42838. });
  42839. }
  42840. }
  42841. get weightClassification () {
  42842. return this.uniforms.wClassification.value;
  42843. }
  42844. set weightClassification (value) {
  42845. if(this.uniforms.wClassification.value !== value){
  42846. this.uniforms.wClassification.value = value;
  42847. this.dispatchEvent({
  42848. type: 'material_property_changed',
  42849. target: this
  42850. });
  42851. }
  42852. }
  42853. get weightReturnNumber () {
  42854. return this.uniforms.wReturnNumber.value;
  42855. }
  42856. set weightReturnNumber (value) {
  42857. if(this.uniforms.wReturnNumber.value !== value){
  42858. this.uniforms.wReturnNumber.value = value;
  42859. this.dispatchEvent({
  42860. type: 'material_property_changed',
  42861. target: this
  42862. });
  42863. }
  42864. }
  42865. get weightSourceID () {
  42866. return this.uniforms.wSourceID.value;
  42867. }
  42868. set weightSourceID (value) {
  42869. if(this.uniforms.wSourceID.value !== value){
  42870. this.uniforms.wSourceID.value = value;
  42871. this.dispatchEvent({
  42872. type: 'material_property_changed',
  42873. target: this
  42874. });
  42875. }
  42876. }
  42877. static generateGradientTexture (gradient) {
  42878. let size = 64;
  42879. // create canvas
  42880. let canvas = document.createElement('canvas');
  42881. canvas.width = size;
  42882. canvas.height = size;
  42883. // get context
  42884. let context = canvas.getContext('2d');
  42885. // draw gradient
  42886. context.rect(0, 0, size, size);
  42887. let ctxGradient = context.createLinearGradient(0, 0, size, size);
  42888. for (let i = 0; i < gradient.length; i++) {
  42889. let step = gradient[i];
  42890. ctxGradient.addColorStop(step[0], '#' + step[1].getHexString());
  42891. }
  42892. context.fillStyle = ctxGradient;
  42893. context.fill();
  42894. //let texture = new THREE.Texture(canvas);
  42895. let texture = new CanvasTexture(canvas);
  42896. texture.needsUpdate = true;
  42897. texture.minFilter = LinearFilter;
  42898. texture.wrap = RepeatWrapping;
  42899. texture.repeat = 2;
  42900. // textureImage = texture.image;
  42901. return texture;
  42902. }
  42903. static generateMatcapTexture (matcap) {
  42904. var url = new URL(Potree.resourcePath + "/textures/matcap/" + matcap).href;
  42905. let texture = new TextureLoader().load( url );
  42906. texture.magFilter = texture.minFilter = LinearFilter;
  42907. texture.needsUpdate = true;
  42908. // PotreeConverter_1.6_2018_07_29_windows_x64\PotreeConverter.exe autzen_xyzrgbXYZ_ascii.xyz -f xyzrgbXYZ -a RGB NORMAL -o autzen_xyzrgbXYZ_ascii_a -p index --overwrite
  42909. // Switch matcap texture on the fly : viewer.scene.pointclouds[0].material.matcap = 'matcap1.jpg';
  42910. // For non power of 2, use LinearFilter and dont generate mipmaps, For power of 2, use NearestFilter and generate mipmaps : matcap2.jpg 1 2 8 11 12 13
  42911. return texture;
  42912. }
  42913. disableEvents(){
  42914. if(this._hiddenListeners === undefined){
  42915. this._hiddenListeners = this._listeners;
  42916. this._listeners = {};
  42917. }
  42918. };
  42919. enableEvents(){
  42920. this._listeners = this._hiddenListeners;
  42921. this._hiddenListeners = undefined;
  42922. };
  42923. ////////////////////////add
  42924. setProjectedPanos(pano0, pano1, progressValue, easeInOutRatio){
  42925. //this.uniforms.usePanoMap.value = 1
  42926. this.usePanoMap = true;
  42927. progressValue!=void 0 && (this.uniforms.progress.value = progressValue);
  42928. //pano0.ensureSkyboxReadyForRender();
  42929. this.uniforms.pano0Map.value = pano0.getSkyboxTexture();
  42930. this.uniforms.pano0Position.value.copy(pano0.position);
  42931. this.uniforms.pano0Matrix.value.copy(pano0.panoMatrix );
  42932. //pano1.ensureSkyboxReadyForRender();
  42933. this.uniforms.easeInOutRatio.value = easeInOutRatio || 0; //之前做点云和全景混合时加的,为了让点云颜色柔和切换到全景颜色。如不混合就0
  42934. this.uniforms.pano1Map.value = pano1.getSkyboxTexture();
  42935. this.uniforms.pano1Position.value.copy(pano1.position);
  42936. this.uniforms.pano1Matrix.value.copy(pano1.panoMatrix );
  42937. //this.updateShaderSource()
  42938. //this.needsUpdate = true;
  42939. }
  42940. stopProjectedPanos(){
  42941. //this.uniforms.usePanoMap.value = 0
  42942. this.usePanoMap = false;
  42943. }
  42944. // copyFrom(from){
  42945. // var a = 10;
  42946. // for(let name of Object.keys(this.uniforms)){
  42947. // this.uniforms[name].value = from.uniforms[name].value;
  42948. // }
  42949. // }
  42950. // copy(from){
  42951. // this.copyFrom(from);
  42952. // }
  42953. }
  42954. var Common = {
  42955. sortByScore: function(list, request, rank){
  42956. var i = request ? Common.filterAll(list, request) : list;
  42957. return 0 === i.length ? null : i = i.map(function(e) {
  42958. return {
  42959. item: e,
  42960. score: rank.reduce(function(t, i) {
  42961. return t + i(e)
  42962. }, 0)
  42963. }
  42964. }).sort(function(e, t) {
  42965. return t.score - e.score;
  42966. })
  42967. }
  42968. ,
  42969. filterAll: function(e, t) {
  42970. return e.filter(function (e) {
  42971. return t.every(function (t) {
  42972. return t(e)
  42973. })
  42974. })
  42975. },
  42976. //---------------
  42977. find : function(list, request, rank, sortByScore ) {
  42978. if(sortByScore){
  42979. var r = this.sortByScore(list, request, rank);
  42980. return r && r[0] && r[0].item
  42981. }else {
  42982. var i = request ? Common.filterAll(list, request) : list;
  42983. return 0 === i.length ? null : (rank && rank.forEach(function(e) {
  42984. i = Common.stableSort(i, e);
  42985. }),
  42986. i[0])
  42987. }
  42988. }
  42989. ,
  42990. stableSort: function(e, f) {//用到排序函数,涉及到两个item相减
  42991. return e.map(function(e, i) {
  42992. return {
  42993. value: e,
  42994. index: i
  42995. }
  42996. }).sort(function(e, u) {
  42997. var n = f(e.value, u.value);
  42998. return 0 !== n ? n : e.index - u.index //似乎就是加多了这一步:若差距为0,按照原顺序
  42999. }).map(function(e) {
  43000. return e.value
  43001. })
  43002. },
  43003. average: function (e, t) {
  43004. if (0 === e.length)
  43005. return null;
  43006. for (var i = 0, n = 0, r = 0; r < e.length; r++) {
  43007. var o = t ? e[r][t] : e[r];
  43008. i += o,
  43009. n++;
  43010. }
  43011. return i / n
  43012. },
  43013. //---------------------------
  43014. getMixedSet : function(arr1, arr2){//交集
  43015. return arr1.filter(item=>arr2.includes(item));
  43016. },
  43017. getUnionSet : function(arr1, arr2){//并集
  43018. return arr1.concat(arr2.filter(item=>!arr1.includes(item)))
  43019. },
  43020. getDifferenceSet : function(arr1, arr2){//差集 不能识别重复的,如getDifferenceSet([1,2,2],[1,1,2]) 为空
  43021. var arr11 = arr1.filter(item=>!arr2.includes(item));
  43022. var arr22 = arr2.filter(item=>!arr1.includes(item));
  43023. return arr11.concat(arr22)
  43024. },
  43025. getDifferenceSetMuti : function(arr){//收集绝对没有重复的元素,也就是判断出现次数=1的
  43026. var set = [];
  43027. arr.forEach(arr1=>{
  43028. arr1.forEach(item=>{
  43029. var index = set.indexOf(item);
  43030. if(index>-1){
  43031. set.splice(index, 1);
  43032. }else {
  43033. set.push(item);
  43034. }
  43035. });
  43036. });
  43037. return set;
  43038. }
  43039. ,
  43040. CloneJson : function(data){
  43041. var str = JSON.stringify(data);
  43042. return JSON.parse(str)
  43043. }
  43044. ,
  43045. CloneObject : function(copyObj, result, isSimpleCopy, simpleCopyList=[]) {
  43046. //isSimpleCopy 只复制最外层
  43047. //复制json result的可能:普通数字或字符串、普通数组、复杂对象
  43048. simpleCopyList.push(Object3D); //遇到simpleCopyList中的类直接使用不拷贝
  43049. if(!copyObj || typeof copyObj == 'number' || typeof copyObj == 'string' || copyObj instanceof Function || simpleCopyList.some(className => copyObj instanceof className)){
  43050. return copyObj
  43051. }
  43052. result = result || {};
  43053. if (copyObj instanceof Array) {
  43054. return copyObj.map(e=>{
  43055. return this.CloneObject(e)
  43056. })
  43057. }else {
  43058. if(copyObj.clone instanceof Function ){ //解决一部分
  43059. return copyObj.clone()
  43060. }
  43061. }
  43062. for (var key in copyObj) {
  43063. if (copyObj[key] instanceof Object && !isSimpleCopy)
  43064. result[key] = this.CloneObject(copyObj[key]);
  43065. else
  43066. result[key] = copyObj[key];
  43067. //如果是函数类同基本数据,即复制引用
  43068. }
  43069. return result;
  43070. }
  43071. ,
  43072. CloneClassObject :function(copyObj ){//复杂类对象
  43073. var newobj = new copyObj.constructor();
  43074. this.CopyClassObject(newobj, copyObj);
  43075. return newobj
  43076. }
  43077. ,
  43078. CopyClassObject :function(targetObj, copyObj){//复杂类对象
  43079. for(let i in copyObj){
  43080. if(i in copyObj.__proto__)break; //到函数了跳出
  43081. targetObj[i] = this.CloneObject(copyObj[i], null );
  43082. /* else if(copyObj[i].clone instanceof Function ){
  43083. targetObj[i] = copyObj[i].clone()
  43084. }else{
  43085. targetObj[i] = copyObj[i];
  43086. } */
  43087. }
  43088. }
  43089. ,
  43090. ifSame : function(object1, object2){
  43091. if(object1 == object2 )return true // 0 != undefined , 0 == ''
  43092. else if(!object1 || !object2) return false
  43093. else if(object1.constructor != object2.constructor){
  43094. return false
  43095. }else if(object1 instanceof Array ) {
  43096. if(object1.length != object2.length)return false;
  43097. var _object2 = object2.slice(0);
  43098. for(let i=0;i<object1.length;i++){
  43099. var u = _object2.find(e=>ifSame(object1[i], e));
  43100. if(u == void 0 && !_object2.includes(u) && !object1.includes(u))return false;
  43101. else {
  43102. let index = _object2.indexOf(u);
  43103. _object2.splice(index,1);
  43104. }
  43105. }
  43106. return true
  43107. }else if(object1.equals instanceof Function ){//复杂数据仅支持这种,其他的可能卡住?
  43108. return object1.equals(object2)
  43109. }else if(typeof object1 == 'number' || typeof object1 == 'string'){
  43110. if(isNaN(object1) && isNaN(object2))return true
  43111. else return object1 == object2
  43112. }else if(typeof object1 == "object"){
  43113. var keys1 = Object.keys(object1);
  43114. var keys2 = Object.keys(object2);
  43115. if(!ifSame(keys1,keys2))return false;
  43116. for(let i in object1){
  43117. var same = ifSame(object1[i], object2[i]);
  43118. if(!same)return false
  43119. }
  43120. return true
  43121. }else {
  43122. console.log('isSame出现例外');
  43123. }
  43124. }
  43125. ,
  43126. replaceAll : function (str, f, e) {
  43127. //f全部替换成e
  43128. var reg = new RegExp(f, "g"); //创建正则RegExp对象
  43129. return str.replace(reg, e);
  43130. }
  43131. ,
  43132. downloadFile : function(data, filename, cb) {
  43133. var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
  43134. save_link.href = data;
  43135. save_link.download = filename;
  43136. var event = document.createEvent('MouseEvents');
  43137. event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  43138. save_link.dispatchEvent(event);
  43139. cb && cb();
  43140. },
  43141. intervalTool:{ //延时update,防止卡顿
  43142. list:[],
  43143. isWaiting:function(name, func, delayTime){
  43144. if(!this.list.includes(name)){ //如果没有该项, 则开始判断
  43145. var needWait = func(); //触发了改变,则等待一段时间后再自动判断
  43146. if(needWait){
  43147. this.list.push(name);
  43148. setTimeout(()=>{
  43149. var a = this.list.indexOf(name);
  43150. this.list.splice(a,1);
  43151. this.isWaiting(name, func, delayTime); //循环
  43152. },delayTime);
  43153. }
  43154. }
  43155. },
  43156. /* wait:function(name, delayTime){
  43157. this.list.push(name);
  43158. setTimeout(()=>{
  43159. },delayTime)
  43160. }, */
  43161. }
  43162. ,
  43163. pushToGroupAuto : function(items, groups, recognizeFunction){//自动分组。 items是将分到一起的组合。items.length = 1 or 2.
  43164. recognizeFunction = recognizeFunction || function(){};
  43165. var atGroups = groups.filter(group=>group.find(
  43166. item => items[0] == item || recognizeFunction(item, items[0]) || items[1] == item || items[1] && recognizeFunction(item, items[1])
  43167. ));
  43168. if(atGroups.length){//在不同组
  43169. //因为items是一组的,所以先都放入组1
  43170. items.forEach(item=> {if(!atGroups[0].includes(item)) atGroups[0].push(item);});
  43171. if(atGroups.length>1){//如果在不同组,说明这两个组需要合并
  43172. var combineGroup = [];
  43173. atGroups.forEach(group=>{
  43174. combineGroup = Common.getUnionSet(combineGroup, group);
  43175. groups.splice(groups.indexOf(group),1);
  43176. });
  43177. groups.push(combineGroup);
  43178. }
  43179. }else {//直接加入为一组
  43180. groups.push(items);
  43181. }
  43182. },
  43183. addOrRemoveDefine(material, defineName, type, value=''){
  43184. let defines = material.defines;
  43185. if(type == 'add'){
  43186. if(defines[defineName] != void 0 && defines[defineName] == value)return
  43187. defines[defineName] = value;
  43188. }else {
  43189. if(defines[defineName] != void 0)return;
  43190. delete defines[defineName];
  43191. }
  43192. material.needsUpdate = true;
  43193. },
  43194. makeTexDontResize(map){//避免贴图因非2的次方而缩小。小心使用
  43195. if(!map || map.image && MathUtils.isPowerOfTwo(map.image.width ) && MathUtils.isPowerOfTwo(map.image.height ))return
  43196. map.wrapS = map.wrapT = ClampToEdgeWrapping; //原默认 RepeatWrapping
  43197. map.minFilter = LinearFilter; // or THREE.NearestFilter 原默认 LinearMipmapLinearFilter
  43198. }
  43199. };
  43200. const planeGeo = new PlaneBufferGeometry(1,1);
  43201. const planeMats$1 = new Map();
  43202. let getPlaneMat = (group, removed)=>{
  43203. let mat = planeMats$1.get(group);
  43204. if(mat)return mat
  43205. var planeMat = new MeshBasicMaterial({
  43206. //color: level == 'removed' ? "#f00" : new THREE.Color(1 - level*0.2, 1,1),
  43207. color: (new Color()).setHSL(Math.random(), 0.5, 0.9) ,
  43208. //color: (new THREE.Color()).setHSL(removed ? 0 : 0.6, Math.random(), 0.9/* Math.random() */) ,
  43209. transparent:true,
  43210. side:2,
  43211. opacity: removed ? 0.3 : 0.9,
  43212. });
  43213. planeMats$1.set(group, planeMat);
  43214. return planeMat
  43215. };
  43216. class PointCloudOctreeNode extends PointCloudTreeNode {
  43217. constructor () {
  43218. super();
  43219. //this.children = {};
  43220. this.children = [];
  43221. this.sceneNode = null;
  43222. this.octree = null;
  43223. }
  43224. getNumPoints () {
  43225. return this.geometryNode.numPoints;
  43226. }
  43227. isLoaded () {
  43228. return true;
  43229. }
  43230. isTreeNode () {
  43231. return true;
  43232. }
  43233. isGeometryNode () {
  43234. return false;
  43235. }
  43236. getLevel () {
  43237. return this.geometryNode.level;
  43238. }
  43239. getBoundingSphere () {
  43240. return this.geometryNode.boundingSphere;
  43241. }
  43242. getBoundingBox () {
  43243. return this.geometryNode.boundingBox;
  43244. }
  43245. getChildren () {
  43246. let children = [];
  43247. for (let i = 0; i < 8; i++) {
  43248. if (this.children[i]) {
  43249. children.push(this.children[i]);
  43250. }
  43251. }
  43252. return children;
  43253. }
  43254. getPointsInBox(boxNode){
  43255. if(!this.sceneNode){
  43256. return null;
  43257. }
  43258. let buffer = this.geometryNode.buffer;
  43259. let posOffset = buffer.offset("position");
  43260. let stride = buffer.stride;
  43261. let view = new DataView(buffer.data);
  43262. let worldToBox = boxNode.matrixWorld.clone().invert();
  43263. let objectToBox = new Matrix4().multiplyMatrices(worldToBox, this.sceneNode.matrixWorld);
  43264. let inBox = [];
  43265. let pos = new Vector4();
  43266. for(let i = 0; i < buffer.numElements; i++){
  43267. let x = view.getFloat32(i * stride + posOffset + 0, true);
  43268. let y = view.getFloat32(i * stride + posOffset + 4, true);
  43269. let z = view.getFloat32(i * stride + posOffset + 8, true);
  43270. pos.set(x, y, z, 1);
  43271. pos.applyMatrix4(objectToBox);
  43272. if(-0.5 < pos.x && pos.x < 0.5){
  43273. if(-0.5 < pos.y && pos.y < 0.5){
  43274. if(-0.5 < pos.z && pos.z < 0.5){
  43275. pos.set(x, y, z, 1).applyMatrix4(this.sceneNode.matrixWorld);
  43276. inBox.push(new Vector3(pos.x, pos.y, pos.z));
  43277. }
  43278. }
  43279. }
  43280. }
  43281. return inBox;
  43282. }
  43283. get name () {
  43284. return this.geometryNode.name;
  43285. }
  43286. };
  43287. class PointCloudOctree extends PointCloudTree {
  43288. constructor (geometry, material) {
  43289. super();
  43290. //this.pointBudget = Infinity;
  43291. this.pcoGeometry = geometry;
  43292. this.boundingBox = this.pcoGeometry.tightBoundingBox;//this.pcoGeometry.boundingBox; //boundingBox是正方体,所以换掉
  43293. this.boundingSphere = this.boundingBox.getBoundingSphere(new Sphere());
  43294. this.material = material || new PointCloudMaterial$1();
  43295. this.visiblePointsTarget = 2 * 1000 * 1000;
  43296. this.minimumNodePixelSize = 150;
  43297. this.level = 0;
  43298. this.position.copy(geometry.offset);
  43299. this.updateMatrix();
  43300. this.nodeMaxLevel = 0;//add
  43301. this.maxLevel = Infinity;
  43302. this.temp = { sizeFitToLevel:{}, opacity:{}};//add
  43303. //add
  43304. this.panos = [];
  43305. this.matrixAutoUpdate = false; //最好禁止updateMatrix 直接使用matrixWorld
  43306. this.orientationUser = 0;
  43307. this.translateUser = new Vector3;
  43308. this.rotateMatrix = new Matrix4;
  43309. this.transformMatrix = new Matrix4;// 数据集的变化矩阵
  43310. this.transformInvMatrix = new Matrix4;
  43311. this.rotateInvMatrix = new Matrix4;
  43312. this.nodeMaxLevelPredict = this.predictNodeMaxLevel();//预测maxNodeLevel
  43313. this.testMaxNodeCount = this.testMaxNodeCount2 = 0;
  43314. this.material.spacing = this.pcoGeometry.spacing;//初始化一下 以便于设置pointsize
  43315. {
  43316. let priorityQueue = ["rgba", "rgb", "intensity", "classification"];
  43317. let selected = "rgba";
  43318. for(let attributeName of priorityQueue){
  43319. let attribute = this.pcoGeometry.pointAttributes.attributes.find(a => a.name === attributeName);
  43320. if(!attribute){
  43321. continue;
  43322. }
  43323. let min = attribute.range[0].constructor.name === "Array" ? attribute.range[0] : [attribute.range[0]];
  43324. let max = attribute.range[1].constructor.name === "Array" ? attribute.range[1] : [attribute.range[1]];
  43325. let range_min = new Vector3(...min);
  43326. let range_max = new Vector3(...max);
  43327. let range = range_min.distanceTo(range_max);
  43328. if(range === 0){
  43329. continue;
  43330. }
  43331. selected = attributeName;
  43332. break;
  43333. }
  43334. this.material.activeAttributeName = selected;
  43335. }
  43336. this.showBoundingBox = false;
  43337. this.boundingBoxNodes = [];
  43338. this.loadQueue = [];
  43339. this.visibleBounds = new Box3();
  43340. this.visibleNodes = [];
  43341. this.visibleGeometry = [];
  43342. this.generateDEM = false;
  43343. this.profileRequests = [];
  43344. this.name = '';
  43345. this._visible = true;
  43346. //this._isVisible = true//add
  43347. //this.unvisibleReasons = []
  43348. {
  43349. let box = [this.pcoGeometry.tightBoundingBox, this.getBoundingBoxWorld()]
  43350. .find(v => v !== undefined);
  43351. this.updateMatrixWorld(true);
  43352. box = Utils.computeTransformedBoundingBox(box, this.matrixWorld);
  43353. let bMin = box.min.z;
  43354. let bMax = box.max.z;
  43355. this.material.heightMin = bMin;
  43356. this.material.heightMax = bMax;
  43357. }
  43358. // TODO read projection from file instead
  43359. this.projection = geometry.projection;
  43360. this.fallbackProjection = geometry.fallbackProjection;
  43361. this.root = this.pcoGeometry.root;
  43362. this.pcoGeometry.addEventListener('updateNodeMaxLevel', this.updateNodeMaxLevel.bind(this));
  43363. this.isPointcloud = true; //add
  43364. }
  43365. /*
  43366. 注释:node的level从最大的box 0开始。
  43367. 且加载任意一个node必定也会加载它的所有祖先。(如visibleNodes中有一个level为4,则一定有3,2,1,0)
  43368. visibleNodes就是所有可见的node,比如:
  43369. 如果相机在0这个位置朝下,这时候的visibleNodes中只有一个level为0的node;
  43370. 而如果朝上看,上方的几个node如果在视野中占据足够大的位置的话,就会加载。
  43371. 如果相机在2这个位置朝上,这时候的visibleNodes中所包含的level为: 0,1,2
  43372. ________________
  43373. | | | |
  43374. |__2| | |
  43375. | 1 | 1 |
  43376. |_______|_______|
  43377. | |
  43378. | |
  43379. | 0 |
  43380. |_______________|
  43381. 查看box可在potree中开启
  43382. */
  43383. updateNodeMaxLevel(e){//目前点云包含node的最高level
  43384. var level = Math.max(e.level, this.nodeMaxLevel);
  43385. if(level != this.nodeMaxLevel){
  43386. this.nodeMaxLevel = level;
  43387. //viewer.dispatchEvent({type:'updateNodeMaxLevel', pointcloud: this, nodeMaxLevel:level})
  43388. console.log('updateNodeMaxLevel ' + this.dataset_id + " : "+ this.nodeMaxLevel);
  43389. this.setPointLevel();//重新计算
  43390. if(!Potree.settings.sizeFitToLevel){
  43391. this.changePointSize();
  43392. }
  43393. }
  43394. }//注:在没有加载到真实的 nodeMaxLevel之前,点云会显示得偏大
  43395. //panoEdit时比预测值小很多?
  43396. testMaxNodeLevel(){//手动使maxLevel达到最高,从而迫使updateNodeMaxLevel。 因为Potree.settings.pointDensity 不为 'high'时,maxLevel不是所加载的最高,就很容易加载不出下一个层级,导致无法知道nodeMaxLevel
  43397. if(this.testMaxNodeLevelDone ) return
  43398. //if(this.nodeMaxLevel > this.nodeMaxLevelPredict.min )return
  43399. if( this.nodeMaxLevel==0 )return true
  43400. if( !viewer.atDatasets.includes(this))return true //否则老远就count++
  43401. let levels = this.visibleNodes.map(e=>e.getLevel());
  43402. let actMaxLevel = Math.max.apply(null, levels); //实际加载到的最高的node level
  43403. if(actMaxLevel < this.maxLevel)return true// 还没加载到能加载到的最高。 但在细节设置较低时,排除作用微弱。
  43404. //尝试加载出更高级的level
  43405. let old = this.maxLevel;
  43406. this.maxLevel = 12;
  43407. //var visibleNodes1 = this.visibleNodes.map(e=>e.getLevel())
  43408. //console.log('visibleNodes1',visibleNodes1)
  43409. Potree.updatePointClouds([this], viewer.scene.getActiveCamera(), viewer.mainViewport.resolution );
  43410. //不在camera可视范围内还是加载不出来。即使临时修改位置
  43411. var visibleNodes2 = this.visibleNodes.map(e=>e.getLevel());
  43412. //console.log('visibleNodes2',visibleNodes2)
  43413. this.maxLevel = old;
  43414. this.testMaxNodeCount ++;
  43415. if(this.testMaxNodeCount > 500){
  43416. console.log('testMaxNodeLevel次数超出,强制结束:',this.dataset_id, this.nodeMaxLevel, this.nodeMaxLevelPredict.min);
  43417. this.testMaxNodeLevelDone = 'moreThanMaxCount';
  43418. return; //在可以看见点云的情况下,超时,有可能是预测的max是错的
  43419. }
  43420. if(this.nodeMaxLevel < this.nodeMaxLevelPredict.min) return true //仍需要继续testMaxNodeLevel
  43421. this.testMaxNodeCount2 ++; // 已经> this.nodeMaxLevelPredict.min 后,开始计数。因为min可能低于真实nodeMaxLevel所以要再试几次
  43422. /* if(this.name == 'SS-t-CWmVgzP4XU'){
  43423. console.log('SS-t-CWmVgzP4XU count++')
  43424. } */
  43425. if(this.testMaxNodeCount2 < 50) return true //再试几次 ( 主要是细节调得低时需要多测几次才加载到
  43426. this.testMaxNodeLevelDone = true;
  43427. }
  43428. setPointLevel(){
  43429. var pointDensity = Potree.settings.pointDensity;
  43430. var config = Potree.config.pointDensity[pointDensity];
  43431. if(!config)return
  43432. /* if(this.testingMaxLevel){
  43433. this.maxLevel = 12;//先加载到最大的直到测试完毕。由于5个level为一组来加载,所以如果写4最高能加载到5,如果写5最高能加载到下一个级别的最高也就是10
  43434. //console.log('maxLevel: '+e.maxLevel + ' testingMaxLevel中 ' )
  43435. }else{ */
  43436. let percent = config.percentByUser && Potree.settings.UserDensityPercent != void 0 ? Potree.settings.UserDensityPercent : config.maxLevelPercent;
  43437. this.maxLevel = Math.round( percent * this.nodeMaxLevel);
  43438. //console.log('maxLevel: '+e.maxLevel + ', density : '+Potree.settings.pointDensity, ", percent :"+percent);
  43439. if(Potree.settings.sizeFitToLevel){
  43440. this.changePointSize();
  43441. }
  43442. this.changePointOpacity();
  43443. //}
  43444. }
  43445. //预测可能的nodeMaxLevel:
  43446. predictNodeMaxLevel(){//预测maxNodeLevel。 可能只适用于我们相机拍的点云
  43447. let spacing = {min:0.005, max:0.014};//最小节的两点间的距离 ,获得方法:spacing / Math.pow(2, nodeMaxLevel)。 目前观测的我们自己拍的这个数值的范围大概是这样
  43448. let min = Math.log2(this.material.spacing / spacing.max); //有见过最大是0.01368
  43449. let max = Math.log2(this.material.spacing / spacing.min); //大部分是 0.006
  43450. //console.log('predictNodeMaxLevel:', this.name , min, max )
  43451. return {min, max}
  43452. }
  43453. getHighestNodeSpacing(){
  43454. return this.material.spacing / Math.pow(2, this.nodeMaxLevel) //前提是这个nodeMaxLevel是准确的
  43455. }
  43456. setName (name) {
  43457. if (this.name !== name) {
  43458. this.name = name;
  43459. this.dispatchEvent({type: 'name_changed', name: name, pointcloud: this});
  43460. }
  43461. }
  43462. getName () {
  43463. return this.name;
  43464. }
  43465. getAttribute(name){
  43466. const attribute = this.pcoGeometry.pointAttributes.attributes.find(a => a.name === name);
  43467. if(attribute){
  43468. return attribute;
  43469. }else {
  43470. return null;
  43471. }
  43472. }
  43473. getAttributes(){
  43474. return this.pcoGeometry.pointAttributes;
  43475. }
  43476. toTreeNode (geometryNode, parent) {
  43477. let node = new PointCloudOctreeNode();
  43478. // if(geometryNode.name === "r40206"){
  43479. // console.log("creating node for r40206");
  43480. // }
  43481. let sceneNode = new Points(geometryNode.geometry, this.material); //好像没什么用
  43482. sceneNode.name = geometryNode.name;
  43483. sceneNode.position.copy(geometryNode.boundingBox.min);
  43484. sceneNode.frustumCulled = false;
  43485. sceneNode.onBeforeRender = (_this, scene, camera, geometry, material, group) => {
  43486. if (material.program) {
  43487. _this.getContext().useProgram(material.program.program);
  43488. if (material.program.getUniforms().map.level) {
  43489. let level = geometryNode.getLevel();
  43490. material.uniforms.level.value = level;
  43491. material.program.getUniforms().map.level.setValue(_this.getContext(), level);
  43492. }
  43493. if (this.visibleNodeTextureOffsets && material.program.getUniforms().map.vnStart) {
  43494. let vnStart = this.visibleNodeTextureOffsets.get(node);
  43495. material.uniforms.vnStart.value = vnStart;
  43496. material.program.getUniforms().map.vnStart.setValue(_this.getContext(), vnStart);
  43497. }
  43498. if (material.program.getUniforms().map.pcIndex) {
  43499. let i = node.pcIndex ? node.pcIndex : this.visibleNodes.indexOf(node);
  43500. material.uniforms.pcIndex.value = i;
  43501. material.program.getUniforms().map.pcIndex.setValue(_this.getContext(), i);
  43502. }
  43503. }
  43504. };
  43505. // { // DEBUG
  43506. // let sg = new THREE.SphereGeometry(1, 16, 16);
  43507. // let sm = new THREE.MeshNormalMaterial();
  43508. // let s = new THREE.Mesh(sg, sm);
  43509. // s.scale.set(5, 5, 5);
  43510. // s.position.copy(geometryNode.mean)
  43511. // .add(this.position)
  43512. // .add(geometryNode.boundingBox.min);
  43513. //
  43514. // viewer.scene.scene.add(s);
  43515. // }
  43516. node.geometryNode = geometryNode;
  43517. node.sceneNode = sceneNode;
  43518. node.pointcloud = this;
  43519. node.children = [];
  43520. //for (let key in geometryNode.children) {
  43521. // node.children[key] = geometryNode.children[key];
  43522. //}
  43523. for(let i = 0; i < 8; i++){
  43524. node.children[i] = geometryNode.children[i];
  43525. }
  43526. if (!parent) {
  43527. this.root = node;
  43528. this.add(sceneNode);
  43529. } else {
  43530. let childIndex = parseInt(geometryNode.name[geometryNode.name.length - 1]);
  43531. parent.sceneNode.add(sceneNode);
  43532. parent.children[childIndex] = node;
  43533. }
  43534. let disposeListener = function () {
  43535. let childIndex = parseInt(geometryNode.name[geometryNode.name.length - 1]);
  43536. parent.sceneNode.remove(node.sceneNode);
  43537. parent.children[childIndex] = geometryNode;
  43538. };
  43539. geometryNode.oneTimeDisposeHandlers.push(disposeListener);
  43540. //this.buildTexMesh(geometryNode,sceneNode)
  43541. return node;
  43542. }
  43543. buildTexMesh11(geometryNode,sceneNode){
  43544. // viewer.scene.pointclouds.forEach(a=>a.areaPlanes.forEach(e=>e.material = viewer.images360.cube.material))
  43545. //还是无法避免不在同一个平面的点被识别到同一个面上,然后法向都算错了。 另外还有就是破面太多。虽然能算出地板也不错。或者只去算水平面和垂直面。
  43546. let startTime = Date.now();
  43547. if(!this.splitSprites){
  43548. let splitSprites = new Object3D;
  43549. splitSprites.name = 'splitSprites_'+this.name;
  43550. splitSprites.matrixAutoUpdate = false; //同pointcloud一样不自动更新,直接使用
  43551. splitSprites.matrix.copy(this.matrix);
  43552. splitSprites.matrixWorld.copy(this.matrixWorld);
  43553. this.splitSprites = splitSprites;
  43554. viewer.scene.scene.add(splitSprites);
  43555. this.areaPlanes = [];
  43556. }
  43557. if(this.texMeshUseLevel == void 0 || geometryNode.level == this.texMeshUseLevel){//只需要某一层level的点
  43558. let showPointLabel = true, showCenterLabel = false;
  43559. //let spritesGeo = new THREE.BufferGeometry();
  43560. let scaleRatio = 1.4; //稍微放大些,填满缝隙
  43561. let spriteWidth1 = this.material.spacing / Math.pow(2, geometryNode.level);
  43562. if(spriteWidth1 > 3)return
  43563. let spriteWidth = spriteWidth1 * scaleRatio;
  43564. if(this.texMeshUseLevel == void 0 ){
  43565. this.texMeshUseLevel = geometryNode.level;
  43566. console.log('texMeshUseLevel ',geometryNode.level);
  43567. }
  43568. let geometry = geometryNode.geometry;
  43569. let count = geometry.attributes.position.count;
  43570. let end = Math.min(count, 6000);
  43571. let start = Math.min(5000, end);
  43572. console.warn('check points count:', end-start);
  43573. let position = geometry.attributes.position.array;
  43574. let normal = geometry.attributes.normal.array;
  43575. let i;
  43576. let up = new Vector3(0,1,0) , zeroVec = new Vector3; //up写成z向上居然结果一样
  43577. let positions = [];
  43578. let normals = [];
  43579. let newPositions = [];
  43580. let newIndices = [];
  43581. let groupMaxPointCount = 1000 ;//太多找环会崩
  43582. let minDisSquare = Math.pow(spriteWidth1 * 1.8 , 2 ); //这个数太小就连不上啦 1.65太小
  43583. let minDot = Math.cos(MathUtils.degToRad(5));//括号内是最小偏差角度, 20太大。太大的话会将立方体的相邻两面视为一个面。
  43584. //根据相邻点位置和角度是否相近来分组。有风险:两大区域可能因为一个模棱两可中间点连接在一起。
  43585. let closeGroups = [];
  43586. let groupTolerateMaxPoint = 6;//组内点<=这个数的最后会被删除
  43587. let removedCount = 0;
  43588. let useGroupCount = 0;
  43589. let splitSprites = new Object3D;
  43590. splitSprites.name = 'sub_splitSprites_'+geometryNode.name;
  43591. splitSprites.position.copy(sceneNode.position);
  43592. splitSprites.rotation.copy(sceneNode.rotation);
  43593. this.splitSprites.add(splitSprites);
  43594. for(i=start;i<end;i++){
  43595. let pos = new Vector3(position[3*i], position[3*i+1], position[3*i+2] );
  43596. let nor = new Vector3(normal[3*i],normal[3*i+1],normal[3*i+2]);
  43597. pos.nor = nor;
  43598. pos.index = i;
  43599. positions.push(pos);
  43600. normals.push(nor);
  43601. let groups = closeGroups.filter(group=>{
  43602. if(group.length>groupMaxPointCount)return //满员了
  43603. var hasClosed = group.some(p=>{
  43604. var dis = p.distanceToSquared(pos);
  43605. var dot = p.nor.dot(nor);
  43606. if(dis<minDisSquare && dot>minDot){
  43607. //return dis / minDisSquare + (Math.abs(p.nor.x - nor.x) + Math.abs(p.nor.y - nor.y) + Math.abs(p.nor.z - nor.z)) < 1.7
  43608. return dis / minDisSquare - p.nor.dot(nor) < 0
  43609. }
  43610. });
  43611. return hasClosed
  43612. });
  43613. if(groups.length == 0){//创建一个新的
  43614. var newGroup = [];
  43615. closeGroups.push(newGroup);
  43616. groups = [newGroup];
  43617. }
  43618. if(groups.length == 1){//直接加入原有的
  43619. pos.belongTo = groups[0];
  43620. }else if(groups.length>1){ // comebine多个组成一个
  43621. let newBigGroup = [];
  43622. groups.forEach(e=>{
  43623. newBigGroup.push(...e);
  43624. let index = closeGroups.indexOf(e);
  43625. closeGroups.splice(index, 1);
  43626. });
  43627. closeGroups.push(newBigGroup);
  43628. pos.belongTo = newBigGroup;
  43629. newBigGroup.forEach(e=>{e.belongTo = newBigGroup;});
  43630. }
  43631. pos.belongTo.push(pos);
  43632. }
  43633. closeGroups.forEach((points,index)=>{//建造面
  43634. if(points.length <= groupTolerateMaxPoint ){
  43635. /* let sprite = new THREE.Mesh(planeGeo, getPlaneMat(pos.belongTo, true))
  43636. sprite.lookAt(nor);
  43637. sprite.position.copy(pos)
  43638. sprite.scale.set(spriteWidth,spriteWidth,spriteWidth)
  43639. sprite.name = geometryNode.name+'_index'+i
  43640. splitSprites.add(sprite)
  43641. removedCount ++; */
  43642. removedCount += points.length;
  43643. return
  43644. }
  43645. useGroupCount ++;
  43646. points.sort(function(a,b){
  43647. return a.index - b.index
  43648. });
  43649. console.log(`开始解析 ${geometryNode.name} - 第${index}组,总第${points[0].index}个点,组内有${points.length}个点`);
  43650. let planeMat = getPlaneMat(points, true);
  43651. if(showPointLabel){
  43652. points.forEach((p,i)=>{
  43653. var label = new TextSprite({
  43654. text : index+"-"+i+" ("+p.index+")"+geometryNode.name, dontFixOrient:true,
  43655. backgroundColor: {r: planeMat.color.r*255, g: planeMat.color.g*255, b: planeMat.color.b*255, a:0.6},
  43656. });
  43657. label.lookAt(p.nor);
  43658. label.position.copy(p);
  43659. label.scale.set(spriteWidth/3, spriteWidth/3, spriteWidth/3);
  43660. splitSprites.add(label);
  43661. /* let sprite = new THREE.Mesh(planeGeo,planeMat)
  43662. sprite.lookAt(p.nor);
  43663. sprite.position.copy(p)
  43664. sprite.scale.set(spriteWidth/3,spriteWidth/3,spriteWidth/3)
  43665. sprite.name = geometryNode.name+'_group'+index+"_"+ i
  43666. splitSprites.add(sprite) */
  43667. });
  43668. }
  43669. var avePos = points.reduce(function(total, currentValue){
  43670. return total.add(currentValue)
  43671. }, new Vector3).multiplyScalar(1/points.length);
  43672. let planeNormals = [];
  43673. {//获得planeNormals
  43674. //随机找两个距离远的点算normal。 按距离排序后, //抽取若干个点,然后算两两之间的法线,其中距离远的多抽取几个。
  43675. var sortPoints = points.slice(0).sort(function(a,b){
  43676. return a.distanceToSquared(avePos) - b.distanceToSquared(avePos)
  43677. });//从小到大
  43678. var pickPoints;
  43679. var length = sortPoints.length;
  43680. if(length>=7){
  43681. var ratio = [0.02,0.15,0.4,0.55,0.7,0.86,0.99];
  43682. var index = ratio.map(e=>Math.round(e * (length-1)));
  43683. //console.log('index ',index)
  43684. pickPoints = index.map(e=>sortPoints[e]);
  43685. }else {
  43686. pickPoints = sortPoints;
  43687. }
  43688. //console.log('pickPoints', pickPoints)
  43689. let num = pickPoints.length;
  43690. for(let i=0;i<num;i++){//任意一个三角形能算出一个normal
  43691. for(let j=i+1;j<num;j++){
  43692. for(let u=j+1;u<num;u++){
  43693. var p1 = pickPoints[i];
  43694. var p2 = pickPoints[j];
  43695. var p3 = pickPoints[u];
  43696. let vec1 = new Vector3().subVectors(p1,p3);
  43697. let vec2 = new Vector3().subVectors(p2,p3);
  43698. let nor = vec1.cross(vec2).normalize();
  43699. if(planeNormals[0]){
  43700. if(nor.dot(planeNormals[0])<0)nor.negate(); //反向下
  43701. }
  43702. console.log('nor',nor);
  43703. planeNormals.push(nor);
  43704. }
  43705. }
  43706. }
  43707. }
  43708. var aveNor = planeNormals.reduce(function(total, currentValue){
  43709. return total.add(currentValue)
  43710. }, new Vector3).normalize();
  43711. console.log('aveNor',aveNor, 'avePos' ,avePos, index);
  43712. if(showCenterLabel){
  43713. var label = new TextSprite({
  43714. //index+"-"+i+" ("+p.index+")"+geometryNode.name
  43715. text : `我是${index}组 ${geometryNode.name} 中心点`, dontFixOrient:true,
  43716. backgroundColor: {r: planeMat.color.r*255, g: planeMat.color.g*255, b: planeMat.color.b*255, a:0.6},
  43717. });
  43718. label.lookAt(aveNor);
  43719. label.position.copy(avePos);
  43720. label.scale.set(spriteWidth, spriteWidth, spriteWidth);
  43721. splitSprites.add(label);
  43722. }
  43723. var facePlane = new Plane().setFromNormalAndCoplanarPoint(aveNor, avePos );
  43724. var coplanarPoints = points.map(p=> facePlane.projectPoint(p, new Vector3() ));
  43725. var originPoint0 = coplanarPoints[0].clone();
  43726. var qua = math.getQuaBetween2Vector(facePlane.normal, new Vector3(0,0,1), new Vector3(0,0,1));
  43727. let points2d = coplanarPoints.map(e=>e.clone().applyQuaternion(qua));
  43728. let quaInverse = qua.clone().invert();
  43729. //--------------------
  43730. let lines = [];
  43731. points2d.forEach((p,j)=>{
  43732. p.id = j;
  43733. for(let i=0;i<j;i++){
  43734. if(p.distanceToSquared(points2d[i])<minDisSquare*1.5){
  43735. lines.push({p1:i,p2:j});
  43736. }
  43737. }
  43738. });
  43739. console.log('points count:',points2d.length, 'lines:',lines);
  43740. var rings = searchRings({
  43741. points:points2d,
  43742. lines,
  43743. onlyGetOutRing:true,
  43744. precision: Math.max(spriteWidth1/10, 0.01)
  43745. });
  43746. console.log( 'rings:', rings );//mesh间可能重叠 但换上贴图材质应该看不出(但只要searchRings时getSliceLines就不会重叠)
  43747. if(!rings)return
  43748. let planeMat2 = planeMat.clone(); planeMat2.opacity = 0.5;
  43749. var firstPos = points2d[0].clone();
  43750. firstPos.z = 0; //因为shape只读取了xy,所以位移下, 再算出最终位置,得到差距
  43751. firstPos.applyQuaternion(quaInverse);
  43752. var vec = originPoint0.clone().sub(firstPos);
  43753. rings.forEach(ring=>{
  43754. var shapeGeo = MeshDraw.getShapeGeo(ring.points);
  43755. var areaPlane = new Mesh(shapeGeo, planeMat2);
  43756. areaPlane.quaternion.copy(quaInverse);
  43757. areaPlane.position.copy(vec);
  43758. areaPlane.name = 'areaPlane_'+index;
  43759. splitSprites.add(areaPlane);
  43760. this.areaPlanes.push(areaPlane);
  43761. });
  43762. });
  43763. console.log(geometryNode.name, '中:');
  43764. console.log('removed point count: ', removedCount/* splitSprites.children.length */);
  43765. console.log(closeGroups);
  43766. console.log('comebine mesh Len:', useGroupCount);
  43767. /*
  43768. spritesGeo.setAttribute('position', new THREE.Float32BufferAttribute(new Float32Array(newPositions), 3));
  43769. spritesGeo.setIndex( newIndices );
  43770. let sprites = new THREE.Mesh(spritesGeo, getPlaneMat('use'))
  43771. sprites.name = geometryNode.name
  43772. sprites.position.copy(sceneNode.position)
  43773. sprites.rotation.copy(sceneNode.rotation)
  43774. sceneNode.sprites = sprites
  43775. sprites.pointsNode = sceneNode
  43776. if(geometryNode.level == 0){
  43777. let root = new THREE.Object3D;
  43778. root.name = 'spriteNodeRoot'
  43779. root.matrixAutoUpdate = false //同pointcloud一样不自动更新,直接使用
  43780. root.matrix.copy(this.matrix)
  43781. root.matrixWorld.copy(this.matrixWorld)
  43782. viewer.scene.scene.add(root)
  43783. this.spriteNodeRoot = root
  43784. }
  43785. this.spriteNodeRoot.add(sprites) */
  43786. console.log('computeTime: ' + (Date.now() - startTime));
  43787. }
  43788. //------------------
  43789. /*
  43790. viewer.scene.pointclouds[0].spriteNodeRoot.traverse(e=>e.material && (e.material = viewer.images360.cube.material))
  43791. viewer.scene.scene.children[12].visible = false
  43792. */
  43793. }
  43794. buildTexMesh(geometryNode,sceneNode){
  43795. if(geometryNode.level <= 0){
  43796. let startTime = Date.now();
  43797. let splitSprites = new Object3D;
  43798. splitSprites.name = 'splitSprites_'+geometryNode.name;
  43799. splitSprites.matrixAutoUpdate = false; //同pointcloud一样不自动更新,直接使用
  43800. splitSprites.matrix.copy(this.matrix);
  43801. splitSprites.matrixWorld.copy(this.matrixWorld);
  43802. viewer.scene.scene.add(splitSprites);
  43803. let spritesGeo = new BufferGeometry();
  43804. let scaleRatio = 1.4; //稍微放大些,填满缝隙
  43805. let spriteWidth1 = this.material.spacing / Math.pow(2, geometryNode.level);
  43806. let spriteWidth = spriteWidth1 * scaleRatio;
  43807. console.log('spriteWidth:',spriteWidth);
  43808. const removeChip = false;
  43809. let geometry = geometryNode.geometry;
  43810. let count = geometry.attributes.position.count;
  43811. //count = 4000
  43812. let position = geometry.attributes.position.array;
  43813. let normal = geometry.attributes.normal.array;
  43814. let i;
  43815. let up = new Vector3(0,1,0) , zeroVec = new Vector3; //up写成z向上居然结果一样
  43816. let positions = [];
  43817. let normals = [];
  43818. let newPositions = [];
  43819. //let newNormals = [];
  43820. let newIndices = [];
  43821. let cornerPoints = [new Vector3(-1,1,0),new Vector3(1,1,0),new Vector3(-1,-1,0),new Vector3(1,-1,0) ];
  43822. let indices = [0, 2, 1, 2, 3, 1];
  43823. cornerPoints.forEach(e=>e.multiplyScalar(spriteWidth/2));
  43824. let minDisSquare = spriteWidth1 * spriteWidth1 * 1.5;
  43825. let closeGroups = [];
  43826. let groupTolerateMaxPoint = 4;//组内点<=这个数的最后会被删除
  43827. let removedCount = 0;
  43828. for(i=0;i<count;i++){
  43829. let pos = new Vector3(position[3*i], position[3*i+1], position[3*i+2] );
  43830. let nor = new Vector3(normal[3*i],normal[3*i+1],normal[3*i+2]);
  43831. pos.nor = nor;
  43832. positions.push(pos);
  43833. normals.push(nor);
  43834. if(removeChip){
  43835. let groups = closeGroups.filter(group=>{
  43836. var hasClosed = group.some(p=>{
  43837. var dis = p.distanceToSquared(pos);
  43838. if(dis<minDisSquare){
  43839. //return dis / minDisSquare + (Math.abs(p.nor.x - nor.x) + Math.abs(p.nor.y - nor.y) + Math.abs(p.nor.z - nor.z)) < 1.7
  43840. return dis / minDisSquare - p.nor.dot(nor) < 0
  43841. }
  43842. });
  43843. return hasClosed
  43844. });
  43845. if(groups.length == 0){//创建一个新的
  43846. var newGroup = [];
  43847. closeGroups.push(newGroup);
  43848. groups = [newGroup];
  43849. }
  43850. if(groups.length == 1){//直接加入原有的
  43851. pos.belongTo = groups[0];
  43852. }else if(groups.length>1){ // comebine多个组成一个
  43853. let newBigGroup = [];
  43854. groups.forEach(e=>{
  43855. newBigGroup.push(...e);
  43856. let index = closeGroups.indexOf(e);
  43857. closeGroups.splice(index, 1);
  43858. });
  43859. closeGroups.push(newBigGroup);
  43860. pos.belongTo = newBigGroup;
  43861. newBigGroup.forEach(e=>{e.belongTo = newBigGroup;});
  43862. }
  43863. pos.belongTo.push(pos);
  43864. }
  43865. }
  43866. for(i=0;i<count;i++){
  43867. let pos = positions[i];
  43868. let nor = normals[i];
  43869. if(Math.abs(nor.z)>0.2)continue
  43870. if(removeChip){
  43871. if(pos.belongTo.length <= groupTolerateMaxPoint){
  43872. let sprite = new Mesh(planeGeo, getPlaneMat(pos.belongTo, true));
  43873. sprite.lookAt(nor);
  43874. sprite.position.copy(pos);
  43875. sprite.scale.set(spriteWidth,spriteWidth,spriteWidth);
  43876. sprite.name = geometryNode.name+'_index'+i;
  43877. splitSprites.add(sprite);
  43878. removedCount ++;
  43879. continue
  43880. }else {
  43881. /*
  43882. let sprite = new THREE.Mesh(planeGeo, getPlaneMat(pos.belongTo))
  43883. sprite.lookAt(nor);
  43884. sprite.position.copy(pos)
  43885. sprite.scale.set(spriteWidth/3,spriteWidth/3,spriteWidth/3)
  43886. sprite.name = geometryNode.name+'_index'+i
  43887. splitSprites.add(sprite)
  43888. */
  43889. }
  43890. }
  43891. let matrix = (new Matrix4).lookAt( nor, zeroVec, up);
  43892. matrix.elements[12] = pos.x;
  43893. matrix.elements[13] = pos.y;
  43894. matrix.elements[14] = pos.z;
  43895. cornerPoints.forEach(p=>{
  43896. let point = p.clone();
  43897. point.applyMatrix4(matrix);
  43898. newPositions.push(...point.toArray());
  43899. //newNormals
  43900. });
  43901. indices.forEach(index=>{
  43902. newIndices.push(index + i*4);
  43903. });
  43904. }
  43905. /* closeGroups.forEach(e=>{
  43906. if(e.length <= groupTolerateMaxPoint )return
  43907. }) */
  43908. console.log('removed count: ', removedCount/* splitSprites.children.length */);
  43909. console.log(closeGroups);
  43910. console.log('computeTime: ' + (Date.now() - startTime));
  43911. spritesGeo.setAttribute('position', new Float32BufferAttribute(new Float32Array(newPositions), 3));
  43912. spritesGeo.setIndex( newIndices );
  43913. let sprites = new Mesh(spritesGeo, getPlaneMat('use'));
  43914. sprites.name = geometryNode.name;
  43915. sprites.position.copy(sceneNode.position);
  43916. sprites.rotation.copy(sceneNode.rotation);
  43917. sceneNode.sprites = sprites;
  43918. sprites.pointsNode = sceneNode;
  43919. if(geometryNode.level == 0){
  43920. let root = new Object3D;
  43921. root.name = 'spriteNodeRoot';
  43922. root.matrixAutoUpdate = false; //同pointcloud一样不自动更新,直接使用
  43923. root.matrix.copy(this.matrix);
  43924. root.matrixWorld.copy(this.matrixWorld);
  43925. viewer.scene.scene.add(root);
  43926. this.spriteNodeRoot = root;
  43927. }
  43928. this.spriteNodeRoot.add(sprites);
  43929. viewer.setObjectLayers(sprites,'sceneObjects');
  43930. }
  43931. }
  43932. updateVisibleBounds () {
  43933. let leafNodes = [];
  43934. for (let i = 0; i < this.visibleNodes.length; i++) {
  43935. let node = this.visibleNodes[i];
  43936. let isLeaf = true;
  43937. for (let j = 0; j < node.children.length; j++) {
  43938. let child = node.children[j];
  43939. if (child instanceof PointCloudOctreeNode) {
  43940. isLeaf = isLeaf && !child.sceneNode.visible;
  43941. } else if (child instanceof PointCloudOctreeGeometryNode) {
  43942. isLeaf = true;
  43943. }
  43944. }
  43945. if (isLeaf) {
  43946. leafNodes.push(node);
  43947. }
  43948. }
  43949. this.visibleBounds.min = new Vector3(Infinity, Infinity, Infinity);
  43950. this.visibleBounds.max = new Vector3(-Infinity, -Infinity, -Infinity);
  43951. for (let i = 0; i < leafNodes.length; i++) {
  43952. let node = leafNodes[i];
  43953. this.visibleBounds.expandByPoint(node.getBoundingBox().min);
  43954. this.visibleBounds.expandByPoint(node.getBoundingBox().max);
  43955. }
  43956. }
  43957. updateMaterial (material, visibleNodes, camera, renderer, resolution) {
  43958. material.fov = camera.fov * (Math.PI / 180);
  43959. /* material.screenWidth = renderer.domElement.clientWidth;
  43960. material.screenHeight = renderer.domElement.clientHeight; */
  43961. material.resolution = resolution;
  43962. //material.spacing = this.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z); //应该不需要
  43963. material.near = camera.near;
  43964. material.far = camera.far;
  43965. material.uniforms.octreeSize.value = this.pcoGeometry.boundingBox.getSize(new Vector3()).x;
  43966. }
  43967. computeVisibilityTextureData(nodes, camera){
  43968. if(Potree.measureTimings) performance.mark("computeVisibilityTextureData-start");
  43969. let data = new Uint8Array(nodes.length * 4);
  43970. let visibleNodeTextureOffsets = new Map();
  43971. // copy array
  43972. nodes = nodes.slice();
  43973. // sort by level and index, e.g. r, r0, r3, r4, r01, r07, r30, ...
  43974. let sort = function (a, b) {
  43975. let na = a.geometryNode.name;
  43976. let nb = b.geometryNode.name;
  43977. if (na.length !== nb.length) return na.length - nb.length;
  43978. if (na < nb) return -1;
  43979. if (na > nb) return 1;
  43980. return 0;
  43981. };
  43982. nodes.sort(sort);
  43983. let worldDir = new Vector3();
  43984. let nodeMap = new Map();
  43985. let offsetsToChild = new Array(nodes.length).fill(Infinity);
  43986. for(let i = 0; i < nodes.length; i++){
  43987. let node = nodes[i];
  43988. nodeMap.set(node.name, node);
  43989. visibleNodeTextureOffsets.set(node, i);
  43990. if(i > 0){
  43991. let index = parseInt(node.name.slice(-1));
  43992. let parentName = node.name.slice(0, -1);
  43993. let parent = nodeMap.get(parentName);
  43994. let parentOffset = visibleNodeTextureOffsets.get(parent);
  43995. let parentOffsetToChild = (i - parentOffset);
  43996. offsetsToChild[parentOffset] = Math.min(offsetsToChild[parentOffset], parentOffsetToChild);
  43997. data[parentOffset * 4 + 0] = data[parentOffset * 4 + 0] | (1 << index);
  43998. data[parentOffset * 4 + 1] = (offsetsToChild[parentOffset] >> 8);
  43999. data[parentOffset * 4 + 2] = (offsetsToChild[parentOffset] % 256);
  44000. }
  44001. let density = node.geometryNode.density;
  44002. if(typeof density === "number"){
  44003. let lodOffset = Math.log2(density) / 2 - 1.5;
  44004. let offsetUint8 = (lodOffset + 10) * 10;
  44005. data[i * 4 + 3] = offsetUint8;
  44006. }else {
  44007. data[i * 4 + 3] = 100;
  44008. }
  44009. }
  44010. if(Potree.measureTimings){
  44011. performance.mark("computeVisibilityTextureData-end");
  44012. performance.measure("render.computeVisibilityTextureData", "computeVisibilityTextureData-start", "computeVisibilityTextureData-end");
  44013. }
  44014. return {
  44015. data: data,
  44016. offsets: visibleNodeTextureOffsets
  44017. };
  44018. }
  44019. nodeIntersectsProfile (node, profile) {
  44020. let bbWorld = node.boundingBox.clone().applyMatrix4(this.matrixWorld);
  44021. let bsWorld = bbWorld.getBoundingSphere(new Sphere());
  44022. let intersects = false;
  44023. for (let i = 0; i < profile.points.length - 1; i++) {
  44024. let start = new Vector3(profile.points[i + 0].x, profile.points[i + 0].y, bsWorld.center.z);
  44025. let end = new Vector3(profile.points[i + 1].x, profile.points[i + 1].y, bsWorld.center.z);
  44026. let closest = new Line3(start, end).closestPointToPoint(bsWorld.center, true, new Vector3());
  44027. let distance = closest.distanceTo(bsWorld.center);
  44028. intersects = intersects || (distance < (bsWorld.radius + profile.width));
  44029. }
  44030. //console.log(`${node.name}: ${intersects}`);
  44031. return intersects;
  44032. }
  44033. deepestNodeAt(position){
  44034. const toObjectSpace = this.matrixWorld.clone().invert();
  44035. const objPos = position.clone().applyMatrix4(toObjectSpace);
  44036. let current = this.root;
  44037. while(true){
  44038. let containingChild = null;
  44039. for(const child of current.children){
  44040. if(child !== undefined){
  44041. if(child.getBoundingBox().containsPoint(objPos)){
  44042. containingChild = child;
  44043. }
  44044. }
  44045. }
  44046. if(containingChild !== null && containingChild instanceof PointCloudOctreeNode){
  44047. current = containingChild;
  44048. }else {
  44049. break;
  44050. }
  44051. }
  44052. const deepest = current;
  44053. return deepest;
  44054. }
  44055. nodesOnRay (nodes, ray) {
  44056. let nodesOnRay = [];
  44057. let _ray = ray.clone();
  44058. for (let i = 0; i < nodes.length; i++) {
  44059. let node = nodes[i];
  44060. let sphere = node.getBoundingSphere().clone().applyMatrix4(this.matrixWorld);
  44061. if (_ray.intersectsSphere(sphere)) {
  44062. nodesOnRay.push(node);
  44063. }
  44064. }
  44065. return nodesOnRay;
  44066. }
  44067. updateMatrixWorld (force) {
  44068. if (this.matrixAutoUpdate === true) this.updateMatrix();
  44069. if (this.matrixWorldNeedsUpdate === true || force === true) {
  44070. if (!this.parent) {
  44071. this.matrixWorld.copy(this.matrix);
  44072. } else {
  44073. this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
  44074. }
  44075. this.matrixWorldNeedsUpdate = false;
  44076. force = true;
  44077. }
  44078. }
  44079. hideDescendants (object) {
  44080. let stack = [];
  44081. for (let i = 0; i < object.children.length; i++) {
  44082. let child = object.children[i];
  44083. if (child.visible) {
  44084. stack.push(child);
  44085. }
  44086. }
  44087. while (stack.length > 0) {
  44088. let object = stack.shift();
  44089. object.visible = false;
  44090. for (let i = 0; i < object.children.length; i++) {
  44091. let child = object.children[i];
  44092. if (child.visible) {
  44093. stack.push(child);
  44094. }
  44095. }
  44096. }
  44097. }
  44098. moveToOrigin () {
  44099. this.position.set(0, 0, 0);
  44100. this.updateMatrixWorld(true);
  44101. let box = this.boundingBox;
  44102. let transform = this.matrixWorld;
  44103. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  44104. this.position.set(0, 0, 0).sub(tBox.getCenter(new Vector3()));
  44105. };
  44106. moveToGroundPlane () {
  44107. this.updateMatrixWorld(true);
  44108. let box = this.boundingBox;
  44109. let transform = this.matrixWorld;
  44110. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  44111. this.position.y += -tBox.min.y;
  44112. };
  44113. getBoundingBoxWorld () {
  44114. this.updateMatrixWorld(true);
  44115. let box = this.boundingBox;
  44116. let transform = this.matrixWorld;
  44117. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  44118. return tBox;
  44119. };
  44120. /**
  44121. * returns points inside the profile points
  44122. *
  44123. * maxDepth: search points up to the given octree depth
  44124. *
  44125. *
  44126. * The return value is an array with all segments of the profile path
  44127. * let segment = {
  44128. * start: THREE.Vector3,
  44129. * end: THREE.Vector3,
  44130. * points: {}
  44131. * project: function()
  44132. * };
  44133. *
  44134. * The project() function inside each segment can be used to transform
  44135. * that segments point coordinates to line up along the x-axis.
  44136. *
  44137. *
  44138. */
  44139. getPointsInProfile (profile, maxDepth, callback) {
  44140. if (callback) {
  44141. let request = new Potree.ProfileRequest(this, profile, maxDepth, callback);
  44142. this.profileRequests.push(request);
  44143. return request;
  44144. }
  44145. let points = {
  44146. segments: [],
  44147. boundingBox: new Box3(),
  44148. projectedBoundingBox: new Box2()
  44149. };
  44150. // evaluate segments
  44151. for (let i = 0; i < profile.points.length - 1; i++) {
  44152. let start = profile.points[i];
  44153. let end = profile.points[i + 1];
  44154. let ps = this.getProfile(start, end, profile.width, maxDepth);
  44155. let segment = {
  44156. start: start,
  44157. end: end,
  44158. points: ps,
  44159. project: null
  44160. };
  44161. points.segments.push(segment);
  44162. points.boundingBox.expandByPoint(ps.boundingBox.min);
  44163. points.boundingBox.expandByPoint(ps.boundingBox.max);
  44164. }
  44165. // add projection functions to the segments
  44166. let mileage = new Vector3();
  44167. for (let i = 0; i < points.segments.length; i++) {
  44168. let segment = points.segments[i];
  44169. let start = segment.start;
  44170. let end = segment.end;
  44171. let project = (function (_start, _end, _mileage, _boundingBox) {
  44172. let start = _start;
  44173. let end = _end;
  44174. let mileage = _mileage;
  44175. let boundingBox = _boundingBox;
  44176. let xAxis = new Vector3(1, 0, 0);
  44177. let dir = new Vector3().subVectors(end, start);
  44178. dir.y = 0;
  44179. dir.normalize();
  44180. let alpha = Math.acos(xAxis.dot(dir));
  44181. if (dir.z > 0) {
  44182. alpha = -alpha;
  44183. }
  44184. return function (position) {
  44185. let toOrigin = new Matrix4().makeTranslation(-start.x, -boundingBox.min.y, -start.z);
  44186. let alignWithX = new Matrix4().makeRotationY(-alpha);
  44187. let applyMileage = new Matrix4().makeTranslation(mileage.x, 0, 0);
  44188. let pos = position.clone();
  44189. pos.applyMatrix4(toOrigin);
  44190. pos.applyMatrix4(alignWithX);
  44191. pos.applyMatrix4(applyMileage);
  44192. return pos;
  44193. };
  44194. }(start, end, mileage.clone(), points.boundingBox.clone()));
  44195. segment.project = project;
  44196. mileage.x += new Vector3(start.x, 0, start.z).distanceTo(new Vector3(end.x, 0, end.z));
  44197. mileage.y += end.y - start.y;
  44198. }
  44199. points.projectedBoundingBox.min.x = 0;
  44200. points.projectedBoundingBox.min.y = points.boundingBox.min.y;
  44201. points.projectedBoundingBox.max.x = mileage.x;
  44202. points.projectedBoundingBox.max.y = points.boundingBox.max.y;
  44203. return points;
  44204. }
  44205. /**
  44206. * returns points inside the given profile bounds.
  44207. *
  44208. * start:
  44209. * end:
  44210. * width:
  44211. * depth: search points up to the given octree depth
  44212. * callback: if specified, points are loaded before searching
  44213. *
  44214. *
  44215. */
  44216. getProfile (start, end, width, depth, callback) {
  44217. let request = new Potree.ProfileRequest(start, end, width, depth, callback);
  44218. this.profileRequests.push(request);
  44219. };
  44220. getVisibleExtent () {
  44221. return this.visibleBounds.applyMatrix4(this.matrixWorld);
  44222. };
  44223. intersectsPoint(position){
  44224. let rootAvailable = this.pcoGeometry.root && this.pcoGeometry.root.geometry;
  44225. if(!rootAvailable){
  44226. return false;
  44227. }
  44228. if(typeof this.signedDistanceField === "undefined"){
  44229. const resolution = 32;
  44230. const field = new Float32Array(resolution ** 3).fill(Infinity);
  44231. const positions = this.pcoGeometry.root.geometry.attributes.position;
  44232. const boundingBox = this.boundingBox;
  44233. const n = positions.count;
  44234. for(let i = 0; i < n; i = i + 3){
  44235. const x = positions.array[3 * i + 0];
  44236. const y = positions.array[3 * i + 1];
  44237. const z = positions.array[3 * i + 2];
  44238. const ix = parseInt(Math.min(resolution * (x / boundingBox.max.x), resolution - 1));
  44239. const iy = parseInt(Math.min(resolution * (y / boundingBox.max.y), resolution - 1));
  44240. const iz = parseInt(Math.min(resolution * (z / boundingBox.max.z), resolution - 1));
  44241. const index = ix + iy * resolution + iz * resolution * resolution;
  44242. field[index] = 0;
  44243. }
  44244. const sdf = {
  44245. resolution: resolution,
  44246. field: field,
  44247. };
  44248. this.signedDistanceField = sdf;
  44249. }
  44250. {
  44251. const sdf = this.signedDistanceField;
  44252. const boundingBox = this.boundingBox;
  44253. const toObjectSpace = this.matrixWorld.clone().invert();
  44254. const objPos = position.clone().applyMatrix4(toObjectSpace);
  44255. const resolution = sdf.resolution;
  44256. const ix = parseInt(resolution * (objPos.x / boundingBox.max.x));
  44257. const iy = parseInt(resolution * (objPos.y / boundingBox.max.y));
  44258. const iz = parseInt(resolution * (objPos.z / boundingBox.max.z));
  44259. if(ix < 0 || iy < 0 || iz < 0){
  44260. return false;
  44261. }
  44262. if(ix >= resolution || iy >= resolution || iz >= resolution){
  44263. return false;
  44264. }
  44265. const index = ix + iy * resolution + iz * resolution * resolution;
  44266. const value = sdf.field[index];
  44267. if(value === 0){
  44268. return true;
  44269. }
  44270. }
  44271. return false;
  44272. }
  44273. /**
  44274. *
  44275. *
  44276. *
  44277. * params.pickWindowSize: Look for points inside a pixel window of this size.
  44278. * Use odd values: 1, 3, 5, ...
  44279. *
  44280. *
  44281. * TODO: only draw pixels that are actually read with readPixels().
  44282. *
  44283. */
  44284. pick(viewer, viewport, camera, ray, params = {}){
  44285. let renderer = viewer.renderer;
  44286. let pRenderer = viewer.pRenderer;
  44287. performance.mark("pick-start");
  44288. let getVal = (a, b) => a != void 0 ? a : b;
  44289. let pickWindowSize_ = MathUtils.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80), 5, 100);
  44290. let pickWindowSize = getVal(params.pickWindowSize, pickWindowSize_ ); /* 65 */ //拾取像素边长,越小越精准,但点云稀疏的话可能容易出现识别不到的情况。 另外左下侧会有缝隙无法识别到,缝隙大小和这个值有关
  44291. let pickOutsideClipRegion = getVal(params.pickOutsideClipRegion, false);
  44292. let size = viewport ? viewport.resolution : renderer.getSize(new Vector2$1());
  44293. let width = Math.ceil(getVal(params.width, size.width)); //renderTarget大小。影响识别精度
  44294. let height = Math.ceil(getVal(params.height, size.height));
  44295. let screenshot = ()=>{
  44296. if(window.testScreen){
  44297. let dataUrl = Potree.Utils.renderTargetToDataUrl(pickState.renderTarget, width, height, renderer);
  44298. Common.downloadFile(dataUrl, 'screenshot.jpg'); //为什么图片上不是只有pickWindowSize区域有颜色??
  44299. window.testScreen = 0;
  44300. }
  44301. };
  44302. let pointSizeType = getVal(params.pointSizeType, this.material.pointSizeType);
  44303. let pointSize = getVal(params.pointSize, this.material.size);
  44304. let nodes = this.nodesOnRay(this.visibleNodes, ray);
  44305. if (nodes.length === 0) {
  44306. return null;
  44307. }
  44308. //console.log('nodes.length != 0', this.name)
  44309. if (!this.pickState) {
  44310. let scene = new Scene();
  44311. let material = new Potree.PointCloudMaterial();
  44312. material.activeAttributeName = "indices";
  44313. let renderTarget = new WebGLRenderTarget(
  44314. 1, 1,
  44315. { minFilter: LinearFilter,
  44316. magFilter: NearestFilter,
  44317. format: RGBAFormat }
  44318. );
  44319. this.pickState = {
  44320. renderTarget: renderTarget,
  44321. material: material,
  44322. scene: scene
  44323. };
  44324. };
  44325. let pickState = this.pickState;
  44326. let pickMaterial = pickState.material;
  44327. { // update pick material
  44328. pickMaterial.pointSizeType = pointSizeType;
  44329. //pickMaterial.shape = this.material.shape;
  44330. pickMaterial.shape = Potree.PointShape.PARABOLOID;
  44331. pickMaterial.uniforms.uFilterReturnNumberRange.value = this.material.uniforms.uFilterReturnNumberRange.value;
  44332. pickMaterial.uniforms.uFilterNumberOfReturnsRange.value = this.material.uniforms.uFilterNumberOfReturnsRange.value;
  44333. pickMaterial.uniforms.uFilterGPSTimeClipRange.value = this.material.uniforms.uFilterGPSTimeClipRange.value;
  44334. pickMaterial.uniforms.uFilterPointSourceIDClipRange.value = this.material.uniforms.uFilterPointSourceIDClipRange.value;
  44335. pickMaterial.activeAttributeName = "indices";
  44336. pickMaterial.size = pointSize;
  44337. pickMaterial.uniforms.minSize.value = this.material.uniforms.minSize.value;
  44338. pickMaterial.uniforms.maxSize.value = this.material.uniforms.maxSize.value;
  44339. pickMaterial.classification = this.material.classification;
  44340. pickMaterial.recomputeClassification();
  44341. if(params.pickClipped){
  44342. pickMaterial.clipBoxes = this.material.clipBoxes;
  44343. pickMaterial.uniforms.clipBoxes = this.material.uniforms.clipBoxes;
  44344. if(this.material.clipTask === Potree.ClipTask.HIGHLIGHT){
  44345. pickMaterial.clipTask = Potree.ClipTask.NONE;
  44346. }else {
  44347. pickMaterial.clipTask = this.material.clipTask;
  44348. }
  44349. pickMaterial.clipMethod = this.material.clipMethod;
  44350. }else {
  44351. pickMaterial.clipBoxes = [];
  44352. }
  44353. this.updateMaterial(pickMaterial, nodes, camera, renderer, new Vector2$1(width, height));
  44354. }
  44355. pickState.renderTarget.setSize(width, height); //仅绘制屏幕大小的,而不乘以devicePixelRatio
  44356. let pixelPos = new Vector2$1(params.x, params.y);
  44357. let gl = renderer.getContext();
  44358. gl.enable(gl.SCISSOR_TEST);
  44359. gl.scissor( //规定渲染范围,只渲染一小块
  44360. parseInt(pixelPos.x - (pickWindowSize - 1) / 2),
  44361. parseInt(pixelPos.y - (pickWindowSize - 1) / 2),
  44362. parseInt(pickWindowSize), parseInt(pickWindowSize));
  44363. renderer.state.buffers.depth.setTest(pickMaterial.depthTest);
  44364. renderer.state.buffers.depth.setMask(pickMaterial.depthWrite);
  44365. renderer.state.setBlending(NoBlending);
  44366. { // RENDER
  44367. renderer.setRenderTarget(pickState.renderTarget);
  44368. gl.clearColor(0, 0, 0, 0);
  44369. renderer.clear(true, true, true);
  44370. let tmp = this.material;
  44371. this.material = pickMaterial;
  44372. pRenderer.renderOctree(this, nodes, camera, pickState.renderTarget);
  44373. screenshot();
  44374. this.material = tmp;
  44375. }
  44376. let clamp = (number, min, max) => Math.min(Math.max(min, number), max);
  44377. let x = parseInt(clamp(pixelPos.x - (pickWindowSize - 1) / 2, 0, width));
  44378. let y = parseInt(clamp(pixelPos.y - (pickWindowSize - 1) / 2, 0, height));
  44379. /* let w = parseInt(Math.min(x + pickWindowSize, width) - x);
  44380. let h = parseInt(Math.min(y + pickWindowSize, height) - y); */
  44381. let pixelCount = pickWindowSize * pickWindowSize;//w * h;
  44382. let buffer = new Uint8Array(4 * pixelCount);
  44383. //w<pickWindowSize会报错
  44384. gl.readPixels(x, y, pickWindowSize, pickWindowSize, gl.RGBA, gl.UNSIGNED_BYTE, buffer);
  44385. renderer.setRenderTarget(null);
  44386. renderer.state.reset();
  44387. renderer.setScissorTest(false);
  44388. gl.disable(gl.SCISSOR_TEST);
  44389. let pixels = buffer;
  44390. let ibuffer = new Uint32Array(buffer.buffer); //四个数整合成一个
  44391. // find closest hit inside pixelWindow boundaries
  44392. let min = Number.MAX_VALUE;
  44393. let hits = [];
  44394. for (let u = 0; u < pickWindowSize; u++) {
  44395. for (let v = 0; v < pickWindowSize; v++) {
  44396. let offset = (u + v * pickWindowSize);
  44397. let distance = Math.pow(u - (pickWindowSize - 1) / 2, 2) + Math.pow(v - (pickWindowSize - 1) / 2, 2);
  44398. let pcIndex = pixels[4 * offset + 3];//nodes index(第四位)
  44399. pixels[4 * offset + 3] = 0; //去除nodes index后剩下的是index(前三位)
  44400. let pIndex = ibuffer[offset]; //index
  44401. if(!(pcIndex === 0 && pIndex === 0) && (pcIndex !== undefined) && (pIndex !== undefined)){
  44402. let hit = {
  44403. pIndex: pIndex,
  44404. pcIndex: pcIndex,
  44405. distanceToCenter: distance
  44406. };
  44407. if(params.all){
  44408. hits.push(hit);
  44409. }else {
  44410. if(hits.length > 0){
  44411. if(distance < hits[0].distanceToCenter){
  44412. hits[0] = hit;
  44413. }
  44414. }else {
  44415. hits.push(hit);
  44416. }
  44417. }
  44418. }
  44419. }
  44420. }
  44421. // { // DEBUG: show panel with pick image
  44422. // let img = Utils.pixelsArrayToImage(buffer, w, h);
  44423. // let screenshot = img.src;
  44424. // if(!this.debugDIV){
  44425. // this.debugDIV = $(`
  44426. // <div id="pickDebug"
  44427. // style="position: absolute;
  44428. // right: 400px; width: 300px;
  44429. // bottom: 44px; width: 300px;
  44430. // z-index: 1000;
  44431. // "></div>`);
  44432. // $(document.body).append(this.debugDIV);
  44433. // }
  44434. // this.debugDIV.empty();
  44435. // this.debugDIV.append($(`<img src="${screenshot}"
  44436. // style="transform: scaleY(-1); width: 300px"/>`));
  44437. // //$(this.debugWindow.document).append($(`<img src="${screenshot}"/>`));
  44438. // //this.debugWindow.document.write('<img src="'+screenshot+'"/>');
  44439. // }
  44440. for(let hit of hits){
  44441. let point = {};
  44442. if (!nodes[hit.pcIndex]) {
  44443. return null;
  44444. }
  44445. let node = nodes[hit.pcIndex];
  44446. let pc = node.sceneNode;
  44447. let geometry = node.geometryNode.geometry;
  44448. for(let attributeName in geometry.attributes){
  44449. let attribute = geometry.attributes[attributeName];
  44450. if (attributeName === 'position') {
  44451. let x = attribute.array[3 * hit.pIndex + 0];
  44452. let y = attribute.array[3 * hit.pIndex + 1];
  44453. let z = attribute.array[3 * hit.pIndex + 2];
  44454. let position = new Vector3(x, y, z);
  44455. position.applyMatrix4( pc.matrixWorld );
  44456. point[attributeName] = position;
  44457. } else if (attributeName === 'indices') {
  44458. } else {
  44459. let values = attribute.array.slice(attribute.itemSize * hit.pIndex, attribute.itemSize * (hit.pIndex + 1)) ;
  44460. if(attribute.potree){
  44461. const {scale, offset} = attribute.potree;
  44462. values = values.map(v => v / scale + offset);
  44463. }
  44464. point[attributeName] = values;
  44465. //debugger;
  44466. //if (values.itemSize === 1) {
  44467. // point[attribute.name] = values.array[hit.pIndex];
  44468. //} else {
  44469. // let value = [];
  44470. // for (let j = 0; j < values.itemSize; j++) {
  44471. // value.push(values.array[values.itemSize * hit.pIndex + j]);
  44472. // }
  44473. // point[attribute.name] = value;
  44474. //}
  44475. }
  44476. }
  44477. hit.point = point;
  44478. }
  44479. performance.mark("pick-end");
  44480. performance.measure("pick", "pick-start", "pick-end");
  44481. if(params.all){
  44482. return hits.map(hit => hit.point);
  44483. }else {
  44484. if(hits.length === 0){
  44485. return null;
  44486. }else {
  44487. return hits[0].point;
  44488. //let sorted = hits.sort( (a, b) => a.distanceToCenter - b.distanceToCenter);
  44489. //return sorted[0].point;
  44490. }
  44491. }
  44492. };
  44493. * getFittedBoxGen(boxNode){//???
  44494. let start = performance.now();
  44495. let shrinkedLocalBounds = new Box3();
  44496. let worldToBox = boxNode.matrixWorld.clone().invert();
  44497. for(let node of this.visibleNodes){
  44498. if(!node.sceneNode){
  44499. continue;
  44500. }
  44501. let buffer = node.geometryNode.buffer;
  44502. let posOffset = buffer.offset("position");
  44503. let stride = buffer.stride;
  44504. let view = new DataView(buffer.data);
  44505. let objectToBox = new Matrix4().multiplyMatrices(worldToBox, node.sceneNode.matrixWorld);
  44506. let pos = new Vector4();
  44507. for(let i = 0; i < buffer.numElements; i++){
  44508. let x = view.getFloat32(i * stride + posOffset + 0, true);
  44509. let y = view.getFloat32(i * stride + posOffset + 4, true);
  44510. let z = view.getFloat32(i * stride + posOffset + 8, true);
  44511. pos.set(x, y, z, 1);
  44512. pos.applyMatrix4(objectToBox);
  44513. if(-0.5 < pos.x && pos.x < 0.5){
  44514. if(-0.5 < pos.y && pos.y < 0.5){
  44515. if(-0.5 < pos.z && pos.z < 0.5){
  44516. shrinkedLocalBounds.expandByPoint(pos);
  44517. }
  44518. }
  44519. }
  44520. }
  44521. yield;
  44522. }
  44523. let fittedPosition = shrinkedLocalBounds.getCenter(new Vector3()).applyMatrix4(boxNode.matrixWorld);
  44524. let fitted = new Object3D();
  44525. fitted.position.copy(fittedPosition);
  44526. fitted.scale.copy(boxNode.scale);
  44527. fitted.rotation.copy(boxNode.rotation);
  44528. let ds = new Vector3().subVectors(shrinkedLocalBounds.max, shrinkedLocalBounds.min);
  44529. fitted.scale.multiply(ds);
  44530. let duration = performance.now() - start;
  44531. console.log("duration: ", duration);
  44532. yield fitted;
  44533. }
  44534. getFittedBox(boxNode, maxLevel = Infinity){
  44535. maxLevel = Infinity;
  44536. let start = performance.now();
  44537. let shrinkedLocalBounds = new Box3();
  44538. let worldToBox = boxNode.matrixWorld.clone().invert();
  44539. for(let node of this.visibleNodes){
  44540. if(!node.sceneNode || node.getLevel() > maxLevel){
  44541. continue;
  44542. }
  44543. let buffer = node.geometryNode.buffer;
  44544. let posOffset = buffer.offset("position");
  44545. let stride = buffer.stride;
  44546. let view = new DataView(buffer.data);
  44547. let objectToBox = new Matrix4().multiplyMatrices(worldToBox, node.sceneNode.matrixWorld);
  44548. let pos = new Vector4();
  44549. for(let i = 0; i < buffer.numElements; i++){
  44550. let x = view.getFloat32(i * stride + posOffset + 0, true);
  44551. let y = view.getFloat32(i * stride + posOffset + 4, true);
  44552. let z = view.getFloat32(i * stride + posOffset + 8, true);
  44553. pos.set(x, y, z, 1);
  44554. pos.applyMatrix4(objectToBox);
  44555. if(-0.5 < pos.x && pos.x < 0.5){
  44556. if(-0.5 < pos.y && pos.y < 0.5){
  44557. if(-0.5 < pos.z && pos.z < 0.5){
  44558. shrinkedLocalBounds.expandByPoint(pos);
  44559. }
  44560. }
  44561. }
  44562. }
  44563. }
  44564. let fittedPosition = shrinkedLocalBounds.getCenter(new Vector3()).applyMatrix4(boxNode.matrixWorld);
  44565. let fitted = new Object3D();
  44566. fitted.position.copy(fittedPosition);
  44567. fitted.scale.copy(boxNode.scale);
  44568. fitted.rotation.copy(boxNode.rotation);
  44569. let ds = new Vector3().subVectors(shrinkedLocalBounds.max, shrinkedLocalBounds.min);
  44570. fitted.scale.multiply(ds);
  44571. let duration = performance.now() - start;
  44572. console.log("duration: ", duration);
  44573. return fitted;
  44574. }
  44575. get progress () {
  44576. return this.visibleNodes.length / this.visibleGeometry.length;
  44577. }
  44578. find(name){
  44579. let node = null;
  44580. for(let char of name){
  44581. if(char === "r"){
  44582. node = this.root;
  44583. }else {
  44584. node = node.children[char];
  44585. }
  44586. }
  44587. return node;
  44588. }
  44589. get visible(){
  44590. return this._visible;
  44591. }
  44592. set visible(value){
  44593. if(value !== this._visible){
  44594. this._visible = value;
  44595. this.dispatchEvent({type: 'visibility_changed', pointcloud: this});
  44596. }
  44597. }
  44598. // 设置点大小
  44599. changePointSize(num, sizeFitToLevel) {
  44600. if(this.material.pointSizeType != PointSizeType.ATTENUATED){
  44601. return num && (this.material.size = num)
  44602. }
  44603. if (num == void 0) {
  44604. num = this.temp.pointSize;
  44605. } else {
  44606. this.temp.pointSize = num;
  44607. }
  44608. num /= (Potree.config.material.realPointSize / Potree.config.material.pointSize); //兼容
  44609. num = Math.pow(num, 1.05) * 6;
  44610. if(sizeFitToLevel || Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本: 近似将pointSizeType换成ADAPTIVE
  44611. let str = this.temp.pointSize+':'+this.maxLevel+':'+this.nodeMaxLevel;
  44612. let value = this.temp.sizeFitToLevel[str]; //储存。防止每次渲染(反复切换density)都要算。
  44613. if(value){
  44614. this.material.size = value;
  44615. }else {
  44616. let base = this.material.spacing / Math.pow(2, this.maxLevel); //点云大小在level为0时设置为spacing,每长一级,大小就除以2
  44617. base *= this.nodeMaxLevel > 0 ? Math.max(0.1, Math.pow(this.maxLevel / this.nodeMaxLevel, 1.3)) : 0.1; //低质量的缩小点,因为视觉上看太大了。navvis是不铺满的,我们也留一点缝隙
  44618. this.material.size = base * 3 * num;/* * window.devicePixelRatio */
  44619. //在t-8BCqxQAr93 会议室 和 t-e2Kb2iU 隧道 两个场景里调节,因为它们的spacing相差较大,观察会议室墙壁的龟裂程度
  44620. this.temp.sizeFitToLevel[str] = this.material.size;
  44621. }
  44622. }else {
  44623. let base = 0.007; //let base = this.material.spacing / Math.pow(2, this.nodeMaxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
  44624. //base的数值理论上应该是右侧算出来的,但发现有的场景nodeMaxLevel和nodeMaxLevelPredict差别较大的点云显示也过大,而直接换成固定值反而可以适应所有场景。该固定值来源于 getHighestNodeSpacing 最小值,修改了下。(会不会是我们的相机其实该值是固定的,根据该值算出的spacing才是有误差的? 如果换了相机是否要改值?)
  44625. this.material.size = base * 5 * num; /* * window.devicePixelRatio */
  44626. }
  44627. //console.log('changePointSize ' + this.dataset_id + ' , num : ' + num + ' , size : ' + this.material.size, this.material.spacing)
  44628. }
  44629. // 设置点透明度
  44630. changePointOpacity(num, canMoreThanOne) {
  44631. //num:0-1 navvis用的是亮度
  44632. if (num == void 0) {
  44633. num = this.temp.pointOpacity;
  44634. } else {
  44635. this.temp.pointOpacity = num;
  44636. }
  44637. if (num == 1) {
  44638. this.material.opacity = 1;
  44639. } else {
  44640. let str = (Potree.settings.sizeFitToLevel?'sizeFit:':'')+ (canMoreThanOne ? 'canMoreThanOne:':'') +this.temp.pointOpacity+':'+this.maxLevel+':'+this.nodeMaxLevel;
  44641. let value = this.temp.opacity[str]; //储存。防止每次渲染(反复切换density)都要算。
  44642. if(value){
  44643. this.material.opacity = value;
  44644. }else {
  44645. if(Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:
  44646. let base = this.material.spacing / Math.pow(1.4, this.maxLevel); //随着level提高,点云重叠几率增多
  44647. let minBase = this.material.spacing / Math.pow(1.4, this.nodeMaxLevel);
  44648. let ratio = Math.min(1 / base, 1 / minBase / 3); //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
  44649. this.material.opacity = base * ratio * num;
  44650. if(!canMoreThanOne){
  44651. this.material.opacity = MathUtils.clamp(this.material.opacity, 0, 0.999); //到1就不透明了(可能出现一段一样)
  44652. }
  44653. }else {
  44654. let base = this.material.spacing / Math.pow(1.8, this.maxLevel);
  44655. let minBase = this.material.spacing / Math.pow(1.8, this.nodeMaxLevel);
  44656. //console.log(1 / base, 1 / minBase / 6)
  44657. let ratio = Math.min(1 / base, 1 / minBase / 6); //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
  44658. this.material.opacity = base * ratio * num;
  44659. if(!canMoreThanOne){
  44660. this.material.opacity = MathUtils.clamp(this.material.opacity, 0, 0.999); //到1就不透明了(可能出现一段一样)
  44661. }
  44662. }
  44663. this.temp.opacity[str] = this.material.opacity;
  44664. }
  44665. //缺点:防止颜色过亮主要是相机离远时,当在漫游点处由于离点云太近,可能会导致高质量点云看起来很暗。
  44666. }
  44667. //console.log('changePointOpacity ' + this.dataset_id + ', num : ' + num + ' , opacity : ' + this.material.opacity) //检查是否做到了低质量时num==opacity,中质量opacity稍小于num,高质量更小
  44668. }
  44669. updateBound(){
  44670. var boundingBox_ = this.pcoGeometry.tightBoundingBox.clone().applyMatrix4(this.matrixWorld);
  44671. this.bound = boundingBox_;
  44672. }
  44673. getPanosBound(){
  44674. if(this.panos.length > 0){
  44675. let minSize = new Vector3(1,1,1);
  44676. this.panosBound = math.getBoundByPoints(this.panos.map(e=>e.position), minSize);
  44677. }else {
  44678. this.panosBound = null;
  44679. }
  44680. }
  44681. getUnrotBoundPoint(type){//获取没有旋转的tightBounding的水平四个点
  44682. //如果alighment支持任意轴旋转,水平面上看到的可能就是六边形了,失去意义,到时候不能用这个。也可以若只绕z旋转, 使用tightBoundingBox,否则bound
  44683. let bound = this.pcoGeometry.tightBoundingBox;
  44684. if(type == 'all'){
  44685. return [new Vector3(bound.min.x, bound.min.y, bound.min.z),
  44686. new Vector3(bound.max.x, bound.min.y, bound.min.z),
  44687. new Vector3(bound.max.x, bound.max.y,bound.min.z),
  44688. new Vector3(bound.min.x, bound.max.y,bound.min.z),
  44689. new Vector3(bound.min.x, bound.min.y, bound.max.z),
  44690. new Vector3(bound.max.x, bound.min.y, bound.max.z),
  44691. new Vector3(bound.max.x, bound.max.y,bound.max.z),
  44692. new Vector3(bound.min.x, bound.max.y,bound.max.z),
  44693. ].map(e=>e.applyMatrix4(this.matrixWorld))
  44694. }else
  44695. return [new Vector3(bound.min.x, bound.min.y,0),
  44696. new Vector3(bound.max.x, bound.min.y,0),
  44697. new Vector3(bound.max.x, bound.max.y,0),
  44698. new Vector3(bound.min.x, bound.max.y,0),
  44699. ].map(e=>e.applyMatrix4(this.matrixWorld))
  44700. }
  44701. ifContainsPoint(pos){
  44702. if(!this.bound.containsPoint(pos))return
  44703. var points = this.getUnrotBoundPoint();
  44704. return math.isPointInArea(points, null, pos)
  44705. }
  44706. getVolume(){
  44707. var points = this.getUnrotBoundPoint();
  44708. var area = Math.abs(math.getArea(points));
  44709. return area * (this.bound.max.z - this.bound.min.z)
  44710. }
  44711. //数据集的显示影响到其下的:点云、marker .不会影响地图上的显示
  44712. /*
  44713. updateVisible(reason, ifShow){//当所有加入的条件都不为false时才显示
  44714. if(ifShow){
  44715. var index = this.unvisibleReasons.indexOf(reason);
  44716. index > -1 && this.unvisibleReasons.splice(index, 1);
  44717. if(this.unvisibleReasons.length == 0){
  44718. this.visible = true;
  44719. this.dispatchEvent({
  44720. type: 'isVisible'
  44721. visible:true
  44722. })
  44723. }
  44724. }else {
  44725. if(!this.unvisibleReasons.includes(reason)) this.unvisibleReasons.push(reason);
  44726. this.visible = false;
  44727. this.dispatchEvent({
  44728. type: 'isVisible'
  44729. visible:false
  44730. })
  44731. }
  44732. }
  44733. getVisible(reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
  44734. if(this.visible)return true
  44735. else{
  44736. return !this.unvisibleReasons.includes(reason)
  44737. }
  44738. } */
  44739. /* get isVisible(){//add 手动在数据集选择是否显示(和是否全景图、隐藏点云无关)
  44740. return this._isVisible
  44741. }
  44742. set isVisible(visi){
  44743. if(!visi)this.visible = false
  44744. this._isVisible = visi
  44745. } */
  44746. }
  44747. /*
  44748. window.searchOutRing = function(points){
  44749. var points = [{x:0,y:0},{x:1,y:1},{x:0,y:1},{x:1,y:0},{x:2,y:1},{x:1,y:2},{x:1,y:3},{x:2,y:3},
  44750. {x:3,y:1},{x:3,y:2},{x:0,y:2},{x:0,y:3},{x:2,y:0},{x:-1,y:0},{x:-1,y:1},{x:-2,y:1},{x:3,y:3},
  44751. {x:3,y:0},{x:2,y:-1},{x:0,y:-1},{x:1,y:0.5},{x:2,y:0.5}, ].map((e,index)=>{
  44752. var a = new THREE.Vector2().copy(e)
  44753. a.id = index;
  44754. return a
  44755. })
  44756. var lines = []
  44757. var minDis = 2*2
  44758. points.forEach((p,j)=>{
  44759. for(let i=0;i<j;i++){
  44760. if(p.distanceToSquared(points[i])<minDis){
  44761. lines.push({p1:i,p2:j})
  44762. }
  44763. }
  44764. })
  44765. searchRings({
  44766. points,
  44767. lines,
  44768. onlyGetOutRing:true
  44769. })
  44770. }
  44771. */
  44772. class Points$1 {
  44773. constructor () {
  44774. this.boundingBox = new Box3();
  44775. this.numPoints = 0;
  44776. this.data = {};
  44777. }
  44778. add (points) {
  44779. let currentSize = this.numPoints;
  44780. let additionalSize = points.numPoints;
  44781. let newSize = currentSize + additionalSize;
  44782. let thisAttributes = Object.keys(this.data);
  44783. let otherAttributes = Object.keys(points.data);
  44784. let attributes = new Set([...thisAttributes, ...otherAttributes]);
  44785. for (let attribute of attributes) {
  44786. if (thisAttributes.includes(attribute) && otherAttributes.includes(attribute)) {
  44787. // attribute in both, merge
  44788. let Type = this.data[attribute].constructor;
  44789. let merged = new Type(this.data[attribute].length + points.data[attribute].length);
  44790. merged.set(this.data[attribute], 0);
  44791. merged.set(points.data[attribute], this.data[attribute].length);
  44792. this.data[attribute] = merged;
  44793. } else if (thisAttributes.includes(attribute) && !otherAttributes.includes(attribute)) {
  44794. // attribute only in this; take over this and expand to new size
  44795. let elementsPerPoint = this.data[attribute].length / this.numPoints;
  44796. let Type = this.data[attribute].constructor;
  44797. let expanded = new Type(elementsPerPoint * newSize);
  44798. expanded.set(this.data[attribute], 0);
  44799. this.data[attribute] = expanded;
  44800. } else if (!thisAttributes.includes(attribute) && otherAttributes.includes(attribute)) {
  44801. // attribute only in points to be added; take over new points and expand to new size
  44802. let elementsPerPoint = points.data[attribute].length / points.numPoints;
  44803. let Type = points.data[attribute].constructor;
  44804. let expanded = new Type(elementsPerPoint * newSize);
  44805. expanded.set(points.data[attribute], elementsPerPoint * currentSize);
  44806. this.data[attribute] = expanded;
  44807. }
  44808. }
  44809. this.numPoints = newSize;
  44810. this.boundingBox.union(points.boundingBox);
  44811. }
  44812. }
  44813. /**
  44814. *
  44815. * code adapted from three.js BoxHelper.js
  44816. * https://github.com/mrdoob/three.js/blob/dev/src/helpers/BoxHelper.js
  44817. *
  44818. * @author mrdoob / http://mrdoob.com/
  44819. * @author Mugen87 / http://github.com/Mugen87
  44820. * @author mschuetz / http://potree.org
  44821. */
  44822. class Box3Helper$1 extends LineSegments {
  44823. constructor (box, color) {
  44824. if (color === undefined) color = 0xffff00;
  44825. let indices = new Uint16Array([ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ]);
  44826. let positions = new Float32Array([
  44827. box.min.x, box.min.y, box.min.z,
  44828. box.max.x, box.min.y, box.min.z,
  44829. box.max.x, box.min.y, box.max.z,
  44830. box.min.x, box.min.y, box.max.z,
  44831. box.min.x, box.max.y, box.min.z,
  44832. box.max.x, box.max.y, box.min.z,
  44833. box.max.x, box.max.y, box.max.z,
  44834. box.min.x, box.max.y, box.max.z
  44835. ]);
  44836. let geometry = new BufferGeometry();
  44837. geometry.setIndex(new BufferAttribute(indices, 1));
  44838. geometry.setAttribute('position', new BufferAttribute(positions, 3));
  44839. let material = new LineBasicMaterial({ color: color });
  44840. super(geometry, material);
  44841. }
  44842. }
  44843. function updatePointClouds(pointclouds,camera, areaSize /* renderer */){
  44844. for (let pointcloud of pointclouds) {
  44845. let start = performance.now();
  44846. for (let profileRequest of pointcloud.profileRequests) {
  44847. profileRequest.update();
  44848. let duration = performance.now() - start;
  44849. if(duration > 5){
  44850. break;
  44851. }
  44852. }
  44853. let duration = performance.now() - start;
  44854. }
  44855. let result = updateVisibility(pointclouds, camera, areaSize );
  44856. for (let pointcloud of pointclouds) {
  44857. //pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);//转移到渲染时
  44858. pointcloud.updateVisibleBounds();
  44859. }
  44860. exports.lru.freeMemory();//即Potree.lru 能看到所有在加载的node
  44861. return result;
  44862. };
  44863. function updateVisibilityStructures(pointclouds, camera, areaSize) {
  44864. let frustums = [];
  44865. let camObjPositions = [];
  44866. let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });
  44867. for (let i = 0; i < pointclouds.length; i++) {
  44868. let pointcloud = pointclouds[i];
  44869. if (!pointcloud.initialized()) {
  44870. continue;
  44871. }
  44872. pointcloud.numVisibleNodes = 0;
  44873. pointcloud.numVisiblePoints = 0;
  44874. pointcloud.deepestVisibleLevel = 0;
  44875. pointcloud.visibleNodes = [];
  44876. pointcloud.visibleGeometry = [];
  44877. // frustum in object space
  44878. camera.updateMatrixWorld();
  44879. let frustum = new Frustum();
  44880. let viewI = camera.matrixWorldInverse;
  44881. let world = pointcloud.matrixWorld;
  44882. // use close near plane for frustum intersection
  44883. let frustumCam = camera.clone();
  44884. frustumCam.near = Math.min(camera.near, 0.1);
  44885. frustumCam.updateProjectionMatrix();
  44886. let proj = camera.projectionMatrix;
  44887. let fm = new Matrix4().multiply(proj).multiply(viewI).multiply(world);
  44888. frustum.setFromProjectionMatrix(fm);
  44889. frustums.push(frustum);
  44890. // camera position in object space
  44891. let view = camera.matrixWorld;
  44892. let worldI = world.clone().invert();
  44893. let camMatrixObject = new Matrix4().multiply(worldI).multiply(view);
  44894. let camObjPos = new Vector3().setFromMatrixPosition(camMatrixObject);
  44895. camObjPositions.push(camObjPos);
  44896. // 因漫游模式而隐藏的话 依旧需要加入visibleNodes,因为pick需要
  44897. /* viewer.getObjVisiByReason(pointcloud, 'datasetSelection') */
  44898. if (pointcloud.visible || pointcloud.unvisibleReasons && pointcloud.unvisibleReasons.length == 1 && pointcloud.unvisibleReasons[0].reason == 'displayMode' && pointcloud.root !== null) {//改 visible ->
  44899. priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
  44900. }
  44901. // hide all previously visible nodes
  44902. // if(pointcloud.root instanceof PointCloudOctreeNode){
  44903. // pointcloud.hideDescendants(pointcloud.root.sceneNode);
  44904. // }
  44905. if (pointcloud.root.isTreeNode()) {
  44906. pointcloud.hideDescendants(pointcloud.root.sceneNode);
  44907. }
  44908. for (let j = 0; j < pointcloud.boundingBoxNodes.length; j++) {
  44909. pointcloud.boundingBoxNodes[j].visible = false;
  44910. }
  44911. }
  44912. return {
  44913. 'frustums': frustums,
  44914. 'camObjPositions': camObjPositions,
  44915. 'priorityQueue': priorityQueue
  44916. };
  44917. };
  44918. function updateVisibility(pointclouds, camera, areaSize){
  44919. let numVisibleNodes = 0;
  44920. let numVisiblePoints = 0;
  44921. let numVisiblePointsInPointclouds = new Map(pointclouds.map(pc => [pc, 0]));
  44922. let visibleNodes = [];
  44923. let visibleGeometry = [];
  44924. let unloadedGeometry = [];
  44925. let lowestSpacing = Infinity;
  44926. // calculate object space frustum and cam pos and setup priority queue
  44927. let s = updateVisibilityStructures(pointclouds, camera, areaSize);//得到相机可见范围
  44928. let frustums = s.frustums;
  44929. let camObjPositions = s.camObjPositions;
  44930. let priorityQueue = s.priorityQueue;
  44931. let loadedToGPUThisFrame = 0;
  44932. let domWidth = areaSize.x; //renderer.domElement.clientWidth;
  44933. let domHeight = areaSize.y;//renderer.domElement.clientHeight;
  44934. // check if pointcloud has been transformed
  44935. // some code will only be executed if changes have been detected
  44936. if(!Potree._pointcloudTransformVersion){
  44937. Potree._pointcloudTransformVersion = new Map();
  44938. }
  44939. let pointcloudTransformVersion = Potree._pointcloudTransformVersion;
  44940. for(let pointcloud of pointclouds){
  44941. if(!viewer.getObjVisiByReason(pointcloud, 'datasetSelection')){//改 visible ->
  44942. continue;
  44943. }
  44944. pointcloud.updateMatrixWorld();
  44945. if(!pointcloudTransformVersion.has(pointcloud)){
  44946. pointcloudTransformVersion.set(pointcloud, {number: 0, transform: pointcloud.matrixWorld.clone()});
  44947. }else {
  44948. let version = pointcloudTransformVersion.get(pointcloud);
  44949. if(!version.transform.equals(pointcloud.matrixWorld)){
  44950. version.number++;
  44951. version.transform.copy(pointcloud.matrixWorld);
  44952. pointcloud.dispatchEvent({
  44953. type: "transformation_changed",
  44954. target: pointcloud
  44955. });
  44956. }
  44957. }
  44958. }
  44959. while (priorityQueue.size() > 0) {
  44960. let element = priorityQueue.pop();//其实是拿第一个, 再把最后一个放到前面
  44961. let node = element.node;
  44962. let parent = element.parent;
  44963. let pointcloud = pointclouds[element.pointcloud];
  44964. // { // restrict to certain nodes for debugging
  44965. // let allowedNodes = ["r", "r0", "r4"];
  44966. // if(!allowedNodes.includes(node.name)){
  44967. // continue;
  44968. // }
  44969. // }
  44970. let box = node.getBoundingBox();
  44971. let frustum = frustums[element.pointcloud];
  44972. let camObjPos = camObjPositions[element.pointcloud];
  44973. let insideFrustum = frustum.intersectsBox(box);
  44974. let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
  44975. let level = node.getLevel();
  44976. let visible = insideFrustum;
  44977. visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
  44978. visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget);
  44979. visible = visible && level <= maxLevel; //< 改为 <=
  44980. //visible = visible || node.getLevel() <= 2;
  44981. let clipBoxes = pointcloud.material.clipBoxes;
  44982. if(true && clipBoxes.length > 0){
  44983. //node.debug = false;
  44984. let numIntersecting = 0;
  44985. let numIntersectionVolumes = 0;
  44986. //if(node.name === "r60"){
  44987. // var a = 10;
  44988. //}
  44989. for(let clipBox of clipBoxes){
  44990. let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
  44991. let toPCObject = pcWorldInverse.multiply(clipBox.box.matrixWorld);
  44992. let px = new Vector3(+0.5, 0, 0).applyMatrix4(pcWorldInverse);
  44993. let nx = new Vector3(-0.5, 0, 0).applyMatrix4(pcWorldInverse);
  44994. let py = new Vector3(0, +0.5, 0).applyMatrix4(pcWorldInverse);
  44995. let ny = new Vector3(0, -0.5, 0).applyMatrix4(pcWorldInverse);
  44996. let pz = new Vector3(0, 0, +0.5).applyMatrix4(pcWorldInverse);
  44997. let nz = new Vector3(0, 0, -0.5).applyMatrix4(pcWorldInverse);
  44998. let pxN = new Vector3().subVectors(nx, px).normalize();
  44999. let nxN = pxN.clone().multiplyScalar(-1);
  45000. let pyN = new Vector3().subVectors(ny, py).normalize();
  45001. let nyN = pyN.clone().multiplyScalar(-1);
  45002. let pzN = new Vector3().subVectors(nz, pz).normalize();
  45003. let nzN = pzN.clone().multiplyScalar(-1);
  45004. let pxPlane = new Plane().setFromNormalAndCoplanarPoint(pxN, px);
  45005. let nxPlane = new Plane().setFromNormalAndCoplanarPoint(nxN, nx);
  45006. let pyPlane = new Plane().setFromNormalAndCoplanarPoint(pyN, py);
  45007. let nyPlane = new Plane().setFromNormalAndCoplanarPoint(nyN, ny);
  45008. let pzPlane = new Plane().setFromNormalAndCoplanarPoint(pzN, pz);
  45009. let nzPlane = new Plane().setFromNormalAndCoplanarPoint(nzN, nz);
  45010. //if(window.debugdraw !== undefined && window.debugdraw === true && node.name === "r60"){
  45011. // Potree.utils.debugPlane(viewer.scene.scene, pxPlane, 1, 0xFF0000);
  45012. // Potree.utils.debugPlane(viewer.scene.scene, nxPlane, 1, 0x990000);
  45013. // Potree.utils.debugPlane(viewer.scene.scene, pyPlane, 1, 0x00FF00);
  45014. // Potree.utils.debugPlane(viewer.scene.scene, nyPlane, 1, 0x009900);
  45015. // Potree.utils.debugPlane(viewer.scene.scene, pzPlane, 1, 0x0000FF);
  45016. // Potree.utils.debugPlane(viewer.scene.scene, nzPlane, 1, 0x000099);
  45017. // Potree.utils.debugBox(viewer.scene.scene, box, new THREE.Matrix4(), 0x00FF00);
  45018. // Potree.utils.debugBox(viewer.scene.scene, box, pointcloud.matrixWorld, 0xFF0000);
  45019. // Potree.utils.debugBox(viewer.scene.scene, clipBox.box.boundingBox, clipBox.box.matrixWorld, 0xFF0000);
  45020. // window.debugdraw = false;
  45021. //}
  45022. let frustum = new Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
  45023. let intersects = frustum.intersectsBox(box);
  45024. if(intersects){
  45025. numIntersecting++;
  45026. }
  45027. numIntersectionVolumes++;
  45028. }
  45029. let insideAny = numIntersecting > 0;
  45030. let insideAll = numIntersecting === numIntersectionVolumes;
  45031. if(pointcloud.material.clipTask === ClipTask.SHOW_INSIDE){
  45032. if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ANY && insideAny){
  45033. //node.debug = true
  45034. }else if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ALL && insideAll){
  45035. //node.debug = true;
  45036. }else {
  45037. visible = false;
  45038. }
  45039. } else if(pointcloud.material.clipTask === ClipTask.SHOW_OUTSIDE){
  45040. //if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ANY && !insideAny){
  45041. // //visible = true;
  45042. // let a = 10;
  45043. //}else if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ALL && !insideAll){
  45044. // //visible = true;
  45045. // let a = 20;
  45046. //}else{
  45047. // visible = false;
  45048. //}
  45049. }
  45050. }
  45051. // visible = ["r", "r0", "r06", "r060"].includes(node.name);
  45052. // visible = ["r"].includes(node.name);
  45053. if (node.spacing) {
  45054. lowestSpacing = Math.min(lowestSpacing, node.spacing);
  45055. } else if (node.geometryNode && node.geometryNode.spacing) {
  45056. lowestSpacing = Math.min(lowestSpacing, node.geometryNode.spacing);
  45057. }
  45058. if (numVisiblePoints + node.getNumPoints() > Potree.pointBudget) {
  45059. break;
  45060. }
  45061. if (!visible) {
  45062. continue;
  45063. }
  45064. // TODO: not used, same as the declaration?
  45065. // numVisibleNodes++;
  45066. numVisiblePoints += node.getNumPoints();
  45067. let numVisiblePointsInPointcloud = numVisiblePointsInPointclouds.get(pointcloud);
  45068. numVisiblePointsInPointclouds.set(pointcloud, numVisiblePointsInPointcloud + node.getNumPoints());
  45069. pointcloud.numVisibleNodes++;
  45070. pointcloud.numVisiblePoints += node.getNumPoints();
  45071. if (node.isGeometryNode() && (!parent || parent.isTreeNode())) {
  45072. if (node.isLoaded() && loadedToGPUThisFrame < 2) {
  45073. node = pointcloud.toTreeNode(node, parent);
  45074. loadedToGPUThisFrame++;
  45075. } else {
  45076. unloadedGeometry.push({pointcloud,node});
  45077. visibleGeometry.push(node);
  45078. }
  45079. }
  45080. if (node.isTreeNode()) {
  45081. exports.lru.touch(node.geometryNode);
  45082. node.sceneNode.visible = true;
  45083. node.sceneNode.material = pointcloud.material;
  45084. visibleNodes.push(node);
  45085. pointcloud.visibleNodes.push(node);
  45086. if(node._transformVersion === undefined){
  45087. node._transformVersion = -1;
  45088. }
  45089. let transformVersion = pointcloudTransformVersion.get(pointcloud);
  45090. if(node._transformVersion !== transformVersion.number){
  45091. node.sceneNode.updateMatrix();
  45092. //node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
  45093. node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
  45094. node._transformVersion = transformVersion.number;
  45095. }
  45096. if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) {
  45097. let boxHelper = new Box3Helper$1(node.getBoundingBox());
  45098. boxHelper.matrixAutoUpdate = false;
  45099. pointcloud.boundingBoxNodes.push(boxHelper);
  45100. node.boundingBoxNode = boxHelper;
  45101. node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
  45102. } else if (pointcloud.showBoundingBox) {
  45103. node.boundingBoxNode.visible = true;
  45104. node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
  45105. } else if (!pointcloud.showBoundingBox && node.boundingBoxNode) {
  45106. node.boundingBoxNode.visible = false;
  45107. }
  45108. // if(node.boundingBoxNode !== undefined && exports.debug.allowedNodes !== undefined){
  45109. // if(!exports.debug.allowedNodes.includes(node.name)){
  45110. // node.boundingBoxNode.visible = false;
  45111. // }
  45112. // }
  45113. }
  45114. // add child nodes to priorityQueue
  45115. let children = node.getChildren();
  45116. for (let i = 0; i < children.length; i++) {
  45117. let child = children[i];
  45118. let weight = 0;
  45119. if(camera.isPerspectiveCamera){
  45120. let sphere = child.getBoundingSphere();
  45121. let center = sphere.center;
  45122. //let distance = sphere.center.distanceTo(camObjPos);
  45123. let dx = camObjPos.x - center.x;
  45124. let dy = camObjPos.y - center.y;
  45125. let dz = camObjPos.z - center.z;
  45126. let dd = dx * dx + dy * dy + dz * dz;
  45127. let distance = Math.sqrt(dd);
  45128. let radius = sphere.radius;
  45129. let fov = (camera.fov * Math.PI) / 180;
  45130. let slope = Math.tan(fov / 2);
  45131. let projFactor = (0.5 * domHeight) / (slope * distance);
  45132. let screenPixelRadius = radius * projFactor;
  45133. if(screenPixelRadius < pointcloud.minimumNodePixelSize){
  45134. continue;
  45135. }
  45136. weight = screenPixelRadius;
  45137. if(distance - radius < 0){
  45138. weight = Number.MAX_VALUE;
  45139. }
  45140. } else {
  45141. // TODO ortho visibility
  45142. let bb = child.getBoundingBox();
  45143. let distance = child.getBoundingSphere().center.distanceTo(camObjPos);
  45144. let diagonal = bb.max.clone().sub(bb.min).length();
  45145. //weight = diagonal / distance;
  45146. weight = diagonal;
  45147. }
  45148. priorityQueue.push({pointcloud: element.pointcloud, node: child, parent: node, weight: weight});
  45149. }
  45150. }// end priority queue loop
  45151. { // update DEM 这是什么
  45152. let maxDEMLevel = 4;
  45153. let candidates = pointclouds.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
  45154. for (let pointcloud of candidates) {
  45155. let updatingNodes = pointcloud.visibleNodes.filter(n => n.getLevel() <= maxDEMLevel);
  45156. pointcloud.dem.update(updatingNodes);
  45157. }
  45158. }
  45159. //加载点云
  45160. for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
  45161. unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
  45162. }
  45163. return {
  45164. visibleNodes: visibleNodes,
  45165. numVisiblePoints: numVisiblePoints,
  45166. lowestSpacing: lowestSpacing
  45167. };
  45168. };
  45169. //console
  45170. //viewer.scene.pointclouds[0].visibleNodes.map(e=> e && e.name )
  45171. //viewer.scene.pointclouds[0].visibleNodes.map(e=>e.children.map(e=>e && e.name))
  45172. class PointCloudArena4DNode extends PointCloudTreeNode {
  45173. constructor () {
  45174. super();
  45175. this.left = null;
  45176. this.right = null;
  45177. this.sceneNode = null;
  45178. this.kdtree = null;
  45179. }
  45180. getNumPoints () {
  45181. return this.geometryNode.numPoints;
  45182. }
  45183. isLoaded () {
  45184. return true;
  45185. }
  45186. isTreeNode () {
  45187. return true;
  45188. }
  45189. isGeometryNode () {
  45190. return false;
  45191. }
  45192. getLevel () {
  45193. return this.geometryNode.level;
  45194. }
  45195. getBoundingSphere () {
  45196. return this.geometryNode.boundingSphere;
  45197. }
  45198. getBoundingBox () {
  45199. return this.geometryNode.boundingBox;
  45200. }
  45201. toTreeNode (child) {
  45202. let geometryNode = null;
  45203. if (this.left === child) {
  45204. geometryNode = this.left;
  45205. } else if (this.right === child) {
  45206. geometryNode = this.right;
  45207. }
  45208. if (!geometryNode.loaded) {
  45209. return;
  45210. }
  45211. let node = new PointCloudArena4DNode();
  45212. let sceneNode = PointCloud(geometryNode.geometry, this.kdtree.material);
  45213. sceneNode.visible = false;
  45214. node.kdtree = this.kdtree;
  45215. node.geometryNode = geometryNode;
  45216. node.sceneNode = sceneNode;
  45217. node.parent = this;
  45218. node.left = this.geometryNode.left;
  45219. node.right = this.geometryNode.right;
  45220. }
  45221. getChildren () {
  45222. let children = [];
  45223. if (this.left) {
  45224. children.push(this.left);
  45225. }
  45226. if (this.right) {
  45227. children.push(this.right);
  45228. }
  45229. return children;
  45230. }
  45231. };
  45232. class PointCloudArena4D$1 extends PointCloudTree{
  45233. constructor (geometry) {
  45234. super();
  45235. this.root = null;
  45236. if (geometry.root) {
  45237. this.root = geometry.root;
  45238. } else {
  45239. geometry.addEventListener('hierarchy_loaded', () => {
  45240. this.root = geometry.root;
  45241. });
  45242. }
  45243. this.visiblePointsTarget = 2 * 1000 * 1000;
  45244. this.minimumNodePixelSize = 150;
  45245. this.position.sub(geometry.offset);
  45246. this.updateMatrix();
  45247. this.numVisibleNodes = 0;
  45248. this.numVisiblePoints = 0;
  45249. this.boundingBoxNodes = [];
  45250. this.loadQueue = [];
  45251. this.visibleNodes = [];
  45252. this.pcoGeometry = geometry;
  45253. this.boundingBox = this.pcoGeometry.boundingBox;
  45254. this.boundingSphere = this.pcoGeometry.boundingSphere;
  45255. this.material = new PointCloudMaterial$1({vertexColors: VertexColors, size: 0.05, treeType: TreeType.KDTREE});
  45256. this.material.sizeType = PointSizeType.ATTENUATED;
  45257. this.material.size = 0.05;
  45258. this.profileRequests = [];
  45259. this.name = '';
  45260. }
  45261. getBoundingBoxWorld () {
  45262. this.updateMatrixWorld(true);
  45263. let box = this.boundingBox;
  45264. let transform = this.matrixWorld;
  45265. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  45266. return tBox;
  45267. };
  45268. setName (name) {
  45269. if (this.name !== name) {
  45270. this.name = name;
  45271. this.dispatchEvent({type: 'name_changed', name: name, pointcloud: this});
  45272. }
  45273. }
  45274. getName () {
  45275. return this.name;
  45276. }
  45277. getLevel () {
  45278. return this.level;
  45279. }
  45280. toTreeNode (geometryNode, parent) {
  45281. let node = new PointCloudArena4DNode();
  45282. let sceneNode = new Points(geometryNode.geometry, this.material);
  45283. sceneNode.frustumCulled = false;
  45284. sceneNode.onBeforeRender = (_this, scene, camera, geometry, material, group) => {
  45285. if (material.program) {
  45286. _this.getContext().useProgram(material.program.program);
  45287. if (material.program.getUniforms().map.level) {
  45288. let level = geometryNode.getLevel();
  45289. material.uniforms.level.value = level;
  45290. material.program.getUniforms().map.level.setValue(_this.getContext(), level);
  45291. }
  45292. if (this.visibleNodeTextureOffsets && material.program.getUniforms().map.vnStart) {
  45293. let vnStart = this.visibleNodeTextureOffsets.get(node);
  45294. material.uniforms.vnStart.value = vnStart;
  45295. material.program.getUniforms().map.vnStart.setValue(_this.getContext(), vnStart);
  45296. }
  45297. if (material.program.getUniforms().map.pcIndex) {
  45298. let i = node.pcIndex ? node.pcIndex : this.visibleNodes.indexOf(node);
  45299. material.uniforms.pcIndex.value = i;
  45300. material.program.getUniforms().map.pcIndex.setValue(_this.getContext(), i);
  45301. }
  45302. }
  45303. };
  45304. node.geometryNode = geometryNode;
  45305. node.sceneNode = sceneNode;
  45306. node.pointcloud = this;
  45307. node.left = geometryNode.left;
  45308. node.right = geometryNode.right;
  45309. if (!parent) {
  45310. this.root = node;
  45311. this.add(sceneNode);
  45312. } else {
  45313. parent.sceneNode.add(sceneNode);
  45314. if (parent.left === geometryNode) {
  45315. parent.left = node;
  45316. } else if (parent.right === geometryNode) {
  45317. parent.right = node;
  45318. }
  45319. }
  45320. let disposeListener = function () {
  45321. parent.sceneNode.remove(node.sceneNode);
  45322. if (parent.left === node) {
  45323. parent.left = geometryNode;
  45324. } else if (parent.right === node) {
  45325. parent.right = geometryNode;
  45326. }
  45327. };
  45328. geometryNode.oneTimeDisposeHandlers.push(disposeListener);
  45329. return node;
  45330. }
  45331. updateMaterial (material, visibleNodes, camera, renderer) {
  45332. material.fov = camera.fov * (Math.PI / 180);
  45333. material.screenWidth = renderer.domElement.clientWidth;
  45334. material.screenHeight = renderer.domElement.clientHeight;
  45335. material.spacing = this.pcoGeometry.spacing;
  45336. material.near = camera.near;
  45337. material.far = camera.far;
  45338. // reduce shader source updates by setting maxLevel slightly higher than actually necessary
  45339. if (this.maxLevel > material.levels) {
  45340. material.levels = this.maxLevel + 2;
  45341. }
  45342. // material.uniforms.octreeSize.value = this.boundingBox.size().x;
  45343. let bbSize = this.boundingBox.getSize(new Vector3());
  45344. material.bbSize = [bbSize.x, bbSize.y, bbSize.z];
  45345. }
  45346. updateVisibleBounds () {
  45347. }
  45348. hideDescendants (object) {
  45349. let stack = [];
  45350. for (let i = 0; i < object.children.length; i++) {
  45351. let child = object.children[i];
  45352. if (child.visible) {
  45353. stack.push(child);
  45354. }
  45355. }
  45356. while (stack.length > 0) {
  45357. let child = stack.shift();
  45358. child.visible = false;
  45359. if (child.boundingBoxNode) {
  45360. child.boundingBoxNode.visible = false;
  45361. }
  45362. for (let i = 0; i < child.children.length; i++) {
  45363. let childOfChild = child.children[i];
  45364. if (childOfChild.visible) {
  45365. stack.push(childOfChild);
  45366. }
  45367. }
  45368. }
  45369. }
  45370. updateMatrixWorld (force) {
  45371. // node.matrixWorld.multiplyMatrices( node.parent.matrixWorld, node.matrix );
  45372. if (this.matrixAutoUpdate === true) this.updateMatrix();
  45373. if (this.matrixWorldNeedsUpdate === true || force === true) {
  45374. if (this.parent === undefined) {
  45375. this.matrixWorld.copy(this.matrix);
  45376. } else {
  45377. this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
  45378. }
  45379. this.matrixWorldNeedsUpdate = false;
  45380. force = true;
  45381. }
  45382. }
  45383. nodesOnRay (nodes, ray) {
  45384. let nodesOnRay = [];
  45385. let _ray = ray.clone();
  45386. for (let i = 0; i < nodes.length; i++) {
  45387. let node = nodes[i];
  45388. let sphere = node.getBoundingSphere().clone().applyMatrix4(node.sceneNode.matrixWorld);
  45389. // TODO Unused: let box = node.getBoundingBox().clone().applyMatrix4(node.sceneNode.matrixWorld);
  45390. if (_ray.intersectsSphere(sphere)) {
  45391. nodesOnRay.push(node);
  45392. }
  45393. // if(_ray.isIntersectionBox(box)){
  45394. // nodesOnRay.push(node);
  45395. // }
  45396. }
  45397. return nodesOnRay;
  45398. }
  45399. pick(viewer, camera, ray, params = {}){
  45400. let renderer = viewer.renderer;
  45401. let pRenderer = viewer.pRenderer;
  45402. performance.mark("pick-start");
  45403. let getVal = (a, b) => a !== undefined ? a : b;
  45404. let pickWindowSize = getVal(params.pickWindowSize, 17);
  45405. let pickOutsideClipRegion = getVal(params.pickOutsideClipRegion, false);
  45406. let size = renderer.getSize(new Vector2$1());
  45407. let width = Math.ceil(getVal(params.width, size.width));
  45408. let height = Math.ceil(getVal(params.height, size.height));
  45409. let pointSizeType = getVal(params.pointSizeType, this.material.pointSizeType);
  45410. let pointSize = getVal(params.pointSize, this.material.size);
  45411. let nodes = this.nodesOnRay(this.visibleNodes, ray);
  45412. if (nodes.length === 0) {
  45413. return null;
  45414. }
  45415. if (!this.pickState) {
  45416. let scene = new Scene();
  45417. let material = new PointCloudMaterial$1();
  45418. material.activeAttributeName = "indices";
  45419. let renderTarget = new WebGLRenderTarget(
  45420. 1, 1,
  45421. { minFilter: LinearFilter,
  45422. magFilter: NearestFilter,
  45423. format: RGBAFormat }
  45424. );
  45425. this.pickState = {
  45426. renderTarget: renderTarget,
  45427. material: material,
  45428. scene: scene
  45429. };
  45430. };
  45431. let pickState = this.pickState;
  45432. let pickMaterial = pickState.material;
  45433. { // update pick material
  45434. pickMaterial.pointSizeType = pointSizeType;
  45435. pickMaterial.shape = this.material.shape;
  45436. pickMaterial.size = pointSize;
  45437. pickMaterial.uniforms.minSize.value = this.material.uniforms.minSize.value;
  45438. pickMaterial.uniforms.maxSize.value = this.material.uniforms.maxSize.value;
  45439. pickMaterial.classification = this.material.classification;
  45440. if(params.pickClipped){
  45441. pickMaterial.clipBoxes = this.material.clipBoxes;
  45442. if(this.material.clipTask === ClipTask.HIGHLIGHT){
  45443. pickMaterial.clipTask = ClipTask.NONE;
  45444. }else {
  45445. pickMaterial.clipTask = this.material.clipTask;
  45446. }
  45447. }else {
  45448. pickMaterial.clipBoxes = [];
  45449. }
  45450. this.updateMaterial(pickMaterial, nodes, camera, renderer);
  45451. }
  45452. pickState.renderTarget.setSize(width, height);
  45453. let pixelPos = new Vector2$1(params.x, params.y);
  45454. let gl = renderer.getContext();
  45455. gl.enable(gl.SCISSOR_TEST);
  45456. gl.scissor(
  45457. parseInt(pixelPos.x - (pickWindowSize - 1) / 2),
  45458. parseInt(pixelPos.y - (pickWindowSize - 1) / 2),
  45459. parseInt(pickWindowSize), parseInt(pickWindowSize));
  45460. renderer.state.buffers.depth.setTest(pickMaterial.depthTest);
  45461. renderer.state.buffers.depth.setMask(pickMaterial.depthWrite);
  45462. renderer.state.setBlending(NoBlending);
  45463. renderer.clearTarget(pickState.renderTarget, true, true, true);
  45464. { // RENDER
  45465. renderer.setRenderTarget(pickState.renderTarget);
  45466. gl.clearColor(0, 0, 0, 0);
  45467. renderer.clearTarget( pickState.renderTarget, true, true, true );
  45468. let tmp = this.material;
  45469. this.material = pickMaterial;
  45470. pRenderer.renderOctree(this, nodes, camera, pickState.renderTarget);
  45471. this.material = tmp;
  45472. }
  45473. let clamp = (number, min, max) => Math.min(Math.max(min, number), max);
  45474. let x = parseInt(clamp(pixelPos.x - (pickWindowSize - 1) / 2, 0, width));
  45475. let y = parseInt(clamp(pixelPos.y - (pickWindowSize - 1) / 2, 0, height));
  45476. let w = parseInt(Math.min(x + pickWindowSize, width) - x);
  45477. let h = parseInt(Math.min(y + pickWindowSize, height) - y);
  45478. let pixelCount = w * h;
  45479. let buffer = new Uint8Array(4 * pixelCount);
  45480. gl.readPixels(x, y, pickWindowSize, pickWindowSize, gl.RGBA, gl.UNSIGNED_BYTE, buffer);
  45481. renderer.setRenderTarget(null);
  45482. renderer.state.reset();
  45483. renderer.setScissorTest(false);
  45484. gl.disable(gl.SCISSOR_TEST);
  45485. let pixels = buffer;
  45486. let ibuffer = new Uint32Array(buffer.buffer);
  45487. // find closest hit inside pixelWindow boundaries
  45488. let min = Number.MAX_VALUE;
  45489. let hits = [];
  45490. for (let u = 0; u < pickWindowSize; u++) {
  45491. for (let v = 0; v < pickWindowSize; v++) {
  45492. let offset = (u + v * pickWindowSize);
  45493. let distance = Math.pow(u - (pickWindowSize - 1) / 2, 2) + Math.pow(v - (pickWindowSize - 1) / 2, 2);
  45494. let pcIndex = pixels[4 * offset + 3];
  45495. pixels[4 * offset + 3] = 0;
  45496. let pIndex = ibuffer[offset];
  45497. if(!(pcIndex === 0 && pIndex === 0) && (pcIndex !== undefined) && (pIndex !== undefined)){
  45498. let hit = {
  45499. pIndex: pIndex,
  45500. pcIndex: pcIndex,
  45501. distanceToCenter: distance
  45502. };
  45503. if(params.all){
  45504. hits.push(hit);
  45505. }else {
  45506. if(hits.length > 0){
  45507. if(distance < hits[0].distanceToCenter){
  45508. hits[0] = hit;
  45509. }
  45510. }else {
  45511. hits.push(hit);
  45512. }
  45513. }
  45514. }
  45515. }
  45516. }
  45517. for(let hit of hits){
  45518. let point = {};
  45519. if (!nodes[hit.pcIndex]) {
  45520. return null;
  45521. }
  45522. let node = nodes[hit.pcIndex];
  45523. let pc = node.sceneNode;
  45524. let geometry = node.geometryNode.geometry;
  45525. for(let attributeName in geometry.attributes){
  45526. let attribute = geometry.attributes[attributeName];
  45527. if (attributeName === 'position') {
  45528. let x = attribute.array[3 * hit.pIndex + 0];
  45529. let y = attribute.array[3 * hit.pIndex + 1];
  45530. let z = attribute.array[3 * hit.pIndex + 2];
  45531. let position = new Vector3(x, y, z);
  45532. position.applyMatrix4(pc.matrixWorld);
  45533. point[attributeName] = position;
  45534. } else if (attributeName === 'indices') {
  45535. } else {
  45536. //if (values.itemSize === 1) {
  45537. // point[attribute.name] = values.array[hit.pIndex];
  45538. //} else {
  45539. // let value = [];
  45540. // for (let j = 0; j < values.itemSize; j++) {
  45541. // value.push(values.array[values.itemSize * hit.pIndex + j]);
  45542. // }
  45543. // point[attribute.name] = value;
  45544. //}
  45545. }
  45546. }
  45547. hit.point = point;
  45548. }
  45549. performance.mark("pick-end");
  45550. performance.measure("pick", "pick-start", "pick-end");
  45551. if(params.all){
  45552. return hits.map(hit => hit.point);
  45553. }else {
  45554. if(hits.length === 0){
  45555. return null;
  45556. }else {
  45557. return hits[0].point;
  45558. }
  45559. }
  45560. }
  45561. computeVisibilityTextureData(nodes){
  45562. if(exports.measureTimings) performance.mark("computeVisibilityTextureData-start");
  45563. let data = new Uint8Array(nodes.length * 3);
  45564. let visibleNodeTextureOffsets = new Map();
  45565. // copy array
  45566. nodes = nodes.slice();
  45567. // sort by level and number
  45568. let sort = function (a, b) {
  45569. let la = a.geometryNode.level;
  45570. let lb = b.geometryNode.level;
  45571. let na = a.geometryNode.number;
  45572. let nb = b.geometryNode.number;
  45573. if (la !== lb) return la - lb;
  45574. if (na < nb) return -1;
  45575. if (na > nb) return 1;
  45576. return 0;
  45577. };
  45578. nodes.sort(sort);
  45579. let visibleNodeNames = [];
  45580. for (let i = 0; i < nodes.length; i++) {
  45581. visibleNodeNames.push(nodes[i].geometryNode.number);
  45582. }
  45583. for (let i = 0; i < nodes.length; i++) {
  45584. let node = nodes[i];
  45585. visibleNodeTextureOffsets.set(node, i);
  45586. let b1 = 0; // children
  45587. let b2 = 0; // offset to first child
  45588. let b3 = 0; // split
  45589. if (node.geometryNode.left && visibleNodeNames.indexOf(node.geometryNode.left.number) > 0) {
  45590. b1 += 1;
  45591. b2 = visibleNodeNames.indexOf(node.geometryNode.left.number) - i;
  45592. }
  45593. if (node.geometryNode.right && visibleNodeNames.indexOf(node.geometryNode.right.number) > 0) {
  45594. b1 += 2;
  45595. b2 = (b2 === 0) ? visibleNodeNames.indexOf(node.geometryNode.right.number) - i : b2;
  45596. }
  45597. if (node.geometryNode.split === 'X') {
  45598. b3 = 1;
  45599. } else if (node.geometryNode.split === 'Y') {
  45600. b3 = 2;
  45601. } else if (node.geometryNode.split === 'Z') {
  45602. b3 = 4;
  45603. }
  45604. data[i * 3 + 0] = b1;
  45605. data[i * 3 + 1] = b2;
  45606. data[i * 3 + 2] = b3;
  45607. }
  45608. if(exports.measureTimings){
  45609. performance.mark("computeVisibilityTextureData-end");
  45610. performance.measure("render.computeVisibilityTextureData", "computeVisibilityTextureData-start", "computeVisibilityTextureData-end");
  45611. }
  45612. return {
  45613. data: data,
  45614. offsets: visibleNodeTextureOffsets
  45615. };
  45616. }
  45617. get progress () {
  45618. if (this.pcoGeometry.root) {
  45619. return exports.numNodesLoading > 0 ? 0 : 1;
  45620. } else {
  45621. return 0;
  45622. }
  45623. }
  45624. };
  45625. // Copied from three.js: WebGLRenderer.js
  45626. function paramThreeToGL(_gl, p) {
  45627. let extension;
  45628. if (p === RepeatWrapping) return _gl.REPEAT;
  45629. if (p === ClampToEdgeWrapping) return _gl.CLAMP_TO_EDGE;
  45630. if (p === MirroredRepeatWrapping) return _gl.MIRRORED_REPEAT;
  45631. if (p === NearestFilter) return _gl.NEAREST;
  45632. if (p === NearestMipMapNearestFilter) return _gl.NEAREST_MIPMAP_NEAREST;
  45633. if (p === NearestMipMapLinearFilter) return _gl.NEAREST_MIPMAP_LINEAR;
  45634. if (p === LinearFilter) return _gl.LINEAR;
  45635. if (p === LinearMipMapNearestFilter) return _gl.LINEAR_MIPMAP_NEAREST;
  45636. if (p === LinearMipMapLinearFilter) return _gl.LINEAR_MIPMAP_LINEAR;
  45637. if (p === UnsignedByteType) return _gl.UNSIGNED_BYTE;
  45638. if (p === UnsignedShort4444Type) return _gl.UNSIGNED_SHORT_4_4_4_4;
  45639. if (p === UnsignedShort5551Type) return _gl.UNSIGNED_SHORT_5_5_5_1;
  45640. if (p === UnsignedShort565Type) return _gl.UNSIGNED_SHORT_5_6_5;
  45641. if (p === ByteType) return _gl.BYTE;
  45642. if (p === ShortType) return _gl.SHORT;
  45643. if (p === UnsignedShortType) return _gl.UNSIGNED_SHORT;
  45644. if (p === IntType) return _gl.INT;
  45645. if (p === UnsignedIntType) return _gl.UNSIGNED_INT;
  45646. if (p === FloatType) return _gl.FLOAT;
  45647. if (p === HalfFloatType) {
  45648. extension = extensions.get('OES_texture_half_float');
  45649. if (extension !== null) return extension.HALF_FLOAT_OES;
  45650. }
  45651. if (p === AlphaFormat) return _gl.ALPHA;
  45652. if (p === RGBFormat) return _gl.RGB;
  45653. if (p === RGBAFormat) return _gl.RGBA;
  45654. if (p === LuminanceFormat) return _gl.LUMINANCE;
  45655. if (p === LuminanceAlphaFormat) return _gl.LUMINANCE_ALPHA;
  45656. if (p === DepthFormat) return _gl.DEPTH_COMPONENT;
  45657. if (p === DepthStencilFormat) return _gl.DEPTH_STENCIL;
  45658. if (p === AddEquation) return _gl.FUNC_ADD;
  45659. if (p === SubtractEquation) return _gl.FUNC_SUBTRACT;
  45660. if (p === ReverseSubtractEquation) return _gl.FUNC_REVERSE_SUBTRACT;
  45661. if (p === ZeroFactor) return _gl.ZERO;
  45662. if (p === OneFactor) return _gl.ONE;
  45663. if (p === SrcColorFactor) return _gl.SRC_COLOR;
  45664. if (p === OneMinusSrcColorFactor) return _gl.ONE_MINUS_SRC_COLOR;
  45665. if (p === SrcAlphaFactor) return _gl.SRC_ALPHA;
  45666. if (p === OneMinusSrcAlphaFactor) return _gl.ONE_MINUS_SRC_ALPHA;
  45667. if (p === DstAlphaFactor) return _gl.DST_ALPHA;
  45668. if (p === OneMinusDstAlphaFactor) return _gl.ONE_MINUS_DST_ALPHA;
  45669. if (p === DstColorFactor) return _gl.DST_COLOR;
  45670. if (p === OneMinusDstColorFactor) return _gl.ONE_MINUS_DST_COLOR;
  45671. if (p === SrcAlphaSaturateFactor) return _gl.SRC_ALPHA_SATURATE;
  45672. if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
  45673. p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) {
  45674. extension = extensions.get('WEBGL_compressed_texture_s3tc');
  45675. if (extension !== null) {
  45676. if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
  45677. if (p === RGBA_S3TC_DXT1_Format$1) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
  45678. if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
  45679. if (p === RGBA_S3TC_DXT5_Format$1) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
  45680. }
  45681. }
  45682. if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
  45683. p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) {
  45684. extension = extensions.get('WEBGL_compressed_texture_pvrtc');
  45685. if (extension !== null) {
  45686. if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
  45687. if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  45688. if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
  45689. if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
  45690. }
  45691. }
  45692. if (p === RGB_ETC1_Format) {
  45693. extension = extensions.get('WEBGL_compressed_texture_etc1');
  45694. if (extension !== null) return extension.COMPRESSED_RGB_ETC1_WEBGL;
  45695. }
  45696. if (p === MinEquation || p === MaxEquation) {
  45697. extension = extensions.get('EXT_blend_minmax');
  45698. if (extension !== null) {
  45699. if (p === MinEquation) return extension.MIN_EXT;
  45700. if (p === MaxEquation) return extension.MAX_EXT;
  45701. }
  45702. }
  45703. if (p === UnsignedInt248Type) {
  45704. extension = extensions.get('WEBGL_depth_texture');
  45705. if (extension !== null) return extension.UNSIGNED_INT_24_8_WEBGL;
  45706. }
  45707. return 0;
  45708. };
  45709. let attributeLocations = {
  45710. "position": {name: "position", location: 0},
  45711. "color": {name: "color", location: 1},
  45712. "rgba": {name: "color", location: 1},
  45713. "intensity": {name: "intensity", location: 2},
  45714. "classification": {name: "classification", location: 3},
  45715. "returnNumber": {name: "returnNumber", location: 4},
  45716. "return number": {name: "returnNumber", location: 4},
  45717. "returns": {name: "returnNumber", location: 4},
  45718. "numberOfReturns": {name: "numberOfReturns", location: 5},
  45719. "number of returns": {name: "numberOfReturns", location: 5},
  45720. "pointSourceID": {name: "pointSourceID", location: 6},
  45721. "source id": {name: "pointSourceID", location: 6},
  45722. "point source id": {name: "pointSourceID", location: 6},
  45723. "indices": {name: "indices", location: 7},
  45724. "normal": {name: "normal", location: 8},
  45725. "spacing": {name: "spacing", location: 9},
  45726. "gps-time": {name: "gpsTime", location: 10},
  45727. "aExtra": {name: "aExtra", location: 11},
  45728. };
  45729. class Shader {
  45730. constructor(gl, name, vsSource, fsSource) {
  45731. this.gl = gl;
  45732. this.name = name;
  45733. this.vsSource = vsSource;
  45734. this.fsSource = fsSource;
  45735. this.cache = new Map();
  45736. this.vs = null;
  45737. this.fs = null;
  45738. this.program = null;
  45739. this.uniformLocations = {};
  45740. this.attributeLocations = {};
  45741. this.uniformBlockIndices = {};
  45742. this.uniformBlocks = {};
  45743. this.uniforms = {};
  45744. this.update(vsSource, fsSource);
  45745. }
  45746. update(vsSource, fsSource) {
  45747. this.vsSource = vsSource;
  45748. this.fsSource = fsSource;
  45749. this.linkProgram();
  45750. }
  45751. compileShader(shader, source){
  45752. let gl = this.gl;
  45753. gl.shaderSource(shader, source);
  45754. gl.compileShader(shader);
  45755. let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  45756. if (!success) {
  45757. let info = gl.getShaderInfoLog(shader);
  45758. let numberedSource = source.split("\n").map((a, i) => `${i + 1}`.padEnd(5) + a).join("\n");
  45759. throw `could not compile shader ${this.name}: ${info}, \n${numberedSource}`;
  45760. }
  45761. }
  45762. linkProgram() {
  45763. const tStart = performance.now();
  45764. let gl = this.gl;
  45765. this.uniformLocations = {};
  45766. this.attributeLocations = {};
  45767. this.uniforms = {};
  45768. gl.useProgram(null);
  45769. let cached = this.cache.get(`${this.vsSource}, ${this.fsSource}`);
  45770. if (cached) {
  45771. this.program = cached.program;
  45772. this.vs = cached.vs;
  45773. this.fs = cached.fs;
  45774. this.attributeLocations = cached.attributeLocations;
  45775. this.uniformLocations = cached.uniformLocations;
  45776. this.uniformBlocks = cached.uniformBlocks;
  45777. this.uniforms = cached.uniforms;
  45778. return;
  45779. } else {
  45780. this.vs = gl.createShader(gl.VERTEX_SHADER);
  45781. this.fs = gl.createShader(gl.FRAGMENT_SHADER);
  45782. this.program = gl.createProgram();
  45783. if( !gl.isProgram(this.program )){//创建失败 开启多个页面可能会,原因是webglcontextlost
  45784. //console.error('创建program失败');
  45785. viewer.dispatchEvent('webglError', {msg: 'potreeRenderer创建program失败'});
  45786. console.log(this.vs);
  45787. console.log(this.fs);
  45788. return;
  45789. }
  45790. for(let name of Object.keys(attributeLocations)){
  45791. let location = attributeLocations[name].location;
  45792. let glslName = attributeLocations[name].name;
  45793. gl.bindAttribLocation(this.program, location, glslName);
  45794. }
  45795. this.compileShader(this.vs, this.vsSource);
  45796. this.compileShader(this.fs, this.fsSource);
  45797. let program = this.program;
  45798. gl.attachShader(program, this.vs);
  45799. gl.attachShader(program, this.fs);
  45800. gl.linkProgram(program);
  45801. gl.detachShader(program, this.vs);
  45802. gl.detachShader(program, this.fs);
  45803. // 检测当前程序链接状态
  45804. let success = gl.getProgramParameter(program, gl.LINK_STATUS);
  45805. if (!success) {
  45806. let info = gl.getProgramInfoLog(program);
  45807. throw `could not link program ${this.name}: ${info}`;
  45808. }
  45809. { // attribute locations
  45810. let numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
  45811. for (let i = 0; i < numAttributes; i++) {
  45812. let attribute = gl.getActiveAttrib(program, i);
  45813. let location = gl.getAttribLocation(program, attribute.name);
  45814. this.attributeLocations[attribute.name] = location;
  45815. }
  45816. }
  45817. { // uniform locations
  45818. let numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
  45819. for (let i = 0; i < numUniforms; i++) {
  45820. let uniform = gl.getActiveUniform(program, i);
  45821. let location = gl.getUniformLocation(program, uniform.name);
  45822. this.uniformLocations[uniform.name] = location;
  45823. this.uniforms[uniform.name] = {
  45824. location: location,
  45825. value: null,
  45826. };
  45827. }
  45828. }
  45829. // uniform blocks
  45830. if( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext){ //WebGL2RenderingContext在mac的safari14以下是没有定义的
  45831. let numBlocks = gl.getProgramParameter(program, gl.ACTIVE_UNIFORM_BLOCKS);
  45832. for (let i = 0; i < numBlocks; i++) {
  45833. let blockName = gl.getActiveUniformBlockName(program, i);
  45834. let blockIndex = gl.getUniformBlockIndex(program, blockName);
  45835. this.uniformBlockIndices[blockName] = blockIndex;
  45836. gl.uniformBlockBinding(program, blockIndex, blockIndex);
  45837. let dataSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
  45838. let uBuffer = gl.createBuffer();
  45839. gl.bindBuffer(gl.UNIFORM_BUFFER, uBuffer);
  45840. gl.bufferData(gl.UNIFORM_BUFFER, dataSize, gl.DYNAMIC_READ);
  45841. gl.bindBufferBase(gl.UNIFORM_BUFFER, blockIndex, uBuffer);
  45842. gl.bindBuffer(gl.UNIFORM_BUFFER, null);
  45843. this.uniformBlocks[blockName] = {
  45844. name: blockName,
  45845. index: blockIndex,
  45846. dataSize: dataSize,
  45847. buffer: uBuffer
  45848. };
  45849. }
  45850. }
  45851. let cached = {
  45852. program: this.program,
  45853. vs: this.vs,
  45854. fs: this.fs,
  45855. attributeLocations: this.attributeLocations,
  45856. uniformLocations: this.uniformLocations,
  45857. uniforms: this.uniforms,
  45858. uniformBlocks: this.uniformBlocks,
  45859. };
  45860. this.cache.set(`${this.vsSource}, ${this.fsSource}`, cached);
  45861. }
  45862. const tEnd = performance.now();
  45863. const duration = tEnd - tStart;
  45864. //console.log(`shader compile duration: ${duration.toFixed(3)}`);
  45865. }
  45866. setUniformMatrix4(name, value) {
  45867. const gl = this.gl;
  45868. const location = this.uniformLocations[name];
  45869. if (location == null) {
  45870. return;
  45871. }
  45872. let tmp = new Float32Array(value.elements);
  45873. gl.uniformMatrix4fv(location, false, tmp);
  45874. }
  45875. setUniform1f(name, value) {
  45876. const gl = this.gl;
  45877. const uniform = this.uniforms[name];
  45878. if (uniform === undefined) {
  45879. return;
  45880. }
  45881. if(uniform.value === value){
  45882. return;
  45883. }
  45884. uniform.value = value;
  45885. gl.uniform1f(uniform.location, value);
  45886. }
  45887. setUniformBoolean(name, value) {
  45888. const gl = this.gl;
  45889. const uniform = this.uniforms[name];
  45890. if (uniform === undefined) {
  45891. return;
  45892. }
  45893. if(uniform.value === value){
  45894. return;
  45895. }
  45896. uniform.value = value;
  45897. gl.uniform1i(uniform.location, value);
  45898. }
  45899. setUniformTexture(name, value) {
  45900. const gl = this.gl;
  45901. const location = this.uniformLocations[name];
  45902. if (location == null) {
  45903. return;
  45904. }
  45905. gl.uniform1i(location, value);
  45906. }
  45907. setUniform2f(name, value) {
  45908. const gl = this.gl;
  45909. const location = this.uniformLocations[name];
  45910. if (location == null) {
  45911. return;
  45912. }
  45913. gl.uniform2f(location, value[0], value[1]);
  45914. }
  45915. setUniform3f(name, value) {
  45916. const gl = this.gl;
  45917. const location = this.uniformLocations[name];
  45918. if (location == null) {
  45919. return;
  45920. }
  45921. gl.uniform3f(location, value[0], value[1], value[2]);
  45922. }
  45923. setUniform(name, value) {
  45924. if (value.constructor === Matrix4) {
  45925. this.setUniformMatrix4(name, value);
  45926. } else if (typeof value === "number") {
  45927. this.setUniform1f(name, value);
  45928. } else if (typeof value === "boolean") {
  45929. this.setUniformBoolean(name, value);
  45930. } else if (value instanceof WebGLTexture) {
  45931. this.setUniformTexture(name, value);
  45932. } else if (value instanceof Array) {
  45933. if (value.length === 2) {
  45934. this.setUniform2f(name, value);
  45935. } else if (value.length === 3) {
  45936. this.setUniform3f(name, value);
  45937. }
  45938. } else {
  45939. console.error("unhandled uniform type: ", name, value);
  45940. }
  45941. }
  45942. setUniform1i(name, value) {
  45943. let gl = this.gl;
  45944. let location = this.uniformLocations[name];
  45945. if (location == null) {
  45946. return;
  45947. }
  45948. gl.uniform1i(location, value);
  45949. }
  45950. };
  45951. class WebGLTexture {
  45952. constructor(gl, texture) {
  45953. this.gl = gl;
  45954. this.texture = texture;
  45955. this.id = gl.createTexture();
  45956. this.target = gl.TEXTURE_2D;
  45957. this.version = -1;
  45958. this.update(texture);
  45959. }
  45960. update() {
  45961. if (!this.texture.image) {
  45962. this.version = this.texture.version;
  45963. return;
  45964. }
  45965. let gl = this.gl;
  45966. let texture = this.texture;
  45967. if (this.version === texture.version) {
  45968. return;
  45969. }
  45970. this.target = gl.TEXTURE_2D;
  45971. gl.bindTexture(this.target, this.id);
  45972. let level = 0;
  45973. let internalFormat = paramThreeToGL(gl, texture.format);
  45974. let width = texture.image.width;
  45975. let height = texture.image.height;
  45976. let border = 0;
  45977. let srcFormat = internalFormat;
  45978. let srcType = paramThreeToGL(gl, texture.type);
  45979. let data;
  45980. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, texture.flipY);
  45981. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha);
  45982. gl.pixelStorei(gl.UNPACK_ALIGNMENT, texture.unpackAlignment);
  45983. if (texture instanceof DataTexture) {
  45984. data = texture.image.data;
  45985. gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  45986. gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  45987. gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, paramThreeToGL(gl, texture.magFilter));
  45988. gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, paramThreeToGL(gl, texture.minFilter));
  45989. gl.texImage2D(this.target, level, internalFormat,
  45990. width, height, border, srcFormat, srcType,
  45991. data);
  45992. }/* else if(texture instanceof THREE.CubeTexture){//add
  45993. } */else if ((texture instanceof CanvasTexture) || (texture instanceof Texture)) {
  45994. data = texture.image;
  45995. gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, paramThreeToGL(gl, texture.wrapS));
  45996. gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, paramThreeToGL(gl, texture.wrapT));
  45997. gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, paramThreeToGL(gl, texture.magFilter));
  45998. gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, paramThreeToGL(gl, texture.minFilter));
  45999. gl.texImage2D(this.target, level, internalFormat,
  46000. internalFormat, srcType, data);
  46001. if (texture instanceof Texture) {gl.generateMipmap(gl.TEXTURE_2D);}
  46002. }
  46003. gl.bindTexture(this.target, null);
  46004. this.version = texture.version;
  46005. }
  46006. };
  46007. class WebGLBuffer {
  46008. constructor() {
  46009. this.numElements = 0;
  46010. this.vao = null;
  46011. this.vbos = new Map();
  46012. }
  46013. };
  46014. class Renderer {
  46015. constructor(threeRenderer) {
  46016. this.threeRenderer = threeRenderer;
  46017. this.gl = this.threeRenderer.getContext();
  46018. this.buffers = new Map();
  46019. this.shaders = new Map();
  46020. this.textures = new Map();
  46021. this.glTypeMapping = new Map();
  46022. this.glTypeMapping.set(Float32Array, this.gl.FLOAT);
  46023. this.glTypeMapping.set(Uint8Array, this.gl.UNSIGNED_BYTE);
  46024. this.glTypeMapping.set(Uint16Array, this.gl.UNSIGNED_SHORT);
  46025. this.toggle = 0;
  46026. }
  46027. deleteBuffer(geometry) {
  46028. let gl = this.gl;
  46029. let webglBuffer = this.buffers.get(geometry);
  46030. if (webglBuffer != null) {
  46031. for (let attributeName in geometry.attributes) {
  46032. gl.deleteBuffer(webglBuffer.vbos.get(attributeName).handle);
  46033. }
  46034. this.buffers.delete(geometry);
  46035. }
  46036. }
  46037. createBuffer(geometry){
  46038. let gl = this.gl;
  46039. let webglBuffer = new WebGLBuffer();
  46040. webglBuffer.vao = gl.createVertexArray();
  46041. webglBuffer.numElements = geometry.attributes.position.count;
  46042. gl.bindVertexArray(webglBuffer.vao);
  46043. for(let attributeName in geometry.attributes){
  46044. let bufferAttribute = geometry.attributes[attributeName];
  46045. let vbo = gl.createBuffer();
  46046. gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
  46047. gl.bufferData(gl.ARRAY_BUFFER, bufferAttribute.array, gl.STATIC_DRAW);
  46048. let normalized = bufferAttribute.normalized;
  46049. let type = this.glTypeMapping.get(bufferAttribute.array.constructor);
  46050. if(attributeLocations[attributeName] === undefined){
  46051. //attributeLocation = attributeLocations["aExtra"];
  46052. }else {
  46053. let attributeLocation = attributeLocations[attributeName].location;
  46054. gl.vertexAttribPointer(attributeLocation, bufferAttribute.itemSize, type, normalized, 0, 0);
  46055. gl.enableVertexAttribArray(attributeLocation);
  46056. }
  46057. webglBuffer.vbos.set(attributeName, {
  46058. handle: vbo,
  46059. name: attributeName,
  46060. count: bufferAttribute.count,
  46061. itemSize: bufferAttribute.itemSize,
  46062. type: geometry.attributes.position.array.constructor,
  46063. version: 0
  46064. });
  46065. }
  46066. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  46067. gl.bindVertexArray(null);
  46068. let disposeHandler = (event) => {
  46069. this.deleteBuffer(geometry);
  46070. geometry.removeEventListener("dispose", disposeHandler);
  46071. };
  46072. geometry.addEventListener("dispose", disposeHandler);
  46073. return webglBuffer;
  46074. }
  46075. updateBuffer(geometry){
  46076. let gl = this.gl;
  46077. let webglBuffer = this.buffers.get(geometry);
  46078. gl.bindVertexArray(webglBuffer.vao);
  46079. for(let attributeName in geometry.attributes){
  46080. let bufferAttribute = geometry.attributes[attributeName];
  46081. let normalized = bufferAttribute.normalized;
  46082. let type = this.glTypeMapping.get(bufferAttribute.array.constructor);
  46083. let vbo = null;
  46084. if(!webglBuffer.vbos.has(attributeName)){
  46085. vbo = gl.createBuffer();
  46086. webglBuffer.vbos.set(attributeName, {
  46087. handle: vbo,
  46088. name: attributeName,
  46089. count: bufferAttribute.count,
  46090. itemSize: bufferAttribute.itemSize,
  46091. type: geometry.attributes.position.array.constructor,
  46092. version: bufferAttribute.version
  46093. });
  46094. }else {
  46095. vbo = webglBuffer.vbos.get(attributeName).handle;
  46096. webglBuffer.vbos.get(attributeName).version = bufferAttribute.version;
  46097. }
  46098. gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
  46099. gl.bufferData(gl.ARRAY_BUFFER, bufferAttribute.array, gl.STATIC_DRAW);
  46100. if(attributeLocations[attributeName] === undefined){
  46101. //attributeLocation = attributeLocations["aExtra"];
  46102. }else {
  46103. let attributeLocation = attributeLocations[attributeName].location;
  46104. gl.vertexAttribPointer(attributeLocation, bufferAttribute.itemSize, type, normalized, 0, 0);
  46105. gl.enableVertexAttribArray(attributeLocation);
  46106. }
  46107. }
  46108. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  46109. gl.bindVertexArray(null);
  46110. }
  46111. traverse(scene) {
  46112. let octrees = [];
  46113. let stack = [scene];
  46114. while (stack.length > 0) {
  46115. let node = stack.pop();
  46116. if (node instanceof PointCloudTree) {
  46117. octrees.push(node);
  46118. continue;
  46119. }
  46120. let visibleChildren = node.children.filter(c => c.visible);
  46121. stack.push(...visibleChildren);
  46122. }
  46123. let result = {
  46124. octrees: octrees
  46125. };
  46126. return result;
  46127. }
  46128. renderNodes(octree, nodes, visibilityTextureData, camera, target, shader, params) {
  46129. if (exports.measureTimings) performance.mark("renderNodes-start");
  46130. let gl = this.gl;
  46131. let material = params.material ? params.material : octree.material;
  46132. let shadowMaps = params.shadowMaps == null ? [] : params.shadowMaps;
  46133. let view = camera.matrixWorldInverse;
  46134. if(params.viewOverride){
  46135. view = params.viewOverride;
  46136. }
  46137. let worldView = new Matrix4();
  46138. let mat4holder = new Float32Array(16);
  46139. let i = 0;
  46140. for (let node of nodes) {
  46141. if(exports.debug.allowedNodes !== undefined){
  46142. if(!exports.debug.allowedNodes.includes(node.name)){
  46143. continue;
  46144. }
  46145. }
  46146. let world = node.sceneNode.matrixWorld;
  46147. worldView.multiplyMatrices(view, world);
  46148. if (visibilityTextureData) {
  46149. let vnStart = visibilityTextureData.offsets.get(node);
  46150. shader.setUniform1f("uVNStart", vnStart);
  46151. }
  46152. let level = node.getLevel();
  46153. if(node.debug){
  46154. shader.setUniform("uDebug", true);
  46155. }else {
  46156. shader.setUniform("uDebug", false);
  46157. }
  46158. // let isLeaf = false;
  46159. // if(node instanceof PointCloudOctreeNode){
  46160. // isLeaf = Object.keys(node.children).length === 0;
  46161. // }else if(node instanceof PointCloudArena4DNode){
  46162. // isLeaf = node.geometryNode.isLeaf;
  46163. // }
  46164. // shader.setUniform("uIsLeafNode", isLeaf);
  46165. // let isLeaf = node.children.filter(n => n != null).length === 0;
  46166. // if(!isLeaf){
  46167. // continue;
  46168. // }
  46169. // TODO consider passing matrices in an array to avoid uniformMatrix4fv overhead
  46170. const lModel = shader.uniformLocations["modelMatrix"];
  46171. if (lModel) {
  46172. mat4holder.set(world.elements);
  46173. gl.uniformMatrix4fv(lModel, false, mat4holder);
  46174. }
  46175. const lModelView = shader.uniformLocations["modelViewMatrix"];
  46176. //mat4holder.set(worldView.elements);
  46177. // faster then set in chrome 63
  46178. for(let j = 0; j < 16; j++){
  46179. mat4holder[j] = worldView.elements[j];
  46180. }
  46181. gl.uniformMatrix4fv(lModelView, false, mat4holder);
  46182. { // Clip Polygons
  46183. if(material.clipPolygons && material.clipPolygons.length > 0){
  46184. let clipPolygonVCount = [];
  46185. let worldViewProjMatrices = [];
  46186. for(let clipPolygon of material.clipPolygons){
  46187. let view = clipPolygon.viewMatrix;
  46188. let proj = clipPolygon.projMatrix;
  46189. let worldViewProj = proj.clone().multiply(view).multiply(world);
  46190. clipPolygonVCount.push(clipPolygon.markers.length);
  46191. worldViewProjMatrices.push(worldViewProj);
  46192. }
  46193. let flattenedMatrices = [].concat(...worldViewProjMatrices.map(m => m.elements));
  46194. let flattenedVertices = new Array(8 * 3 * material.clipPolygons.length);
  46195. for(let i = 0; i < material.clipPolygons.length; i++){
  46196. let clipPolygon = material.clipPolygons[i];
  46197. for(let j = 0; j < clipPolygon.markers.length; j++){
  46198. flattenedVertices[i * 24 + (j * 3 + 0)] = clipPolygon.markers[j].position.x;
  46199. flattenedVertices[i * 24 + (j * 3 + 1)] = clipPolygon.markers[j].position.y;
  46200. flattenedVertices[i * 24 + (j * 3 + 2)] = clipPolygon.markers[j].position.z;
  46201. }
  46202. }
  46203. const lClipPolygonVCount = shader.uniformLocations["uClipPolygonVCount[0]"];
  46204. gl.uniform1iv(lClipPolygonVCount, clipPolygonVCount);
  46205. const lClipPolygonVP = shader.uniformLocations["uClipPolygonWVP[0]"];
  46206. gl.uniformMatrix4fv(lClipPolygonVP, false, flattenedMatrices);
  46207. const lClipPolygons = shader.uniformLocations["uClipPolygonVertices[0]"];
  46208. gl.uniform3fv(lClipPolygons, flattenedVertices);
  46209. }
  46210. }
  46211. //shader.setUniformMatrix4("modelMatrix", world);
  46212. //shader.setUniformMatrix4("modelViewMatrix", worldView);
  46213. shader.setUniform1f("uLevel", level);
  46214. shader.setUniform1f("uNodeSpacing", node.geometryNode.estimatedSpacing);
  46215. shader.setUniform1f("uPCIndex", i);
  46216. // uBBSize
  46217. if (shadowMaps.length > 0) {
  46218. const lShadowMap = shader.uniformLocations["uShadowMap[0]"];
  46219. shader.setUniform3f("uShadowColor", material.uniforms.uShadowColor.value);
  46220. let bindingStart = 5;
  46221. let bindingPoints = new Array(shadowMaps.length).fill(bindingStart).map((a, i) => (a + i));
  46222. gl.uniform1iv(lShadowMap, bindingPoints);
  46223. for (let i = 0; i < shadowMaps.length; i++) {
  46224. let shadowMap = shadowMaps[i];
  46225. let bindingPoint = bindingPoints[i];
  46226. let glTexture = this.threeRenderer.properties.get(shadowMap.target.texture).__webglTexture;
  46227. gl.activeTexture(gl[`TEXTURE${bindingPoint}`]);
  46228. gl.bindTexture(gl.TEXTURE_2D, glTexture);
  46229. }
  46230. {
  46231. let worldViewMatrices = shadowMaps
  46232. .map(sm => sm.camera.matrixWorldInverse)
  46233. .map(view => new Matrix4().multiplyMatrices(view, world));
  46234. let flattenedMatrices = [].concat(...worldViewMatrices.map(c => c.elements));
  46235. const lWorldView = shader.uniformLocations["uShadowWorldView[0]"];
  46236. gl.uniformMatrix4fv(lWorldView, false, flattenedMatrices);
  46237. }
  46238. {
  46239. let flattenedMatrices = [].concat(...shadowMaps.map(sm => sm.camera.projectionMatrix.elements));
  46240. const lProj = shader.uniformLocations["uShadowProj[0]"];
  46241. gl.uniformMatrix4fv(lProj, false, flattenedMatrices);
  46242. }
  46243. }
  46244. const geometry = node.geometryNode.geometry;
  46245. if(geometry.attributes["gps-time"]){
  46246. const bufferAttribute = geometry.attributes["gps-time"];
  46247. const attGPS = octree.getAttribute("gps-time");
  46248. let initialRange = attGPS.initialRange;
  46249. let initialRangeSize = initialRange[1] - initialRange[0];
  46250. let globalRange = attGPS.range;
  46251. let globalRangeSize = globalRange[1] - globalRange[0];
  46252. let scale = initialRangeSize / globalRangeSize;
  46253. let offset = -(globalRange[0] - initialRange[0]) / initialRangeSize;
  46254. scale = Number.isNaN(scale) ? 1 : scale;
  46255. offset = Number.isNaN(offset) ? 0 : offset;
  46256. shader.setUniform1f("uGpsScale", scale);
  46257. shader.setUniform1f("uGpsOffset", offset);
  46258. //shader.setUniform2f("uFilterGPSTimeClipRange", [-Infinity, Infinity]);
  46259. let uFilterGPSTimeClipRange = material.uniforms.uFilterGPSTimeClipRange.value;
  46260. // let gpsCliPRangeMin = uFilterGPSTimeClipRange[0]
  46261. // let gpsCliPRangeMax = uFilterGPSTimeClipRange[1]
  46262. // shader.setUniform2f("uFilterGPSTimeClipRange", [gpsCliPRangeMin, gpsCliPRangeMax]);
  46263. let normalizedClipRange = [
  46264. (uFilterGPSTimeClipRange[0] - globalRange[0]) / globalRangeSize,
  46265. (uFilterGPSTimeClipRange[1] - globalRange[0]) / globalRangeSize,
  46266. ];
  46267. shader.setUniform2f("uFilterGPSTimeClipRange", normalizedClipRange);
  46268. // // ranges in full gps coordinate system
  46269. // const globalRange = attGPS.range;
  46270. // const bufferRange = bufferAttribute.potree.range;
  46271. // // ranges in [0, 1]
  46272. // // normalizedGlobalRange = [0, 1]
  46273. // // normalizedBufferRange: norm buffer within norm global range e.g. [0.2, 0.8]
  46274. // const globalWidth = globalRange[1] - globalRange[0];
  46275. // const normalizedBufferRange = [
  46276. // (bufferRange[0] - globalRange[0]) / globalWidth,
  46277. // (bufferRange[1] - globalRange[0]) / globalWidth,
  46278. // ];
  46279. // shader.setUniform2f("uNormalizedGpsBufferRange", normalizedBufferRange);
  46280. // let uFilterGPSTimeClipRange = material.uniforms.uFilterGPSTimeClipRange.value;
  46281. // let gpsCliPRangeMin = uFilterGPSTimeClipRange[0]
  46282. // let gpsCliPRangeMax = uFilterGPSTimeClipRange[1]
  46283. // shader.setUniform2f("uFilterGPSTimeClipRange", [gpsCliPRangeMin, gpsCliPRangeMax]);
  46284. // shader.setUniform1f("uGpsScale", bufferAttribute.potree.scale);
  46285. // shader.setUniform1f("uGpsOffset", bufferAttribute.potree.offset);
  46286. }
  46287. {
  46288. let uFilterReturnNumberRange = material.uniforms.uFilterReturnNumberRange.value;
  46289. let uFilterNumberOfReturnsRange = material.uniforms.uFilterNumberOfReturnsRange.value;
  46290. let uFilterPointSourceIDClipRange = material.uniforms.uFilterPointSourceIDClipRange.value;
  46291. shader.setUniform2f("uFilterReturnNumberRange", uFilterReturnNumberRange);
  46292. shader.setUniform2f("uFilterNumberOfReturnsRange", uFilterNumberOfReturnsRange);
  46293. shader.setUniform2f("uFilterPointSourceIDClipRange", uFilterPointSourceIDClipRange);
  46294. }
  46295. let webglBuffer = null;
  46296. if(!this.buffers.has(geometry)){
  46297. webglBuffer = this.createBuffer(geometry);
  46298. this.buffers.set(geometry, webglBuffer);
  46299. }else {
  46300. webglBuffer = this.buffers.get(geometry);
  46301. for(let attributeName in geometry.attributes){
  46302. let attribute = geometry.attributes[attributeName];
  46303. if(attribute.version > webglBuffer.vbos.get(attributeName).version){
  46304. this.updateBuffer(geometry);
  46305. }
  46306. }
  46307. }
  46308. gl.bindVertexArray(webglBuffer.vao);
  46309. let isExtraAttribute =
  46310. attributeLocations[material.activeAttributeName] === undefined
  46311. && Object.keys(geometry.attributes).includes(material.activeAttributeName);
  46312. if(isExtraAttribute){
  46313. const attributeLocation = attributeLocations["aExtra"].location;
  46314. for(const attributeName in geometry.attributes){
  46315. const bufferAttribute = geometry.attributes[attributeName];
  46316. const vbo = webglBuffer.vbos.get(attributeName);
  46317. gl.bindBuffer(gl.ARRAY_BUFFER, vbo.handle);
  46318. gl.disableVertexAttribArray(attributeLocation);
  46319. }
  46320. const attName = material.activeAttributeName;
  46321. const bufferAttribute = geometry.attributes[attName];
  46322. const vbo = webglBuffer.vbos.get(attName);
  46323. if(bufferAttribute !== undefined && vbo !== undefined){
  46324. let type = this.glTypeMapping.get(bufferAttribute.array.constructor);
  46325. let normalized = bufferAttribute.normalized;
  46326. gl.bindBuffer(gl.ARRAY_BUFFER, vbo.handle);
  46327. gl.vertexAttribPointer(attributeLocation, bufferAttribute.itemSize, type, normalized, 0, 0);
  46328. gl.enableVertexAttribArray(attributeLocation);
  46329. }
  46330. {
  46331. const attExtra = octree.pcoGeometry.pointAttributes.attributes
  46332. .find(a => a.name === attName);
  46333. let range = material.getRange(attName);
  46334. if(!range){
  46335. range = attExtra.range;
  46336. }
  46337. if(!range){
  46338. range = [0, 1];
  46339. }
  46340. let initialRange = attExtra.initialRange;
  46341. let initialRangeSize = initialRange[1] - initialRange[0];
  46342. let globalRange = range;
  46343. let globalRangeSize = globalRange[1] - globalRange[0];
  46344. let scale = initialRangeSize / globalRangeSize;
  46345. let offset = -(globalRange[0] - initialRange[0]) / initialRangeSize;
  46346. scale = Number.isNaN(scale) ? 1 : scale;
  46347. offset = Number.isNaN(offset) ? 0 : offset;
  46348. shader.setUniform1f("uExtraScale", scale);
  46349. shader.setUniform1f("uExtraOffset", offset);
  46350. }
  46351. }else {
  46352. for(const attributeName in geometry.attributes){
  46353. const bufferAttribute = geometry.attributes[attributeName];
  46354. const vbo = webglBuffer.vbos.get(attributeName);
  46355. if(attributeLocations[attributeName] !== undefined){
  46356. const attributeLocation = attributeLocations[attributeName].location;
  46357. let type = this.glTypeMapping.get(bufferAttribute.array.constructor);
  46358. let normalized = bufferAttribute.normalized;
  46359. gl.bindBuffer(gl.ARRAY_BUFFER, vbo.handle);
  46360. gl.vertexAttribPointer(attributeLocation, bufferAttribute.itemSize, type, normalized, 0, 0);
  46361. gl.enableVertexAttribArray(attributeLocation);
  46362. }
  46363. }
  46364. }
  46365. let numPoints = webglBuffer.numElements;
  46366. gl.drawArrays(gl.POINTS, 0, numPoints);
  46367. //gl.drawArrays(gl.TRIANGLES, 0, numPoints);
  46368. i++;
  46369. }
  46370. gl.bindVertexArray(null);
  46371. if (exports.measureTimings) {
  46372. performance.mark("renderNodes-end");
  46373. performance.measure("render.renderNodes", "renderNodes-start", "renderNodes-end");
  46374. }
  46375. }
  46376. renderOctree(octree, nodes, camera, target, params = {}){
  46377. let gl = this.gl;
  46378. let material = params.material ? params.material : octree.material;
  46379. let shadowMaps = params.shadowMaps == null ? [] : params.shadowMaps;
  46380. let view = camera.matrixWorldInverse;
  46381. let viewInv = camera.matrixWorld;
  46382. if(params.viewOverride){
  46383. view = params.viewOverride;
  46384. viewInv = view.clone().invert();
  46385. }
  46386. let proj = camera.projectionMatrix;
  46387. let projInv = proj.clone().invert();
  46388. //let worldView = new THREE.Matrix4();
  46389. let shader = null;
  46390. let visibilityTextureData = null;
  46391. let currentTextureBindingPoint = 0;
  46392. if (material.pointSizeType >= 0) {
  46393. if (material.pointSizeType === PointSizeType.ADAPTIVE ||
  46394. material.activeAttributeName === "level of detail") {
  46395. let vnNodes = (params.vnTextureNodes != null) ? params.vnTextureNodes : nodes;
  46396. visibilityTextureData = octree.computeVisibilityTextureData(vnNodes, camera);
  46397. const vnt = material.visibleNodesTexture;
  46398. const data = vnt.image.data;
  46399. data.set(visibilityTextureData.data);
  46400. vnt.needsUpdate = true;
  46401. }
  46402. }
  46403. { // UPDATE SHADER AND TEXTURES
  46404. if (!this.shaders.has(material)) {
  46405. let [vs, fs] = [material.vertexShader, material.fragmentShader];
  46406. let shader = new Shader(gl, "pointcloud", vs, fs);
  46407. this.shaders.set(material, shader);
  46408. }
  46409. shader = this.shaders.get(material);
  46410. //if(material.needsUpdate){
  46411. {
  46412. let [vs, fs] = [material.vertexShader, material.fragmentShader];
  46413. let numSnapshots = material.snapEnabled ? material.numSnapshots : 0;
  46414. let numClipBoxes = (material.clipBoxes && material.clipBoxes.length) ? material.clipBoxes.length : 0;
  46415. let numClipSpheres = (params.clipSpheres && params.clipSpheres.length) ? params.clipSpheres.length : 0;
  46416. let numClipPolygons = (material.clipPolygons && material.clipPolygons.length) ? material.clipPolygons.length : 0;
  46417. let defines = [
  46418. `#define num_shadowmaps ${shadowMaps.length}`,
  46419. `#define num_snapshots ${numSnapshots}`,
  46420. `#define num_clipboxes ${numClipBoxes}`,
  46421. `#define num_clipspheres ${numClipSpheres}`,
  46422. `#define num_clippolygons ${numClipPolygons}`,
  46423. ];
  46424. //add:-----------
  46425. if(material.usePanoMap){
  46426. defines.push("#define usePanoMap");
  46427. }
  46428. if(material.useFilterByNormal){
  46429. defines.push("#define use_filter_by_normal");
  46430. //Potree.settings.editType == 'pano' ? defines.push("#define attenuated_opacity2") : defines.push("#define attenuated_opacity");
  46431. }
  46432. //---------------
  46433. if(octree.pcoGeometry.root.isLoaded()){
  46434. let attributes = octree.pcoGeometry.root.geometry.attributes;
  46435. if(attributes["gps-time"]){
  46436. defines.push("#define clip_gps_enabled");
  46437. }
  46438. if(attributes["return number"]){
  46439. defines.push("#define clip_return_number_enabled");
  46440. }
  46441. if(attributes["number of returns"]){
  46442. defines.push("#define clip_number_of_returns_enabled");
  46443. }
  46444. if(attributes["source id"] || attributes["point source id"]){
  46445. defines.push("#define clip_point_source_id_enabled");
  46446. }
  46447. }
  46448. let definesString = defines.join("\n");
  46449. let vsVersionIndex = vs.indexOf("#version ");
  46450. let fsVersionIndex = fs.indexOf("#version ");
  46451. if(vsVersionIndex >= 0){
  46452. vs = vs.replace(/(#version .*)/, `$1\n${definesString}`);
  46453. }else {
  46454. vs = `${definesString}\n${vs}`;
  46455. }
  46456. if(fsVersionIndex >= 0){
  46457. fs = fs.replace(/(#version .*)/, `$1\n${definesString}`);
  46458. }else {
  46459. fs = `${definesString}\n${fs}`;
  46460. }
  46461. shader.update(vs, fs);
  46462. material.needsUpdate = false;
  46463. }
  46464. for (let uniformName of Object.keys(material.uniforms)) {
  46465. let uniform = material.uniforms[uniformName];
  46466. if (uniform.type == "t") {
  46467. let texture = uniform.value;
  46468. if (!texture) {
  46469. continue;
  46470. }
  46471. //add
  46472. if(uniformName == 'pano0Map' || uniformName == 'pano1Map' ){ //属于cubeTex,另外设置
  46473. continue
  46474. }
  46475. if (!this.textures.has(texture)) {
  46476. let webglTexture = new WebGLTexture(gl, texture);
  46477. this.textures.set(texture, webglTexture);
  46478. }
  46479. let webGLTexture = this.textures.get(texture);
  46480. webGLTexture.update();
  46481. }
  46482. }
  46483. }
  46484. gl.useProgram(shader.program);
  46485. let transparent = false;
  46486. if(params.transparent !== undefined){
  46487. transparent = params.transparent && material.opacity < 1;
  46488. }else {
  46489. transparent = material.usePanoMap ? false : (material.useFilterByNormal || material.opacity < 1); //add useFilterByNormal
  46490. }
  46491. if (transparent){
  46492. gl.enable(gl.BLEND);
  46493. gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
  46494. gl.depthMask(false);
  46495. gl.disable(gl.DEPTH_TEST);
  46496. } else {
  46497. gl.disable(gl.BLEND);
  46498. gl.depthMask(true);
  46499. gl.enable(gl.DEPTH_TEST);
  46500. }
  46501. if(params.blendFunc !== undefined){
  46502. gl.enable(gl.BLEND);
  46503. gl.blendFunc(...params.blendFunc);
  46504. }
  46505. if(params.depthTest !== undefined){
  46506. if(params.depthTest === true){
  46507. gl.enable(gl.DEPTH_TEST);
  46508. }else {
  46509. gl.disable(gl.DEPTH_TEST);
  46510. }
  46511. }
  46512. if(params.depthWrite !== undefined){
  46513. if(params.depthWrite === true){
  46514. gl.depthMask(true);
  46515. }else {
  46516. gl.depthMask(false);
  46517. }
  46518. }
  46519. { // UPDATE UNIFORMS
  46520. shader.setUniformMatrix4("projectionMatrix", proj);
  46521. shader.setUniformMatrix4("viewMatrix", view);
  46522. shader.setUniformMatrix4("uViewInv", viewInv);
  46523. shader.setUniformMatrix4("uProjInv", projInv);
  46524. /* let screenWidth = target ? target.width : material.screenWidth;
  46525. let screenHeight = target ? target.height : material.screenHeight;
  46526. shader.setUniform1f("uScreenWidth", screenWidth);
  46527. shader.setUniform1f("uScreenHeight", screenHeight); */
  46528. shader.setUniform2f('resolution', material.resolution.toArray());
  46529. shader.setUniform1f("fov", Math.PI * camera.fov / 180);
  46530. shader.setUniform1f("near", camera.near);
  46531. shader.setUniform1f("far", camera.far);
  46532. if(camera instanceof OrthographicCamera){
  46533. shader.setUniform("uUseOrthographicCamera", true);
  46534. shader.setUniform("uOrthoWidth", camera.right - camera.left);
  46535. shader.setUniform("uOrthoHeight", camera.top - camera.bottom);
  46536. }else {
  46537. shader.setUniform("uUseOrthographicCamera", false);
  46538. }
  46539. if(material.clipBoxes.length + material.clipPolygons.length === 0){
  46540. shader.setUniform1i("clipTask", ClipTask.NONE);
  46541. }else {
  46542. shader.setUniform1i("clipTask", material.clipTask);
  46543. }
  46544. shader.setUniform1i("clipMethod", material.clipMethod);
  46545. if (material.clipBoxes && material.clipBoxes.length > 0) {
  46546. //let flattenedMatrices = [].concat(...material.clipBoxes.map(c => c.inverse.elements));
  46547. //const lClipBoxes = shader.uniformLocations["clipBoxes[0]"];
  46548. //gl.uniformMatrix4fv(lClipBoxes, false, flattenedMatrices);
  46549. const lClipBoxes = shader.uniformLocations["clipBoxes[0]"];
  46550. gl.uniformMatrix4fv(lClipBoxes, false, material.uniforms.clipBoxes.value);
  46551. }
  46552. // TODO CLIPSPHERES
  46553. if(params.clipSpheres && params.clipSpheres.length > 0){
  46554. let clipSpheres = params.clipSpheres;
  46555. let matrices = [];
  46556. for(let clipSphere of clipSpheres){
  46557. //let mScale = new THREE.Matrix4().makeScale(...clipSphere.scale.toArray());
  46558. //let mTranslate = new THREE.Matrix4().makeTranslation(...clipSphere.position.toArray());
  46559. //let clipToWorld = new THREE.Matrix4().multiplyMatrices(mTranslate, mScale);
  46560. let clipToWorld = clipSphere.matrixWorld;
  46561. let viewToWorld = camera.matrixWorld;
  46562. let worldToClip = clipToWorld.clone().invert();
  46563. let viewToClip = new Matrix4().multiplyMatrices(worldToClip, viewToWorld);
  46564. matrices.push(viewToClip);
  46565. }
  46566. let flattenedMatrices = [].concat(...matrices.map(matrix => matrix.elements));
  46567. const lClipSpheres = shader.uniformLocations["uClipSpheres[0]"];
  46568. gl.uniformMatrix4fv(lClipSpheres, false, flattenedMatrices);
  46569. //const lClipSpheres = shader.uniformLocations["uClipSpheres[0]"];
  46570. //gl.uniformMatrix4fv(lClipSpheres, false, material.uniforms.clipSpheres.value);
  46571. }
  46572. shader.setUniform1f("size", material.usePanoMap ? Potree.config.material.absolutePanoramaSize * Math.min(window.devicePixelRatio,2) : material.size);//usePanoMap时控制在不大不小的范围内感觉较好,考虑到有的点云稀疏,用大一点的点
  46573. shader.setUniform1f("maxSize", material.uniforms.maxSize.value);
  46574. shader.setUniform1f("minSize", material.uniforms.minSize.value);
  46575. // uniform float uPCIndex
  46576. shader.setUniform1f("uOctreeSpacing", material.spacing);
  46577. shader.setUniform("uOctreeSize", material.uniforms.octreeSize.value);
  46578. //uniform vec3 uColor;
  46579. shader.setUniform3f("uColor", material.color.toArray());
  46580. //uniform float opacity;
  46581. shader.setUniform1f("uOpacity", material.usePanoMap ? 1: material.opacity);
  46582. shader.setUniform2f("elevationRange", material.elevationRange);
  46583. shader.setUniform2f("intensityRange", material.intensityRange);
  46584. shader.setUniform3f("uIntensity_gbc", [
  46585. material.intensityGamma,
  46586. material.intensityBrightness,
  46587. material.intensityContrast
  46588. ]);
  46589. shader.setUniform3f("uRGB_gbc", [
  46590. material.rgbGamma,
  46591. material.rgbBrightness,
  46592. material.rgbContrast
  46593. ]);
  46594. shader.setUniform1f("uTransition", material.transition);
  46595. shader.setUniform1f("wRGB", material.weightRGB);
  46596. shader.setUniform1f("wIntensity", material.weightIntensity);
  46597. shader.setUniform1f("wElevation", material.weightElevation);
  46598. shader.setUniform1f("wClassification", material.weightClassification);
  46599. shader.setUniform1f("wReturnNumber", material.weightReturnNumber);
  46600. shader.setUniform1f("wSourceID", material.weightSourceID);
  46601. shader.setUniform("backfaceCulling", material.uniforms.backfaceCulling.value);
  46602. //==========================
  46603. //gl.TEXTURE_CUBE_MAP: 34067
  46604. //gl.TEXTURE0=33984 , vnWebGLTexture.target=gl.TEXTURE_2D = 3353
  46605. let vnWebGLTexture = this.textures.get(material.visibleNodesTexture);
  46606. if(vnWebGLTexture){
  46607. shader.setUniform1i("visibleNodesTexture", currentTextureBindingPoint);
  46608. gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
  46609. gl.bindTexture(vnWebGLTexture.target, vnWebGLTexture.id);
  46610. currentTextureBindingPoint++;
  46611. }
  46612. let gradientTexture = this.textures.get(material.gradientTexture);
  46613. shader.setUniform1i("gradient", currentTextureBindingPoint);
  46614. gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
  46615. gl.bindTexture(gradientTexture.target, gradientTexture.id);
  46616. const repeat = material.elevationGradientRepeat;
  46617. if(repeat === ElevationGradientRepeat.REPEAT){
  46618. gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_S, gl.REPEAT);
  46619. gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_T, gl.REPEAT);
  46620. }else if(repeat === ElevationGradientRepeat.MIRRORED_REPEAT){
  46621. gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
  46622. gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
  46623. }else {
  46624. gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  46625. gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  46626. }
  46627. currentTextureBindingPoint++;
  46628. let classificationTexture = this.textures.get(material.classificationTexture);
  46629. shader.setUniform1i("classificationLUT", currentTextureBindingPoint);
  46630. gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
  46631. gl.bindTexture(classificationTexture.target, classificationTexture.id);
  46632. currentTextureBindingPoint++;
  46633. let matcapTexture = this.textures.get(material.matcapTexture);
  46634. shader.setUniform1i("matcapTextureUniform", currentTextureBindingPoint);
  46635. gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
  46636. gl.bindTexture(matcapTexture.target, matcapTexture.id);
  46637. currentTextureBindingPoint++;
  46638. if (material.snapEnabled === true) {
  46639. {
  46640. const lSnapshot = shader.uniformLocations["uSnapshot[0]"];
  46641. const lSnapshotDepth = shader.uniformLocations["uSnapshotDepth[0]"];
  46642. let bindingStart = currentTextureBindingPoint;
  46643. let lSnapshotBindingPoints = new Array(5).fill(bindingStart).map((a, i) => (a + i));
  46644. let lSnapshotDepthBindingPoints = new Array(5)
  46645. .fill(1 + Math.max(...lSnapshotBindingPoints))
  46646. .map((a, i) => (a + i));
  46647. currentTextureBindingPoint = 1 + Math.max(...lSnapshotDepthBindingPoints);
  46648. gl.uniform1iv(lSnapshot, lSnapshotBindingPoints);
  46649. gl.uniform1iv(lSnapshotDepth, lSnapshotDepthBindingPoints);
  46650. for (let i = 0; i < 5; i++) {
  46651. let texture = material.uniforms[`uSnapshot`].value[i];
  46652. let textureDepth = material.uniforms[`uSnapshotDepth`].value[i];
  46653. if (!texture) {
  46654. break;
  46655. }
  46656. let snapTexture = this.threeRenderer.properties.get(texture).__webglTexture;
  46657. let snapTextureDepth = this.threeRenderer.properties.get(textureDepth).__webglTexture;
  46658. let bindingPoint = lSnapshotBindingPoints[i];
  46659. let depthBindingPoint = lSnapshotDepthBindingPoints[i];
  46660. gl.activeTexture(gl[`TEXTURE${bindingPoint}`]);
  46661. gl.bindTexture(gl.TEXTURE_2D, snapTexture);
  46662. gl.activeTexture(gl[`TEXTURE${depthBindingPoint}`]);
  46663. gl.bindTexture(gl.TEXTURE_2D, snapTextureDepth);
  46664. }
  46665. }
  46666. {
  46667. let flattenedMatrices = [].concat(...material.uniforms.uSnapView.value.map(c => c.elements));
  46668. const lSnapView = shader.uniformLocations["uSnapView[0]"];
  46669. gl.uniformMatrix4fv(lSnapView, false, flattenedMatrices);
  46670. }
  46671. {
  46672. let flattenedMatrices = [].concat(...material.uniforms.uSnapProj.value.map(c => c.elements));
  46673. const lSnapProj = shader.uniformLocations["uSnapProj[0]"];
  46674. gl.uniformMatrix4fv(lSnapProj, false, flattenedMatrices);
  46675. }
  46676. {
  46677. let flattenedMatrices = [].concat(...material.uniforms.uSnapProjInv.value.map(c => c.elements));
  46678. const lSnapProjInv = shader.uniformLocations["uSnapProjInv[0]"];
  46679. gl.uniformMatrix4fv(lSnapProjInv, false, flattenedMatrices);
  46680. }
  46681. {
  46682. let flattenedMatrices = [].concat(...material.uniforms.uSnapViewInv.value.map(c => c.elements));
  46683. const lSnapViewInv = shader.uniformLocations["uSnapViewInv[0]"];
  46684. gl.uniformMatrix4fv(lSnapViewInv, false, flattenedMatrices);
  46685. }
  46686. }
  46687. //=============add===========
  46688. if(material.usePanoMap){//为什么pointsize失效
  46689. shader.setUniform1f("progress", material.uniforms.progress.value);
  46690. shader.setUniform1f("easeInOutRatio", material.uniforms.easeInOutRatio.value);
  46691. shader.setUniform3f("pano0Position", material.uniforms.pano0Position.value.toArray());
  46692. shader.setUniform3f("pano1Position", material.uniforms.pano1Position.value.toArray());
  46693. shader.setUniform('pano0Matrix', material.uniforms.pano0Matrix.value);
  46694. shader.setUniform('pano1Matrix', material.uniforms.pano1Matrix.value);
  46695. let pano0Map = material.uniforms.pano0Map.value;
  46696. if(pano0Map){
  46697. this.threeRenderer._textures.safeSetTextureCube( pano0Map, ++currentTextureBindingPoint );
  46698. shader.setUniform1i('pano0Map', currentTextureBindingPoint);
  46699. }
  46700. let pano1Map = material.uniforms.pano1Map.value;
  46701. if(pano1Map){
  46702. this.threeRenderer._textures.safeSetTextureCube( pano1Map, ++currentTextureBindingPoint );
  46703. shader.setUniform1i('pano1Map', currentTextureBindingPoint);
  46704. }
  46705. //注: three.js我添加了个 _textures, safeSetTextureCube里主要就是activeTexture和bindTexture
  46706. }
  46707. }
  46708. this.renderNodes(octree, nodes, visibilityTextureData, camera, target, shader, params);
  46709. gl.activeTexture(gl.TEXTURE2);
  46710. gl.bindTexture(gl.TEXTURE_2D, null);
  46711. gl.activeTexture(gl.TEXTURE0);
  46712. //gl.bindTexture(gl.TEXTURE_2D, null); //add
  46713. //add 恢复为不透明(否则renderToCubeMap时的贴图会被渲染成高亮的颜色)
  46714. gl.disable(gl.BLEND);
  46715. gl.depthMask(true);
  46716. gl.enable(gl.DEPTH_TEST);
  46717. //DEPTH_TEST等需要恢复吗
  46718. }
  46719. render(scene, camera, target = null, params = {}) {
  46720. const gl = this.gl;
  46721. // PREPARE
  46722. if (target != null) {
  46723. this.threeRenderer.setRenderTarget(target);
  46724. }
  46725. //camera.updateProjectionMatrix();
  46726. // camera.matrixWorldInverse.invert(camera.matrixWorld);
  46727. const traversalResult = this.traverse(scene);
  46728. // RENDER
  46729. for (const octree of traversalResult.octrees) {
  46730. let nodes = octree.visibleNodes;
  46731. this.renderOctree(octree, nodes, camera, target, params);
  46732. }
  46733. // CLEANUP
  46734. gl.activeTexture(gl.TEXTURE1);
  46735. gl.bindTexture(gl.TEXTURE_2D, null);
  46736. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  46737. gl.bindVertexArray(null);
  46738. this.threeRenderer.resetState();
  46739. }
  46740. };
  46741. /*
  46742. 中东的链接http://indoor.popsmart.cn:8094/zdoblh-yz/?vlon=5.14&vlat=-0.13&fov=100.0&pc=true&lon=121.61136592&lat=29.87855579&z=16.577
  46743. geometry: 有的attributes: 属性是:
  46744. classification:
  46745. color:
  46746. indices:
  46747. normal:
  46748. position:
  46749. 最好有个spacing
  46750. */
  46751. class ProfileData {
  46752. constructor (profile) {
  46753. this.profile = profile;
  46754. this.segments = [];
  46755. this.boundingBox = new Box3();
  46756. for (let i = 0; i < profile.points.length - 1; i++) {
  46757. let start = profile.points[i];
  46758. let end = profile.points[i + 1];
  46759. let startGround = new Vector3(start.x, start.y, 0);
  46760. let endGround = new Vector3(end.x, end.y, 0);
  46761. let center = new Vector3().addVectors(endGround, startGround).multiplyScalar(0.5);
  46762. let length = startGround.distanceTo(endGround);
  46763. let side = new Vector3().subVectors(endGround, startGround).normalize();
  46764. let up = new Vector3(0, 0, 1);
  46765. let forward = new Vector3().crossVectors(side, up).normalize();
  46766. let N = forward;
  46767. let cutPlane = new Plane().setFromNormalAndCoplanarPoint(N, startGround);
  46768. let halfPlane = new Plane().setFromNormalAndCoplanarPoint(side, center);
  46769. let segment = {
  46770. start: start,
  46771. end: end,
  46772. cutPlane: cutPlane,
  46773. halfPlane: halfPlane,
  46774. length: length,
  46775. points: new Points$1()
  46776. };
  46777. this.segments.push(segment);
  46778. }
  46779. }
  46780. size () {
  46781. let size = 0;
  46782. for (let segment of this.segments) {
  46783. size += segment.points.numPoints;
  46784. }
  46785. return size;
  46786. }
  46787. };
  46788. class ProfileRequest {
  46789. constructor (pointcloud, profile, maxDepth, callback) {
  46790. this.pointcloud = pointcloud;
  46791. this.profile = profile;
  46792. this.maxDepth = maxDepth || Number.MAX_VALUE;
  46793. this.callback = callback;
  46794. this.temporaryResult = new ProfileData(this.profile);
  46795. this.pointsServed = 0;
  46796. this.highestLevelServed = 0;
  46797. this.priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });
  46798. this.initialize();
  46799. }
  46800. initialize () {
  46801. this.priorityQueue.push({node: this.pointcloud.pcoGeometry.root, weight: Infinity});
  46802. };
  46803. // traverse the node and add intersecting descendants to queue
  46804. traverse (node) {
  46805. let stack = [];
  46806. for (let i = 0; i < 8; i++) {
  46807. let child = node.children[i];
  46808. if (child && this.pointcloud.nodeIntersectsProfile(child, this.profile)) {
  46809. stack.push(child);
  46810. }
  46811. }
  46812. while (stack.length > 0) {
  46813. let node = stack.pop();
  46814. let weight = node.boundingSphere.radius;
  46815. this.priorityQueue.push({node: node, weight: weight});
  46816. // add children that intersect the cutting plane
  46817. if (node.level < this.maxDepth) {
  46818. for (let i = 0; i < 8; i++) {
  46819. let child = node.children[i];
  46820. if (child && this.pointcloud.nodeIntersectsProfile(child, this.profile)) {
  46821. stack.push(child);
  46822. }
  46823. }
  46824. }
  46825. }
  46826. }
  46827. update(){
  46828. if(!this.updateGeneratorInstance){
  46829. this.updateGeneratorInstance = this.updateGenerator();
  46830. }
  46831. let result = this.updateGeneratorInstance.next();
  46832. if(result.done){
  46833. this.updateGeneratorInstance = null;
  46834. }
  46835. }
  46836. * updateGenerator(){
  46837. // load nodes in queue
  46838. // if hierarchy expands, also load nodes from expanded hierarchy
  46839. // once loaded, add data to this.points and remove node from queue
  46840. // only evaluate 1-50 nodes per frame to maintain responsiveness
  46841. let start = performance.now();
  46842. let maxNodesPerUpdate = 1;
  46843. let intersectedNodes = [];
  46844. for (let i = 0; i < Math.min(maxNodesPerUpdate, this.priorityQueue.size()); i++) {
  46845. let element = this.priorityQueue.pop();
  46846. let node = element.node;
  46847. if(node.level > this.maxDepth){
  46848. continue;
  46849. }
  46850. if (node.loaded) {
  46851. // add points to result
  46852. intersectedNodes.push(node);
  46853. exports.lru.touch(node);
  46854. this.highestLevelServed = Math.max(node.getLevel(), this.highestLevelServed);
  46855. var geom = node.pcoGeometry;
  46856. var hierarchyStepSize = geom ? geom.hierarchyStepSize : 1;
  46857. var doTraverse = node.getLevel() === 0 ||
  46858. (node.level % hierarchyStepSize === 0 && node.hasChildren);
  46859. if (doTraverse) {
  46860. this.traverse(node);
  46861. }
  46862. } else {
  46863. node.load();
  46864. this.priorityQueue.push(element);
  46865. }
  46866. }
  46867. if (intersectedNodes.length > 0) {
  46868. for(let done of this.getPointsInsideProfile(intersectedNodes, this.temporaryResult)){
  46869. if(!done){
  46870. //console.log("updateGenerator yields");
  46871. yield false;
  46872. }
  46873. }
  46874. if (this.temporaryResult.size() > 100) {
  46875. this.pointsServed += this.temporaryResult.size();
  46876. this.callback.onProgress({request: this, points: this.temporaryResult});
  46877. this.temporaryResult = new ProfileData(this.profile);
  46878. }
  46879. }
  46880. if (this.priorityQueue.size() === 0) {
  46881. // we're done! inform callback and remove from pending requests
  46882. if (this.temporaryResult.size() > 0) {
  46883. this.pointsServed += this.temporaryResult.size();
  46884. this.callback.onProgress({request: this, points: this.temporaryResult});
  46885. this.temporaryResult = new ProfileData(this.profile);
  46886. }
  46887. this.callback.onFinish({request: this});
  46888. let index = this.pointcloud.profileRequests.indexOf(this);
  46889. if (index >= 0) {
  46890. this.pointcloud.profileRequests.splice(index, 1);
  46891. }
  46892. }
  46893. yield true;
  46894. };
  46895. * getAccepted(numPoints, node, matrix, segment, segmentDir, points, totalMileage){
  46896. let checkpoint = performance.now();
  46897. let accepted = new Uint32Array(numPoints);
  46898. let mileage = new Float64Array(numPoints);
  46899. let acceptedPositions = new Float32Array(numPoints * 3);
  46900. let numAccepted = 0;
  46901. let pos = new Vector3();
  46902. let svp = new Vector3();
  46903. let view = new Float32Array(node.geometry.attributes.position.array);
  46904. for (let i = 0; i < numPoints; i++) {
  46905. pos.set(
  46906. view[i * 3 + 0],
  46907. view[i * 3 + 1],
  46908. view[i * 3 + 2]);
  46909. pos.applyMatrix4(matrix);
  46910. let distance = Math.abs(segment.cutPlane.distanceToPoint(pos));
  46911. let centerDistance = Math.abs(segment.halfPlane.distanceToPoint(pos));
  46912. if (distance < this.profile.width / 2 && centerDistance < segment.length / 2) {
  46913. svp.subVectors(pos, segment.start);
  46914. let localMileage = segmentDir.dot(svp);
  46915. accepted[numAccepted] = i;
  46916. mileage[numAccepted] = localMileage + totalMileage;
  46917. points.boundingBox.expandByPoint(pos);
  46918. pos.sub(this.pointcloud.position);
  46919. acceptedPositions[3 * numAccepted + 0] = pos.x;
  46920. acceptedPositions[3 * numAccepted + 1] = pos.y;
  46921. acceptedPositions[3 * numAccepted + 2] = pos.z;
  46922. numAccepted++;
  46923. }
  46924. if((i % 1000) === 0){
  46925. let duration = performance.now() - checkpoint;
  46926. if(duration > 4){
  46927. //console.log(`getAccepted yield after ${duration}ms`);
  46928. yield false;
  46929. checkpoint = performance.now();
  46930. }
  46931. }
  46932. }
  46933. accepted = accepted.subarray(0, numAccepted);
  46934. mileage = mileage.subarray(0, numAccepted);
  46935. acceptedPositions = acceptedPositions.subarray(0, numAccepted * 3);
  46936. //let end = performance.now();
  46937. //let duration = end - start;
  46938. //console.log("accepted duration ", duration)
  46939. //console.log(`getAccepted finished`);
  46940. yield [accepted, mileage, acceptedPositions];
  46941. }
  46942. * getPointsInsideProfile(nodes, target){
  46943. let checkpoint = performance.now();
  46944. let totalMileage = 0;
  46945. let pointsProcessed = 0;
  46946. for (let segment of target.segments) {
  46947. for (let node of nodes) {
  46948. let numPoints = node.numPoints;
  46949. let geometry = node.geometry;
  46950. if(!numPoints){
  46951. continue;
  46952. }
  46953. { // skip if current node doesn't intersect current segment
  46954. let bbWorld = node.boundingBox.clone().applyMatrix4(this.pointcloud.matrixWorld);
  46955. let bsWorld = bbWorld.getBoundingSphere(new Sphere());
  46956. let start = new Vector3(segment.start.x, segment.start.y, bsWorld.center.z);
  46957. let end = new Vector3(segment.end.x, segment.end.y, bsWorld.center.z);
  46958. let closest = new Line3(start, end).closestPointToPoint(bsWorld.center, true, new Vector3());
  46959. let distance = closest.distanceTo(bsWorld.center);
  46960. let intersects = (distance < (bsWorld.radius + target.profile.width));
  46961. if(!intersects){
  46962. continue;
  46963. }
  46964. }
  46965. //{// DEBUG
  46966. // console.log(node.name);
  46967. // let boxHelper = new Potree.Box3Helper(node.getBoundingBox());
  46968. // boxHelper.matrixAutoUpdate = false;
  46969. // boxHelper.matrix.copy(viewer.scene.pointclouds[0].matrixWorld);
  46970. // viewer.scene.scene.add(boxHelper);
  46971. //}
  46972. let sv = new Vector3().subVectors(segment.end, segment.start).setZ(0);
  46973. let segmentDir = sv.clone().normalize();
  46974. let points = new Points$1();
  46975. let nodeMatrix = new Matrix4().makeTranslation(...node.boundingBox.min.toArray());
  46976. let matrix = new Matrix4().multiplyMatrices(
  46977. this.pointcloud.matrixWorld, nodeMatrix);
  46978. pointsProcessed = pointsProcessed + numPoints;
  46979. let accepted = null;
  46980. let mileage = null;
  46981. let acceptedPositions = null;
  46982. for(let result of this.getAccepted(numPoints, node, matrix, segment, segmentDir, points,totalMileage)){
  46983. if(!result){
  46984. let duration = performance.now() - checkpoint;
  46985. //console.log(`getPointsInsideProfile yield after ${duration}ms`);
  46986. yield false;
  46987. checkpoint = performance.now();
  46988. }else {
  46989. [accepted, mileage, acceptedPositions] = result;
  46990. }
  46991. }
  46992. let duration = performance.now() - checkpoint;
  46993. if(duration > 4){
  46994. //console.log(`getPointsInsideProfile yield after ${duration}ms`);
  46995. yield false;
  46996. checkpoint = performance.now();
  46997. }
  46998. points.data.position = acceptedPositions;
  46999. let relevantAttributes = Object.keys(geometry.attributes).filter(a => !["position", "indices"].includes(a));
  47000. for(let attributeName of relevantAttributes){
  47001. let attribute = geometry.attributes[attributeName];
  47002. let numElements = attribute.array.length / numPoints;
  47003. if(numElements !== parseInt(numElements)){
  47004. debugger;
  47005. }
  47006. let Type = attribute.array.constructor;
  47007. let filteredBuffer = new Type(numElements * accepted.length);
  47008. let source = attribute.array;
  47009. let target = filteredBuffer;
  47010. for(let i = 0; i < accepted.length; i++){
  47011. let index = accepted[i];
  47012. let start = index * numElements;
  47013. let end = start + numElements;
  47014. let sub = source.subarray(start, end);
  47015. target.set(sub, i * numElements);
  47016. }
  47017. points.data[attributeName] = filteredBuffer;
  47018. }
  47019. points.data['mileage'] = mileage;
  47020. points.numPoints = accepted.length;
  47021. segment.points.add(points);
  47022. }
  47023. totalMileage += segment.length;
  47024. }
  47025. for (let segment of target.segments) {
  47026. target.boundingBox.union(segment.points.boundingBox);
  47027. }
  47028. //console.log(`getPointsInsideProfile finished`);
  47029. yield true;
  47030. };
  47031. finishLevelThenCancel () {
  47032. if (this.cancelRequested) {
  47033. return;
  47034. }
  47035. this.maxDepth = this.highestLevelServed;
  47036. this.cancelRequested = true;
  47037. //console.log(`maxDepth: ${this.maxDepth}`);
  47038. };
  47039. cancel () {
  47040. this.callback.onCancel();
  47041. this.priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });
  47042. let index = this.pointcloud.profileRequests.indexOf(this);
  47043. if (index >= 0) {
  47044. this.pointcloud.profileRequests.splice(index, 1);
  47045. }
  47046. };
  47047. }
  47048. class Version{
  47049. constructor(version){
  47050. this.version = version;
  47051. let vmLength = (version.indexOf('.') === -1) ? version.length : version.indexOf('.');
  47052. this.versionMajor = parseInt(version.substr(0, vmLength));
  47053. this.versionMinor = parseInt(version.substr(vmLength + 1));
  47054. if (this.versionMinor.length === 0) {
  47055. this.versionMinor = 0;
  47056. }
  47057. }
  47058. newerThan(version){
  47059. let v = new Version(version);
  47060. if (this.versionMajor > v.versionMajor) {
  47061. return true;
  47062. } else if (this.versionMajor === v.versionMajor && this.versionMinor > v.versionMinor) {
  47063. return true;
  47064. } else {
  47065. return false;
  47066. }
  47067. }
  47068. equalOrHigher(version){
  47069. let v = new Version(version);
  47070. if (this.versionMajor > v.versionMajor) {
  47071. return true;
  47072. } else if (this.versionMajor === v.versionMajor && this.versionMinor >= v.versionMinor) {
  47073. return true;
  47074. } else {
  47075. return false;
  47076. }
  47077. }
  47078. upTo(version){
  47079. return !this.newerThan(version);
  47080. }
  47081. }
  47082. class WorkerPool{
  47083. constructor(){
  47084. this.workers = {};
  47085. }
  47086. getWorker(url){
  47087. if (!this.workers[url]){
  47088. this.workers[url] = [];
  47089. }
  47090. if (this.workers[url].length === 0){
  47091. let worker = new Worker(url);
  47092. this.workers[url].push(worker);
  47093. }
  47094. let worker = this.workers[url].pop();
  47095. return worker;
  47096. }
  47097. returnWorker(url, worker){
  47098. this.workers[url].push(worker);
  47099. }
  47100. };
  47101. //Potree.workerPool = new Potree.WorkerPool();
  47102. function createPointcloudData(pointcloud) {
  47103. let material = pointcloud.material;
  47104. let ranges = [];
  47105. for(let [name, value] of material.ranges){
  47106. ranges.push({
  47107. name: name,
  47108. value: value,
  47109. });
  47110. }
  47111. if(typeof material.elevationRange[0] === "number"){
  47112. ranges.push({
  47113. name: "elevationRange",
  47114. value: material.elevationRange,
  47115. });
  47116. }
  47117. if(typeof material.intensityRange[0] === "number"){
  47118. ranges.push({
  47119. name: "intensityRange",
  47120. value: material.intensityRange,
  47121. });
  47122. }
  47123. let pointSizeTypeName = Object.entries(Potree.PointSizeType).find(e => e[1] === material.pointSizeType)[0];
  47124. let jsonMaterial = {
  47125. activeAttributeName: material.activeAttributeName,
  47126. ranges: ranges,
  47127. size: material.size,
  47128. minSize: material.minSize,
  47129. pointSizeType: pointSizeTypeName,
  47130. matcap: material.matcap,
  47131. };
  47132. const pcdata = {
  47133. name: pointcloud.name,
  47134. url: pointcloud.pcoGeometry.url,
  47135. position: pointcloud.position.toArray(),
  47136. rotation: pointcloud.rotation.toArray(),
  47137. scale: pointcloud.scale.toArray(),
  47138. material: jsonMaterial,
  47139. };
  47140. return pcdata;
  47141. }
  47142. function createProfileData(profile){
  47143. const data = {
  47144. uuid: profile.uuid,
  47145. name: profile.name,
  47146. points: profile.points.map(p => p.toArray()),
  47147. height: profile.height,
  47148. width: profile.width,
  47149. };
  47150. return data;
  47151. }
  47152. function createVolumeData(volume){
  47153. const data = {
  47154. uuid: volume.uuid,
  47155. type: volume.constructor.name,
  47156. name: volume.name,
  47157. position: volume.position.toArray(),
  47158. rotation: volume.rotation.toArray(),
  47159. scale: volume.scale.toArray(),
  47160. visible: volume.visible,
  47161. clip: volume.clip,
  47162. };
  47163. return data;
  47164. }
  47165. function createCameraAnimationData(animation){
  47166. const controlPoints = animation.controlPoints.map( cp => {
  47167. const cpdata = {
  47168. position: cp.position.toArray(),
  47169. target: cp.target.toArray(),
  47170. };
  47171. return cpdata;
  47172. });
  47173. const data = {
  47174. uuid: animation.uuid,
  47175. name: animation.name,
  47176. duration: animation.duration,
  47177. t: animation.t,
  47178. curveType: animation.curveType,
  47179. visible: animation.visible,
  47180. controlPoints: controlPoints,
  47181. };
  47182. return data;
  47183. }
  47184. function createMeasurementData(measurement){
  47185. /* const data = {
  47186. uuid: measurement.uuid,
  47187. name: measurement.name,
  47188. measureType:measurement.measureType, //add
  47189. direction:measurement.direction,//add
  47190. minMarkers:measurement.minMarkers,//add
  47191. maxMarkers: measurement.maxMarkers,//add
  47192. isRect: measurement.isRect,//add
  47193. faceDirection: measurement.faceDirection,//add
  47194. points: measurement.points.map(p => p.position.toArray()),
  47195. showDistances: measurement.showDistances,
  47196. showCoordinates: measurement.showCoordinates,
  47197. showArea: measurement.showArea,
  47198. closed: measurement.closed,
  47199. showAngles: measurement.showAngles,
  47200. showHeight: measurement.showHeight,
  47201. showCircle: measurement.showCircle,
  47202. showAzimuth: measurement.showAzimuth,
  47203. showEdges: measurement.showEdges,
  47204. color: measurement.color.toArray(),
  47205. }; */
  47206. const data = {
  47207. uuid: measurement.uuid,
  47208. name: measurement.name,
  47209. measureType:measurement.measureType, //add
  47210. points: measurement.points.map(p => p.toArray()),
  47211. };
  47212. return data;
  47213. }
  47214. function createOrientedImagesData(images){
  47215. const data = {
  47216. cameraParamsPath: images.cameraParamsPath,
  47217. imageParamsPath: images.imageParamsPath,
  47218. };
  47219. return data;
  47220. }
  47221. function createGeopackageData(geopackage){
  47222. const data = {
  47223. path: geopackage.path,
  47224. };
  47225. return data;
  47226. }
  47227. function createAnnotationData(annotation){
  47228. const data = {
  47229. uuid: annotation.uuid,
  47230. title: annotation.title.toString(),
  47231. description: annotation.description,
  47232. position: annotation.position.toArray(),
  47233. offset: annotation.offset.toArray(),
  47234. children: [],
  47235. };
  47236. if(annotation.cameraPosition){
  47237. data.cameraPosition = annotation.cameraPosition.toArray();
  47238. }
  47239. if(annotation.cameraTarget){
  47240. data.cameraTarget = annotation.cameraTarget.toArray();
  47241. }
  47242. if(typeof annotation.radius !== "undefined"){
  47243. data.radius = annotation.radius;
  47244. }
  47245. return data;
  47246. }
  47247. function createAnnotationsData(viewer){
  47248. const map = new Map();
  47249. viewer.scene.annotations.traverseDescendants(a => {
  47250. const aData = createAnnotationData(a);
  47251. map.set(a, aData);
  47252. });
  47253. for(const [annotation, data] of map){
  47254. for(const child of annotation.children){
  47255. const childData = map.get(child);
  47256. data.children.push(childData);
  47257. }
  47258. }
  47259. const annotations = viewer.scene.annotations.children.map(a => map.get(a));
  47260. return annotations;
  47261. }
  47262. function createSettingsData(viewer){
  47263. return {
  47264. pointBudget: viewer.getPointBudget(),
  47265. fov: viewer.getFOV(),
  47266. edlEnabled: viewer.getEDLEnabled(),
  47267. edlRadius: viewer.getEDLRadius(),
  47268. edlStrength: viewer.getEDLStrength(),
  47269. background: viewer.getBackground(),
  47270. minNodeSize: viewer.getMinNodeSize(),
  47271. showBoundingBoxes: viewer.getShowBoundingBox(),
  47272. };
  47273. }
  47274. function createSceneContentData(viewer){
  47275. const data = [];
  47276. const potreeObjects = [];
  47277. viewer.scene.scene.traverse(node => {
  47278. if(node.potree){
  47279. potreeObjects.push(node);
  47280. }
  47281. });
  47282. for(const object of potreeObjects){
  47283. if(object.potree.file){
  47284. const saveObject = {
  47285. file: object.potree.file,
  47286. };
  47287. data.push(saveObject);
  47288. }
  47289. }
  47290. return data;
  47291. }
  47292. function createViewData(viewer){
  47293. const view = viewer.scene.view;
  47294. const data = {
  47295. position: view.position.toArray(),
  47296. target: view.getPivot().toArray(),
  47297. };
  47298. return data;
  47299. }
  47300. function createClassificationData(viewer){
  47301. const classifications = viewer.classifications;
  47302. const data = classifications;
  47303. return data;
  47304. }
  47305. function saveProject(viewer) {
  47306. const scene = viewer.scene;
  47307. const data = {
  47308. type: "Potree",
  47309. version: 1.7,
  47310. settings: createSettingsData(viewer),
  47311. view: createViewData(viewer),
  47312. classification: createClassificationData(viewer),
  47313. pointclouds: scene.pointclouds.map(createPointcloudData),
  47314. measurements: scene.measurements.map(createMeasurementData),
  47315. volumes: scene.volumes.map(createVolumeData),
  47316. cameraAnimations: scene.cameraAnimations.map(createCameraAnimationData),
  47317. profiles: scene.profiles.map(createProfileData),
  47318. annotations: createAnnotationsData(viewer),
  47319. orientedImages: scene.orientedImages.map(createOrientedImagesData),
  47320. geopackages: scene.geopackages.map(createGeopackageData),
  47321. // objects: createSceneContentData(viewer),
  47322. };
  47323. return data;
  47324. }
  47325. class HandleSvg extends EventDispatcher{
  47326. constructor(position, color){
  47327. super();
  47328. this.position = position;
  47329. this.color = '#'+new Color(color).getHexString();
  47330. this.svg = this.create();
  47331. this.visible_ = true;
  47332. let update = ()=>{
  47333. this.update();
  47334. };
  47335. viewer.addEventListener("camera_changed", update);
  47336. this.addEventListener('dispose', ()=>{
  47337. viewer.removeEventListener("camera_changed", update);
  47338. });
  47339. }
  47340. create(){
  47341. const svgns = "http://www.w3.org/2000/svg";
  47342. const svg = document.createElementNS(svgns, "svg");
  47343. svg.setAttribute("width", "2em");
  47344. svg.setAttribute("height", "2em");
  47345. svg.setAttribute("position", "absolute");
  47346. svg.style.left = "50px";
  47347. svg.style.top = "50px";
  47348. svg.style.position = "absolute";
  47349. svg.style.zIndex = "10000";
  47350. svg.style.cursor = 'grab';
  47351. svg.style.transform = 'translate(-50%,-50%)';
  47352. const circle = document.createElementNS(svgns, 'circle');
  47353. circle.setAttributeNS(null, 'cx', "1em");
  47354. circle.setAttributeNS(null, 'cy', "1em");
  47355. circle.setAttributeNS(null, 'r', "0.5em");
  47356. circle.setAttributeNS(null, 'style', 'fill: '+this.color+'; stroke: black; stroke-width: 0.2em;' );
  47357. svg.appendChild(circle);
  47358. const element = viewer.renderer.domElement.parentElement;
  47359. element.appendChild(svg);
  47360. const startDrag = (evt) => {
  47361. /* if(evt.button === THREE.MOUSE.RIGHT){
  47362. return
  47363. } */
  47364. this.selectedElement = svg;
  47365. document.addEventListener("mousemove", drag);
  47366. };
  47367. const endDrag = (evt) => {
  47368. this.selectedElement = null;
  47369. document.removeEventListener("mousemove", drag);
  47370. };
  47371. const drag = (evt) => {
  47372. if (this.selectedElement) {
  47373. evt.preventDefault();
  47374. const rect = viewer.renderer.domElement.getBoundingClientRect();
  47375. const x = evt.clientX - rect.x;
  47376. const y = evt.clientY - rect.y;
  47377. const {width, height} = viewer.renderer.getSize(new Vector2$1());
  47378. const camera = viewer.scene.getActiveCamera();
  47379. const projected = this.position.clone().project(camera);
  47380. projected.x = ((x / width) - 0.5) / 0.5;
  47381. projected.y = (-(y - height) / height - 0.5) / 0.5;
  47382. const unprojected = projected.clone().unproject(camera);
  47383. this.position.set(unprojected.x, unprojected.y, unprojected.z);
  47384. this.update();
  47385. this.dispatchEvent({type:'dragged', position: this.position});
  47386. }
  47387. };
  47388. svg.addEventListener('mousedown', startDrag);
  47389. svg.addEventListener('mouseup', endDrag);
  47390. svg.style.display = this.visible ? "" : "none";
  47391. this.addEventListener('dispose',()=>{
  47392. svg.removeEventListener('mousedown', startDrag);
  47393. svg.removeEventListener('mouseup', endDrag);
  47394. });
  47395. return svg
  47396. }
  47397. set visible(v){
  47398. this.visible_ = v;
  47399. if(v){
  47400. this.update();
  47401. }else {
  47402. this.svg.style.display = "none";
  47403. }
  47404. }
  47405. get visible(){
  47406. return this.visible_
  47407. }
  47408. update(){
  47409. if(!this.visible)return
  47410. let camera = viewer.scene.getActiveCamera();
  47411. var p = Potree.Utils.getPos2d( this.position, camera , viewer.renderArea, viewer.mainViewport);
  47412. if(!p.trueSide){
  47413. return this.svg.style.display = 'none';
  47414. }
  47415. this.svg.style.left = p.posInViewport.x;
  47416. this.svg.style.top = p.posInViewport.y;
  47417. this.svg.style.display = '';
  47418. }
  47419. dispose(){
  47420. this.svg.remove();
  47421. this.dispatchEvent('dispose');
  47422. }
  47423. }
  47424. /*
  47425. 两种拖拽方式:
  47426. 1 只依附在点云上
  47427. 2 平行于镜头view移动 */
  47428. const geo$1 = new PlaneBufferGeometry(1,1);
  47429. class HandleSprite extends Sprite$1{
  47430. constructor(position,options={}){
  47431. options.sizeInfo = {width2d:60};
  47432. super(options);
  47433. this.position.copy(position);
  47434. this.dragStyle = options.dragStyle || 'default'; //'default'||'onPointCloud'
  47435. this.bindEvent();
  47436. }
  47437. bindEvent(){
  47438. let projectedStart, pointerStart;
  47439. const drag = (e)=>{
  47440. /* if(e.hoverViewport != e.drag.dragViewport){//不能使用e.dragViewport,要使用drag中的,因为drag中存储的要一直继承下来,不因mouseup了而改变。
  47441. viewer.dispatchEvent({
  47442. type : "CursorChange", action : "add", name:"polygon_AtWrongPlace"
  47443. })
  47444. return
  47445. } */
  47446. const camera = viewer.scene.getActiveCamera();
  47447. if(projectedStart){
  47448. let move2d = new Vector2$1().subVectors(e.pointer, pointerStart);
  47449. let projectNow = projectedStart.clone();
  47450. projectNow.x += move2d.x;
  47451. projectNow.y += move2d.y;
  47452. let unprojected = projectNow.clone().unproject(camera);
  47453. this.position.set(unprojected.x, unprojected.y, unprojected.z);
  47454. }else {
  47455. projectedStart = this.position.clone().project(camera);
  47456. pointerStart = e.pointer.clone();
  47457. }
  47458. this.update();
  47459. this.dispatchEvent({type:'dragged', position: this.position });
  47460. };
  47461. const drop = (e)=>{
  47462. projectedStart = null, pointerStart = null;
  47463. };
  47464. const mouseover = (e) => {
  47465. viewer.dispatchEvent({
  47466. type : "CursorChange", action : "add", name:"markerMove"
  47467. });
  47468. };
  47469. const mouseleave = (e) => {
  47470. viewer.dispatchEvent({
  47471. type : "CursorChange", action : "remove", name:"markerMove"
  47472. });
  47473. };
  47474. this.addEventListener('drag', drag);
  47475. this.addEventListener('drop', drop);
  47476. this.addEventListener('mouseover', mouseover);
  47477. this.addEventListener('mouseleave', mouseleave);
  47478. }
  47479. }
  47480. const sphere = new Mesh(new SphereBufferGeometry(0.08,0.08,3,2), new MeshBasicMaterial({color:'#f88'}));
  47481. class CurveCtrl extends Object3D {
  47482. constructor(points, lineMat, color, name, options={}){
  47483. super();
  47484. this.curve = new CatmullRomCurve3(points, false, "centripetal" /* , tension */);
  47485. this.name = name || 'curveNode';
  47486. this.handleMat = options.handleMat;
  47487. this.lineMat = lineMat;
  47488. this.createPath();
  47489. this.color = color;
  47490. this.handles = [];
  47491. this.wholeLength = 0;
  47492. this.viewports = options.viewports || [viewer.mainViewport]; //for HandleSprite
  47493. for(let i=0,j=this.points.length; i<j;i++){
  47494. this.handles.push(this.createHandle(this.points[i]));
  47495. }
  47496. this.visible_ = true;
  47497. if(Potree.settings.isTest){
  47498. this.spheres = new Object3D;
  47499. /* let i = Count+1;
  47500. while(i>0){
  47501. this.spheres.add(sphere.clone());
  47502. i--;
  47503. } */
  47504. this.add(this.spheres);
  47505. }
  47506. this.updatePath();
  47507. }
  47508. addPoint(position, index, ifUpdate){
  47509. let length = this.points.length;
  47510. if(index == void 0 ){
  47511. index = length;
  47512. }
  47513. let handle = this.createHandle(position);
  47514. this.handles = [...this.handles.slice(0,index), handle, ...this.handles.slice(index,length)];
  47515. this.points = [...this.points.slice(0,index), position, ...this.points.slice(index,length)];
  47516. ifUpdate && (this.updatePath(), this.updateHandle(index));
  47517. }
  47518. removePoint(index){
  47519. let handle = this.handles[index];
  47520. handle.dispose();
  47521. this.handles.splice(index,1);
  47522. this.points.splice(index,1);
  47523. this.updatePath();
  47524. }
  47525. createPath(){
  47526. const line = LineDraw.createFatLine( [ ],this.lineMat);
  47527. this.line = line;
  47528. this.add(line);
  47529. }
  47530. updatePath(){
  47531. this.curve.needsUpdate = true; //如果不更新,得到的点不均匀,开头点少。
  47532. let points, length = this.points.length;
  47533. this.wholeLength = this.points.reduce((total, currentValue, currentIndex, arr)=>{ //所有端点的距离总和
  47534. if(currentIndex == 0)return 0
  47535. return total + currentValue.distanceTo(arr[currentIndex-1]);
  47536. },0);
  47537. if(length > 1){
  47538. const count = MathUtils.clamp(Math.ceil(this.wholeLength * 5), 30, 500);
  47539. points = this.curve.getSpacedPoints( count );
  47540. if(this.needsPercent){ //获取每个节点在整条中的百分比,便于定位(但不精确)
  47541. this.pointsPercent = [0];
  47542. let sums = [0];
  47543. let sum = 0, last = points[0];
  47544. for(let i=1;i<length;i++){
  47545. let point = this.points[i];
  47546. sum += point.distanceTo(last); //参考getLengths函数,根据长度得到百分比
  47547. last = point;
  47548. sums.push(sum);
  47549. }
  47550. for(let i=1;i<length;i++){
  47551. this.pointsPercent.push(sum == 0 ? i/length : sums[i] / sum);
  47552. }
  47553. }
  47554. if(Potree.settings.isTest){
  47555. this.spheres.children.forEach(e=>e.visible = false);
  47556. points.forEach((e,i)=>{
  47557. let sphere1 = this.spheres.children[i];
  47558. if(!sphere1){
  47559. sphere1 = sphere.clone();
  47560. this.spheres.add(sphere1);
  47561. }
  47562. sphere1.position.copy(e);
  47563. sphere1.visible = true;
  47564. });
  47565. }
  47566. }else {
  47567. points = [];
  47568. }
  47569. LineDraw.updateLine(this.line, points);
  47570. this.dispatchEvent('updatePath');
  47571. }
  47572. createHandle(position){
  47573. if(this.handleMat){
  47574. var handle = new HandleSprite(position, {mat:this.handleMat, viewports:this.viewports});
  47575. this.add(handle);
  47576. }else {
  47577. var handle = new HandleSvg(position, this.color);
  47578. }
  47579. handle.visible = this.visible;
  47580. handle.addEventListener('dragged',(e)=>{
  47581. let index = this.handles.indexOf(handle);
  47582. this.points[index].copy(e.position);
  47583. this.updatePath();
  47584. this.dispatchEvent({type:'dragCurvePoint', index});
  47585. });
  47586. return handle
  47587. }
  47588. updateHandle(index){
  47589. if(!this.visible)return
  47590. this.handles[index].update();
  47591. }
  47592. updateHandles(){
  47593. this.handles.forEach((handle,index)=>{
  47594. this.updateHandle(index);
  47595. });
  47596. }
  47597. update(){
  47598. this.updateHandles();
  47599. this.updatePath();
  47600. }
  47601. set visible(v){
  47602. if(v != this.visible_ ){
  47603. this.visible_ = v;
  47604. this.visible = v;
  47605. if(this.handles){
  47606. this.handles.forEach(e=>e.visible = v );
  47607. if(v) this.updateHandles(); //因为不可见时没更新位置
  47608. }
  47609. }
  47610. }
  47611. get visible(){
  47612. return this.visible_
  47613. }
  47614. /* set visible(v){
  47615. this.handles.forEach(e=>e.svg.style.display = v ? "" : "none" )
  47616. if(v) this.updateHandles() //因为不可见时没更新位置
  47617. } */
  47618. get points(){
  47619. return this.curve.points;
  47620. }
  47621. set points(points){
  47622. this.curve.points = points;
  47623. }
  47624. getPointAt(t){
  47625. return this.curve.getPointAt(t)
  47626. }
  47627. getSpacedPoints(t){
  47628. return this.curve.getSpacedPoints(t)
  47629. }
  47630. dispose(){
  47631. this.parent && this.parent.remove(this);
  47632. this.handles.forEach(e=>e.dispose() );
  47633. this.line.geometry && this.line.geometry.dispose();
  47634. }
  47635. }
  47636. var easing = {};
  47637. //渐变曲线函数,反应加速度的变化
  47638. //currentTime:x轴当前时间(从0-到duration), startY:起始点, duration:总时长, wholeY:路程 (即endY-startY)
  47639. //参数基本是 x, 0, 1, 1
  47640. /*
  47641. easeOut 基本是y= m * (x-dur)^k + n, 若k为偶数,m<0, 若k为奇数,m>0; (因为偶数的话必须开口向下才能获得斜率递减的递增的那段,而奇数是对称的,单调递增. )
  47642. 根据x=0时y=0, x=dur时y=S , 得 n = S,m = -S/(-dur)^k
  47643. */
  47644. easing.getEaseOut = function(k){// k 是>=2的整数. 越大变化率越大, 相同初始速度所需要时间越久
  47645. let easeFun;
  47646. k = Math.round(k);
  47647. if(k<2){
  47648. k = Math.PI / 2;
  47649. easeFun = easing.easeOutSine;
  47650. }else {
  47651. easeFun = function(currentTime, startY, wholeY, duration) {
  47652. if(k>2){
  47653. console.log(k);
  47654. }
  47655. return -wholeY/Math.pow(-duration, k) * Math.pow(currentTime-duration, k) + wholeY
  47656. };
  47657. }
  47658. return {
  47659. k,
  47660. easeFun
  47661. }
  47662. };
  47663. easing.linearTween = function(currentTime, startY, wholeY, duration) {
  47664. return wholeY * currentTime / duration + startY
  47665. }
  47666. ,
  47667. easing.easeInQuad = function(currentTime, startY, wholeY, duration) {
  47668. return currentTime /= duration,
  47669. wholeY * currentTime * currentTime + startY
  47670. }
  47671. ,
  47672. easing.easeOutQuad = function(currentTime, startY, wholeY, duration) { // 如套上实际的距离S和时长dur, y = - S / dur *(x^2-2x) 当s为1,dur为1时,是 y = -(x-1)^2 + 1 , 在0-1中是斜率递减的递增函数. 导数- S / dur *(2x-2 ) 可求出实时速度 故在0这一时刻,速度为 2S/dur
  47673. return currentTime /= duration,
  47674. -wholeY * currentTime * (currentTime - 2) + startY
  47675. }
  47676. ,
  47677. easing.easeInOutQuad = function(currentTime, startY, wholeY, duration) {
  47678. return currentTime /= duration / 2,
  47679. currentTime < 1 ? wholeY / 2 * currentTime * currentTime + startY : (currentTime--,
  47680. -wholeY / 2 * (currentTime * (currentTime - 2) - 1) + startY)
  47681. }
  47682. ,
  47683. easing.easeInCubic = function(currentTime, startY, wholeY, duration) {
  47684. return currentTime /= duration,
  47685. wholeY * currentTime * currentTime * currentTime + startY
  47686. }
  47687. ,
  47688. easing.easeOutCubic = function(currentTime, startY, wholeY, duration) {// y = S / dur^3 *(x-dur)^3 + S,对称中心是(dur,S),从0-dur是 斜率递减的递增函数,导数为3S/dur^3 * (x-dur)^2, 0时速度为3S/dur
  47689. return currentTime /= duration,
  47690. currentTime--,
  47691. wholeY * (currentTime * currentTime * currentTime + 1) + startY
  47692. }
  47693. ,
  47694. easing.easeInOutCubic = function(currentTime, startY, wholeY, duration) {
  47695. return currentTime /= duration / 2,
  47696. currentTime < 1 ? wholeY / 2 * currentTime * currentTime * currentTime + startY : (currentTime -= 2,
  47697. wholeY / 2 * (currentTime * currentTime * currentTime + 2) + startY)
  47698. }
  47699. ,
  47700. easing.easeInQuart = function(currentTime, startY, wholeY, duration) {
  47701. return currentTime /= duration,
  47702. wholeY * currentTime * currentTime * currentTime * currentTime + startY
  47703. }
  47704. ,
  47705. easing.easeOutQuart = function(currentTime, startY, wholeY, duration) {//根据上面的计算,估计0时速度应该是4S/dur吧……
  47706. return currentTime /= duration,
  47707. currentTime--,
  47708. -wholeY * (currentTime * currentTime * currentTime * currentTime - 1) + startY
  47709. }
  47710. ,
  47711. easing.easeInOutQuart = function(currentTime, startY, wholeY, duration) {
  47712. return currentTime /= duration / 2,
  47713. currentTime < 1 ? wholeY / 2 * currentTime * currentTime * currentTime * currentTime + startY : (currentTime -= 2,
  47714. -wholeY / 2 * (currentTime * currentTime * currentTime * currentTime - 2) + startY)
  47715. }
  47716. ,
  47717. easing.easeInQuint = function(currentTime, startY, wholeY, duration) {
  47718. return currentTime /= duration,
  47719. wholeY * currentTime * currentTime * currentTime * currentTime * currentTime + startY
  47720. }
  47721. ,
  47722. easing.easeOutQuint = function(currentTime, startY, wholeY, duration) {
  47723. return currentTime /= duration,
  47724. currentTime--,
  47725. wholeY * (currentTime * currentTime * currentTime * currentTime * currentTime + 1) + startY
  47726. }
  47727. ,
  47728. easing.easeInOutQuint = function(currentTime, startY, wholeY, duration) {
  47729. return currentTime /= duration / 2,
  47730. currentTime < 1 ? wholeY / 2 * currentTime * currentTime * currentTime * currentTime * currentTime + startY : (currentTime -= 2,
  47731. wholeY / 2 * (currentTime * currentTime * currentTime * currentTime * currentTime + 2) + startY)
  47732. }
  47733. ,
  47734. easing.easeInSine = function(currentTime, startY, wholeY, duration) {
  47735. return -wholeY * Math.cos(currentTime / duration * (Math.PI / 2)) + wholeY + startY
  47736. }
  47737. ,
  47738. easing.easeOutSine = function(currentTime, startY, wholeY, duration) {// y' = S * PI / 2 / dur * cos(PI/2/dur * x)
  47739. console.log('easeOutSine');
  47740. return wholeY * Math.sin(currentTime / duration * (Math.PI / 2)) + startY
  47741. }
  47742. ,
  47743. easing.easeInOutSine = function(currentTime, startY, wholeY, duration) {
  47744. return -wholeY / 2 * (Math.cos(Math.PI * currentTime / duration) - 1) + startY
  47745. }
  47746. ,
  47747. easing.easeInExpo = function(currentTime, startY, wholeY, duration) {
  47748. return wholeY * Math.pow(2, 10 * (currentTime / duration - 1)) + startY
  47749. }
  47750. ,
  47751. easing.easeOutExpo = function(currentTime, startY, wholeY, duration) {
  47752. return wholeY * (-Math.pow(2, -10 * currentTime / duration) + 1) + startY
  47753. }
  47754. ,
  47755. easing.easeInOutExpo = function(currentTime, startY, wholeY, duration) {
  47756. return currentTime /= duration / 2,
  47757. currentTime < 1 ? wholeY / 2 * Math.pow(2, 10 * (currentTime - 1)) + startY : (currentTime--,
  47758. wholeY / 2 * (-Math.pow(2, -10 * currentTime) + 2) + startY)
  47759. }
  47760. ,
  47761. easing.easeInCirc = function(currentTime, startY, wholeY, duration) {
  47762. return currentTime /= duration,
  47763. -wholeY * (Math.sqrt(1 - currentTime * currentTime) - 1) + startY
  47764. }
  47765. ,
  47766. easing.easeOutCirc = function(currentTime, startY, wholeY, duration) {
  47767. return currentTime /= duration,
  47768. currentTime--,
  47769. wholeY * Math.sqrt(1 - currentTime * currentTime) + startY
  47770. }
  47771. ,
  47772. easing.easeInOutCirc = function(currentTime, startY, wholeY, duration) {
  47773. return currentTime /= duration / 2,
  47774. currentTime < 1 ? -wholeY / 2 * (Math.sqrt(1 - currentTime * currentTime) - 1) + startY : (currentTime -= 2,
  47775. wholeY / 2 * (Math.sqrt(1 - currentTime * currentTime) + 1) + startY)
  47776. }
  47777. ,
  47778. easing.easeInElastic = function(currentTime, startY, wholeY, duration) {
  47779. var r = 1.70158
  47780. , o = 0
  47781. , a = wholeY;
  47782. return 0 === currentTime ? startY : 1 === (currentTime /= duration) ? startY + wholeY : (o || (o = .3 * duration),
  47783. a < Math.abs(wholeY) ? (a = wholeY,
  47784. r = o / 4) : r = o / (2 * Math.PI) * Math.asin(wholeY / a),
  47785. -(a * Math.pow(2, 10 * (currentTime -= 1)) * Math.sin((currentTime * duration - r) * (2 * Math.PI) / o)) + startY)
  47786. }
  47787. ,
  47788. easing.easeOutElastic = function(currentTime, startY, wholeY, duration) {
  47789. var r = 1.70158
  47790. , o = 0
  47791. , a = wholeY;
  47792. return 0 === currentTime ? startY : 1 === (currentTime /= duration) ? startY + wholeY : (o || (o = .3 * duration),
  47793. a < Math.abs(wholeY) ? (a = wholeY,
  47794. r = o / 4) : r = o / (2 * Math.PI) * Math.asin(wholeY / a),
  47795. a * Math.pow(2, -10 * currentTime) * Math.sin((currentTime * duration - r) * (2 * Math.PI) / o) + wholeY + startY)
  47796. }
  47797. ,
  47798. easing.easeInOutElastic = function(currentTime, startY, wholeY, duration) {
  47799. var r = 1.70158
  47800. , o = 0
  47801. , a = wholeY;
  47802. return 0 === currentTime ? startY : 2 === (currentTime /= duration / 2) ? startY + wholeY : (o || (o = duration * (.3 * 1.5)),
  47803. a < Math.abs(wholeY) ? (a = wholeY,
  47804. r = o / 4) : r = o / (2 * Math.PI) * Math.asin(wholeY / a),
  47805. currentTime < 1 ? -.5 * (a * Math.pow(2, 10 * (currentTime -= 1)) * Math.sin((currentTime * duration - r) * (2 * Math.PI) / o)) + startY : a * Math.pow(2, -10 * (currentTime -= 1)) * Math.sin((currentTime * duration - r) * (2 * Math.PI) / o) * .5 + wholeY + startY)
  47806. }
  47807. ,
  47808. easing.easeInBack = function(currentTime, startY, wholeY, duration, r) {
  47809. return void 0 === r && (r = 1.70158),
  47810. wholeY * (currentTime /= duration) * currentTime * ((r + 1) * currentTime - r) + startY
  47811. }
  47812. ,
  47813. easing.easeOutBack = function(currentTime, startY, wholeY, duration, r) {
  47814. return void 0 === r && (r = 1.70158),
  47815. wholeY * ((currentTime = currentTime / duration - 1) * currentTime * ((r + 1) * currentTime + r) + 1) + startY
  47816. }
  47817. ,
  47818. easing.easeInOutBack = function(currentTime, startY, wholeY, duration, r) {
  47819. return void 0 === r && (r = 1.70158),
  47820. (currentTime /= duration / 2) < 1 ? wholeY / 2 * (currentTime * currentTime * (((r *= 1.525) + 1) * currentTime - r)) + startY : wholeY / 2 * ((currentTime -= 2) * currentTime * (((r *= 1.525) + 1) * currentTime + r) + 2) + startY
  47821. }
  47822. ,
  47823. easing.easeOutBounce = function(currentTime, startY, wholeY, duration) {
  47824. return (currentTime /= duration) < 1 / 2.75 ? wholeY * (7.5625 * currentTime * currentTime) + startY : currentTime < 2 / 2.75 ? wholeY * (7.5625 * (currentTime -= 1.5 / 2.75) * currentTime + .75) + startY : currentTime < 2.5 / 2.75 ? wholeY * (7.5625 * (currentTime -= 2.25 / 2.75) * currentTime + .9375) + startY : wholeY * (7.5625 * (currentTime -= 2.625 / 2.75) * currentTime + .984375) + startY
  47825. }
  47826. ,
  47827. easing.easeInBounce = function(currentTime, startY, wholeY, r) {
  47828. return wholeY - easing.easeOutBounce(r - currentTime, 0, wholeY, r) + startY
  47829. }
  47830. ,
  47831. easing.easeInOutBounce = function(currentTime, startY, wholeY, r) {
  47832. return currentTime < r / 2 ? .5 * easing.easeInBounce(2 * currentTime, 0, wholeY, r) + startY : .5 * easing.easeOutBounce(x, 2 * currentTime - r, 0, wholeY, r) + .5 * wholeY + startY
  47833. };
  47834. var lerp = {
  47835. /* vector: function(currentTime, startY, f) {//xzw change, add f
  47836. var wholeY = currentTime.clone();
  47837. return startY = startY.clone(),
  47838. function(duration) {
  47839. currentTime.set(wholeY.x * (1 - duration) + startY.x * duration, wholeY.y * (1 - duration) + startY.y * duration, wholeY.z * (1 - duration) + startY.z * duration)
  47840. f && f(currentTime,duration);
  47841. }
  47842. },
  47843. quaternion: function(currentTime, startY, f) {//xzw change, add f
  47844. var wholeY = currentTime.clone();
  47845. return function(duration) {
  47846. currentTime.copy(wholeY).slerp(startY, duration);
  47847. f && f(currentTime,duration);
  47848. }
  47849. },
  47850. property: function(currentTime, startY, wholeY, duration) {
  47851. var r = currentTime[startY];
  47852. return function(o) {
  47853. currentTime[startY] = r * (1 - o) + wholeY * o,
  47854. duration && duration(currentTime[startY])
  47855. }
  47856. },
  47857. uniform: function(currentTime, startY, wholeY) {
  47858. var duration = currentTime.material.uniforms[startY].value;
  47859. return function(r) {
  47860. try{
  47861. currentTime.material.uniforms[startY] && (currentTime.material.uniforms[startY].value = duration * (1 - r) + wholeY * r)
  47862. }catch(currentTime){
  47863. console.log(1)
  47864. }
  47865. }
  47866. },
  47867. matrix4: function(currentTime, startY) {
  47868. var wholeY = currentTime.clone();
  47869. return function(duration) {
  47870. for (var r = currentTime.elements, o = wholeY.elements, a = startY.elements, s = 0; s < 16; s++)
  47871. r[s] = o[s] * (1 - duration) + a[s] * duration
  47872. }
  47873. },
  47874. allUniforms: function(currentTime, startY, wholeY) {
  47875. var duration = currentTime.map(function(currentTime) {
  47876. return this.uniform(currentTime, startY, wholeY)
  47877. }
  47878. .bind(this));
  47879. return function(currentTime) {
  47880. duration.forEach(function(startY) {
  47881. startY(currentTime)
  47882. })
  47883. }
  47884. } */
  47885. vector: function(t, i, f) {//xzw change, add f
  47886. var n = t.clone();
  47887. return i = i.clone(),
  47888. function(e) {
  47889. t.set(n.x * (1 - e) + i.x * e, n.y * (1 - e) + i.y * e, n.z * (1 - e) + i.z * e);
  47890. f && f(t,e);
  47891. }
  47892. },
  47893. quaternion: function(t, i, f) {//xzw change, add f
  47894. var n = t.clone();
  47895. return function(e) {
  47896. t.copy(n).slerp(i, e);
  47897. f && f(t,e);
  47898. }
  47899. },
  47900. property: function(t, i, n, r) {
  47901. var o = t[i];
  47902. return function(e) {
  47903. t[i] = o * (1 - e) + n * e,
  47904. r && r(t[i]);
  47905. }
  47906. },
  47907. uniform: function(t, i, n) {
  47908. var r = t.material.uniforms[i].value;
  47909. return function(e) {
  47910. t.material.uniforms[i] && (t.material.uniforms[i].value = r * (1 - e) + n * e);
  47911. }
  47912. },
  47913. matrix4: function(o, a) {
  47914. var s = o.clone();
  47915. return function(e) {
  47916. for (var t = o.elements, i = s.elements, n = a.elements, r = 0; r < 16; r++)
  47917. t[r] = i[r] * (1 - e) + n[r] * e;
  47918. }
  47919. },
  47920. allUniforms: function(e, t, i) {
  47921. var n = e.map(function(e) {
  47922. return this.uniform(e, t, i)
  47923. }
  47924. .bind(this));
  47925. return function(t) {
  47926. n.forEach(function(e) {
  47927. e(t);
  47928. });
  47929. }
  47930. }
  47931. };
  47932. /*
  47933. 渐变
  47934. */
  47935. var transitions = {
  47936. globalDone: null,
  47937. funcs: [],
  47938. counter: 0,
  47939. uniqueID: 0,
  47940. start: function(func, duration, done, delay, ease, name, id, cancelFun) {
  47941. return delay = delay || 0,
  47942. this.funcs.push({
  47943. func: func,
  47944. current: -delay * Math.abs(duration), //当前时间
  47945. duration: (1 - Math.max(delay, 0)) * Math.abs(duration), //总时长
  47946. done: done,
  47947. easing: ease || easing.linearTween, //渐变曲线
  47948. cycling: duration < 0,
  47949. running: !0,
  47950. debug: delay < 0,
  47951. name: name || "T" + this.counter,
  47952. id: void 0 === id ? this.counter : id,
  47953. paused: !1,
  47954. cancelFun : cancelFun, //取消时执行的函数
  47955. }),
  47956. func(0, 16),
  47957. this.counter += 1,
  47958. func
  47959. },
  47960. trigger: function(e) {
  47961. var t = void 0 === e.delayRatio ? 0 : e.delayRatio
  47962. , u = e.func || function() {}
  47963. , r = void 0 === e.duration ? 0 : e.duration;
  47964. void 0 !== e.cycling && e.cycling && (r = -Math.abs(r));
  47965. var o = e.done || null
  47966. , a = e.easing || easing.linearTween
  47967. , s = e.name || "R" + this.counter
  47968. , l = void 0 === e.id ? this.counter : e.id;
  47969. return this.start(u, r, o, t, a, s, l)
  47970. },
  47971. setTimeout: function(e, t, u) {
  47972. var duration = void 0 === u ? this.counter : u;
  47973. return this.trigger({
  47974. done: e,
  47975. duration: void 0 === t ? 0 : t,
  47976. name: "O" + this.counter,
  47977. id: duration
  47978. })
  47979. },
  47980. pause: function() {
  47981. this.paused = !0;
  47982. },
  47983. resume: function() {
  47984. this.paused = !1;
  47985. },
  47986. update: function(e) {
  47987. this.funcs.forEach(function(t) {
  47988. if (!(t.paused || (t.current += 1e3 * e,
  47989. t.current < 0)))
  47990. if (t.current >= t.duration && !t.cycling) {
  47991. var u = t.easing(1, 0, 1, 1);
  47992. t.func(u, 1e3 * e),
  47993. t.done && t.done(),
  47994. t.running = !1;
  47995. } else {
  47996. var duration = t.easing(t.current % t.duration / t.duration, 0, 1, 1)
  47997. , r = t.func(duration, 1e3 * e) || !1;
  47998. r && (t.done && t.done(),
  47999. t.running = !1);
  48000. }
  48001. });
  48002. var t = this.funcs.length;
  48003. this.funcs = this.funcs.filter(function(e) {
  48004. return e.running
  48005. });
  48006. var u = this.funcs.length;
  48007. if (t > 0 && 0 === u && this.globalDone) {
  48008. var duration = this.globalDone;
  48009. this.globalDone = null,
  48010. duration();
  48011. }
  48012. },
  48013. adjustSpeed: function(e, t) {
  48014. for (var u = this.getById(e), duration = 0; duration < u.length; duration++) {
  48015. var r = u[duration];
  48016. r.duration /= t,
  48017. r.current /= t;
  48018. }
  48019. },
  48020. getById: function(e) {
  48021. return this.funcs.filter(function(t) {
  48022. return e === t.id
  48023. })
  48024. },
  48025. get: function(e) {
  48026. for (var t = 0; t < this.funcs.length; t += 1)
  48027. if (this.funcs[t].func === e)
  48028. return this.funcs[t];
  48029. return null
  48030. },
  48031. isRunning: function(e) {
  48032. var t = this.get(e);
  48033. return null !== t && t.running
  48034. },
  48035. countActive: function() {
  48036. for (var e = 0, t = 0; t < this.funcs.length; t += 1)
  48037. e += this.funcs[t].running;
  48038. return e
  48039. },
  48040. listActive: function() {
  48041. for (var e = [], t = 0; t < this.funcs.length; t += 1)
  48042. this.funcs[t].running && e.push(this.funcs[t].name);
  48043. return e
  48044. },
  48045. done: function(e) {
  48046. this.globalDone = e;
  48047. },
  48048. cancelById: function(e, dealCancelFun) { //xzw add dealDone
  48049. var t = void 0 === e ? 0 : e;
  48050. let cancels = [];
  48051. this.funcs = this.funcs.filter(function(e) {
  48052. var is = e.id == t;
  48053. if(is && dealCancelFun){
  48054. e.cancelFun && cancels.push(e.cancelFun);
  48055. //e.cancelFun && e.cancelFun()
  48056. }
  48057. return !is
  48058. });
  48059. cancels.forEach(e=>{e();}); //先从funcs中去除后再执行
  48060. },
  48061. cancel: function(e) {
  48062. this.funcs = this.funcs.filter(function(t) {
  48063. return t.func !== e
  48064. });
  48065. },
  48066. getUniqueId: function() {
  48067. return this.uniqueID -= 1,
  48068. this.uniqueID
  48069. }
  48070. };
  48071. const colors = {
  48072. position: 'red',
  48073. target : 'blue'
  48074. };
  48075. let lineMats$1;
  48076. const getLineMat = function(name){
  48077. if(!lineMats$1){
  48078. lineMats$1 = {
  48079. position: LineDraw.createFatLineMat({
  48080. color: colors.position,
  48081. lineWidth: 3
  48082. }),
  48083. target : LineDraw.createFatLineMat({
  48084. color: colors.target,
  48085. lineWidth: 3
  48086. }),
  48087. frustum: LineDraw.createFatLineMat({
  48088. color: colors.position,
  48089. lineWidth: 2
  48090. }),
  48091. aimAtTarget: new LineBasicMaterial({color:colors.target})
  48092. };
  48093. }
  48094. return lineMats$1[name]
  48095. };
  48096. class CameraAnimation extends EventDispatcher{
  48097. constructor(viewer){
  48098. super();
  48099. this.viewer = viewer;
  48100. this.selectedElement = null;
  48101. //this.controlPoints = [];
  48102. this.uuid = MathUtils.generateUUID();
  48103. this.node = new Object3D();
  48104. this.node.name = "camera animation";
  48105. this.viewer.scene.scene.add(this.node);
  48106. this.frustum = this.createFrustum();
  48107. this.node.add(this.frustum);
  48108. this.name = "Camera Animation";
  48109. // "centripetal", "chordal", "catmullrom"
  48110. this.curveType = "centripetal";
  48111. this.visible = true;
  48112. this.targets = [];
  48113. this.createPath();
  48114. this.duration = 5;
  48115. this.percent = 0;
  48116. this.currentIndex = 0;
  48117. this.durations = [];
  48118. this.quaternions = [];
  48119. if(!Potree.settings.isTest){
  48120. this.setVisible(false);
  48121. }
  48122. this.addEventListener('dispose', ()=>{
  48123. this.dispose();
  48124. });
  48125. this.targetLines = new Object3D;
  48126. this.node.add(this.targetLines);
  48127. }
  48128. static defaultFromView(viewer){
  48129. const animation = new CameraAnimation(viewer);
  48130. const camera = viewer.scene.getActiveCamera();
  48131. const target = viewer.scene.view.getPivot();
  48132. const cpCenter = new Vector3(
  48133. 0.3 * camera.position.x + 0.7 * target.x,
  48134. 0.3 * camera.position.y + 0.7 * target.y,
  48135. 0.3 * camera.position.z + 0.7 * target.z,
  48136. );
  48137. const targetCenter = new Vector3(
  48138. 0.05 * camera.position.x + 0.95 * target.x,
  48139. 0.05 * camera.position.y + 0.95 * target.y,
  48140. 0.05 * camera.position.z + 0.95 * target.z,
  48141. );
  48142. const r = 2;//camera.position.distanceTo(target) * 0.3;
  48143. //const dir = target.clone().sub(camera.position).normalize();
  48144. const angle = Utils.computeAzimuth(camera.position, target);
  48145. const n = 5;
  48146. for(let i = 0; i < n; i++){
  48147. let u = 1.5 * Math.PI * (i / n) + angle;
  48148. const dx = r * Math.cos(u);
  48149. const dy = r * Math.sin(u);
  48150. const cpPos = new Vector3(
  48151. cpCenter.x + dx,
  48152. cpCenter.y + dy,
  48153. cpCenter.z,
  48154. );
  48155. const targetPos = new Vector3(
  48156. targetCenter.x + dx * 0.1,
  48157. targetCenter.y + dy * 0.1,
  48158. targetCenter.z,
  48159. );
  48160. animation.createControlPoint(null,{position:cpPos, target:targetPos});
  48161. }
  48162. animation.changeCallback();
  48163. return animation;
  48164. }
  48165. createControlPoint(index, posInfo ){
  48166. const length = this.posCurve.points.length;
  48167. const position = new Vector3;
  48168. const target = new Vector3;
  48169. if(index == void 0 ){
  48170. index = length;
  48171. }
  48172. if(!posInfo){
  48173. if(length >= 2 && index === 0){
  48174. const dir = new Vector3().subVectors(this.posCurve.points[0], this.posCurve.points[1] );
  48175. position.copy(this.posCurve.points[0]).add(dir);
  48176. const tDir = new Vector3().subVectors(this.targets[0].position, this.targets[1].position );
  48177. target.copy(this.targets[0].position).add(dir);
  48178. }else if(length >= 2 && index === length){
  48179. const dir = new Vector3().subVectors(this.posCurve.points[length-1], this.posCurve.points[length-2] );
  48180. position.copy(this.posCurve.points[length-2]).add(dir);
  48181. const tDir = new Vector3().subVectors(this.targets[length-1].position, this.targets[length-2].position );
  48182. target.copy(this.targets[length-2].position).add(dir);
  48183. }else if(length >= 2){
  48184. position.copy(this.posCurve.points[index-1].clone().add(this.posCurve.points[index]).multiplyScalar(0.5));
  48185. target.copy(this.targets[length-1].position.clone().add(this.targets[length]).multiplyScalar(0.5));
  48186. }
  48187. }else {
  48188. position.copy(posInfo.position);
  48189. target.copy(posInfo.target);
  48190. }
  48191. this.posCurve.addPoint(position, index/* , true */);
  48192. //this.targetCurve.addPoint(target, index/* , true */)
  48193. let targetSvg = new HandleSvg(target, colors.target);
  48194. targetSvg.visible = this.visible;
  48195. this.targets = [...this.targets.slice(0,index), targetSvg, ...this.targets.slice(index,length)];
  48196. if(this.useDurSlice){//不使用全局的duration,而是分段的
  48197. this.durations = [...this.durations.slice(0,index), posInfo.duration, ...this.durations.slice(index,length)];
  48198. }
  48199. this.dispatchEvent({
  48200. type: "controlpoint_added",
  48201. index
  48202. });
  48203. {
  48204. let targetLine = LineDraw.createLine([position,target] ,{mat: getLineMat('aimAtTarget')});
  48205. this.targetLines.children = [...this.targetLines.children.slice(0,index), targetLine, ...this.targetLines.children.slice(index,length)];
  48206. this.targets[index].addEventListener('dragged', (e)=>{
  48207. this.updatePathCallback();
  48208. this.dragPointCallback(e);
  48209. });
  48210. }
  48211. }
  48212. dragPointCallback(e){
  48213. let index = e.index;
  48214. if(e.index == void 0){
  48215. index = this.targets.indexOf(e.target);
  48216. }
  48217. LineDraw.moveLine(this.targetLines.children[index], [this.posCurve.points[index], this.targets[index].position] );
  48218. this.updateFrustum();
  48219. }
  48220. updatePathCallback(){
  48221. {
  48222. this.quaternions = [];
  48223. let length = this.posCurve.points.length;
  48224. for(let i=0; i<length; i++){
  48225. let quaternion = math.getQuaFromPosAim(this.posCurve.points[i], this.targets[i].position);
  48226. this.quaternions.push( quaternion);
  48227. }
  48228. }
  48229. this.reMapCurvePercent();
  48230. }
  48231. removeControlPoint(index){
  48232. this.posCurve.removePoint(index);
  48233. //this.targetCurve.removePoint(index)
  48234. this.targets[index].dispose();
  48235. this.targets.splice(index, 1);
  48236. this.dispatchEvent({
  48237. type: "controlpoint_removed",
  48238. index
  48239. });
  48240. this.targetLines.remove(this.targetLines.children[index]);
  48241. if(this.useDurSlice){
  48242. this.durations.splice(index, 1);
  48243. }
  48244. }
  48245. createPath(){
  48246. this.posCurve = new CurveCtrl([],getLineMat('position'), colors.position, 'posCurve');
  48247. //this.targetCurve = new CurveCtrl([], getLineMat('target'), colors.target, 'targetCurve', {noLine:true});
  48248. this.posCurve.needsPercent = true;
  48249. this.node.add(this.posCurve);
  48250. //this.node.add(this.targetCurve)
  48251. this.posCurve.addEventListener('dragCurvePoint', this.dragPointCallback.bind(this));
  48252. this.posCurve.addEventListener('updatePath', this.updatePathCallback.bind(this));
  48253. }
  48254. createFrustum(){
  48255. const f = 0.3;
  48256. const positions = [
  48257. new Vector3( 0, 0, 0),
  48258. new Vector3(-f, -f, +1),
  48259. new Vector3( 0, 0, 0),
  48260. new Vector3( f, -f, +1),
  48261. new Vector3( 0, 0, 0),
  48262. new Vector3( f, f, +1),
  48263. new Vector3( 0, 0, 0),
  48264. new Vector3(-f, f, +1),
  48265. new Vector3(-f, -f, +1),
  48266. new Vector3( f, -f, +1),
  48267. new Vector3( f, -f, +1),
  48268. new Vector3( f, f, +1),
  48269. new Vector3( f, f, +1),
  48270. new Vector3(-f, f, +1),
  48271. new Vector3(-f, f, +1),
  48272. new Vector3(-f, -f, +1),
  48273. ];
  48274. positions.forEach(e=>e.z *= -1); //因为得到的rotation是camera的,作用在物体上要反向,所以这里反向一下
  48275. //geometry.computeBoundingSphere();//?
  48276. const line = LineDraw.createFatLine( positions, {material:getLineMat('frustum')});
  48277. //line.scale.set(20, 20, 20);
  48278. line.visible = false;
  48279. return line;
  48280. }
  48281. reMapCurvePercent(){ //因在不同点在相同位置旋转,由于间隔仅和位置距离相关,导致时间间隔为0,采取重新调整间隔的策略。
  48282. var length = this.posCurve.points.length;
  48283. if(length<2){
  48284. return this.newPointsPercents = []
  48285. }
  48286. var newPercents = [0];
  48287. if(this.useDurSlice){ //已经设定好了每一段的duration的话
  48288. let sums = [0];
  48289. let sum = 0, last = this.durations[0];
  48290. for(let i=1;i<length;i++){
  48291. let duration = this.durations[i];
  48292. sum += duration;
  48293. last = duration;
  48294. sums.push(sum);
  48295. }
  48296. for(let i=1;i<length;i++){
  48297. newPercents.push(sum == 0 ? i/length : sums[i] / sum);
  48298. }
  48299. }else {
  48300. const maxSpaceDur = this.duration / length; //每两点之间修改间隔时间后,最大时间
  48301. const durPerRad = 0.8; //每弧度应该占用的时间
  48302. const minSpaceDur = Math.min(0.8, maxSpaceDur);//每两点之间修改间隔时间后,最小时间
  48303. const maxAngleSpaceDur = MathUtils.clamp(durPerRad * Math.PI, minSpaceDur, maxSpaceDur );// 最大可能差距是180度
  48304. var percents = this.posCurve.pointsPercent;
  48305. for(let i=1;i<length;i++){
  48306. let diff = (percents[i] - percents[i-1]) * this.duration; //间隔时间
  48307. let percent;
  48308. let curMin = minSpaceDur;
  48309. if(diff < maxAngleSpaceDur){ //若小于最大旋转时间
  48310. let rad = this.quaternions[i].angleTo(this.quaternions[i-1]);
  48311. curMin = MathUtils.clamp(rad * durPerRad, minSpaceDur, maxSpaceDur);
  48312. }
  48313. diff = Math.max(diff, curMin);
  48314. percent = newPercents[i-1] + (diff / this.duration); //得到新的percent
  48315. newPercents.push(percent);
  48316. }
  48317. let maxPercent = newPercents[length-1]; //最后一个,若扩充过时间,就会>1
  48318. if( !math.closeTo(maxPercent, 1)){
  48319. let scale = 1 / maxPercent; //需要压缩的比例 <1 这一步会让实际得到的间隔更小
  48320. newPercents = newPercents.map(e=> e*=scale );
  48321. }
  48322. }
  48323. this.newPointsPercents = newPercents;
  48324. //console.log(newPercents)
  48325. }
  48326. at(originPercent, delta, transitionRatio){
  48327. originPercent = MathUtils.clamp(originPercent, 0, 1);
  48328. //修改第一层:起始时间
  48329. let percent = originPercent;
  48330. /* const easePercent = 0.3; //缓动占比 //如果能在所有从静止到运动的中间加缓动就好了呀:lastPos * 0.9 + currentPos * 0.1 ?
  48331. if(originPercent < easePercent){
  48332. console.log('easeIn')
  48333. percent = easing.easeInSine(originPercent, 0, easePercent, easePercent) //currentTime, startY, wholeY, duration 选了一个衔接时接近斜率1的缓动函数
  48334. }else if(originPercent > 1-easePercent){
  48335. console.log('easeOut')
  48336. percent = easing.easeOutSine(originPercent-(1-easePercent), 1-easePercent, easePercent, easePercent)
  48337. } */
  48338. let quaternion;
  48339. if(percent < 1){
  48340. //修改第二层:使用每个点的重定位的 newPointsPercents
  48341. this.currentIndex = this.newPointsPercents.findIndex(e=> e>percent ) - 1;
  48342. //假设每个节点的百分比是精确的,那么:
  48343. let curIndexPercent = this.newPointsPercents[this.currentIndex];
  48344. let nextIndexPercent = this.newPointsPercents[this.currentIndex+1];
  48345. let progress = (percent - curIndexPercent) / (nextIndexPercent - curIndexPercent);//在这两个节点间的百分比
  48346. //投影到原本的 posCurve.pointsPercent上:
  48347. let curIndexOriPercent = this.posCurve.pointsPercent[this.currentIndex];
  48348. let nextIndexOriPercent = this.posCurve.pointsPercent[this.currentIndex+1];
  48349. percent = curIndexOriPercent + (nextIndexOriPercent - curIndexOriPercent) * progress;
  48350. let endQuaternion = this.quaternions[this.currentIndex+1];
  48351. let startQuaternion = this.quaternions[this.currentIndex];
  48352. quaternion = (new Quaternion()).copy(startQuaternion);
  48353. lerp.quaternion(quaternion, endQuaternion)(progress);
  48354. }else {
  48355. this.currentIndex = this.posCurve.points.length - 1;
  48356. quaternion = math.getQuaFromPosAim(this.posCurve.points[this.currentIndex], this.targets[this.currentIndex].position);
  48357. }
  48358. const position = this.posCurve.getPointAt(percent); // 需要this.posCurve.points.length>1 否则报错
  48359. //console.log(this.currentIndex, originPercent)
  48360. //缓动:
  48361. var aimQua, aimPos;
  48362. if(delta != void 0 ){
  48363. if(Potree.settings.tourTestCameraMove){
  48364. aimQua = this.frustum.quaternion.clone();
  48365. aimPos = this.frustum.position.clone();
  48366. }else {
  48367. var camera = viewer.scene.getActiveCamera();
  48368. aimQua = camera.quaternion.clone();
  48369. aimPos = camera.position.clone();
  48370. }
  48371. transitionRatio = transitionRatio || 1 / Potree.settings.cameraAniSmoothRatio;//渐变系数,越小缓动程度越高,越平滑
  48372. transitionRatio *= delta * 60; //假设标准帧率为60fps,当帧率低时(delta大时)要降低缓动
  48373. //console.log(transitionRatio, delta) //画面ui变化会使delta变大
  48374. transitionRatio = MathUtils.clamp(transitionRatio, 0, 1);
  48375. lerp.quaternion(aimQua, quaternion)(transitionRatio); //每次只改变一点点
  48376. lerp.vector(aimPos, position)(transitionRatio);
  48377. }else {
  48378. aimQua = quaternion; aimPos = position;
  48379. }
  48380. let rotation = new Euler().setFromQuaternion(aimQua );
  48381. const frame = {
  48382. position: aimPos,
  48383. rotation
  48384. };
  48385. return frame;
  48386. }
  48387. set(percent){
  48388. this.percent = percent;
  48389. }
  48390. setVisible(visible){
  48391. this.node.visible = visible;
  48392. this.posCurve.visible = visible;
  48393. this.targets.forEach(e=>e.visible = visible );
  48394. this.visible = visible;
  48395. }
  48396. setDuration(duration){
  48397. if(duration != this.duration){
  48398. this.duration = duration;
  48399. if(this.quaternions.length == this.posCurve.points.length)this.reMapCurvePercent();
  48400. }
  48401. }
  48402. getDuration(duration){
  48403. return this.duration;
  48404. }
  48405. play(startOptions={}){
  48406. if(this.onUpdate){
  48407. return console.error('已经开始播放')
  48408. }
  48409. let startPercent = 0, currentIndex = 0;
  48410. if(startOptions.percent != void 0 ){
  48411. startPercent = startOptions.percent;
  48412. }else if(startOptions.index){
  48413. currentIndex = index;
  48414. //startPercent = index/(this.posCurve.points.length-1)
  48415. startPercent = this.posCurve.pointsPercent[index];
  48416. }
  48417. //const tStart = performance.now();
  48418. const duration = this.duration;
  48419. this.originalyVisible = this.visible;
  48420. Potree.settings.tourTestCameraMove || this.setVisible(false);
  48421. let tStart, startTransitionRatio = 0.2;
  48422. let startDelay = 1/startTransitionRatio / 20 ;//因为缓动所以延迟开始,前面前都是at(0),使过渡到开始点位(但是依旧不能准确停在起始点,因为缓动是乘百分比有残留。所以直接平滑衔接到开始后的位置)
  48423. let hasPlayedTime = 0;
  48424. let finishDelay = Potree.settings.cameraAniSmoothRatio / 60 * 3;//结束后还需要多久时间才能大致达到缓动的最终目标
  48425. let hasStoppedTime = 0;
  48426. this.onUpdate = (e) => {
  48427. if(this.posCurve.points.length<2){
  48428. if(this.posCurve.points.length == 1){
  48429. viewer.scene.view.position.copy(this.posCurve.points[0]);
  48430. viewer.scene.view.rotation = new Euler().setFromQuaternion(this.quaternions[0]);
  48431. }
  48432. this.pause();
  48433. return
  48434. }
  48435. let percent, transitionRatio;
  48436. if(tStart){
  48437. let tNow = performance.now();
  48438. let elapsed = (tNow - tStart) / 1000;
  48439. percent = elapsed / duration + startPercent;
  48440. }else {//从当前位置过渡到开始位置
  48441. percent = 0;
  48442. hasPlayedTime += e.delta;
  48443. transitionRatio = startTransitionRatio;
  48444. console.log('延迟开始');
  48445. if(hasPlayedTime > startDelay){
  48446. tStart = performance.now();
  48447. }
  48448. }
  48449. this.set(percent);
  48450. const frame = this.at(percent, e.delta, transitionRatio);
  48451. if(currentIndex != this.currentIndex){
  48452. currentIndex = this.currentIndex;
  48453. console.log('updateCurrentIndex', currentIndex);
  48454. this.dispatchEvent({type:'updateCurrentIndex', currentIndex });
  48455. }
  48456. if(!Potree.settings.tourTestCameraMove){
  48457. viewer.scene.view.position.copy(frame.position);
  48458. //viewer.scene.view.lookAt(frame.target);
  48459. viewer.scene.view.rotation = frame.rotation;
  48460. }
  48461. this.updateFrustum(frame);
  48462. if(percent >= 1){
  48463. if(hasStoppedTime > finishDelay){
  48464. this.pause();
  48465. }else {
  48466. hasStoppedTime += e.delta;
  48467. console.log('延迟结束');
  48468. }
  48469. }
  48470. };
  48471. this.viewer.addEventListener("update", this.onUpdate);
  48472. }
  48473. pause(){
  48474. this.setVisible(this.originalyVisible);
  48475. this.viewer.removeEventListener("update", this.onUpdate);
  48476. this.dispatchEvent('playDone');
  48477. this.onUpdate = null;
  48478. }
  48479. updateFrustum(frame){
  48480. const frustum = this.frustum;
  48481. if(this.posCurve.points.length>1){
  48482. frustum.visible = true;
  48483. }else {
  48484. frustum.visible = false;
  48485. return
  48486. }
  48487. frame = frame || this.at(this.percent);
  48488. frustum.position.copy(frame.position);
  48489. //frustum.lookAt(...frame.target.toArray());
  48490. frustum.rotation.copy(frame.rotation);
  48491. }
  48492. changeCallback(){
  48493. this.posCurve.update();
  48494. //this.targetCurve.update()
  48495. this.targets.forEach(e=>e.update());
  48496. this.updateFrustum();
  48497. }
  48498. dispose(){//add
  48499. this.posCurve.dispose();
  48500. //this.targetCurve.dispatchEvent({type:'dispose'})
  48501. this.targets.forEach(e=>e.dispose());
  48502. this.durations = [];
  48503. this.node.parent.remove(this.node);
  48504. }
  48505. }
  48506. //scene.removeCameraAnimation
  48507. //修改:不使用targetCurve作为target曲线,因为播放时posCuve的节点和targetCurve并没有对应,且使用target的曲线会使角度变化大的情况过渡生硬。
  48508. // 改完旋转了。但是位置也有问题。速度完全和路程相关,当在同一位置设置多点时,这段的总时长为0. (是否要设置最小时长?不过也做不到 - -)
  48509. function loadPointCloud(viewer, data){
  48510. let loadMaterial = (target) => {
  48511. if(data.material){
  48512. if(data.material.activeAttributeName != null){
  48513. target.activeAttributeName = data.material.activeAttributeName;
  48514. }
  48515. if(data.material.ranges != null){
  48516. for(let range of data.material.ranges){
  48517. if(range.name === "elevationRange"){
  48518. target.elevationRange = range.value;
  48519. }else if(range.name === "intensityRange"){
  48520. target.intensityRange = range.value;
  48521. }else {
  48522. target.setRange(range.name, range.value);
  48523. }
  48524. }
  48525. }
  48526. if(data.material.size != null){
  48527. target.size = data.material.size;
  48528. }
  48529. if(data.material.minSize != null){
  48530. target.minSize = data.material.minSize;
  48531. }
  48532. if(data.material.pointSizeType != null){
  48533. target.pointSizeType = PointSizeType[data.material.pointSizeType];
  48534. }
  48535. if(data.material.matcap != null){
  48536. target.matcap = data.material.matcap;
  48537. }
  48538. }else if(data.activeAttributeName != null){
  48539. target.activeAttributeName = data.activeAttributeName;
  48540. }else {
  48541. // no material data
  48542. }
  48543. };
  48544. const promise = new Promise((resolve) => {
  48545. const names = viewer.scene.pointclouds.map(p => p.name);
  48546. const alreadyExists = names.includes(data.name);
  48547. if(alreadyExists){
  48548. resolve();
  48549. return;
  48550. }
  48551. Potree.loadPointCloud(data.url, data.name, (e) => {
  48552. const {pointcloud} = e;
  48553. pointcloud.position.set(...data.position);
  48554. pointcloud.rotation.set(...data.rotation);
  48555. pointcloud.scale.set(...data.scale);
  48556. loadMaterial(pointcloud.material);
  48557. viewer.scene.addPointCloud(pointcloud);
  48558. resolve(pointcloud);
  48559. });
  48560. });
  48561. return promise;
  48562. }
  48563. function loadMeasurement(viewer, data){
  48564. const duplicate = viewer.scene.measurements.find(measure => measure.uuid === data.uuid);
  48565. if(duplicate){
  48566. return;
  48567. }
  48568. data.points = data.points.map(point=>new Vector3(...point));
  48569. const measure = viewer.measuringTool.createMeasureFromData(data);
  48570. }
  48571. function loadVolume(viewer, data){
  48572. const duplicate = viewer.scene.volumes.find(volume => volume.uuid === data.uuid);
  48573. if(duplicate){
  48574. return;
  48575. }
  48576. let volume = new Potree[data.type];
  48577. volume.uuid = data.uuid;
  48578. volume.name = data.name;
  48579. volume.position.set(...data.position);
  48580. volume.rotation.set(...data.rotation);
  48581. volume.scale.set(...data.scale);
  48582. volume.visible = data.visible;
  48583. volume.clip = data.clip;
  48584. viewer.scene.addVolume(volume);
  48585. }
  48586. function loadCameraAnimation(viewer, data){
  48587. const duplicate = viewer.scene.cameraAnimations.find(a => a.uuid === data.uuid);
  48588. if(duplicate){
  48589. return;
  48590. }
  48591. const animation = new CameraAnimation(viewer);
  48592. animation.uuid = data.uuid;
  48593. animation.name = data.name;
  48594. animation.duration = data.duration;
  48595. animation.t = data.t;
  48596. animation.curveType = data.curveType;
  48597. animation.visible = data.visible;
  48598. animation.controlPoints = [];
  48599. for(const cpdata of data.controlPoints){
  48600. const cp = animation.createControlPoint();
  48601. cp.position.set(...cpdata.position);
  48602. cp.target.set(...cpdata.target);
  48603. }
  48604. viewer.scene.addCameraAnimation(animation);
  48605. }
  48606. function loadOrientedImages(viewer, images){
  48607. const {cameraParamsPath, imageParamsPath} = images;
  48608. const duplicate = viewer.scene.orientedImages.find(i => i.imageParamsPath === imageParamsPath);
  48609. if(duplicate){
  48610. return;
  48611. }
  48612. Potree.OrientedImageLoader.load(cameraParamsPath, imageParamsPath, viewer).then( images => {
  48613. viewer.scene.addOrientedImages(images);
  48614. });
  48615. }
  48616. function loadGeopackage(viewer, geopackage){
  48617. const path = geopackage.path;
  48618. const duplicate = viewer.scene.geopackages.find(i => i.path === path);
  48619. if(duplicate){
  48620. return;
  48621. }
  48622. const projection = viewer.getProjection();
  48623. proj4.defs("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
  48624. proj4.defs("pointcloud", projection);
  48625. const transform = proj4("WGS84", "pointcloud");
  48626. const params = {
  48627. transform: transform,
  48628. };
  48629. Potree.GeoPackageLoader.loadUrl(path, params).then(data => {
  48630. viewer.scene.addGeopackage(data);
  48631. });
  48632. }
  48633. function loadSettings(viewer, data){
  48634. if(!data){
  48635. return;
  48636. }
  48637. viewer.setPointBudget(data.pointBudget);
  48638. viewer.setFOV(data.fov);
  48639. viewer.setEDLEnabled(data.edlEnabled);
  48640. viewer.setEDLRadius(data.edlRadius);
  48641. viewer.setEDLStrength(data.edlStrength);
  48642. viewer.setBackground(data.background);
  48643. viewer.setMinNodeSize(data.minNodeSize);
  48644. viewer.setShowBoundingBox(data.showBoundingBoxes);
  48645. }
  48646. function loadView(viewer, view){
  48647. viewer.scene.view.position.set(...view.position);
  48648. viewer.scene.view.lookAt(...view.target);
  48649. }
  48650. function loadAnnotationItem(item){
  48651. const annotation = new Annotation({
  48652. position: item.position,
  48653. title: item.title,
  48654. cameraPosition: item.cameraPosition,
  48655. cameraTarget: item.cameraTarget,
  48656. });
  48657. annotation.description = item.description;
  48658. annotation.uuid = item.uuid;
  48659. if(item.offset){
  48660. annotation.offset.set(...item.offset);
  48661. }
  48662. return annotation;
  48663. }
  48664. function loadAnnotations(viewer, data){
  48665. if(!data){
  48666. return;
  48667. }
  48668. const findDuplicate = (item) => {
  48669. let duplicate = null;
  48670. viewer.scene.annotations.traverse( a => {
  48671. if(a.uuid === item.uuid){
  48672. duplicate = a;
  48673. }
  48674. });
  48675. return duplicate;
  48676. };
  48677. const traverse = (item, parent) => {
  48678. const duplicate = findDuplicate(item);
  48679. if(duplicate){
  48680. return;
  48681. }
  48682. const annotation = loadAnnotationItem(item);
  48683. for(const childItem of item.children){
  48684. traverse(childItem, annotation);
  48685. }
  48686. parent.add(annotation);
  48687. };
  48688. for(const item of data){
  48689. traverse(item, viewer.scene.annotations);
  48690. }
  48691. }
  48692. function loadProfile(viewer, data){
  48693. const {name, points} = data;
  48694. const duplicate = viewer.scene.profiles.find(profile => profile.uuid === data.uuid);
  48695. if(duplicate){
  48696. return;
  48697. }
  48698. let profile = new Potree.Profile();
  48699. profile.name = name;
  48700. profile.uuid = data.uuid;
  48701. profile.setWidth(data.width);
  48702. for(const point of points){
  48703. profile.addMarker(new Vector3(...point));
  48704. }
  48705. viewer.scene.addProfile(profile);
  48706. }
  48707. function loadClassification(viewer, data){
  48708. if(!data){
  48709. return;
  48710. }
  48711. const classifications = data;
  48712. viewer.setClassifications(classifications);
  48713. }
  48714. async function loadProject(viewer, data, done){
  48715. if(data.type !== "Potree"){
  48716. console.error("not a valid Potree project");
  48717. return;
  48718. }
  48719. loadSettings(viewer, data.settings);
  48720. loadView(viewer, data.view);
  48721. /* const pointcloudPromises = [];
  48722. for(const pointcloud of data.pointclouds){
  48723. const promise = loadPointCloud(viewer, pointcloud);
  48724. pointcloudPromises.push(promise);
  48725. } */
  48726. for(const measure of data.measurements){
  48727. loadMeasurement(viewer, measure);
  48728. }
  48729. for(const volume of data.volumes){
  48730. loadVolume(viewer, volume);
  48731. }
  48732. for(const animation of data.cameraAnimations){
  48733. loadCameraAnimation(viewer, animation);
  48734. }
  48735. for(const profile of data.profiles){
  48736. loadProfile(viewer, profile);
  48737. }
  48738. if(data.orientedImages){
  48739. for(const images of data.orientedImages){
  48740. loadOrientedImages(viewer, images);
  48741. }
  48742. }
  48743. loadAnnotations(viewer, data.annotations);
  48744. loadClassification(viewer, data.classification);
  48745. done && done();
  48746. // need to load at least one point cloud that defines the scene projection,
  48747. // before we can load stuff in other projections such as geopackages
  48748. //await Promise.any(pointcloudPromises); // (not yet supported)
  48749. /* Utils.waitAny(pointcloudPromises).then( () => {
  48750. if(data.geopackages){
  48751. for(const geopackage of data.geopackages){
  48752. loadGeopackage(viewer, geopackage);
  48753. }
  48754. }
  48755. });
  48756. await Promise.all(pointcloudPromises); */
  48757. }
  48758. //
  48759. // Algorithm by Christian Boucheny
  48760. // shader code taken and adapted from CloudCompare
  48761. //
  48762. // see
  48763. // https://github.com/cloudcompare/trunk/tree/master/plugins/qEDL/shaders/EDL
  48764. // http://www.kitware.com/source/home/post/9
  48765. // https://tel.archives-ouvertes.fr/tel-00438464/document p. 115+ (french)
  48766. class EyeDomeLightingMaterial extends RawShaderMaterial{
  48767. constructor(parameters = {}){
  48768. super();
  48769. let uniforms = {
  48770. /* screenWidth: { type: 'f', value: 0 },
  48771. screenHeight: { type: 'f', value: 0 }, */
  48772. resolution: { type: 'v2', value: new Vector2$1() },
  48773. edlStrength: { type: 'f', value: 1.0 },
  48774. uNear: { type: 'f', value: 1.0 },
  48775. uFar: { type: 'f', value: 1.0 },
  48776. radius: { type: 'f', value: 1.0 },
  48777. neighbours: { type: '2fv', value: [] },
  48778. depthMap: { type: 't', value: null },
  48779. uEDLColor: { type: 't', value: null },
  48780. uEDLDepth: { type: 't', value: null },
  48781. opacity: { type: 'f', value: 1.0 },
  48782. uProj: { type: "Matrix4fv", value: [] },
  48783. useEDL: { type: 'i', value: 1 }//add
  48784. };
  48785. this.setValues({
  48786. uniforms: uniforms,
  48787. vertexShader: this.getDefines() + Shaders['edl.vs'],
  48788. fragmentShader: this.getDefines() + Shaders['edl.fs'],
  48789. lights: false
  48790. });
  48791. this.neighbourCount = 8;
  48792. }
  48793. getDefines() {
  48794. let defines = '';
  48795. defines += '#define NEIGHBOUR_COUNT ' + this.neighbourCount + '\n';
  48796. return defines;
  48797. }
  48798. updateShaderSource() {
  48799. let vs = this.getDefines() + Shaders['edl.vs'];
  48800. let fs = this.getDefines() + Shaders['edl.fs'];
  48801. this.setValues({
  48802. vertexShader: vs,
  48803. fragmentShader: fs
  48804. });
  48805. this.uniforms.neighbours.value = this.neighbours;
  48806. this.needsUpdate = true;
  48807. }
  48808. get neighbourCount(){
  48809. return this._neighbourCount;
  48810. }
  48811. set neighbourCount(value){
  48812. if (this._neighbourCount !== value) { //周围八个格子
  48813. this._neighbourCount = value;
  48814. this.neighbours = new Float32Array(this._neighbourCount * 2);
  48815. for (let c = 0; c < this._neighbourCount; c++) {
  48816. this.neighbours[2 * c + 0] = Math.cos(2 * c * Math.PI / this._neighbourCount);
  48817. this.neighbours[2 * c + 1] = Math.sin(2 * c * Math.PI / this._neighbourCount);
  48818. }
  48819. this.updateShaderSource();
  48820. }
  48821. }
  48822. }
  48823. class NormalizationEDLMaterial extends RawShaderMaterial{
  48824. constructor(parameters = {}){
  48825. super();
  48826. let uniforms = {
  48827. screenWidth: { type: 'f', value: 0 },
  48828. screenHeight: { type: 'f', value: 0 },
  48829. edlStrength: { type: 'f', value: 1.0 },
  48830. radius: { type: 'f', value: 1.0 },
  48831. neighbours: { type: '2fv', value: [] },
  48832. uEDLMap: { type: 't', value: null },
  48833. uDepthMap: { type: 't', value: null },
  48834. uWeightMap: { type: 't', value: null },
  48835. };
  48836. this.setValues({
  48837. uniforms: uniforms,
  48838. vertexShader: this.getDefines() + Shaders['normalize.vs'],
  48839. fragmentShader: this.getDefines() + Shaders['normalize_and_edl.fs'],
  48840. });
  48841. this.neighbourCount = 8;
  48842. }
  48843. getDefines() {
  48844. let defines = '';
  48845. defines += '#define NEIGHBOUR_COUNT ' + this.neighbourCount + '\n';
  48846. return defines;
  48847. }
  48848. updateShaderSource() {
  48849. let vs = this.getDefines() + Shaders['normalize.vs'];
  48850. let fs = this.getDefines() + Shaders['normalize_and_edl.fs'];
  48851. this.setValues({
  48852. vertexShader: vs,
  48853. fragmentShader: fs
  48854. });
  48855. this.uniforms.neighbours.value = this.neighbours;
  48856. this.needsUpdate = true;
  48857. }
  48858. get neighbourCount(){
  48859. return this._neighbourCount;
  48860. }
  48861. set neighbourCount(value){
  48862. if (this._neighbourCount !== value) {
  48863. this._neighbourCount = value;
  48864. this.neighbours = new Float32Array(this._neighbourCount * 2);
  48865. for (let c = 0; c < this._neighbourCount; c++) {
  48866. this.neighbours[2 * c + 0] = Math.cos(2 * c * Math.PI / this._neighbourCount);
  48867. this.neighbours[2 * c + 1] = Math.sin(2 * c * Math.PI / this._neighbourCount);
  48868. }
  48869. this.updateShaderSource();
  48870. }
  48871. }
  48872. }
  48873. class NormalizationMaterial extends RawShaderMaterial{
  48874. constructor(parameters = {}){
  48875. super();
  48876. let uniforms = {
  48877. uDepthMap: { type: 't', value: null },
  48878. uWeightMap: { type: 't', value: null },
  48879. };
  48880. this.setValues({
  48881. uniforms: uniforms,
  48882. vertexShader: this.getDefines() + Shaders['normalize.vs'],
  48883. fragmentShader: this.getDefines() + Shaders['normalize.fs'],
  48884. });
  48885. }
  48886. getDefines() {
  48887. let defines = '';
  48888. return defines;
  48889. }
  48890. updateShaderSource() {
  48891. let vs = this.getDefines() + Shaders['normalize.vs'];
  48892. let fs = this.getDefines() + Shaders['normalize.fs'];
  48893. this.setValues({
  48894. vertexShader: vs,
  48895. fragmentShader: fs
  48896. });
  48897. this.needsUpdate = true;
  48898. }
  48899. }
  48900. /**
  48901. * laslaz code taken and adapted from plas.io js-laslaz
  48902. * http://plas.io/
  48903. * https://github.com/verma/plasio
  48904. *
  48905. * Thanks to Uday Verma and Howard Butler
  48906. *
  48907. */
  48908. class LasLazLoader {
  48909. constructor (version, extension) {
  48910. if (typeof (version) === 'string') {
  48911. this.version = new Version(version);
  48912. } else {
  48913. this.version = version;
  48914. }
  48915. this.extension = extension;
  48916. }
  48917. static progressCB () {
  48918. }
  48919. load (node) {
  48920. if (node.loaded) {
  48921. return;
  48922. }
  48923. let url = node.getURL();
  48924. if (this.version.equalOrHigher('1.4')) {
  48925. url += `.${this.extension}`;
  48926. }
  48927. let xhr = XHRFactory.createXMLHttpRequest();
  48928. xhr.open('GET', url, true);
  48929. xhr.responseType = 'arraybuffer';
  48930. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  48931. xhr.onreadystatechange = () => {
  48932. if (xhr.readyState === 4) {
  48933. if (xhr.status === 200 || xhr.status === 0) {
  48934. let buffer = xhr.response;
  48935. this.parse(node, buffer);
  48936. } else {
  48937. console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + url);
  48938. }
  48939. }
  48940. };
  48941. xhr.send(null);
  48942. }
  48943. async parse(node, buffer){
  48944. let lf = new LASFile(buffer);
  48945. let handler = new LasLazBatcher(node);
  48946. try{
  48947. await lf.open();
  48948. lf.isOpen = true;
  48949. }catch(e){
  48950. console.log("failed to open file. :(");
  48951. return;
  48952. }
  48953. let header = await lf.getHeader();
  48954. let skip = 1;
  48955. let totalRead = 0;
  48956. let totalToRead = (skip <= 1 ? header.pointsCount : header.pointsCount / skip);
  48957. let hasMoreData = true;
  48958. while(hasMoreData){
  48959. let data = await lf.readData(1000 * 1000, 0, skip);
  48960. handler.push(new LASDecoder(data.buffer,
  48961. header.pointsFormatId,
  48962. header.pointsStructSize,
  48963. data.count,
  48964. header.scale,
  48965. header.offset,
  48966. header.mins, header.maxs));
  48967. totalRead += data.count;
  48968. LasLazLoader.progressCB(totalRead / totalToRead);
  48969. hasMoreData = data.hasMoreData;
  48970. }
  48971. header.totalRead = totalRead;
  48972. header.versionAsString = lf.versionAsString;
  48973. header.isCompressed = lf.isCompressed;
  48974. LasLazLoader.progressCB(1);
  48975. try{
  48976. await lf.close();
  48977. lf.isOpen = false;
  48978. }catch(e){
  48979. console.error("failed to close las/laz file!!!");
  48980. throw e;
  48981. }
  48982. }
  48983. handle (node, url) {
  48984. }
  48985. };
  48986. class LasLazBatcher{
  48987. constructor (node) {
  48988. this.node = node;
  48989. }
  48990. push (lasBuffer) {
  48991. const workerPath = Potree.scriptPath + '/workers/LASDecoderWorker.js';
  48992. const worker = Potree.workerPool.getWorker(workerPath);
  48993. const node = this.node;
  48994. const pointAttributes = node.pcoGeometry.pointAttributes;
  48995. worker.onmessage = (e) => {
  48996. let geometry = new BufferGeometry();
  48997. let numPoints = lasBuffer.pointsCount;
  48998. let positions = new Float32Array(e.data.position);
  48999. let colors = new Uint8Array(e.data.color);
  49000. let intensities = new Float32Array(e.data.intensity);
  49001. let classifications = new Uint8Array(e.data.classification);
  49002. let returnNumbers = new Uint8Array(e.data.returnNumber);
  49003. let numberOfReturns = new Uint8Array(e.data.numberOfReturns);
  49004. let pointSourceIDs = new Uint16Array(e.data.pointSourceID);
  49005. let indices = new Uint8Array(e.data.indices);
  49006. geometry.setAttribute('position', new BufferAttribute(positions, 3));
  49007. geometry.setAttribute('color', new BufferAttribute(colors, 4, true));
  49008. geometry.setAttribute('intensity', new BufferAttribute(intensities, 1));
  49009. geometry.setAttribute('classification', new BufferAttribute(classifications, 1));
  49010. geometry.setAttribute('return number', new BufferAttribute(returnNumbers, 1));
  49011. geometry.setAttribute('number of returns', new BufferAttribute(numberOfReturns, 1));
  49012. geometry.setAttribute('source id', new BufferAttribute(pointSourceIDs, 1));
  49013. geometry.setAttribute('indices', new BufferAttribute(indices, 4));
  49014. geometry.attributes.indices.normalized = true;
  49015. for(const key in e.data.ranges){
  49016. const range = e.data.ranges[key];
  49017. const attribute = pointAttributes.attributes.find(a => a.name === key);
  49018. attribute.range[0] = Math.min(attribute.range[0], range[0]);
  49019. attribute.range[1] = Math.max(attribute.range[1], range[1]);
  49020. }
  49021. let tightBoundingBox = new Box3(
  49022. new Vector3().fromArray(e.data.tightBoundingBox.min),
  49023. new Vector3().fromArray(e.data.tightBoundingBox.max)
  49024. );
  49025. geometry.boundingBox = this.node.boundingBox;
  49026. this.node.tightBoundingBox = tightBoundingBox;
  49027. this.node.geometry = geometry;
  49028. this.node.numPoints = numPoints;
  49029. this.node.loaded = true;
  49030. this.node.loading = false;
  49031. Potree.numNodesLoading--;
  49032. this.node.mean = new Vector3(...e.data.mean);
  49033. Potree.workerPool.returnWorker(workerPath, worker);
  49034. };
  49035. let message = {
  49036. buffer: lasBuffer.arrayb,
  49037. numPoints: lasBuffer.pointsCount,
  49038. pointSize: lasBuffer.pointSize,
  49039. pointFormatID: 2,
  49040. scale: lasBuffer.scale,
  49041. offset: lasBuffer.offset,
  49042. mins: lasBuffer.mins,
  49043. maxs: lasBuffer.maxs
  49044. };
  49045. worker.postMessage(message, [message.buffer]);
  49046. };
  49047. }
  49048. //加载 解析点云
  49049. class BinaryLoader{
  49050. constructor(version, boundingBox, scale){
  49051. if (typeof (version) === 'string') {
  49052. this.version = new Version(version);
  49053. } else {
  49054. this.version = version;
  49055. }
  49056. this.boundingBox = boundingBox;
  49057. this.scale = scale;
  49058. }
  49059. load(node){
  49060. if (node.loaded) {
  49061. return;
  49062. }
  49063. let url = node.getURL();
  49064. if (this.version.equalOrHigher('1.4')) {
  49065. url += '.bin';
  49066. }
  49067. url += '?m='+node.pcoGeometry.timeStamp; //add
  49068. let xhr = XHRFactory.createXMLHttpRequest();
  49069. xhr.open('GET', url, true);
  49070. xhr.responseType = 'arraybuffer';
  49071. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  49072. xhr.onreadystatechange = () => {
  49073. if (xhr.readyState === 4) {
  49074. if((xhr.status === 200 || xhr.status === 0) && xhr.response !== null){
  49075. let buffer = xhr.response;
  49076. this.parse(node, buffer);
  49077. } else {
  49078. //console.error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
  49079. throw new Error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
  49080. }
  49081. }
  49082. };
  49083. try {
  49084. xhr.send(null);
  49085. } catch (e) {
  49086. console.log('fehler beim laden der punktwolke: ' + e);
  49087. }
  49088. };
  49089. parse(node, buffer){ //解析点云
  49090. let pointAttributes = node.pcoGeometry.pointAttributes;
  49091. let numPoints = buffer.byteLength / node.pcoGeometry.pointAttributes.byteSize;
  49092. if (this.version.upTo('1.5')) {
  49093. node.numPoints = numPoints;
  49094. }
  49095. let workerPath = Potree.scriptPath + '/workers/BinaryDecoderWorker.js';
  49096. let worker = Potree.workerPool.getWorker(workerPath);
  49097. worker.onmessage = function (e) {
  49098. let data = e.data;
  49099. let buffers = data.attributeBuffers;
  49100. let tightBoundingBox = new Box3(
  49101. new Vector3().fromArray(data.tightBoundingBox.min),
  49102. new Vector3().fromArray(data.tightBoundingBox.max)
  49103. );
  49104. Potree.workerPool.returnWorker(workerPath, worker);
  49105. let geometry = new BufferGeometry();
  49106. for(let property in buffers){
  49107. let buffer = buffers[property].buffer;
  49108. let batchAttribute = buffers[property].attribute;
  49109. if (property === "POSITION_CARTESIAN") {
  49110. geometry.setAttribute('position', new BufferAttribute(new Float32Array(buffer), 3));
  49111. } else if (property === "rgba") {
  49112. geometry.setAttribute("rgba", new BufferAttribute(new Uint8Array(buffer), 4, true));
  49113. } else if (property === "NORMAL_SPHEREMAPPED") {
  49114. geometry.setAttribute('normal', new BufferAttribute(new Float32Array(buffer), 3));
  49115. } else if (property === "NORMAL_OCT16") {
  49116. geometry.setAttribute('normal', new BufferAttribute(new Float32Array(buffer), 3));
  49117. } else if (property === "NORMAL") {
  49118. geometry.setAttribute('normal', new BufferAttribute(new Float32Array(buffer), 3));
  49119. } else if (property === "INDICES") {
  49120. let bufferAttribute = new BufferAttribute(new Uint8Array(buffer), 4);
  49121. bufferAttribute.normalized = true;
  49122. geometry.setAttribute('indices', bufferAttribute);
  49123. } else if (property === "SPACING") {
  49124. let bufferAttribute = new BufferAttribute(new Float32Array(buffer), 1);
  49125. geometry.setAttribute('spacing', bufferAttribute);
  49126. } else {
  49127. const bufferAttribute = new BufferAttribute(new Float32Array(buffer), 1);
  49128. bufferAttribute.potree = {
  49129. offset: buffers[property].offset,
  49130. scale: buffers[property].scale,
  49131. preciseBuffer: buffers[property].preciseBuffer,
  49132. range: batchAttribute.range,
  49133. };
  49134. geometry.setAttribute(property, bufferAttribute);
  49135. const attribute = pointAttributes.attributes.find(a => a.name === batchAttribute.name);
  49136. attribute.range[0] = Math.min(attribute.range[0], batchAttribute.range[0]);
  49137. attribute.range[1] = Math.max(attribute.range[1], batchAttribute.range[1]);
  49138. if(node.getLevel() === 0){
  49139. attribute.initialRange = batchAttribute.range;
  49140. }
  49141. }
  49142. }
  49143. tightBoundingBox.max.sub(tightBoundingBox.min);
  49144. tightBoundingBox.min.set(0, 0, 0);
  49145. let numPoints = e.data.buffer.byteLength / pointAttributes.byteSize;
  49146. node.numPoints = numPoints;
  49147. node.geometry = geometry;
  49148. node.mean = new Vector3(...data.mean);
  49149. node.tightBoundingBox = tightBoundingBox;
  49150. node.loaded = true;
  49151. node.loading = false;
  49152. node.estimatedSpacing = data.estimatedSpacing;
  49153. Potree.numNodesLoading--;
  49154. };
  49155. let message = {
  49156. buffer: buffer,
  49157. pointAttributes: pointAttributes,
  49158. version: this.version.version,
  49159. min: [ node.boundingBox.min.x, node.boundingBox.min.y, node.boundingBox.min.z ],
  49160. offset: [node.pcoGeometry.offset.x, node.pcoGeometry.offset.y, node.pcoGeometry.offset.z],
  49161. scale: this.scale,
  49162. spacing: node.spacing,
  49163. hasChildren: node.hasChildren,
  49164. name: node.name
  49165. };
  49166. worker.postMessage(message, [message.buffer]);
  49167. };
  49168. }
  49169. var transformFrom4dkk = function(name){
  49170. var jsAttribute = PointAttribute[name];
  49171. return jsAttribute
  49172. /* if(name == "POSITION_CARTESIAN"){
  49173. jsAttribute = {
  49174. description: "",
  49175. elementSize: 4,
  49176. elements: 3,
  49177. name: "POSITION_CARTESIAN",
  49178. size: 12,
  49179. type: "int32",
  49180. }
  49181. }else if(name == "COLOR_PACKED"){
  49182. jsAttribute = {
  49183. description: "" ,
  49184. elementSize: 1,
  49185. elements: 4,
  49186. name: "RGBA",
  49187. size: 4,
  49188. type: 'int8',
  49189. }
  49190. }else if(name == "NORMAL_OCT16"){
  49191. jsAttribute = {
  49192. description: "" ,
  49193. elementSize: 4,
  49194. elements: 2,
  49195. name: "NORMAL_OCT16",
  49196. size: 12,
  49197. type: "uint8",
  49198. }
  49199. } */
  49200. /* var Q = q(L.COLOR_PACKED, K.DATA_TYPE_INT8, 4)
  49201. POSITION_CARTESIAN: q(L.POSITION_CARTESIAN, K.DATA_TYPE_FLOAT, 3),
  49202. RGBA_PACKED: Q,
  49203. COLOR_PACKED: Q,
  49204. RGB_PACKED: q(L.COLOR_PACKED, K.DATA_TYPE_INT8, 3),
  49205. NORMAL_FLOATS: q(L.NORMAL_FLOATS, K.DATA_TYPE_FLOAT, 3),
  49206. FILLER_1B: q(L.FILLER, K.DATA_TYPE_UINT8, 1),
  49207. INTENSITY: q(L.INTENSITY, K.DATA_TYPE_UINT16, 1),
  49208. CLASSIFICATION: q(L.CLASSIFICATION, K.DATA_TYPE_UINT8, 1),
  49209. NORMAL_SPHEREMAPPED: q(L.NORMAL_SPHEREMAPPED, K.DATA_TYPE_UINT8, 2),
  49210. NORMAL_OCT16: q(L.NORMAL_OCT16, K.DATA_TYPE_UINT8, 2),
  49211. NORMAL: q(L.NORMAL, K.DATA_TYPE_FLOAT, 3) */
  49212. };
  49213. function parseAttributes(cloudjs){
  49214. let version = new Version(cloudjs.version);
  49215. const replacements = {
  49216. "COLOR_PACKED": "rgba",
  49217. "RGBA": "rgba",
  49218. "INTENSITY": "intensity",
  49219. "CLASSIFICATION": "classification",
  49220. "GPS_TIME": "gps-time",
  49221. };
  49222. const replaceOldNames = (old) => {
  49223. if(replacements[old]){
  49224. return replacements[old];
  49225. }else {
  49226. return old;
  49227. }
  49228. };
  49229. const pointAttributes = [];
  49230. if(version.upTo('1.7')){
  49231. for(let attributeName of cloudjs.pointAttributes){
  49232. const oldAttribute = PointAttribute[attributeName];
  49233. const attribute = {
  49234. name: oldAttribute.name,
  49235. size: oldAttribute.byteSize,
  49236. elements: oldAttribute.numElements,
  49237. elementSize: oldAttribute.byteSize / oldAttribute.numElements,
  49238. type: oldAttribute.type.name,
  49239. description: "",
  49240. };
  49241. pointAttributes.push(attribute);
  49242. }
  49243. }else {
  49244. pointAttributes.push(...cloudjs.pointAttributes);
  49245. }
  49246. {
  49247. const attributes = new PointAttributes();
  49248. const typeConversion = {
  49249. int8: PointAttributeTypes.DATA_TYPE_INT8,
  49250. int16: PointAttributeTypes.DATA_TYPE_INT16,
  49251. int32: PointAttributeTypes.DATA_TYPE_INT32,
  49252. int64: PointAttributeTypes.DATA_TYPE_INT64,
  49253. uint8: PointAttributeTypes.DATA_TYPE_UINT8,
  49254. uint16: PointAttributeTypes.DATA_TYPE_UINT16,
  49255. uint32: PointAttributeTypes.DATA_TYPE_UINT32,
  49256. uint64: PointAttributeTypes.DATA_TYPE_UINT64,
  49257. double: PointAttributeTypes.DATA_TYPE_DOUBLE,
  49258. float: PointAttributeTypes.DATA_TYPE_FLOAT,
  49259. };
  49260. for(let jsAttribute of pointAttributes){
  49261. if(jsAttribute.name == void 0){//是来自四维看看的数据
  49262. //attribute = transformFrom4dkk(jsAttribute)
  49263. var attribute_ = PointAttribute[jsAttribute];
  49264. attributes.add(attribute_);
  49265. continue;
  49266. }
  49267. const name = replaceOldNames(jsAttribute.name);
  49268. const type = typeConversion[jsAttribute.type];
  49269. const numElements = jsAttribute.elements;
  49270. const description = jsAttribute.description;
  49271. const attribute = new PointAttribute(name, type, numElements);
  49272. attributes.add(attribute);
  49273. }
  49274. {
  49275. // check if it has normals
  49276. let hasNormals =
  49277. pointAttributes.find(a => a.name === "NormalX") !== undefined &&
  49278. pointAttributes.find(a => a.name === "NormalY") !== undefined &&
  49279. pointAttributes.find(a => a.name === "NormalZ") !== undefined;
  49280. if(hasNormals){
  49281. let vector = {
  49282. name: "NORMAL",
  49283. attributes: ["NormalX", "NormalY", "NormalZ"],
  49284. };
  49285. attributes.addVector(vector);
  49286. }
  49287. }
  49288. return attributes;
  49289. }
  49290. }
  49291. function lasLazAttributes(fMno){
  49292. const attributes = new PointAttributes();
  49293. attributes.add(PointAttribute.POSITION_CARTESIAN);
  49294. attributes.add(new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_UINT8, 4));
  49295. attributes.add(new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1));
  49296. attributes.add(new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  49297. attributes.add(new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1));
  49298. attributes.add(new PointAttribute("number of returns", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  49299. attributes.add(new PointAttribute("return number", PointAttributeTypes.DATA_TYPE_UINT8, 1));
  49300. attributes.add(new PointAttribute("source id", PointAttributeTypes.DATA_TYPE_UINT16, 1));
  49301. //attributes.add(new PointAttribute("pointSourceID", PointAttributeTypes.DATA_TYPE_INT8, 4));
  49302. return attributes;
  49303. }
  49304. class POCLoader {
  49305. static load(url, timeStamp, callback){ //add timeStamp
  49306. try {
  49307. let pco = new PointCloudOctreeGeometry();
  49308. pco.timeStamp = timeStamp;
  49309. pco.url = url;
  49310. let xhr = XHRFactory.createXMLHttpRequest();
  49311. xhr.open('GET', url+'?m='+timeStamp, true);
  49312. xhr.onreadystatechange = function () {
  49313. if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 0)) {
  49314. let fMno = JSON.parse(xhr.responseText);
  49315. let version = new Version(fMno.version);
  49316. // assume octreeDir is absolute if it starts with http
  49317. if (fMno.octreeDir.indexOf('http') === 0) {
  49318. pco.octreeDir = fMno.octreeDir;
  49319. } else {
  49320. pco.octreeDir = url + '/../' + fMno.octreeDir;
  49321. }
  49322. pco.spacing = fMno.spacing;
  49323. pco.hierarchyStepSize = fMno.hierarchyStepSize;
  49324. pco.pointAttributes = fMno.pointAttributes;
  49325. let min = new Vector3(fMno.boundingBox.lx, fMno.boundingBox.ly, fMno.boundingBox.lz);
  49326. let max = new Vector3(fMno.boundingBox.ux, fMno.boundingBox.uy, fMno.boundingBox.uz);
  49327. let boundingBox = new Box3(min, max);
  49328. let tightBoundingBox = boundingBox.clone();
  49329. if (fMno.tightBoundingBox) {//这个才是真实的bounding,前面那个bounding的size是个正方体,似乎取了最长边作为边长
  49330. tightBoundingBox.min.copy(new Vector3(fMno.tightBoundingBox.lx, fMno.tightBoundingBox.ly, fMno.tightBoundingBox.lz));
  49331. tightBoundingBox.max.copy(new Vector3(fMno.tightBoundingBox.ux, fMno.tightBoundingBox.uy, fMno.tightBoundingBox.uz));
  49332. }
  49333. let offset = min.clone(); //将成为点云的position,被我用作旋转中心(但在点云中不那么居中,navvis也是这样, 这样可能是为了让模型在这数据的bounding上)
  49334. boundingBox.min.sub(offset); //点云的真实坐标的min都是0,0,0吗(我看案例是,因绕角落旋转,也就是原点)
  49335. boundingBox.max.sub(offset);
  49336. tightBoundingBox.min.sub(offset);
  49337. tightBoundingBox.max.sub(offset);
  49338. //改
  49339. //pco.projection = fMno.projection || "+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs ",
  49340. //"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" //给地图
  49341. pco.boundingBox = boundingBox;
  49342. pco.tightBoundingBox = tightBoundingBox;
  49343. pco.boundingSphere = boundingBox.getBoundingSphere(new Sphere());
  49344. pco.tightBoundingSphere = tightBoundingBox.getBoundingSphere(new Sphere());
  49345. pco.offset = offset;
  49346. if (fMno.pointAttributes === 'LAS') {
  49347. pco.loader = new LasLazLoader(fMno.version, "las");
  49348. pco.pointAttributes = lasLazAttributes(fMno);
  49349. } else if (fMno.pointAttributes === 'LAZ') {
  49350. pco.loader = new LasLazLoader(fMno.version, "laz");
  49351. pco.pointAttributes = lasLazAttributes(fMno);
  49352. } else {
  49353. pco.loader = new BinaryLoader(fMno.version, boundingBox, fMno.scale);
  49354. pco.pointAttributes = parseAttributes(fMno);
  49355. }
  49356. let nodes = {};
  49357. { // load root
  49358. let name = 'r';
  49359. let root = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  49360. root.level = 0;
  49361. root.hasChildren = true;
  49362. root.spacing = pco.spacing;
  49363. if (version.upTo('1.5')) {
  49364. root.numPoints = fMno.hierarchy[0][1];
  49365. } else {
  49366. root.numPoints = 0;
  49367. }
  49368. pco.root = root;
  49369. pco.root.load();
  49370. nodes[name] = root;
  49371. }
  49372. // load remaining hierarchy
  49373. if (version.upTo('1.4')) {
  49374. for (let i = 1; i < fMno.hierarchy.length; i++) {
  49375. let name = fMno.hierarchy[i][0];
  49376. let numPoints = fMno.hierarchy[i][1];
  49377. let index = parseInt(name.charAt(name.length - 1));
  49378. let parentName = name.substring(0, name.length - 1);
  49379. let parentNode = nodes[parentName];
  49380. let level = name.length - 1;
  49381. //let boundingBox = POCLoader.createChildAABB(parentNode.boundingBox, index);
  49382. let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
  49383. let node = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  49384. node.level = level;
  49385. node.numPoints = numPoints;
  49386. node.spacing = pco.spacing / Math.pow(2, level);
  49387. parentNode.addChild(node);
  49388. nodes[name] = node;
  49389. }
  49390. }
  49391. pco.nodes = nodes;
  49392. callback(pco);
  49393. }
  49394. };
  49395. xhr.send(null);
  49396. } catch (e) {
  49397. console.log("loading failed: '" + url + "'");
  49398. console.log(e);
  49399. callback();
  49400. }
  49401. }
  49402. loadPointAttributes(mno){
  49403. let fpa = mno.pointAttributes;
  49404. let pa = new PointAttributes();
  49405. for (let i = 0; i < fpa.length; i++) {
  49406. let pointAttribute = PointAttribute[fpa[i]];
  49407. pa.add(pointAttribute);
  49408. }
  49409. return pa;
  49410. }
  49411. createChildAABB(aabb, index){
  49412. let min = aabb.min.clone();
  49413. let max = aabb.max.clone();
  49414. let size = new Vector3().subVectors(max, min);
  49415. if ((index & 0b0001) > 0) {
  49416. min.z += size.z / 2;
  49417. } else {
  49418. max.z -= size.z / 2;
  49419. }
  49420. if ((index & 0b0010) > 0) {
  49421. min.y += size.y / 2;
  49422. } else {
  49423. max.y -= size.y / 2;
  49424. }
  49425. if ((index & 0b0100) > 0) {
  49426. min.x += size.x / 2;
  49427. } else {
  49428. max.x -= size.x / 2;
  49429. }
  49430. return new Box3(min, max);
  49431. }
  49432. }
  49433. /**
  49434. * @author Connor Manning
  49435. */
  49436. class EptLoader {
  49437. static async load(file, callback) {
  49438. let response = await fetch(file);
  49439. let json = await response.json();
  49440. let url = file.substr(0, file.lastIndexOf('ept.json'));
  49441. let geometry = new Potree.PointCloudEptGeometry(url, json);
  49442. let root = new Potree.PointCloudEptGeometryNode(geometry);
  49443. geometry.root = root;
  49444. geometry.root.load();
  49445. callback(geometry);
  49446. }
  49447. };
  49448. class EptBinaryLoader {
  49449. extension() {
  49450. return '.bin';
  49451. }
  49452. workerPath() {
  49453. return Potree.scriptPath + '/workers/EptBinaryDecoderWorker.js';
  49454. }
  49455. load(node) {
  49456. if (node.loaded) return;
  49457. let url = node.url() + this.extension();
  49458. let xhr = XHRFactory.createXMLHttpRequest();
  49459. xhr.open('GET', url, true);
  49460. xhr.responseType = 'arraybuffer';
  49461. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  49462. xhr.onreadystatechange = () => {
  49463. if (xhr.readyState === 4) {
  49464. if (xhr.status === 200) {
  49465. let buffer = xhr.response;
  49466. this.parse(node, buffer);
  49467. } else {
  49468. console.log('Failed ' + url + ': ' + xhr.status);
  49469. }
  49470. }
  49471. };
  49472. try {
  49473. xhr.send(null);
  49474. }
  49475. catch (e) {
  49476. console.log('Failed request: ' + e);
  49477. }
  49478. }
  49479. parse(node, buffer) {
  49480. let workerPath = this.workerPath();
  49481. let worker = Potree.workerPool.getWorker(workerPath);
  49482. worker.onmessage = function(e) {
  49483. let g = new BufferGeometry();
  49484. let numPoints = e.data.numPoints;
  49485. let position = new Float32Array(e.data.position);
  49486. g.setAttribute('position', new BufferAttribute(position, 3));
  49487. let indices = new Uint8Array(e.data.indices);
  49488. g.setAttribute('indices', new BufferAttribute(indices, 4));
  49489. if (e.data.color) {
  49490. let color = new Uint8Array(e.data.color);
  49491. g.setAttribute('color', new BufferAttribute(color, 4, true));
  49492. }
  49493. if (e.data.intensity) {
  49494. let intensity = new Float32Array(e.data.intensity);
  49495. g.setAttribute('intensity',
  49496. new BufferAttribute(intensity, 1));
  49497. }
  49498. if (e.data.classification) {
  49499. let classification = new Uint8Array(e.data.classification);
  49500. g.setAttribute('classification',
  49501. new BufferAttribute(classification, 1));
  49502. }
  49503. if (e.data.returnNumber) {
  49504. let returnNumber = new Uint8Array(e.data.returnNumber);
  49505. g.setAttribute('return number',
  49506. new BufferAttribute(returnNumber, 1));
  49507. }
  49508. if (e.data.numberOfReturns) {
  49509. let numberOfReturns = new Uint8Array(e.data.numberOfReturns);
  49510. g.setAttribute('number of returns',
  49511. new BufferAttribute(numberOfReturns, 1));
  49512. }
  49513. if (e.data.pointSourceId) {
  49514. let pointSourceId = new Uint16Array(e.data.pointSourceId);
  49515. g.setAttribute('source id',
  49516. new BufferAttribute(pointSourceId, 1));
  49517. }
  49518. g.attributes.indices.normalized = true;
  49519. let tightBoundingBox = new Box3(
  49520. new Vector3().fromArray(e.data.tightBoundingBox.min),
  49521. new Vector3().fromArray(e.data.tightBoundingBox.max)
  49522. );
  49523. node.doneLoading(
  49524. g,
  49525. tightBoundingBox,
  49526. numPoints,
  49527. new Vector3(...e.data.mean));
  49528. Potree.workerPool.returnWorker(workerPath, worker);
  49529. };
  49530. let toArray = (v) => [v.x, v.y, v.z];
  49531. let message = {
  49532. buffer: buffer,
  49533. schema: node.ept.schema,
  49534. scale: node.ept.eptScale,
  49535. offset: node.ept.eptOffset,
  49536. mins: toArray(node.key.b.min)
  49537. };
  49538. worker.postMessage(message, [message.buffer]);
  49539. }
  49540. };
  49541. /**
  49542. * laslaz code taken and adapted from plas.io js-laslaz
  49543. * http://plas.io/
  49544. * https://github.com/verma/plasio
  49545. *
  49546. * Thanks to Uday Verma and Howard Butler
  49547. *
  49548. */
  49549. class EptLaszipLoader {
  49550. load(node) {
  49551. if (node.loaded) return;
  49552. let url = node.url() + '.laz';
  49553. let xhr = XHRFactory.createXMLHttpRequest();
  49554. xhr.open('GET', url, true);
  49555. xhr.responseType = 'arraybuffer';
  49556. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  49557. xhr.onreadystatechange = () => {
  49558. if (xhr.readyState === 4) {
  49559. if (xhr.status === 200) {
  49560. let buffer = xhr.response;
  49561. this.parse(node, buffer);
  49562. } else {
  49563. console.log('Failed ' + url + ': ' + xhr.status);
  49564. }
  49565. }
  49566. };
  49567. xhr.send(null);
  49568. }
  49569. async parse(node, buffer){
  49570. let lf = new LASFile(buffer);
  49571. let handler = new EptLazBatcher(node);
  49572. try{
  49573. await lf.open();
  49574. lf.isOpen = true;
  49575. const header = await lf.getHeader();
  49576. {
  49577. let i = 0;
  49578. let toArray = (v) => [v.x, v.y, v.z];
  49579. let mins = toArray(node.key.b.min);
  49580. let maxs = toArray(node.key.b.max);
  49581. let hasMoreData = true;
  49582. while(hasMoreData){
  49583. const data = await lf.readData(1000000, 0, 1);
  49584. let d = new LASDecoder(
  49585. data.buffer,
  49586. header.pointsFormatId,
  49587. header.pointsStructSize,
  49588. data.count,
  49589. header.scale,
  49590. header.offset,
  49591. mins,
  49592. maxs);
  49593. d.extraBytes = header.extraBytes;
  49594. d.pointsFormatId = header.pointsFormatId;
  49595. handler.push(d);
  49596. i += data.count;
  49597. hasMoreData = data.hasMoreData;
  49598. }
  49599. header.totalRead = i;
  49600. header.versionAsString = lf.versionAsString;
  49601. header.isCompressed = lf.isCompressed;
  49602. await lf.close();
  49603. lf.isOpen = false;
  49604. }
  49605. }catch(err){
  49606. console.error('Error reading LAZ:', err);
  49607. if (lf.isOpen) {
  49608. await lf.close();
  49609. lf.isOpen = false;
  49610. }
  49611. throw err;
  49612. }
  49613. }
  49614. };
  49615. class EptLazBatcher {
  49616. constructor(node) { this.node = node; }
  49617. push(las) {
  49618. let workerPath = Potree.scriptPath +
  49619. '/workers/EptLaszipDecoderWorker.js';
  49620. let worker = Potree.workerPool.getWorker(workerPath);
  49621. worker.onmessage = (e) => {
  49622. let g = new BufferGeometry();
  49623. let numPoints = las.pointsCount;
  49624. let positions = new Float32Array(e.data.position);
  49625. let colors = new Uint8Array(e.data.color);
  49626. let intensities = new Float32Array(e.data.intensity);
  49627. let classifications = new Uint8Array(e.data.classification);
  49628. let returnNumbers = new Uint8Array(e.data.returnNumber);
  49629. let numberOfReturns = new Uint8Array(e.data.numberOfReturns);
  49630. let pointSourceIDs = new Uint16Array(e.data.pointSourceID);
  49631. let indices = new Uint8Array(e.data.indices);
  49632. let gpsTime = new Float32Array(e.data.gpsTime);
  49633. g.setAttribute('position',
  49634. new BufferAttribute(positions, 3));
  49635. g.setAttribute('rgba',
  49636. new BufferAttribute(colors, 4, true));
  49637. g.setAttribute('intensity',
  49638. new BufferAttribute(intensities, 1));
  49639. g.setAttribute('classification',
  49640. new BufferAttribute(classifications, 1));
  49641. g.setAttribute('return number',
  49642. new BufferAttribute(returnNumbers, 1));
  49643. g.setAttribute('number of returns',
  49644. new BufferAttribute(numberOfReturns, 1));
  49645. g.setAttribute('source id',
  49646. new BufferAttribute(pointSourceIDs, 1));
  49647. g.setAttribute('indices',
  49648. new BufferAttribute(indices, 4));
  49649. g.setAttribute('gpsTime',
  49650. new BufferAttribute(gpsTime, 1));
  49651. this.node.gpsTime = e.data.gpsMeta;
  49652. g.attributes.indices.normalized = true;
  49653. let tightBoundingBox = new Box3(
  49654. new Vector3().fromArray(e.data.tightBoundingBox.min),
  49655. new Vector3().fromArray(e.data.tightBoundingBox.max)
  49656. );
  49657. this.node.doneLoading(
  49658. g,
  49659. tightBoundingBox,
  49660. numPoints,
  49661. new Vector3(...e.data.mean));
  49662. Potree.workerPool.returnWorker(workerPath, worker);
  49663. };
  49664. let message = {
  49665. buffer: las.arrayb,
  49666. numPoints: las.pointsCount,
  49667. pointSize: las.pointSize,
  49668. pointFormatID: las.pointsFormatId,
  49669. scale: las.scale,
  49670. offset: las.offset,
  49671. mins: las.mins,
  49672. maxs: las.maxs
  49673. };
  49674. worker.postMessage(message, [message.buffer]);
  49675. };
  49676. };
  49677. class EptZstandardLoader extends EptBinaryLoader {
  49678. extension() {
  49679. return '.zst';
  49680. }
  49681. workerPath() {
  49682. return Potree.scriptPath + '/workers/EptZstandardDecoderWorker.js';
  49683. }
  49684. };
  49685. class ShapefileLoader{
  49686. constructor(){
  49687. this.transform = null;
  49688. }
  49689. async load(path){
  49690. const matLine = new LineMaterial( {
  49691. color: 0xff0000,
  49692. lineWidth: 3, // in pixels
  49693. resolution: new Vector2$1(1000, 1000),
  49694. dashed: false
  49695. } );
  49696. const features = await this.loadShapefileFeatures(path);
  49697. const node = new Object3D();
  49698. for(const feature of features){
  49699. const fnode = this.featureToSceneNode(feature, matLine);
  49700. node.add(fnode);
  49701. }
  49702. let setResolution = (x, y) => {
  49703. matLine.resolution.set(x, y);
  49704. };
  49705. const result = {
  49706. features: features,
  49707. node: node,
  49708. setResolution: setResolution,
  49709. };
  49710. return result;
  49711. }
  49712. featureToSceneNode(feature, matLine){
  49713. let geometry = feature.geometry;
  49714. let color = new Color(1, 1, 1);
  49715. let transform = this.transform;
  49716. if(transform === null){
  49717. transform = {forward: (v) => v};
  49718. }
  49719. if(feature.geometry.type === "Point"){
  49720. let sg = new SphereGeometry(1, 18, 18);
  49721. let sm = new MeshNormalMaterial();
  49722. let s = new Mesh(sg, sm);
  49723. let [long, lat] = geometry.coordinates;
  49724. let pos = transform.forward([long, lat]);
  49725. s.position.set(...pos, 20);
  49726. s.scale.set(10, 10, 10);
  49727. return s;
  49728. }else if(geometry.type === "LineString"){
  49729. let coordinates = [];
  49730. let min = new Vector3(Infinity, Infinity, Infinity);
  49731. for(let i = 0; i < geometry.coordinates.length; i++){
  49732. let [long, lat] = geometry.coordinates[i];
  49733. let pos = transform.forward([long, lat]);
  49734. min.x = Math.min(min.x, pos[0]);
  49735. min.y = Math.min(min.y, pos[1]);
  49736. min.z = Math.min(min.z, 20);
  49737. coordinates.push(...pos, 20);
  49738. if(i > 0 && i < geometry.coordinates.length - 1){
  49739. coordinates.push(...pos, 20);
  49740. }
  49741. }
  49742. for(let i = 0; i < coordinates.length; i += 3){
  49743. coordinates[i+0] -= min.x;
  49744. coordinates[i+1] -= min.y;
  49745. coordinates[i+2] -= min.z;
  49746. }
  49747. const lineGeometry = new LineGeometry();
  49748. lineGeometry.setPositions( coordinates );
  49749. const line = new Line2( lineGeometry, matLine );
  49750. line.computeLineDistances();
  49751. line.scale.set( 1, 1, 1 );
  49752. line.position.copy(min);
  49753. return line;
  49754. }else if(geometry.type === "Polygon"){
  49755. for(let pc of geometry.coordinates){
  49756. let coordinates = [];
  49757. let min = new Vector3(Infinity, Infinity, Infinity);
  49758. for(let i = 0; i < pc.length; i++){
  49759. let [long, lat] = pc[i];
  49760. let pos = transform.forward([long, lat]);
  49761. min.x = Math.min(min.x, pos[0]);
  49762. min.y = Math.min(min.y, pos[1]);
  49763. min.z = Math.min(min.z, 20);
  49764. coordinates.push(...pos, 20);
  49765. if(i > 0 && i < pc.length - 1){
  49766. coordinates.push(...pos, 20);
  49767. }
  49768. }
  49769. for(let i = 0; i < coordinates.length; i += 3){
  49770. coordinates[i+0] -= min.x;
  49771. coordinates[i+1] -= min.y;
  49772. coordinates[i+2] -= min.z;
  49773. }
  49774. const lineGeometry = new LineGeometry();
  49775. lineGeometry.setPositions( coordinates );
  49776. const line = new Line2( lineGeometry, matLine );
  49777. line.computeLineDistances();
  49778. line.scale.set( 1, 1, 1 );
  49779. line.position.copy(min);
  49780. return line;
  49781. }
  49782. }else {
  49783. console.log("unhandled feature: ", feature);
  49784. }
  49785. }
  49786. async loadShapefileFeatures(file){
  49787. let features = [];
  49788. let source = await shapefile.open(file);
  49789. while(true){
  49790. let result = await source.read();
  49791. if (result.done) {
  49792. break;
  49793. }
  49794. if (result.value && result.value.type === 'Feature' && result.value.geometry !== undefined) {
  49795. features.push(result.value);
  49796. }
  49797. }
  49798. return features;
  49799. }
  49800. };
  49801. const defaultColors = {
  49802. "landuse": [0.5, 0.5, 0.5],
  49803. "natural": [0.0, 1.0, 0.0],
  49804. "places": [1.0, 0.0, 1.0],
  49805. "points": [0.0, 1.0, 1.0],
  49806. "roads": [1.0, 1.0, 0.0],
  49807. "waterways": [0.0, 0.0, 1.0],
  49808. "default": [0.9, 0.6, 0.1],
  49809. };
  49810. function getColor(feature){
  49811. let color = defaultColors[feature];
  49812. if(!color){
  49813. color = defaultColors["default"];
  49814. }
  49815. return color;
  49816. }
  49817. class Geopackage$1{
  49818. constructor(){
  49819. this.path = null;
  49820. this.node = null;
  49821. }
  49822. };
  49823. class GeoPackageLoader{
  49824. constructor(){
  49825. }
  49826. static async loadUrl(url, params){
  49827. await Promise.all([
  49828. Utils.loadScript(`${Potree.scriptPath}/lazylibs/geopackage/geopackage.js`),
  49829. Utils.loadScript(`${Potree.scriptPath}/lazylibs/sql.js/sql-wasm.js`),
  49830. ]);
  49831. const result = await fetch(url);
  49832. const buffer = await result.arrayBuffer();
  49833. params = params || {};
  49834. params.source = url;
  49835. return GeoPackageLoader.loadBuffer(buffer, params);
  49836. }
  49837. static async loadBuffer(buffer, params){
  49838. await Promise.all([
  49839. Utils.loadScript(`${Potree.scriptPath}/lazylibs/geopackage/geopackage.js`),
  49840. Utils.loadScript(`${Potree.scriptPath}/lazylibs/sql.js/sql-wasm.js`),
  49841. ]);
  49842. params = params || {};
  49843. const resolver = async (resolve) => {
  49844. let transform = params.transform;
  49845. if(!transform){
  49846. transform = {forward: (arg) => arg};
  49847. }
  49848. const wasmPath = `${Potree.scriptPath}/lazylibs/sql.js/sql-wasm.wasm`;
  49849. const SQL = await initSqlJs({ locateFile: filename => wasmPath});
  49850. const u8 = new Uint8Array(buffer);
  49851. const data = await geopackage.open(u8);
  49852. window.data = data;
  49853. const geopackageNode = new Object3D();
  49854. geopackageNode.name = params.source;
  49855. geopackageNode.potree = {
  49856. source: params.source,
  49857. };
  49858. const geo = new Geopackage$1();
  49859. geo.path = params.source;
  49860. geo.node = geopackageNode;
  49861. const tables = data.getTables();
  49862. for(const table of tables.features){
  49863. const dao = data.getFeatureDao(table);
  49864. let boundingBox = dao.getBoundingBox();
  49865. boundingBox = boundingBox.projectBoundingBox(dao.projection, 'EPSG:4326');
  49866. const geoJson = data.queryForGeoJSONFeaturesInTable(table, boundingBox);
  49867. const matLine = new LineMaterial( {
  49868. color: new Color().setRGB(...getColor(table)),
  49869. lineWidth: 2,
  49870. resolution: new Vector2$1(1000, 1000),
  49871. dashed: false
  49872. } );
  49873. const node = new Object3D();
  49874. node.name = table;
  49875. geo.node.add(node);
  49876. for(const [index, feature] of Object.entries(geoJson)){
  49877. //const featureNode = GeoPackageLoader.featureToSceneNode(feature, matLine, transform);
  49878. const featureNode = GeoPackageLoader.featureToSceneNode(feature, matLine, dao.projection, transform);
  49879. node.add(featureNode);
  49880. }
  49881. }
  49882. resolve(geo);
  49883. };
  49884. return new Promise(resolver);
  49885. }
  49886. static featureToSceneNode(feature, matLine, geopackageProjection, transform){
  49887. let geometry = feature.geometry;
  49888. let color = new Color(1, 1, 1);
  49889. if(feature.geometry.type === "Point"){
  49890. let sg = new SphereGeometry(1, 18, 18);
  49891. let sm = new MeshNormalMaterial();
  49892. let s = new Mesh(sg, sm);
  49893. let [long, lat] = geometry.coordinates;
  49894. let pos = transform.forward(geopackageProjection.forward([long, lat]));
  49895. s.position.set(...pos, 20);
  49896. s.scale.set(10, 10, 10);
  49897. return s;
  49898. }else if(geometry.type === "LineString"){
  49899. let coordinates = [];
  49900. let min = new Vector3(Infinity, Infinity, Infinity);
  49901. for(let i = 0; i < geometry.coordinates.length; i++){
  49902. let [long, lat] = geometry.coordinates[i];
  49903. let pos = transform.forward(geopackageProjection.forward([long, lat]));
  49904. min.x = Math.min(min.x, pos[0]);
  49905. min.y = Math.min(min.y, pos[1]);
  49906. min.z = Math.min(min.z, 20);
  49907. coordinates.push(...pos, 20);
  49908. if(i > 0 && i < geometry.coordinates.length - 1){
  49909. coordinates.push(...pos, 20);
  49910. }
  49911. }
  49912. for(let i = 0; i < coordinates.length; i += 3){
  49913. coordinates[i+0] -= min.x;
  49914. coordinates[i+1] -= min.y;
  49915. coordinates[i+2] -= min.z;
  49916. }
  49917. const lineGeometry = new LineGeometry();
  49918. lineGeometry.setPositions( coordinates );
  49919. const line = new Line2( lineGeometry, matLine );
  49920. line.computeLineDistances();
  49921. line.scale.set( 1, 1, 1 );
  49922. line.position.copy(min);
  49923. return line;
  49924. }else if(geometry.type === "Polygon"){
  49925. for(let pc of geometry.coordinates){
  49926. let coordinates = [];
  49927. let min = new Vector3(Infinity, Infinity, Infinity);
  49928. for(let i = 0; i < pc.length; i++){
  49929. let [long, lat] = pc[i];
  49930. let pos = transform.forward(geopackageProjection.forward([long, lat]));
  49931. min.x = Math.min(min.x, pos[0]);
  49932. min.y = Math.min(min.y, pos[1]);
  49933. min.z = Math.min(min.z, 20);
  49934. coordinates.push(...pos, 20);
  49935. if(i > 0 && i < pc.length - 1){
  49936. coordinates.push(...pos, 20);
  49937. }
  49938. }
  49939. for(let i = 0; i < coordinates.length; i += 3){
  49940. coordinates[i+0] -= min.x;
  49941. coordinates[i+1] -= min.y;
  49942. coordinates[i+2] -= min.z;
  49943. }
  49944. const lineGeometry = new LineGeometry();
  49945. lineGeometry.setPositions( coordinates );
  49946. const line = new Line2( lineGeometry, matLine );
  49947. line.computeLineDistances();
  49948. line.scale.set( 1, 1, 1 );
  49949. line.position.copy(min);
  49950. return line;
  49951. }
  49952. }else {
  49953. console.log("unhandled feature: ", feature);
  49954. }
  49955. }
  49956. };
  49957. class ClipVolume extends Object3D{
  49958. constructor(args={}){
  49959. super();
  49960. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  49961. this.name = "clip_volume_" + this.constructor.counter;
  49962. let alpha = args.alpha || 0;
  49963. let beta = args.beta || 0;
  49964. let gamma = args.gamma || 0;
  49965. this.rotation.x = alpha;
  49966. this.rotation.y = beta;
  49967. this.rotation.z = gamma;
  49968. this.clipOffset = 0.001;
  49969. this.clipRotOffset = 1;
  49970. let boxGeometry = new BoxGeometry(1, 1, 1);
  49971. boxGeometry.computeBoundingBox();
  49972. let boxFrameGeometry = new Geometry();
  49973. {
  49974. // bottom
  49975. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.5));
  49976. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.5));
  49977. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.5));
  49978. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, -0.5));
  49979. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, -0.5));
  49980. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, -0.5));
  49981. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, -0.5));
  49982. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.5));
  49983. // top
  49984. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.5));
  49985. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.5));
  49986. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.5));
  49987. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, -0.5));
  49988. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, -0.5));
  49989. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, -0.5));
  49990. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, -0.5));
  49991. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.5));
  49992. // sides
  49993. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.5));
  49994. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.5));
  49995. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.5));
  49996. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.5));
  49997. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, -0.5));
  49998. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, -0.5));
  49999. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, -0.5));
  50000. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, -0.5));
  50001. boxFrameGeometry.colors.push(new Vector3(1, 1, 1));
  50002. }
  50003. let planeFrameGeometry = new Geometry();
  50004. {
  50005. // middle line
  50006. planeFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.0));
  50007. planeFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.0));
  50008. planeFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.0));
  50009. planeFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.0));
  50010. planeFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.0));
  50011. planeFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.0));
  50012. planeFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.0));
  50013. planeFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.0));
  50014. }
  50015. this.dimension = new Vector3(1, 1, 1);
  50016. this.material = new MeshBasicMaterial( {
  50017. color: 0x00ff00,
  50018. transparent: true,
  50019. opacity: 0.3,
  50020. depthTest: true,
  50021. depthWrite: false} );
  50022. this.box = new Mesh(boxGeometry, this.material);
  50023. this.box.geometry.computeBoundingBox();
  50024. this.boundingBox = this.box.geometry.boundingBox;
  50025. this.add(this.box);
  50026. this.frame = new LineSegments( boxFrameGeometry, new LineBasicMaterial({color: 0x000000}));
  50027. this.add(this.frame);
  50028. this.planeFrame = new LineSegments( planeFrameGeometry, new LineBasicMaterial({color: 0xff0000}));
  50029. this.add(this.planeFrame);
  50030. // set default thickness
  50031. this.setScaleZ(0.1);
  50032. // create local coordinate system
  50033. let createArrow = (name, direction, color) => {
  50034. let material = new MeshBasicMaterial({
  50035. color: color,
  50036. depthTest: false,
  50037. depthWrite: false});
  50038. let shaftGeometry = new Geometry();
  50039. shaftGeometry.vertices.push(new Vector3(0, 0, 0));
  50040. shaftGeometry.vertices.push(new Vector3(0, 1, 0));
  50041. let shaftMaterial = new LineBasicMaterial({
  50042. color: color,
  50043. depthTest: false,
  50044. depthWrite: false,
  50045. transparent: true
  50046. });
  50047. let shaft = new Line(shaftGeometry, shaftMaterial);
  50048. shaft.name = name + "_shaft";
  50049. let headGeometry = new CylinderGeometry(0, 0.04, 0.1, 10, 1, false);
  50050. let headMaterial = material;
  50051. let head = new Mesh(headGeometry, headMaterial);
  50052. head.name = name + "_head";
  50053. head.position.y = 1;
  50054. let arrow = new Object3D();
  50055. arrow.name = name;
  50056. arrow.add(shaft);
  50057. arrow.add(head);
  50058. return arrow;
  50059. };
  50060. this.arrowX = createArrow("arrow_x", new Vector3(1, 0, 0), 0xFF0000);
  50061. this.arrowY = createArrow("arrow_y", new Vector3(0, 1, 0), 0x00FF00);
  50062. this.arrowZ = createArrow("arrow_z", new Vector3(0, 0, 1), 0x0000FF);
  50063. this.arrowX.rotation.z = -Math.PI / 2;
  50064. this.arrowZ.rotation.x = Math.PI / 2;
  50065. this.arrowX.visible = false;
  50066. this.arrowY.visible = false;
  50067. this.arrowZ.visible = false;
  50068. this.add(this.arrowX);
  50069. this.add(this.arrowY);
  50070. this.add(this.arrowZ);
  50071. { // event listeners
  50072. this.addEventListener("ui_select", e => {
  50073. this.arrowX.visible = true;
  50074. this.arrowY.visible = true;
  50075. this.arrowZ.visible = true;
  50076. });
  50077. this.addEventListener("ui_deselect", e => {
  50078. this.arrowX.visible = false;
  50079. this.arrowY.visible = false;
  50080. this.arrowZ.visible = false;
  50081. });
  50082. this.addEventListener("select", e => {
  50083. let scene_header = $("#" + this.name + " .scene_header");
  50084. if(!scene_header.next().is(":visible")) {
  50085. scene_header.click();
  50086. }
  50087. });
  50088. this.addEventListener("deselect", e => {
  50089. let scene_header = $("#" + this.name + " .scene_header");
  50090. if(scene_header.next().is(":visible")) {
  50091. scene_header.click();
  50092. }
  50093. });
  50094. }
  50095. this.update();
  50096. };
  50097. setClipOffset(offset) {
  50098. this.clipOffset = offset;
  50099. }
  50100. setClipRotOffset(offset) {
  50101. this.clipRotOffset = offset;
  50102. }
  50103. setScaleX(x) {
  50104. this.box.scale.x = x;
  50105. this.frame.scale.x = x;
  50106. this.planeFrame.scale.x = x;
  50107. }
  50108. setScaleY(y) {
  50109. this.box.scale.y = y;
  50110. this.frame.scale.y = y;
  50111. this.planeFrame.scale.y = y;
  50112. }
  50113. setScaleZ(z) {
  50114. this.box.scale.z = z;
  50115. this.frame.scale.z = z;
  50116. this.planeFrame.scale.z = z;
  50117. }
  50118. offset(args) {
  50119. let cs = args.cs || null;
  50120. let axis = args.axis || null;
  50121. let dir = args.dir || null;
  50122. if(!cs || !axis || !dir) return;
  50123. if(axis === "x") {
  50124. if(cs === "local") {
  50125. this.position.add(this.localX.clone().multiplyScalar(dir * this.clipOffset));
  50126. } else if(cs === "global") {
  50127. this.position.x = this.position.x + dir * this.clipOffset;
  50128. }
  50129. }else if(axis === "y") {
  50130. if(cs === "local") {
  50131. this.position.add(this.localY.clone().multiplyScalar(dir * this.clipOffset));
  50132. } else if(cs === "global") {
  50133. this.position.y = this.position.y + dir * this.clipOffset;
  50134. }
  50135. }else if(axis === "z") {
  50136. if(cs === "local") {
  50137. this.position.add(this.localZ.clone().multiplyScalar(dir * this.clipOffset));
  50138. } else if(cs === "global") {
  50139. this.position.z = this.position.z + dir * this.clipOffset;
  50140. }
  50141. }
  50142. this.dispatchEvent({"type": "clip_volume_changed", "viewer": viewer, "volume": this});
  50143. }
  50144. rotate(args) {
  50145. let cs = args.cs || null;
  50146. let axis = args.axis || null;
  50147. let dir = args.dir || null;
  50148. if(!cs || !axis || !dir) return;
  50149. if(cs === "local") {
  50150. if(axis === "x") {
  50151. this.rotateOnAxis(new Vector3(1, 0, 0), dir * this.clipRotOffset * Math.PI / 180);
  50152. } else if(axis === "y") {
  50153. this.rotateOnAxis(new Vector3(0, 1, 0), dir * this.clipRotOffset * Math.PI / 180);
  50154. } else if(axis === "z") {
  50155. this.rotateOnAxis(new Vector3(0, 0, 1), dir * this.clipRotOffset * Math.PI / 180);
  50156. }
  50157. } else if(cs === "global") {
  50158. let rotaxis = new Vector4(1, 0, 0, 0);
  50159. if(axis === "y") {
  50160. rotaxis = new Vector4(0, 1, 0, 0);
  50161. } else if(axis === "z") {
  50162. rotaxis = new Vector4(0, 0, 1, 0);
  50163. }
  50164. this.updateMatrixWorld();
  50165. let invM = newthis.matrixWorld.clone().invert();
  50166. rotaxis = rotaxis.applyMatrix4(invM).normalize();
  50167. rotaxis = new Vector3(rotaxis.x, rotaxis.y, rotaxis.z);
  50168. this.rotateOnAxis(rotaxis, dir * this.clipRotOffset * Math.PI / 180);
  50169. }
  50170. this.updateLocalSystem();
  50171. this.dispatchEvent({"type": "clip_volume_changed", "viewer": viewer, "volume": this});
  50172. }
  50173. update(){
  50174. this.boundingBox = this.box.geometry.boundingBox;
  50175. this.boundingSphere = this.boundingBox.getBoundingSphere(new Sphere());
  50176. this.box.visible = false;
  50177. this.updateLocalSystem();
  50178. };
  50179. updateLocalSystem() {
  50180. // extract local coordinate axes
  50181. let rotQuat = this.getWorldQuaternion();
  50182. this.localX = new Vector3(1, 0, 0).applyQuaternion(rotQuat).normalize();
  50183. this.localY = new Vector3(0, 1, 0).applyQuaternion(rotQuat).normalize();
  50184. this.localZ = new Vector3(0, 0, 1).applyQuaternion(rotQuat).normalize();
  50185. }
  50186. raycast(raycaster, intersects){
  50187. let is = [];
  50188. this.box.raycast(raycaster, is);
  50189. if(is.length > 0){
  50190. let I = is[0];
  50191. intersects.push({
  50192. distance: I.distance,
  50193. object: this,
  50194. point: I.point.clone()
  50195. });
  50196. }
  50197. };
  50198. };
  50199. class ClippingTool extends EventDispatcher{
  50200. constructor(viewer){
  50201. super();
  50202. this.viewer = viewer;
  50203. this.maxPolygonVertices = 8;
  50204. this.addEventListener("start_inserting_clipping_volume", e => {
  50205. this.viewer.dispatchEvent({
  50206. type: "cancel_insertions"
  50207. });
  50208. });
  50209. this.sceneMarker = new Scene();
  50210. this.sceneVolume = new Scene();
  50211. this.sceneVolume.name = "scene_clip_volume";
  50212. this.viewer.inputHandler.registerInteractiveScene(this.sceneVolume);
  50213. this.onRemove = e => {
  50214. this.sceneVolume.remove(e.volume);
  50215. };
  50216. this.onAdd = e => {
  50217. this.sceneVolume.add(e.volume);
  50218. };
  50219. this.viewer.inputHandler.addEventListener("delete", e => {
  50220. let volumes = e.selection.filter(e => (e instanceof ClipVolume));
  50221. volumes.forEach(e => this.viewer.scene.removeClipVolume(e));
  50222. let polyVolumes = e.selection.filter(e => (e instanceof PolygonClipVolume));
  50223. polyVolumes.forEach(e => this.viewer.scene.removePolygonClipVolume(e));
  50224. });
  50225. //----
  50226. /* var a = new ClipVolume()
  50227. viewer.scene.addVolume(a);
  50228. viewer.setObjectLayers(a, 'volume' ) */
  50229. }
  50230. setScene(scene){
  50231. if(this.scene === scene){
  50232. return;
  50233. }
  50234. if(this.scene){
  50235. this.scene.removeEventListeners("clip_volume_added", this.onAdd);
  50236. this.scene.removeEventListeners("clip_volume_removed", this.onRemove);
  50237. this.scene.removeEventListeners("polygon_clip_volume_added", this.onAdd);
  50238. this.scene.removeEventListeners("polygon_clip_volume_removed", this.onRemove);
  50239. }
  50240. this.scene = scene;
  50241. this.scene.addEventListener("clip_volume_added", this.onAdd);
  50242. this.scene.addEventListener("clip_volume_removed", this.onRemove);
  50243. this.scene.addEventListener("polygon_clip_volume_added", this.onAdd);
  50244. this.scene.addEventListener("polygon_clip_volume_removed", this.onRemove);
  50245. }
  50246. startInsertion(args = {}) {
  50247. let type = args.type || null;
  50248. if(!type) return null;
  50249. let domElement = this.viewer.renderer.domElement;
  50250. let canvasSize = this.viewer.renderer.getSize(new Vector2$1());
  50251. let svg = $(`
  50252. <svg height="${canvasSize.height}" width="${canvasSize.width}" style="position:absolute; pointer-events: none">
  50253. <defs>
  50254. <marker id="diamond" markerWidth="24" markerHeight="24" refX="12" refY="12"
  50255. markerUnits="userSpaceOnUse">
  50256. <circle cx="12" cy="12" r="6" fill="white" stroke="black" stroke-width="3"/>
  50257. </marker>
  50258. </defs>
  50259. <polyline fill="none" stroke="black"
  50260. style="stroke:rgb(0, 0, 0);
  50261. stroke-width:6;"
  50262. stroke-dasharray="9, 6"
  50263. stroke-dashoffset="2"
  50264. />
  50265. <polyline fill="none" stroke="black"
  50266. style="stroke:rgb(255, 255, 255);
  50267. stroke-width:2;"
  50268. stroke-dasharray="5, 10"
  50269. marker-start="url(#diamond)"
  50270. marker-mid="url(#diamond)"
  50271. marker-end="url(#diamond)"
  50272. />
  50273. </svg>`);
  50274. $(domElement.parentElement).append(svg);
  50275. let polyClipVol = new PolygonClipVolume(this.viewer.scene.getActiveCamera().clone());
  50276. this.dispatchEvent({"type": "start_inserting_clipping_volume"});
  50277. this.viewer.scene.addPolygonClipVolume(polyClipVol);
  50278. this.sceneMarker.add(polyClipVol);
  50279. let cancel = {
  50280. callback: null
  50281. };
  50282. let insertionCallback = (e) => {
  50283. if(e.button === MOUSE.LEFT){
  50284. polyClipVol.addMarker();
  50285. // SVC Screen Line
  50286. svg.find("polyline").each((index, target) => {
  50287. let newPoint = svg[0].createSVGPoint();
  50288. newPoint.x = e.offsetX;
  50289. newPoint.y = e.offsetY;
  50290. let polyline = target.points.appendItem(newPoint);
  50291. });
  50292. if(polyClipVol.markers.length > this.maxPolygonVertices){
  50293. cancel.callback();
  50294. }
  50295. this.viewer.inputHandler.startDragging(
  50296. polyClipVol.markers[polyClipVol.markers.length - 1]);
  50297. }else if(e.button === MOUSE.RIGHT){
  50298. cancel.callback(e);
  50299. }
  50300. };
  50301. cancel.callback = e => {
  50302. //let first = svg.find("polyline")[0].points[0];
  50303. //svg.find("polyline").each((index, target) => {
  50304. // let newPoint = svg[0].createSVGPoint();
  50305. // newPoint.x = first.x;
  50306. // newPoint.y = first.y;
  50307. // let polyline = target.points.appendItem(newPoint);
  50308. //});
  50309. svg.remove();
  50310. if(polyClipVol.markers.length > 3) {
  50311. polyClipVol.removeLastMarker();
  50312. polyClipVol.initialized = true;
  50313. } else {
  50314. this.viewer.scene.removePolygonClipVolume(polyClipVol);
  50315. }
  50316. this.viewer.renderer.domElement.removeEventListener("mouseup", insertionCallback, true);
  50317. this.viewer.removeEventListener("cancel_insertions", cancel.callback);
  50318. this.viewer.inputHandler.enabled = true;
  50319. };
  50320. this.viewer.addEventListener("cancel_insertions", cancel.callback);
  50321. this.viewer.renderer.domElement.addEventListener("mouseup", insertionCallback , true);
  50322. this.viewer.inputHandler.enabled = false;
  50323. polyClipVol.addMarker();
  50324. this.viewer.inputHandler.startDragging(
  50325. polyClipVol.markers[polyClipVol.markers.length - 1]);
  50326. return polyClipVol;
  50327. }
  50328. update() {
  50329. }
  50330. };
  50331. var GeoTIFF = (function (exports) {
  50332. 'use strict';
  50333. const Endianness = new Enum({
  50334. LITTLE: "II",
  50335. BIG: "MM",
  50336. });
  50337. const Type = new Enum({
  50338. BYTE: {value: 1, bytes: 1},
  50339. ASCII: {value: 2, bytes: 1},
  50340. SHORT: {value: 3, bytes: 2},
  50341. LONG: {value: 4, bytes: 4},
  50342. RATIONAL: {value: 5, bytes: 8},
  50343. SBYTE: {value: 6, bytes: 1},
  50344. UNDEFINED: {value: 7, bytes: 1},
  50345. SSHORT: {value: 8, bytes: 2},
  50346. SLONG: {value: 9, bytes: 4},
  50347. SRATIONAL: {value: 10, bytes: 8},
  50348. FLOAT: {value: 11, bytes: 4},
  50349. DOUBLE: {value: 12, bytes: 8},
  50350. });
  50351. const Tag = new Enum({
  50352. IMAGE_WIDTH: 256,
  50353. IMAGE_HEIGHT: 257,
  50354. BITS_PER_SAMPLE: 258,
  50355. COMPRESSION: 259,
  50356. PHOTOMETRIC_INTERPRETATION: 262,
  50357. STRIP_OFFSETS: 273,
  50358. ORIENTATION: 274,
  50359. SAMPLES_PER_PIXEL: 277,
  50360. ROWS_PER_STRIP: 278,
  50361. STRIP_BYTE_COUNTS: 279,
  50362. X_RESOLUTION: 282,
  50363. Y_RESOLUTION: 283,
  50364. PLANAR_CONFIGURATION: 284,
  50365. RESOLUTION_UNIT: 296,
  50366. SOFTWARE: 305,
  50367. COLOR_MAP: 320,
  50368. SAMPLE_FORMAT: 339,
  50369. MODEL_PIXEL_SCALE: 33550, // [GeoTIFF] TYPE: double N: 3
  50370. MODEL_TIEPOINT: 33922, // [GeoTIFF] TYPE: double N: 6 * NUM_TIEPOINTS
  50371. GEO_KEY_DIRECTORY: 34735, // [GeoTIFF] TYPE: short N: >= 4
  50372. GEO_DOUBLE_PARAMS: 34736, // [GeoTIFF] TYPE: short N: variable
  50373. GEO_ASCII_PARAMS: 34737, // [GeoTIFF] TYPE: ascii N: variable
  50374. });
  50375. const typeMapping = new Map([
  50376. [Type.BYTE, Uint8Array],
  50377. [Type.ASCII, Uint8Array],
  50378. [Type.SHORT, Uint16Array],
  50379. [Type.LONG, Uint32Array],
  50380. [Type.RATIONAL, Uint32Array],
  50381. [Type.SBYTE, Int8Array],
  50382. [Type.UNDEFINED, Uint8Array],
  50383. [Type.SSHORT, Int16Array],
  50384. [Type.SLONG, Int32Array],
  50385. [Type.SRATIONAL, Int32Array],
  50386. [Type.FLOAT, Float32Array],
  50387. [Type.DOUBLE, Float64Array],
  50388. ]);
  50389. class IFDEntry{
  50390. constructor(tag, type, count, offset, value){
  50391. this.tag = tag;
  50392. this.type = type;
  50393. this.count = count;
  50394. this.offset = offset;
  50395. this.value = value;
  50396. }
  50397. }
  50398. class Image{
  50399. constructor(){
  50400. this.width = 0;
  50401. this.height = 0;
  50402. this.buffer = null;
  50403. this.metadata = [];
  50404. }
  50405. }
  50406. class Reader{
  50407. constructor(){
  50408. }
  50409. static read(data){
  50410. let endiannessTag = String.fromCharCode(...Array.from(data.slice(0, 2)));
  50411. let endianness = Endianness.fromValue(endiannessTag);
  50412. let tiffCheckTag = data.readUInt8(2);
  50413. if(tiffCheckTag !== 42){
  50414. throw new Error("not a valid tiff file");
  50415. }
  50416. let offsetToFirstIFD = data.readUInt32LE(4);
  50417. console.log("offsetToFirstIFD", offsetToFirstIFD);
  50418. let ifds = [];
  50419. let IFDsRead = false;
  50420. let currentIFDOffset = offsetToFirstIFD;
  50421. let i = 0;
  50422. while(IFDsRead || i < 100){
  50423. console.log("currentIFDOffset", currentIFDOffset);
  50424. let numEntries = data.readUInt16LE(currentIFDOffset);
  50425. let nextIFDOffset = data.readUInt32LE(currentIFDOffset + 2 + numEntries * 12);
  50426. console.log("next offset: ", currentIFDOffset + 2 + numEntries * 12);
  50427. let entryBuffer = data.slice(currentIFDOffset + 2, currentIFDOffset + 2 + 12 * numEntries);
  50428. for(let i = 0; i < numEntries; i++){
  50429. let tag = Tag.fromValue(entryBuffer.readUInt16LE(i * 12));
  50430. let type = Type.fromValue(entryBuffer.readUInt16LE(i * 12 + 2));
  50431. let count = entryBuffer.readUInt32LE(i * 12 + 4);
  50432. let offsetOrValue = entryBuffer.readUInt32LE(i * 12 + 8);
  50433. let valueBytes = type.bytes * count;
  50434. let value;
  50435. if(valueBytes <= 4){
  50436. value = offsetOrValue;
  50437. }else {
  50438. let valueBuffer = new Uint8Array(valueBytes);
  50439. valueBuffer.set(data.slice(offsetOrValue, offsetOrValue + valueBytes));
  50440. let ArrayType = typeMapping.get(type);
  50441. value = new ArrayType(valueBuffer.buffer);
  50442. if(type === Type.ASCII){
  50443. value = String.fromCharCode(...value);
  50444. }
  50445. }
  50446. let ifd = new IFDEntry(tag, type, count, offsetOrValue, value);
  50447. ifds.push(ifd);
  50448. }
  50449. console.log("nextIFDOffset", nextIFDOffset);
  50450. if(nextIFDOffset === 0){
  50451. break;
  50452. }
  50453. currentIFDOffset = nextIFDOffset;
  50454. i++;
  50455. }
  50456. let ifdForTag = (tag) => {
  50457. for(let entry of ifds){
  50458. if(entry.tag === tag){
  50459. return entry;
  50460. }
  50461. }
  50462. return null;
  50463. };
  50464. let width = ifdForTag(Tag.IMAGE_WIDTH, ifds).value;
  50465. let height = ifdForTag(Tag.IMAGE_HEIGHT, ifds).value;
  50466. let compression = ifdForTag(Tag.COMPRESSION, ifds).value;
  50467. let rowsPerStrip = ifdForTag(Tag.ROWS_PER_STRIP, ifds).value;
  50468. let ifdStripOffsets = ifdForTag(Tag.STRIP_OFFSETS, ifds);
  50469. let ifdStripByteCounts = ifdForTag(Tag.STRIP_BYTE_COUNTS, ifds);
  50470. let numStrips = Math.ceil(height / rowsPerStrip);
  50471. let stripByteCounts = [];
  50472. for(let i = 0; i < ifdStripByteCounts.count; i++){
  50473. let type = ifdStripByteCounts.type;
  50474. let offset = ifdStripByteCounts.offset + i * type.bytes;
  50475. let value;
  50476. if(type === Type.SHORT){
  50477. value = data.readUInt16LE(offset);
  50478. }else if(type === Type.LONG){
  50479. value = data.readUInt32LE(offset);
  50480. }
  50481. stripByteCounts.push(value);
  50482. }
  50483. let stripOffsets = [];
  50484. for(let i = 0; i < ifdStripOffsets.count; i++){
  50485. let type = ifdStripOffsets.type;
  50486. let offset = ifdStripOffsets.offset + i * type.bytes;
  50487. let value;
  50488. if(type === Type.SHORT){
  50489. value = data.readUInt16LE(offset);
  50490. }else if(type === Type.LONG){
  50491. value = data.readUInt32LE(offset);
  50492. }
  50493. stripOffsets.push(value);
  50494. }
  50495. let imageBuffer = new Uint8Array(width * height * 3);
  50496. let linesProcessed = 0;
  50497. for(let i = 0; i < numStrips; i++){
  50498. let stripOffset = stripOffsets[i];
  50499. let stripBytes = stripByteCounts[i];
  50500. let stripData = data.slice(stripOffset, stripOffset + stripBytes);
  50501. let lineBytes = width * 3;
  50502. for(let y = 0; y < rowsPerStrip; y++){
  50503. let line = stripData.slice(y * lineBytes, y * lineBytes + lineBytes);
  50504. imageBuffer.set(line, linesProcessed * lineBytes);
  50505. if(line.length === lineBytes){
  50506. linesProcessed++;
  50507. }else {
  50508. break;
  50509. }
  50510. }
  50511. }
  50512. console.log(`width: ${width}`);
  50513. console.log(`height: ${height}`);
  50514. console.log(`numStrips: ${numStrips}`);
  50515. console.log("stripByteCounts", stripByteCounts.join(", "));
  50516. console.log("stripOffsets", stripOffsets.join(", "));
  50517. let image = new Image();
  50518. image.width = width;
  50519. image.height = height;
  50520. image.buffer = imageBuffer;
  50521. image.metadata = ifds;
  50522. return image;
  50523. }
  50524. }
  50525. class Exporter{
  50526. constructor(){
  50527. }
  50528. static toTiffBuffer(image, params = {}){
  50529. let offsetToFirstIFD = 8;
  50530. let headerBuffer = new Uint8Array([0x49, 0x49, 42, 0, offsetToFirstIFD, 0, 0, 0]);
  50531. let [width, height] = [image.width, image.height];
  50532. let ifds = [
  50533. new IFDEntry(Tag.IMAGE_WIDTH, Type.SHORT, 1, null, width),
  50534. new IFDEntry(Tag.IMAGE_HEIGHT, Type.SHORT, 1, null, height),
  50535. new IFDEntry(Tag.BITS_PER_SAMPLE, Type.SHORT, 4, null, new Uint16Array([8, 8, 8, 8])),
  50536. new IFDEntry(Tag.COMPRESSION, Type.SHORT, 1, null, 1),
  50537. new IFDEntry(Tag.PHOTOMETRIC_INTERPRETATION, Type.SHORT, 1, null, 2),
  50538. new IFDEntry(Tag.ORIENTATION, Type.SHORT, 1, null, 1),
  50539. new IFDEntry(Tag.SAMPLES_PER_PIXEL, Type.SHORT, 1, null, 4),
  50540. new IFDEntry(Tag.ROWS_PER_STRIP, Type.LONG, 1, null, height),
  50541. new IFDEntry(Tag.STRIP_BYTE_COUNTS, Type.LONG, 1, null, width * height * 3),
  50542. new IFDEntry(Tag.PLANAR_CONFIGURATION, Type.SHORT, 1, null, 1),
  50543. new IFDEntry(Tag.RESOLUTION_UNIT, Type.SHORT, 1, null, 1),
  50544. new IFDEntry(Tag.SOFTWARE, Type.ASCII, 6, null, "......"),
  50545. new IFDEntry(Tag.STRIP_OFFSETS, Type.LONG, 1, null, null),
  50546. new IFDEntry(Tag.X_RESOLUTION, Type.RATIONAL, 1, null, new Uint32Array([1, 1])),
  50547. new IFDEntry(Tag.Y_RESOLUTION, Type.RATIONAL, 1, null, new Uint32Array([1, 1])),
  50548. ];
  50549. if(params.ifdEntries){
  50550. ifds.push(...params.ifdEntries);
  50551. }
  50552. let valueOffset = offsetToFirstIFD + 2 + ifds.length * 12 + 4;
  50553. // create 12 byte buffer for each ifd and variable length buffers for ifd values
  50554. let ifdEntryBuffers = new Map();
  50555. let ifdValueBuffers = new Map();
  50556. for(let ifd of ifds){
  50557. let entryBuffer = new ArrayBuffer(12);
  50558. let entryView = new DataView(entryBuffer);
  50559. let valueBytes = ifd.type.bytes * ifd.count;
  50560. entryView.setUint16(0, ifd.tag.value, true);
  50561. entryView.setUint16(2, ifd.type.value, true);
  50562. entryView.setUint32(4, ifd.count, true);
  50563. if(ifd.count === 1 && ifd.type.bytes <= 4){
  50564. entryView.setUint32(8, ifd.value, true);
  50565. }else {
  50566. entryView.setUint32(8, valueOffset, true);
  50567. let valueBuffer = new Uint8Array(ifd.count * ifd.type.bytes);
  50568. if(ifd.type === Type.ASCII){
  50569. valueBuffer.set(new Uint8Array(ifd.value.split("").map(c => c.charCodeAt(0))));
  50570. }else {
  50571. valueBuffer.set(new Uint8Array(ifd.value.buffer));
  50572. }
  50573. ifdValueBuffers.set(ifd.tag, valueBuffer);
  50574. valueOffset = valueOffset + valueBuffer.byteLength;
  50575. }
  50576. ifdEntryBuffers.set(ifd.tag, entryBuffer);
  50577. }
  50578. let imageBufferOffset = valueOffset;
  50579. new DataView(ifdEntryBuffers.get(Tag.STRIP_OFFSETS)).setUint32(8, imageBufferOffset, true);
  50580. let concatBuffers = (buffers) => {
  50581. let totalLength = buffers.reduce( (sum, buffer) => (sum + buffer.byteLength), 0);
  50582. let merged = new Uint8Array(totalLength);
  50583. let offset = 0;
  50584. for(let buffer of buffers){
  50585. merged.set(new Uint8Array(buffer), offset);
  50586. offset += buffer.byteLength;
  50587. }
  50588. return merged;
  50589. };
  50590. let ifdBuffer = concatBuffers([
  50591. new Uint16Array([ifds.length]),
  50592. ...ifdEntryBuffers.values(),
  50593. new Uint32Array([0])]);
  50594. let ifdValueBuffer = concatBuffers([...ifdValueBuffers.values()]);
  50595. let tiffBuffer = concatBuffers([
  50596. headerBuffer,
  50597. ifdBuffer,
  50598. ifdValueBuffer,
  50599. image.buffer
  50600. ]);
  50601. return {width: width, height: height, buffer: tiffBuffer};
  50602. }
  50603. }
  50604. exports.Tag = Tag;
  50605. exports.Type = Type;
  50606. exports.IFDEntry = IFDEntry;
  50607. exports.Image = Image;
  50608. exports.Reader = Reader;
  50609. exports.Exporter = Exporter;
  50610. return exports;
  50611. }({}));
  50612. function updateAzimuth(viewer, measure){
  50613. if(!measure.showAzimuth)return
  50614. const azimuth = measure.azimuth;
  50615. const isOkay = measure.points.length === 2;
  50616. azimuth.node.visible = isOkay;
  50617. if(!azimuth.node.visible){
  50618. return;
  50619. }
  50620. const camera = viewer.scene.getActiveCamera();
  50621. const renderAreaSize = viewer.renderer.getSize(new Vector2$1());
  50622. const width = renderAreaSize.width;
  50623. const height = renderAreaSize.height;
  50624. const [p0, p1] = measure.points;
  50625. const r = p0.position.distanceTo(p1.position);
  50626. const northVec = Utils.getNorthVec(p0.position, r, viewer.getProjection());
  50627. const northPos = p0.position.clone().add(northVec);
  50628. azimuth.center.position.copy(p0.position);
  50629. azimuth.center.scale.set(2, 2, 2);
  50630. azimuth.center.visible = false;
  50631. // azimuth.target.visible = false;
  50632. { // north
  50633. azimuth.north.position.copy(northPos);
  50634. azimuth.north.scale.set(2, 2, 2);
  50635. let distance = azimuth.north.position.distanceTo(camera.position);
  50636. let pr = Utils.projectedRadius(1, camera, distance, width, height);
  50637. let scale = (5 / pr);
  50638. azimuth.north.scale.set(scale, scale, scale);
  50639. }
  50640. { // target
  50641. azimuth.target.position.copy(p1.position);
  50642. azimuth.target.position.z = azimuth.north.position.z;
  50643. let distance = azimuth.target.position.distanceTo(camera.position);
  50644. let pr = Utils.projectedRadius(1, camera, distance, width, height);
  50645. let scale = (5 / pr);
  50646. azimuth.target.scale.set(scale, scale, scale);
  50647. }
  50648. azimuth.circle.position.copy(p0.position);
  50649. azimuth.circle.scale.set(r, r, r);
  50650. azimuth.circle.material.resolution.set(width, height);
  50651. // to target
  50652. azimuth.centerToTarget.geometry.setPositions([
  50653. 0, 0, 0,
  50654. ...p1.position.clone().sub(p0.position).toArray(),
  50655. ]);
  50656. azimuth.centerToTarget.position.copy(p0.position);
  50657. azimuth.centerToTarget.geometry.verticesNeedUpdate = true;
  50658. azimuth.centerToTarget.geometry.computeBoundingSphere();
  50659. azimuth.centerToTarget.computeLineDistances();
  50660. azimuth.centerToTarget.material.resolution.set(width, height);
  50661. // to target ground
  50662. azimuth.centerToTargetground.geometry.setPositions([
  50663. 0, 0, 0,
  50664. p1.position.x - p0.position.x,
  50665. p1.position.y - p0.position.y,
  50666. 0,
  50667. ]);
  50668. azimuth.centerToTargetground.position.copy(p0.position);
  50669. azimuth.centerToTargetground.geometry.verticesNeedUpdate = true;
  50670. azimuth.centerToTargetground.geometry.computeBoundingSphere();
  50671. azimuth.centerToTargetground.computeLineDistances();
  50672. azimuth.centerToTargetground.material.resolution.set(width, height);
  50673. // to north
  50674. azimuth.centerToNorth.geometry.setPositions([
  50675. 0, 0, 0,
  50676. northPos.x - p0.position.x,
  50677. northPos.y - p0.position.y,
  50678. 0,
  50679. ]);
  50680. azimuth.centerToNorth.position.copy(p0.position);
  50681. azimuth.centerToNorth.geometry.verticesNeedUpdate = true;
  50682. azimuth.centerToNorth.geometry.computeBoundingSphere();
  50683. azimuth.centerToNorth.computeLineDistances();
  50684. azimuth.centerToNorth.material.resolution.set(width, height);
  50685. // label
  50686. const radians = Utils.computeAzimuth(p0.position, p1.position, viewer.getProjection());
  50687. let degrees = MathUtils.radToDeg(radians);
  50688. if(degrees < 0){
  50689. degrees = 360 + degrees;
  50690. }
  50691. const txtDegrees = `${degrees.toFixed(2)}°`;
  50692. const labelDir = northPos.clone().add(p1.position).multiplyScalar(0.5).sub(p0.position);
  50693. if(labelDir.length() > 0){
  50694. labelDir.z = 0;
  50695. labelDir.normalize();
  50696. const labelVec = labelDir.clone().multiplyScalar(r);
  50697. const labelPos = p0.position.clone().add(labelVec);
  50698. azimuth.label.position.copy(labelPos);
  50699. }
  50700. azimuth.label.setText(txtDegrees);
  50701. let distance = azimuth.label.position.distanceTo(camera.position);
  50702. let pr = Utils.projectedRadius(1, camera, distance, width, height);
  50703. let scale = (70 / pr);
  50704. azimuth.label.scale.set(scale, scale, scale);
  50705. }
  50706. class MeasuringTool extends EventDispatcher{
  50707. constructor (viewer) {
  50708. super();
  50709. this.viewer = viewer;
  50710. this.renderer = viewer.renderer;
  50711. this.viewer.addEventListener('start_inserting_measurement', e => {
  50712. this.viewer.dispatchEvent({
  50713. type: 'cancel_insertions'
  50714. });
  50715. });
  50716. this.showLabels = true;
  50717. this.scene = new Scene();
  50718. this.scene.name = 'scene_measurement';
  50719. //this.light = new THREE.PointLight(0xffffff, 1.0);
  50720. //this.scene.add(this.light);
  50721. this.viewer.inputHandler.registerInteractiveScene(this.scene);
  50722. //this.scene = viewer.overlay//
  50723. this.onRemove = (e) => { e.measurement.dispose();/* this.scene.remove(e.measurement); */};
  50724. this.onAdd = e => {this.scene.add(e.measurement);};
  50725. for(let measurement of viewer.scene.measurements){
  50726. this.onAdd({measurement: measurement});
  50727. }
  50728. viewer.addEventListener('camera_changed',(e)=>{
  50729. if(e.viewport == viewer.mainViewport ) this.update();
  50730. });
  50731. //viewer.addEventListener("update", this.update.bind(this));
  50732. viewer.addEventListener("render.pass.perspective_overlay", this.render.bind(this));
  50733. viewer.addEventListener("scene_changed", this.onSceneChange.bind(this));
  50734. viewer.scene.addEventListener('measurement_added', this.onAdd);
  50735. viewer.scene.addEventListener('measurement_removed', this.onRemove);
  50736. viewer.addEventListener('resize',this.setSize.bind(this));
  50737. }
  50738. onSceneChange(e){
  50739. if(e.oldScene){
  50740. e.oldScene.removeEventListener('measurement_added', this.onAdd);
  50741. e.oldScene.removeEventListener('measurement_removed', this.onRemove);
  50742. }
  50743. e.scene.addEventListener('measurement_added', this.onAdd);
  50744. e.scene.addEventListener('measurement_removed', this.onRemove);
  50745. }
  50746. createMeasureFromData(data){//add
  50747. const measure = new Measure(data);
  50748. viewer.scene.addMeasurement(measure);
  50749. if(measure.guideLine)measure.guideLine.visible = false;
  50750. return measure
  50751. }
  50752. update(){
  50753. return;
  50754. let camera = this.viewer.scene.getActiveCamera();
  50755. let domElement = this.renderer.domElement;
  50756. let measurements = this.viewer.scene.measurements;
  50757. // make size independant of distance
  50758. let mainLabels = [], subLabels = [];
  50759. for (let measure of measurements) {
  50760. measure.lengthUnit = this.viewer.lengthUnit;
  50761. measure.lengthUnitDisplay = this.viewer.lengthUnitDisplay;
  50762. //measure.update();
  50763. updateAzimuth(this.viewer, measure);
  50764. /* [...measure.markers, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{
  50765. e && e.update()
  50766. }); */
  50767. // labels
  50768. /* let labels = measure.edgeLabels.concat(measure.angleLabels);
  50769. for(let label of labels){
  50770. label.update()
  50771. if(label.elem.hasClass('sub')){
  50772. subLabels.push(label)
  50773. }else{
  50774. mainLabels.push(label)
  50775. }
  50776. }
  50777. // coordinate labels
  50778. for (let j = 0; j < measure.coordinateLabels.length; j++) {
  50779. let label = measure.coordinateLabels[j];
  50780. label.update()
  50781. mainLabels.push(label)
  50782. }
  50783. if(measure.showArea){ // area label
  50784. let label = measure.areaLabel;
  50785. label.update()
  50786. mainLabels.push(label)
  50787. } */
  50788. /* if(measure.showCircle){ // radius label
  50789. let label = measure.circleRadiusLabel;
  50790. let distance = label.position.distanceTo(camera.position);
  50791. let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
  50792. let scale = (70 / pr);
  50793. label.scale.set(scale, scale, scale);
  50794. } */
  50795. if(!this.showLabels){
  50796. const labels = [
  50797. ...measure.sphereLabels,
  50798. ...measure.angleLabels,
  50799. measure.circleRadiusLabel,
  50800. ];
  50801. for(const label of labels){
  50802. label.visible = false;
  50803. }
  50804. }
  50805. }
  50806. //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
  50807. }
  50808. setSize(e){ //e.resolution
  50809. /* if(Measure.lineMats){
  50810. for(var m in Measure.lineMats){
  50811. Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
  50812. }
  50813. }
  50814. if(Measure.sphereMats){
  50815. for(var s in Measure.sphereMats){
  50816. Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
  50817. }
  50818. }
  50819. for (let measure of this.viewer.scene.measurements) {
  50820. measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{
  50821. label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
  50822. })
  50823. } */
  50824. }
  50825. updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
  50826. group.forEach((e,i)=>{
  50827. e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0;
  50828. var labels = e.labels.sort((a,b)=>{
  50829. return b.pos2d.z - a.pos2d.z
  50830. });
  50831. labels.forEach((label,index)=>{
  50832. $(label.elem).css('z-index', e.base+index);
  50833. });
  50834. });
  50835. }
  50836. editStateChange(e){
  50837. //console.log("editStateChange" , e.state)
  50838. let state = e.state;
  50839. if(!state){
  50840. state = viewer.scene.measurements.some(e=>e.isEditing);
  50841. }
  50842. if(state){
  50843. viewer.dispatchEvent({type:"measureMovePoint"});
  50844. }else {
  50845. viewer.dispatchEvent({type:"endMeasureMove"});
  50846. }
  50847. //this.editing =
  50848. }
  50849. startInsertion (args = {}, callback, cancelFun) {
  50850. let domElement = this.viewer.renderer.domElement;
  50851. const pick = (defaul, alternative) => {
  50852. if(defaul != null){
  50853. return defaul;
  50854. }else {
  50855. return alternative;
  50856. }
  50857. };
  50858. args.showDistances = (args.showDistances === null) ? true : args.showDistances;
  50859. args.showArea = pick(args.showArea, false);
  50860. args.showAngles = pick(args.showAngles, false);
  50861. args.showCoordinates = pick(args.showCoordinates, false);
  50862. args.showHeight = pick(args.showHeight, false);
  50863. args.showCircle = pick(args.showCircle, false);
  50864. args.showAzimuth = pick(args.showAzimuth, false);
  50865. args.showEdges = pick(args.showEdges, true);
  50866. args.closed = pick(args.closed, false);
  50867. args.maxMarkers = pick(args.maxMarkers, Infinity);
  50868. args.direction = args.direction;//add
  50869. args.type = args.type; /* || 'Measurement'; */
  50870. args.showGuideLine = pick(args.showGuideLine, false);
  50871. args.isRect = pick(args.isRect, false);
  50872. let measure = new Measure(args);
  50873. this.scene.add(measure);
  50874. measure.isNew = true;
  50875. this.viewer.dispatchEvent({
  50876. type: 'start_inserting_measurement',
  50877. measure: measure
  50878. });
  50879. measure.addEventListener('editStateChange', this.editStateChange.bind(this));
  50880. measure.editStateChange(true);
  50881. let timer;
  50882. let endDragFun = (e) => {
  50883. let length = measure.points.length;
  50884. if (e.button == MOUSE.LEFT || e.isTouch) {
  50885. if (length >= measure.maxMarkers) {
  50886. end({finish:true});
  50887. }else {
  50888. var marker = measure.addMarker({point:measure.points[length - 1].clone()});
  50889. if(args.isRect && measure.markers.length == 3){//marker全可见
  50890. measure.addMarker({point:measure.points[0].clone()});
  50891. }else {
  50892. measure.markers[length].visible = false;
  50893. measure.edges[length].visible = false;
  50894. }
  50895. measure.edges[length-1].visible = true;
  50896. measure.markers[length-1].visible = true;
  50897. measure.editStateChange(true); //重新激活reticule状态
  50898. marker.isDragging = true;
  50899. measure.continueDrag(marker, e);
  50900. }
  50901. } else if (e.button === MOUSE.RIGHT ) { //触屏怎么取消?
  50902. if(e.pressDistance < Potree.config.clickMaxDragDis )end(e);//非拖拽的话
  50903. else measure.continueDrag(null, e);
  50904. }
  50905. };
  50906. let end = (e={}) => {//确定、结束
  50907. if(!measure.isNew)return
  50908. if(args.minMarkers != void 0){
  50909. if(!e.finish && measure.markers.length<=args.minMarkers){//右键 当个数不够时取消
  50910. //this.viewer.scene.removeMeasurement(measure)
  50911. //cancelFun && cancelFun()
  50912. //重新开始画
  50913. measure.markers[0].removeEventListener('mousedown',end);
  50914. measure.reDraw();
  50915. this.viewer.addEventListener('global_click', click, 10);
  50916. measure.editStateChange(true);
  50917. return
  50918. /* if(!Potree.settings.isOfficial) this.viewer.scene.removeMeasurement(measure)
  50919. else if(e.drag){ //正式版本不允许右键退出, 继续
  50920. continueDrag(e.drag.object)
  50921. measure.editStateChange(true)
  50922. return
  50923. } */
  50924. }
  50925. }
  50926. if (!e.finish && measure.markers.length > 3) {
  50927. measure.removeMarker(measure.points.length - 1);
  50928. measure.markers[0].removeEventListener('mouseover', mouseover);
  50929. measure.markers[0].removeEventListener('mouseleave', mouseleave);
  50930. measure.markers[0].removeEventListener('click'/* 'mousedown' */,Exit);
  50931. }
  50932. measure.isNew = false;
  50933. let length = measure.points.length;
  50934. if(length){
  50935. measure.markers[length-1].visible = true;
  50936. measure.edges[length-1].visible = true;
  50937. measure.markers.forEach(marker=>{marker.dispatchEvent('addHoverEvent'); });
  50938. measure.edges.forEach(edge=>{edge.dispatchEvent('addHoverEvent'); });
  50939. }
  50940. clearTimeout(timer);
  50941. this.viewer.removeEventListener('cancel_insertions', Exit);
  50942. //pressExit && this.viewer.inputHandler.removeEventListener('keydown', pressExit);
  50943. this.viewer.removeEventListener('global_click', click);
  50944. this.viewer.removeEventListener('global_mousemove', ifAtWrongPlace);
  50945. viewer.dispatchEvent({
  50946. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  50947. });
  50948. viewer.inputHandler.dispatchEvent({type:'isMeasuring', v:false, cause:'stopInsertion'} );
  50949. e.remove || callback && callback();
  50950. /* this.viewer.dispatchEvent({
  50951. type: 'finish_inserting_measurement',
  50952. measure: measure
  50953. }); */
  50954. };
  50955. let Exit = (e)=>{//强制退出
  50956. if(e.measure && e.measure != measure){
  50957. return;//若指定了退出的measure但和该measure不一致,就返回
  50958. }
  50959. console.log('Exit: ' + measure.id);
  50960. if(e.remove){
  50961. viewer.scene.removeMeasurement(measure);
  50962. }
  50963. measure.editStateChange(false);
  50964. if(this.viewer.inputHandler.drag && !e.remove){//还未触发drop的话
  50965. this.viewer.inputHandler.drag.object.dispatchEvent({
  50966. type: 'drop',
  50967. drag: this.viewer.inputHandler.drag,
  50968. viewer: this.viewer,
  50969. pressDistance:0,
  50970. button : MOUSE.RIGHT
  50971. });
  50972. }else {
  50973. end({finish:true, remove:e.remove}); //未结束时添加新的measure时会触发
  50974. }
  50975. this.viewer.inputHandler.drag = null;
  50976. };
  50977. this.viewer.addEventListener('cancel_insertions', Exit);
  50978. /*let pressExit
  50979. if(!Potree.settings.isOfficial){
  50980. pressExit = (e)=>{
  50981. if(e.keyCode == 27){//Esc
  50982. //Exit()
  50983. //怎么模拟右键???//现由前端发出
  50984. }
  50985. }
  50986. this.viewer.inputHandler.addEventListener('keydown', pressExit)
  50987. } */
  50988. let mouseover = (e) => {
  50989. measure.setMarkerSelected(e.object, 'hover', 'single');
  50990. };
  50991. let mouseleave = (e) => {
  50992. measure.setMarkerSelected(e.object, 'unhover', 'single');
  50993. };
  50994. let click = (e)=>{//一旦点击就立刻增加两marker
  50995. if(ifAtWrongPlace(e))return
  50996. if(e.button === MOUSE.RIGHT)return
  50997. //console.log('measure clicked33', !!e.intersectPoint)
  50998. //var I = e.intersectPoint && (e.intersectPoint.orthoIntersect || e.intersectPoint.location)
  50999. var I = e.intersect && (e.intersect.orthoIntersect || e.intersect.location);
  51000. if(!I){
  51001. return measure.dispatchEvent('intersectNoPointcloud')
  51002. }
  51003. var atMap = e.drag.dragViewport.name == 'mapViewport';
  51004. //在地图上测量的首个点按楼层高度(暂时先只按mainViewport相机高度吧,但navvis是按楼层,画在楼层的地面上,可能因为平面图显示的是楼层近地面),
  51005. if(atMap){
  51006. I = I.clone().setZ(viewer.mainViewport.camera.position.z );
  51007. }
  51008. var marker = measure.addMarker({point:I});
  51009. marker.isDragging = true;
  51010. this.viewer.inputHandler.startDragging(marker , {endDragFun, notPressMouse:true} ); //notPressMouse代表不是通过按下鼠标来拖拽
  51011. e.drag = this.viewer.inputHandler.drag;
  51012. e.drag.endDragFun = endDragFun;
  51013. e.drag.notPressMouse = true;
  51014. //if(!measure.dragMarker(e) || !measure.dropMarker(e))return
  51015. measure.dragMarker(e);
  51016. measure.dropMarker(e);
  51017. if(measure.maxMarkers > 1 ){
  51018. measure.markers[1].visible = false;
  51019. measure.edges[1].visible = false;
  51020. }
  51021. if(measure.maxMarkers>2 && !measure.isRect){
  51022. measure.markers[0].addEventListener('mouseover', mouseover);
  51023. measure.markers[0].addEventListener('mouseleave', mouseleave);
  51024. measure.markers[0].addEventListener('click'/* 'mousedown' */,Exit); //点击到第一个marker就结束
  51025. }
  51026. this.viewer.removeEventListener('global_click', click);///* global_drop */
  51027. //console.log('measure clicked')
  51028. return {stopContinue:true}//防止继续执行别的侦听,如flytopano
  51029. };
  51030. //点击第n下拥有n+1个marker, n>0
  51031. viewer.inputHandler.dispatchEvent({type: 'isMeasuring', v: true, cause:'startInsertion'});
  51032. this.viewer.addEventListener('global_click', click, 10);//add importance:10
  51033. let ifAtWrongPlace = (e)=>{
  51034. if(measure.unableDragAtMap && e.hoverViewport.name == 'mapViewport' ){
  51035. if(e.isTouch){
  51036. viewer.dispatchEvent({type:'reticule_forbit', v:true});
  51037. }else {
  51038. viewer.dispatchEvent({
  51039. type : "CursorChange", action : "add", name:"polygon_AtWrongPlace"
  51040. });
  51041. }
  51042. return true
  51043. }else {
  51044. if(e.isTouch){
  51045. viewer.dispatchEvent({type:'reticule_forbit',v:false});
  51046. }else {
  51047. viewer.dispatchEvent({
  51048. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  51049. });
  51050. }
  51051. }
  51052. };
  51053. if(measure.unableDragAtMap){
  51054. this.viewer.addEventListener('global_mousemove', ifAtWrongPlace);
  51055. }
  51056. this.viewer.scene.addMeasurement(measure);
  51057. return measure;
  51058. }
  51059. render(o={}){
  51060. viewer.setCameraLayers(o.camera, ['measure']);
  51061. if(o.screenshot){ //抗锯齿
  51062. this.viewer.ssaaRenderPass.sampleLevel = 4;
  51063. this.viewer.composer.render(this.scene, o.camera );
  51064. /* viewer.scene.measurements.forEach(e=>{ //隐藏除了label以外的
  51065. e.children.forEach((c)=>{
  51066. if(!(c instanceof TextSprite)){
  51067. c.visible = false
  51068. }
  51069. })
  51070. }) */
  51071. }else {
  51072. this.viewer.renderer.render(this.scene, o.camera );
  51073. }
  51074. }
  51075. };
  51076. class Message{
  51077. constructor(content){
  51078. this.content = content;
  51079. let closeIcon = `${exports.resourcePath}/icons/close.svg`;
  51080. this.element = $(`
  51081. <div class="potree_message">
  51082. <span name="content_container" style="flex-grow: 1; padding: 5px"></span>
  51083. <img name="close" src="${closeIcon}" class="button-icon" style="width: 16px; height: 16px;">
  51084. </div>`);
  51085. this.elClose = this.element.find("img[name=close]");
  51086. this.elContainer = this.element.find("span[name=content_container]");
  51087. if(typeof content === "string"){
  51088. this.elContainer.append($(`<span>${content}</span>`));
  51089. }else {
  51090. this.elContainer.append(content);
  51091. }
  51092. }
  51093. setMessage(content){
  51094. this.elContainer.empty();
  51095. if(typeof content === "string"){
  51096. this.elContainer.append($(`<span>${content}</span>`));
  51097. }else {
  51098. this.elContainer.append(content);
  51099. }
  51100. }
  51101. }
  51102. class PointCloudSM{//shadow material ?
  51103. constructor(potreeRenderer){
  51104. this.potreeRenderer = potreeRenderer;
  51105. this.threeRenderer = this.potreeRenderer.threeRenderer;
  51106. this.target = new WebGLRenderTarget(2 * 1024, 2 * 1024, {
  51107. minFilter: LinearFilter,
  51108. magFilter: LinearFilter,
  51109. format: RGBAFormat,
  51110. type: FloatType,
  51111. });
  51112. this.target.depthTexture = new DepthTexture();
  51113. this.target.depthTexture.type = UnsignedIntType;
  51114. //this.threeRenderer.setClearColor(0x000000, 1);
  51115. this.threeRenderer.setClearColor(0xff0000, 1);
  51116. //HACK? removed while moving to three.js 109
  51117. //this.threeRenderer.clearTarget(this.target, true, true, true);
  51118. {
  51119. const oldTarget = this.threeRenderer.getRenderTarget();
  51120. this.threeRenderer.setRenderTarget(this.target);
  51121. //this.threeRenderer.clear(true, true, true); //救命,为什么iphoneX ios13.6执行这一句clear会崩溃?即使把target的大小改为1*1.
  51122. this.threeRenderer.setRenderTarget(oldTarget);
  51123. }
  51124. }
  51125. setLight(light){
  51126. this.light = light;
  51127. let fov = (180 * light.angle) / Math.PI;
  51128. let aspect = light.shadow.mapSize.width / light.shadow.mapSize.height;
  51129. let near = 0.1;
  51130. let far = light.distance === 0 ? 10000 : light.distance;
  51131. this.camera = new PerspectiveCamera(fov, aspect, near, far);
  51132. this.camera.up.set(0, 0, 1);
  51133. this.camera.position.copy(light.position);
  51134. let target = new Vector3().subVectors(light.position, light.getWorldDirection(new Vector3()));
  51135. this.camera.lookAt(target);
  51136. this.camera.updateProjectionMatrix();
  51137. this.camera.updateMatrix();
  51138. this.camera.updateMatrixWorld();
  51139. this.camera.matrixWorldInverse.copy(this.camera.matrixWorld).invert();
  51140. }
  51141. setSize(width, height){
  51142. if(this.target.width !== width || this.target.height !== height){
  51143. this.target.dispose();
  51144. }
  51145. this.target.setSize(width, height);
  51146. }
  51147. render(scene, camera){
  51148. this.threeRenderer.setClearColor(0x000000, 1);
  51149. const oldTarget = this.threeRenderer.getRenderTarget();
  51150. this.threeRenderer.setRenderTarget(this.target);
  51151. this.threeRenderer.clear(true, true, true);
  51152. this.potreeRenderer.render(scene, this.camera, this.target, {});
  51153. this.threeRenderer.setRenderTarget(oldTarget);
  51154. }
  51155. }
  51156. class ProfileTool extends EventDispatcher {
  51157. constructor (viewer) {
  51158. super();
  51159. this.viewer = viewer;
  51160. this.renderer = viewer.renderer;
  51161. this.addEventListener('start_inserting_profile', e => {
  51162. this.viewer.dispatchEvent({
  51163. type: 'cancel_insertions'
  51164. });
  51165. });
  51166. this.scene = new Scene();
  51167. this.scene.name = 'scene_profile';
  51168. this.light = new PointLight(0xffffff, 1.0);
  51169. this.scene.add(this.light);
  51170. this.viewer.inputHandler.registerInteractiveScene(this.scene);
  51171. this.onRemove = e => this.scene.remove(e.profile);
  51172. this.onAdd = e => this.scene.add(e.profile);
  51173. for(let profile of viewer.scene.profiles){
  51174. this.onAdd({profile: profile});
  51175. }
  51176. viewer.addEventListener("update", this.update.bind(this));
  51177. viewer.addEventListener("render.pass.perspective_overlay", this.render.bind(this));
  51178. viewer.addEventListener("scene_changed", this.onSceneChange.bind(this));
  51179. viewer.scene.addEventListener('profile_added', this.onAdd);
  51180. viewer.scene.addEventListener('profile_removed', this.onRemove);
  51181. }
  51182. onSceneChange(e){
  51183. if(e.oldScene){
  51184. e.oldScene.removeEventListeners('profile_added', this.onAdd);
  51185. e.oldScene.removeEventListeners('profile_removed', this.onRemove);
  51186. }
  51187. e.scene.addEventListener('profile_added', this.onAdd);
  51188. e.scene.addEventListener('profile_removed', this.onRemove);
  51189. }
  51190. startInsertion (args = {}) {
  51191. let domElement = this.viewer.renderer.domElement;
  51192. let profile = new Profile();
  51193. profile.name = args.name || 'Profile';
  51194. this.dispatchEvent({
  51195. type: 'start_inserting_profile',
  51196. profile: profile
  51197. });
  51198. this.scene.add(profile);
  51199. let cancel = {
  51200. callback: null
  51201. };
  51202. let insertionCallback = (e) => {
  51203. if(e.button === MOUSE.LEFT){
  51204. if(profile.points.length <= 1){
  51205. let camera = this.viewer.scene.getActiveCamera();
  51206. let distance = camera.position.distanceTo(profile.points[0]);
  51207. let clientSize = this.viewer.renderer.getSize(new Vector2$1());
  51208. let pr = Utils.projectedRadius(1, camera, distance, clientSize.width, clientSize.height);
  51209. let width = (10 / pr);
  51210. profile.setWidth(width);
  51211. }
  51212. profile.addMarker(profile.points[profile.points.length - 1].clone());
  51213. this.viewer.inputHandler.startDragging(
  51214. profile.spheres[profile.spheres.length - 1]);
  51215. } else if (e.button === MOUSE.RIGHT) {
  51216. cancel.callback();
  51217. }
  51218. };
  51219. cancel.callback = e => {
  51220. profile.removeMarker(profile.points.length - 1);
  51221. domElement.removeEventListener('mouseup', insertionCallback, false);
  51222. this.viewer.removeEventListener('cancel_insertions', cancel.callback);
  51223. };
  51224. this.viewer.addEventListener('cancel_insertions', cancel.callback);
  51225. domElement.addEventListener('mouseup', insertionCallback, false);
  51226. profile.addMarker(new Vector3(0, 0, 0));
  51227. this.viewer.inputHandler.startDragging(
  51228. profile.spheres[profile.spheres.length - 1]);
  51229. this.viewer.scene.addProfile(profile);
  51230. return profile;
  51231. }
  51232. update(){
  51233. let camera = this.viewer.scene.getActiveCamera();
  51234. let profiles = this.viewer.scene.profiles;
  51235. let renderAreaSize = this.viewer.renderer.getSize(new Vector2$1());
  51236. let clientWidth = renderAreaSize.width;
  51237. let clientHeight = renderAreaSize.height;
  51238. this.light.position.copy(camera.position);
  51239. // make size independant of distance
  51240. for(let profile of profiles){
  51241. for(let sphere of profile.spheres){
  51242. let distance = camera.position.distanceTo(sphere.getWorldPosition(new Vector3()));
  51243. let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
  51244. let scale = (15 / pr);
  51245. sphere.scale.set(scale, scale, scale);
  51246. }
  51247. }
  51248. }
  51249. render(){
  51250. this.viewer.renderer.render(this.scene, this.viewer.scene.getActiveCamera());
  51251. }
  51252. }
  51253. class ScreenBoxSelectTool extends EventDispatcher{
  51254. constructor(viewer){
  51255. super();
  51256. this.viewer = viewer;
  51257. this.scene = new Scene();
  51258. viewer.addEventListener("update", this.update.bind(this));
  51259. viewer.addEventListener("render.pass.perspective_overlay", this.render.bind(this));
  51260. viewer.addEventListener("scene_changed", this.onSceneChange.bind(this));
  51261. }
  51262. onSceneChange(scene){
  51263. console.log("scene changed");
  51264. }
  51265. startInsertion(){
  51266. let domElement = this.viewer.renderer.domElement;
  51267. let volume = new BoxVolume();
  51268. volume.position.set(12345, 12345, 12345);
  51269. volume.showVolumeLabel = false;
  51270. volume.visible = false;
  51271. volume.update();
  51272. this.viewer.scene.addVolume(volume);
  51273. this.importance = 10;
  51274. let selectionBox = $(`<div style="position: absolute; border: 2px solid white; pointer-events: none; border-style:dashed"></div>`);
  51275. $(domElement.parentElement).append(selectionBox);
  51276. selectionBox.css("right", "10px");
  51277. selectionBox.css("bottom", "10px");
  51278. let drag = e =>{
  51279. volume.visible = true;
  51280. let mStart = e.drag.start;
  51281. let mEnd = e.drag.end;
  51282. let box2D = new Box2();
  51283. box2D.expandByPoint(mStart);
  51284. box2D.expandByPoint(mEnd);
  51285. selectionBox.css("left", `${box2D.min.x}px`);
  51286. selectionBox.css("top", `${box2D.min.y}px`);
  51287. selectionBox.css("width", `${box2D.max.x - box2D.min.x}px`);
  51288. selectionBox.css("height", `${box2D.max.y - box2D.min.y}px`);
  51289. let camera = e.viewer.scene.getActiveCamera();
  51290. let size = e.viewer.renderer.getSize(new Vector2$1());
  51291. let frustumSize = new Vector2$1(
  51292. camera.right - camera.left,
  51293. camera.top - camera.bottom);
  51294. let screenCentroid = new Vector2$1().addVectors(e.drag.end, e.drag.start).multiplyScalar(0.5);
  51295. let pointer = new Vector3(0, 0, 0.5);
  51296. Utils.convertScreenPositionToNDC(pointer, screenCentroid, size.width, size.height);
  51297. pointer.unproject(camera);
  51298. //let ray = Utils.mouseToRay( pointer, camera, size.width, size.height);
  51299. let diff = new Vector2$1().subVectors(e.drag.end, e.drag.start);
  51300. diff.divide(size).multiply(frustumSize);
  51301. volume.position.copy(pointer);
  51302. //volume.position.copy(ray.origin); //orthographicCamera不能用这种方式 而且也该是用end
  51303. volume.up.copy(camera.up);
  51304. volume.rotation.copy(camera.rotation);
  51305. volume.scale.set(diff.x, diff.y, 1000 * 100);
  51306. e.consume();
  51307. };
  51308. let drop = e => {
  51309. this.importance = 0;
  51310. $(selectionBox).remove();
  51311. this.viewer.inputHandler.deselectAll();
  51312. this.viewer.inputHandler.toggleSelection(volume);
  51313. let camera = e.viewer.scene.getActiveCamera();
  51314. let size = e.viewer.renderer.getSize(new Vector2$1());
  51315. let screenCentroid = new Vector2$1().addVectors(e.drag.end, e.drag.start).multiplyScalar(0.5);
  51316. let pointer = new Vector3(0, 0, 0.5);
  51317. Utils.convertScreenPositionToNDC(pointer, screenCentroid, size.width, size.height);
  51318. let ray = Utils.mouseToRay(pointer/* screenCentroid */, camera, size.width, size.height);
  51319. //let line = new THREE.Line3(ray.origin, new THREE.Vector3().addVectors(ray.origin, ray.direction));
  51320. this.removeEventListener("drag", drag);
  51321. this.removeEventListener("drop", drop);
  51322. let allPointsNear = [];
  51323. let allPointsFar = [];
  51324. // TODO support more than one point cloud
  51325. for(let pointcloud of this.viewer.scene.pointclouds){
  51326. if(!pointcloud.visible){
  51327. continue;
  51328. }
  51329. let volCam = camera.clone();
  51330. volCam.left = -volume.scale.x / 2;
  51331. volCam.right = +volume.scale.x / 2;
  51332. volCam.top = +volume.scale.y / 2;
  51333. volCam.bottom = -volume.scale.y / 2;
  51334. volCam.near = -volume.scale.z / 2;
  51335. volCam.far = +volume.scale.z / 2;
  51336. volCam.rotation.copy(volume.rotation);
  51337. volCam.position.copy(volume.position);
  51338. volCam.updateMatrix();
  51339. volCam.updateMatrixWorld();
  51340. volCam.updateProjectionMatrix();
  51341. volCam.matrixWorldInverse.copy(volCam.matrixWorld).invert();
  51342. let ray = new Ray(volCam.getWorldPosition(new Vector3()), volCam.getWorldDirection(new Vector3()));
  51343. let rayInverse = new Ray(
  51344. ray.origin.clone().add(ray.direction.clone().multiplyScalar(volume.scale.z)),
  51345. ray.direction.clone().multiplyScalar(-1));
  51346. let diff = new Vector2$1().subVectors(e.drag.end, e.drag.start);
  51347. let pickerSettings = {
  51348. width: 16, //renderTarget大小,数值越大识别精度越高 原本的8太低了
  51349. height: 16,
  51350. pickWindowSize: 16, //??????
  51351. all: true,
  51352. pickClipped: true,
  51353. pointSizeType: PointSizeType.FIXED,
  51354. pointSize: 1
  51355. };
  51356. let pointsNear = pointcloud.pick(viewer, null, volCam, ray, pickerSettings);
  51357. volCam.rotateX(Math.PI);
  51358. volCam.updateMatrix();
  51359. volCam.updateMatrixWorld();
  51360. volCam.updateProjectionMatrix();
  51361. volCam.matrixWorldInverse.copy(volCam.matrixWorld).invert();
  51362. let pointsFar = pointcloud.pick(viewer,null, volCam, rayInverse, pickerSettings);
  51363. pointsNear && allPointsNear.push(...pointsNear);
  51364. pointsFar && allPointsFar.push(...pointsFar);
  51365. }
  51366. /* if(allPointsNear.length > 0 && allPointsFar.length > 0){
  51367. let viewLine = new THREE.Line3(ray.origin, new THREE.Vector3().addVectors(ray.origin, ray.direction));
  51368. let closestOnLine = allPointsNear.map(p => viewLine.closestPointToPoint(p.position, false, new THREE.Vector3()));
  51369. let closest = closestOnLine.sort( (a, b) => ray.origin.distanceTo(a) - ray.origin.distanceTo(b))[0];
  51370. let farthestOnLine = allPointsFar.map(p => viewLine.closestPointToPoint(p.position, false, new THREE.Vector3()));
  51371. let farthest = farthestOnLine.sort( (a, b) => ray.origin.distanceTo(b) - ray.origin.distanceTo(a))[0];
  51372. let distance = closest.distanceTo(farthest);
  51373. let centroid = new THREE.Vector3().addVectors(closest, farthest).multiplyScalar(0.5);
  51374. volume.scale.z = distance * 1.1;
  51375. volume.position.copy(centroid);
  51376. } */
  51377. if(allPointsNear.length > 0 || allPointsFar.length > 0){
  51378. let viewLine = new Line3(ray.origin, new Vector3().addVectors(ray.origin, ray.direction));
  51379. let closestOnLine = allPointsNear.map(p => viewLine.closestPointToPoint(p.position, false, new Vector3()));
  51380. let closests = closestOnLine.sort( (a, b) => ray.origin.distanceTo(a) - ray.origin.distanceTo(b));//[0];
  51381. let farthestOnLine = allPointsFar.map(p => viewLine.closestPointToPoint(p.position, false, new Vector3()));
  51382. let farthests = farthestOnLine.sort( (a, b) => ray.origin.distanceTo(b) - ray.origin.distanceTo(a));//[0];
  51383. let closest, farthest;
  51384. if(closests.length == 0){
  51385. closest = farthests[farthests.length-1];
  51386. farthest = farthests[0];
  51387. }else if(farthests.length == 0){
  51388. closest = closests[closests.length-1];
  51389. farthest = closests[0];
  51390. }else {
  51391. closest = closests[0];
  51392. farthest = farthests[0];
  51393. }
  51394. let distance = closest.distanceTo(farthest);
  51395. let centroid = new Vector3().addVectors(closest, farthest).multiplyScalar(0.5);
  51396. volume.scale.z = distance * 1.1;
  51397. //volume.position.copy(centroid);
  51398. var pos2d = centroid.project(camera); //改变深度
  51399. pointer.setZ(pos2d.z);
  51400. pointer.unproject(camera);
  51401. volume.position.copy(pointer);
  51402. }
  51403. volume.clip = true;
  51404. };
  51405. this.addEventListener("drag", drag);
  51406. this.addEventListener("drop", drop);
  51407. viewer.inputHandler.addInputListener(this);
  51408. return volume;
  51409. }
  51410. update(e){
  51411. //console.log(e.delta)
  51412. }
  51413. render(){
  51414. this.viewer.renderer.render(this.scene, this.viewer.scene.getActiveCamera());
  51415. }
  51416. }
  51417. class SpotLightHelper$1 extends Object3D{
  51418. constructor(light, color){
  51419. super();
  51420. this.light = light;
  51421. this.color = color;
  51422. //this.up.set(0, 0, 1);
  51423. this.updateMatrix();
  51424. this.updateMatrixWorld();
  51425. { // SPHERE
  51426. let sg = new SphereGeometry(1, 32, 32);
  51427. let sm = new MeshNormalMaterial();
  51428. this.sphere = new Mesh(sg, sm);
  51429. this.sphere.scale.set(0.5, 0.5, 0.5);
  51430. this.add(this.sphere);
  51431. }
  51432. { // LINES
  51433. let positions = new Float32Array([
  51434. +0, +0, +0, +0, +0, -1,
  51435. +0, +0, +0, -1, -1, -1,
  51436. +0, +0, +0, +1, -1, -1,
  51437. +0, +0, +0, +1, +1, -1,
  51438. +0, +0, +0, -1, +1, -1,
  51439. -1, -1, -1, +1, -1, -1,
  51440. +1, -1, -1, +1, +1, -1,
  51441. +1, +1, -1, -1, +1, -1,
  51442. -1, +1, -1, -1, -1, -1,
  51443. ]);
  51444. let geometry = new BufferGeometry();
  51445. geometry.setAttribute("position", new BufferAttribute(positions, 3));
  51446. let material = new LineBasicMaterial();
  51447. this.frustum = new LineSegments(geometry, material);
  51448. this.add(this.frustum);
  51449. }
  51450. this.update();
  51451. }
  51452. update(){
  51453. this.light.updateMatrix();
  51454. this.light.updateMatrixWorld();
  51455. let position = this.light.position;
  51456. let target = new Vector3().addVectors(
  51457. this.light.position, this.light.getWorldDirection(new Vector3()).multiplyScalar(-1));
  51458. let quat = new Quaternion().setFromRotationMatrix(
  51459. new Matrix4().lookAt( position, target, new Vector3( 0, 0, 1 ) )
  51460. );
  51461. this.setRotationFromQuaternion(quat);
  51462. this.position.copy(position);
  51463. let coneLength = (this.light.distance > 0) ? this.light.distance : 1000;
  51464. let coneWidth = coneLength * Math.tan( this.light.angle * 0.5 );
  51465. this.frustum.scale.set(coneWidth, coneWidth, coneLength);
  51466. }
  51467. }
  51468. //add-------------------------------------
  51469. const OpaWhenNotSelect = 0.75;
  51470. const ScaleRatio = 4;
  51471. const OutlineColor = 0x666666;
  51472. //----------------------------------------
  51473. const hideFocusHandles = true;//add
  51474. class TransformationTool {
  51475. constructor(viewer) {
  51476. this.viewer = viewer;
  51477. this.scene = new Scene();
  51478. this.selection = [];
  51479. this.pivot = new Vector3();
  51480. this.dragging = false;
  51481. this.showPickVolumes = false;
  51482. this.viewer.inputHandler.registerInteractiveScene(this.scene);
  51483. this.viewer.inputHandler.addEventListener('selection_changed', (e) => {
  51484. for(let selected of this.selection){
  51485. this.viewer.inputHandler.blacklist.delete(selected);
  51486. }
  51487. this.selection = e.selection;
  51488. for(let selected of this.selection){
  51489. this.viewer.inputHandler.blacklist.add(selected);
  51490. }
  51491. });
  51492. this.viewer.addEventListener('global_touchstart',(e)=>{ //add
  51493. this.update();
  51494. });
  51495. let red = Potree.config.axis.x.color;
  51496. let green = Potree.config.axis.y.color;
  51497. let blue = Potree.config.axis.z.color;
  51498. this.activeHandle = null;
  51499. this.scaleHandles = {
  51500. "scale.x+": {name: "scale.x+", node: new Object3D(), color: red, alignment: [+1, +0, +0]},
  51501. "scale.x-": {name: "scale.x-", node: new Object3D(), color: red, alignment: [-1, +0, +0]},
  51502. "scale.y+": {name: "scale.y+", node: new Object3D(), color: green, alignment: [+0, +1, +0]},
  51503. "scale.y-": {name: "scale.y-", node: new Object3D(), color: green, alignment: [+0, -1, +0]},
  51504. "scale.z+": {name: "scale.z+", node: new Object3D(), color: blue, alignment: [+0, +0, +1]},
  51505. "scale.z-": {name: "scale.z-", node: new Object3D(), color: blue, alignment: [+0, +0, -1]},
  51506. };
  51507. this.focusHandles = {
  51508. "focus.x+": {name: "focus.x+", node: new Object3D(), color: red, alignment: [+1, +0, +0]},
  51509. "focus.x-": {name: "focus.x-", node: new Object3D(), color: red, alignment: [-1, +0, +0]},
  51510. "focus.y+": {name: "focus.y+", node: new Object3D(), color: green, alignment: [+0, +1, +0]},
  51511. "focus.y-": {name: "focus.y-", node: new Object3D(), color: green, alignment: [+0, -1, +0]},
  51512. "focus.z+": {name: "focus.z+", node: new Object3D(), color: blue, alignment: [+0, +0, +1]},
  51513. "focus.z-": {name: "focus.z-", node: new Object3D(), color: blue, alignment: [+0, +0, -1]},
  51514. };
  51515. this.translationHandles = {
  51516. "translation.x": {name: "translation.x", node: new Object3D(), color: red, alignment: [1, 0, 0]},
  51517. "translation.y": {name: "translation.y", node: new Object3D(), color: green, alignment: [0, 1, 0]},
  51518. "translation.z": {name: "translation.z", node: new Object3D(), color: blue, alignment: [0, 0, 1]},
  51519. };
  51520. this.rotationHandles = {
  51521. "rotation.x": {name: "rotation.x", node: new Object3D(), color: red, alignment: [1, 0, 0]},
  51522. "rotation.y": {name: "rotation.y", node: new Object3D(), color: green, alignment: [0, 1, 0]},
  51523. "rotation.z": {name: "rotation.z", node: new Object3D(), color: blue, alignment: [0, 0, 1]},
  51524. };
  51525. this.handles = Object.assign({}, this.scaleHandles, hideFocusHandles?{}:this.focusHandles, this.translationHandles, this.rotationHandles);
  51526. this.pickVolumes = [];
  51527. this.initializeScaleHandles();
  51528. this.initializeFocusHandles();
  51529. this.initializeTranslationHandles();
  51530. this.initializeRotationHandles();
  51531. let boxFrameGeometry = new Geometry();
  51532. {
  51533. // bottom
  51534. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.5));
  51535. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.5));
  51536. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.5));
  51537. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, -0.5));
  51538. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, -0.5));
  51539. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, -0.5));
  51540. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, -0.5));
  51541. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.5));
  51542. // top
  51543. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.5));
  51544. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.5));
  51545. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.5));
  51546. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, -0.5));
  51547. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, -0.5));
  51548. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, -0.5));
  51549. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, -0.5));
  51550. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.5));
  51551. // sides
  51552. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, 0.5));
  51553. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, 0.5));
  51554. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, 0.5));
  51555. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, 0.5));
  51556. boxFrameGeometry.vertices.push(new Vector3(0.5, -0.5, -0.5));
  51557. boxFrameGeometry.vertices.push(new Vector3(0.5, 0.5, -0.5));
  51558. boxFrameGeometry.vertices.push(new Vector3(-0.5, -0.5, -0.5));
  51559. boxFrameGeometry.vertices.push(new Vector3(-0.5, 0.5, -0.5));
  51560. }
  51561. this.frame = new LineSegments(boxFrameGeometry, new LineBasicMaterial({color: 0xffff00}));
  51562. this.scene.add(this.frame);
  51563. viewer.setObjectLayers(this.scene, 'transformationTool' );
  51564. }
  51565. setModeEnable(mode,enable){//xzw add
  51566. let handels = this[mode + 'Handles'];
  51567. if(!handels)return
  51568. for(let o in handels){
  51569. handels[o].node.visible = !!enable;
  51570. }
  51571. }
  51572. initializeScaleHandles(){
  51573. let sgSphere = new SphereGeometry(1, 32, 32);
  51574. let sgLowPolySphere = new SphereGeometry(1, 16, 16);
  51575. for(let handleName of Object.keys(this.scaleHandles)){
  51576. let handle = this.scaleHandles[handleName];
  51577. let node = handle.node;
  51578. this.scene.add(node);
  51579. node.position.set(...handle.alignment).multiplyScalar(0.5);
  51580. let material = new MeshBasicMaterial({
  51581. color: handle.color,
  51582. opacity: OpaWhenNotSelect,
  51583. transparent: true
  51584. });
  51585. let outlineMaterial = new MeshBasicMaterial({
  51586. color: OutlineColor,
  51587. side: BackSide,
  51588. opacity: OpaWhenNotSelect,
  51589. transparent: true});
  51590. let pickMaterial = new MeshNormalMaterial({
  51591. opacity: 0.2,
  51592. transparent: true,
  51593. visible: this.showPickVolumes});
  51594. let sphere = new Mesh(sgSphere, material);
  51595. sphere.scale.set(2, 2, 2 );
  51596. sphere.name = `${handleName}.handle`;
  51597. node.add(sphere);
  51598. let outline = new Mesh(sgSphere, outlineMaterial);
  51599. outline.scale.set(1.1, 1.1, 1.1);
  51600. outline.name = `${handleName}.outline`;
  51601. sphere.add(outline);
  51602. let pickSphere = new Mesh(sgLowPolySphere, pickMaterial);
  51603. pickSphere.name = `${handleName}.pick_volume`;
  51604. pickSphere.scale.set(2, 2, 2);
  51605. sphere.add(pickSphere);
  51606. pickSphere.handle = handleName;
  51607. this.pickVolumes.push(pickSphere);
  51608. node.setOpacity = (target) => {
  51609. let opacity = {x: material.opacity};
  51610. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  51611. t.onUpdate(() => {
  51612. sphere.visible = opacity.x > 0;
  51613. pickSphere.visible = opacity.x > 0;
  51614. material.opacity = opacity.x;
  51615. outlineMaterial.opacity = opacity.x;
  51616. pickSphere.material.opacity = opacity.x * 0.5;
  51617. });
  51618. t.start();
  51619. };
  51620. pickSphere.addEventListener("drag", (e) => this.dragScaleHandle(e));
  51621. pickSphere.addEventListener("drop", (e) => this.dropScaleHandle(e));
  51622. pickSphere.addEventListener("mouseover", e => {
  51623. //node.setOpacity(1);
  51624. });
  51625. pickSphere.addEventListener("click", e => {
  51626. e.consume();
  51627. });
  51628. pickSphere.addEventListener("mouseleave", e => {
  51629. //node.setOpacity(OpaWhenNotSelect);
  51630. });
  51631. }
  51632. }
  51633. initializeFocusHandles(){
  51634. if(hideFocusHandles)return//add
  51635. //let sgBox = new THREE.BoxGeometry(1, 1, 1);
  51636. let sgPlane = new PlaneGeometry(4, 4, 1, 1);
  51637. let sgLowPolySphere = new SphereGeometry(1, 16, 16);
  51638. let texture = new TextureLoader().load(`${exports.resourcePath}/icons/eye_2.png`);
  51639. for(let handleName of Object.keys(this.focusHandles)){
  51640. let handle = this.focusHandles[handleName];
  51641. let node = handle.node;
  51642. this.scene.add(node);
  51643. let align = handle.alignment;
  51644. //node.lookAt(new THREE.Vector3().addVectors(node.position, new THREE.Vector3(...align)));
  51645. node.lookAt(new Vector3(...align));
  51646. let off = 0.8;
  51647. if(align[0] === 1){
  51648. node.position.set(1, off, -off).multiplyScalar(0.5);
  51649. node.rotation.z = Math.PI / 2;
  51650. }else if(align[0] === -1){
  51651. node.position.set(-1, -off, -off).multiplyScalar(0.5);
  51652. node.rotation.z = Math.PI / 2;
  51653. }else if(align[1] === 1){
  51654. node.position.set(-off, 1, -off).multiplyScalar(0.5);
  51655. node.rotation.set(Math.PI / 2, Math.PI, 0.0);
  51656. }else if(align[1] === -1){
  51657. node.position.set(off, -1, -off).multiplyScalar(0.5);
  51658. node.rotation.set(Math.PI / 2, 0.0, 0.0);
  51659. }else if(align[2] === 1){
  51660. node.position.set(off, off, 1).multiplyScalar(0.5);
  51661. }else if(align[2] === -1){
  51662. node.position.set(-off, off, -1).multiplyScalar(0.5);
  51663. }
  51664. let material = new MeshBasicMaterial({
  51665. color: handle.color,
  51666. opacity: 0,
  51667. transparent: true,
  51668. map: texture
  51669. });
  51670. //let outlineMaterial = new THREE.MeshBasicMaterial({
  51671. // color: 0x000000,
  51672. // side: THREE.BackSide,
  51673. // opacity: 0,
  51674. // transparent: true});
  51675. let pickMaterial = new MeshNormalMaterial({
  51676. //opacity: 0,
  51677. transparent: true,
  51678. visible: this.showPickVolumes});
  51679. let box = new Mesh(sgPlane, material);
  51680. box.name = `${handleName}.handle`;
  51681. box.scale.set(1.5, 1.5, 1.5);
  51682. box.position.set(0, 0, 0);
  51683. box.visible = false;
  51684. node.add(box);
  51685. //handle.focusNode = box;
  51686. //let outline = new THREE.Mesh(sgPlane, outlineMaterial);
  51687. //outline.scale.set(1.4, 1.4, 1.4);
  51688. //outline.name = `${handleName}.outline`;
  51689. //box.add(outline);
  51690. let pickSphere = new Mesh(sgLowPolySphere, pickMaterial);
  51691. pickSphere.name = `${handleName}.pick_volume`;
  51692. pickSphere.scale.set(2, 2, 2);
  51693. box.add(pickSphere);
  51694. pickSphere.handle = handleName;
  51695. this.pickVolumes.push(pickSphere);
  51696. node.setOpacity = (target) => {
  51697. let opacity = {x: material.opacity};
  51698. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  51699. t.onUpdate(() => {
  51700. pickSphere.visible = opacity.x > 0;
  51701. box.visible = opacity.x > 0;
  51702. material.opacity = opacity.x;
  51703. //outlineMaterial.opacity = opacity.x;
  51704. pickSphere.material.opacity = opacity.x * 0.5;
  51705. });
  51706. t.start();
  51707. };
  51708. //pickSphere.addEventListener("drag", e => {});
  51709. pickSphere.addEventListener("mouseup", e => {
  51710. e.consume();
  51711. });
  51712. pickSphere.addEventListener("mousedown", e => {
  51713. e.consume();
  51714. });
  51715. pickSphere.addEventListener("click", e => {
  51716. e.consume();
  51717. let selected = this.selection[0];
  51718. let maxScale = Math.max(...selected.scale.toArray());
  51719. let minScale = Math.min(...selected.scale.toArray());
  51720. let handleLength = Math.abs(selected.scale.dot(new Vector3(...handle.alignment)));
  51721. let alignment = new Vector3(...handle.alignment).multiplyScalar(2 * maxScale / handleLength);
  51722. alignment.applyMatrix4(selected.matrixWorld);
  51723. let newCamPos = alignment;
  51724. let newCamTarget = selected.getWorldPosition(new Vector3());
  51725. Utils.moveTo(this.viewer.scene, newCamPos, newCamTarget);
  51726. });
  51727. pickSphere.addEventListener("mouseover", e => {
  51728. //box.setOpacity(1);
  51729. });
  51730. pickSphere.addEventListener("mouseleave", e => {
  51731. //box.setOpacity(OpaWhenNotSelect);
  51732. });
  51733. }
  51734. }
  51735. initializeTranslationHandles(){
  51736. let boxGeometry = new BoxGeometry(1, 1, 1);
  51737. for(let handleName of Object.keys(this.translationHandles)){
  51738. let handle = this.handles[handleName];
  51739. let node = handle.node;
  51740. this.scene.add(node);
  51741. let material = new MeshBasicMaterial({
  51742. color: handle.color,
  51743. opacity: OpaWhenNotSelect,
  51744. transparent: true});
  51745. let outlineMaterial = new MeshBasicMaterial({
  51746. color: OutlineColor,
  51747. side: BackSide,
  51748. opacity: OpaWhenNotSelect,
  51749. transparent: true});
  51750. let pickMaterial = new MeshNormalMaterial({
  51751. opacity: 0.2,
  51752. transparent: true,
  51753. visible: this.showPickVolumes
  51754. });
  51755. let box = new Mesh(boxGeometry, material);
  51756. box.name = `${handleName}.handle`;
  51757. box.scale.set(1, 1, 36);
  51758. box.lookAt(new Vector3(...handle.alignment));
  51759. box.renderOrder = 10;
  51760. node.add(box);
  51761. handle.translateNode = box;
  51762. let outline = new Mesh(boxGeometry, outlineMaterial);
  51763. outline.name = `${handleName}.outline`;
  51764. outline.scale.set(1.3, 1.3, 1.01);
  51765. outline.renderOrder = 0;
  51766. box.add(outline);
  51767. let pickVolume = new Mesh(boxGeometry, pickMaterial);
  51768. pickVolume.name = `${handleName}.pick_volume`;
  51769. pickVolume.scale.set(4, 4, 1.1);
  51770. pickVolume.handle = handleName;
  51771. box.add(pickVolume);
  51772. this.pickVolumes.push(pickVolume);
  51773. node.setOpacity = (target) => {
  51774. let opacity = {x: material.opacity};
  51775. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  51776. t.onUpdate(() => {
  51777. box.visible = opacity.x > 0;
  51778. pickVolume.visible = opacity.x > 0;
  51779. material.opacity = opacity.x;
  51780. outlineMaterial.opacity = opacity.x;
  51781. pickMaterial.opacity = opacity.x * 0.5;
  51782. });
  51783. t.start();
  51784. };
  51785. pickVolume.addEventListener("drag", (e) => {this.dragTranslationHandle(e);});
  51786. pickVolume.addEventListener("drop", (e) => {this.dropTranslationHandle(e);});
  51787. }
  51788. }
  51789. initializeRotationHandles(){
  51790. let adjust = 1.5;
  51791. let torusGeometry = new TorusGeometry(1, adjust * 0.015, 8, 64, Math.PI / 2);
  51792. let outlineGeometry = new TorusGeometry(1, adjust * 0.018, 8, 64, Math.PI / 2);
  51793. let pickGeometry = new TorusGeometry(1, adjust * 0.04, 6, 4, Math.PI / 2);
  51794. for(let handleName of Object.keys(this.rotationHandles)){
  51795. let handle = this.handles[handleName];
  51796. let node = handle.node;
  51797. this.scene.add(node);
  51798. let material = new MeshBasicMaterial({
  51799. color: handle.color,
  51800. opacity: OpaWhenNotSelect,
  51801. transparent: true
  51802. });
  51803. let outlineMaterial = new MeshBasicMaterial({
  51804. color: OutlineColor,
  51805. side: BackSide,
  51806. opacity: OpaWhenNotSelect,
  51807. transparent: true
  51808. });
  51809. let pickMaterial = new MeshNormalMaterial({
  51810. opacity: 0.2,
  51811. transparent: true,
  51812. visible: this.showPickVolumes
  51813. });
  51814. let box = new Mesh(torusGeometry, material);
  51815. box.name = `${handleName}.handle`;
  51816. box.scale.set(30, 30, 30);
  51817. box.lookAt(new Vector3(...handle.alignment));
  51818. node.add(box);
  51819. handle.translateNode = box;
  51820. let outline = new Mesh(outlineGeometry, outlineMaterial);
  51821. outline.name = `${handleName}.outline`;
  51822. outline.scale.set(1, 1, 1);
  51823. outline.renderOrder = 0;
  51824. box.add(outline);
  51825. let pickVolume = new Mesh(pickGeometry, pickMaterial);
  51826. pickVolume.name = `${handleName}.pick_volume`;
  51827. pickVolume.scale.set(1, 1, 1);
  51828. pickVolume.handle = handleName;
  51829. box.add(pickVolume);
  51830. this.pickVolumes.push(pickVolume);
  51831. node.setOpacity = (target) => {
  51832. let opacity = {x: material.opacity};
  51833. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  51834. t.onUpdate(() => {
  51835. box.visible = opacity.x > 0;
  51836. pickVolume.visible = opacity.x > 0;
  51837. material.opacity = opacity.x;
  51838. outlineMaterial.opacity = opacity.x;
  51839. pickMaterial.opacity = opacity.x * 0.5;
  51840. });
  51841. t.start();
  51842. };
  51843. //pickVolume.addEventListener("mouseover", (e) => {
  51844. // //let a = this.viewer.scene.getActiveCamera().getWorldDirection(new THREE.Vector3()).dot(pickVolume.getWorldDirection(new THREE.Vector3()));
  51845. // console.log(pickVolume.getWorldDirection(new THREE.Vector3()));
  51846. //});
  51847. pickVolume.addEventListener("drag", (e) => {this.dragRotationHandle(e);});
  51848. pickVolume.addEventListener("drop", (e) => {this.dropRotationHandle(e);});
  51849. }
  51850. }
  51851. dragRotationHandle(e){
  51852. let drag = e.drag;
  51853. let handle = this.activeHandle;
  51854. let camera = this.viewer.scene.getActiveCamera();
  51855. if(!handle){
  51856. return
  51857. };
  51858. let localNormal = new Vector3(...handle.alignment);
  51859. let n = new Vector3();
  51860. n.copy(new Vector4(...localNormal.toArray(), 0).applyMatrix4(handle.node.matrixWorld));
  51861. n.normalize();
  51862. if (!drag.intersectionStart){
  51863. //this.viewer.scene.scene.remove(this.debug);
  51864. //this.debug = new THREE.Object3D();
  51865. //this.viewer.scene.scene.add(this.debug);
  51866. //Utils.debugSphere(this.debug, drag.location, 3, 0xaaaaaa);
  51867. //let debugEnd = drag.location.clone().add(n.clone().multiplyScalar(20));
  51868. //Utils.debugLine(this.debug, drag.location, debugEnd, 0xff0000);
  51869. drag.intersectionStart = drag.location;
  51870. drag.objectStart = drag.object.getWorldPosition(new Vector3());
  51871. drag.handle = handle;
  51872. let plane = new Plane().setFromNormalAndCoplanarPoint(n, drag.intersectionStart);
  51873. drag.dragPlane = plane;
  51874. drag.pivot = drag.intersectionStart;
  51875. }else {
  51876. handle = drag.handle;
  51877. }
  51878. this.dragging = true;
  51879. let pointer = this.viewer.inputHandler.pointer;
  51880. let domElement = this.viewer.renderer.domElement;
  51881. let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
  51882. let I = ray.intersectPlane(drag.dragPlane, new Vector3());
  51883. if (I) {
  51884. let center = this.scene.getWorldPosition(new Vector3());
  51885. let from = drag.pivot;
  51886. let to = I;
  51887. let v1 = from.clone().sub(center).normalize();
  51888. let v2 = to.clone().sub(center).normalize();
  51889. let angle = Math.acos(v1.dot(v2));
  51890. let sign = Math.sign(v1.cross(v2).dot(n));
  51891. angle = angle * sign;
  51892. if (Number.isNaN(angle)) {
  51893. return;
  51894. }
  51895. let normal = new Vector3(...handle.alignment);
  51896. for (let selection of this.selection) {
  51897. selection.rotateOnAxis(normal, angle);
  51898. selection.dispatchEvent({
  51899. type: "orientation_changed",
  51900. object: selection
  51901. });
  51902. }
  51903. drag.pivot = I;
  51904. }
  51905. }
  51906. dropRotationHandle(e){
  51907. this.dragging = false;
  51908. this.setActiveHandle(null);
  51909. }
  51910. dragTranslationHandle(e){
  51911. let drag = e.drag;
  51912. let handle = this.activeHandle;
  51913. let camera = this.viewer.scene.getActiveCamera();
  51914. if(!drag.intersectionStart && handle){
  51915. drag.intersectionStart = drag.location;
  51916. drag.objectStart = drag.object.getWorldPosition(new Vector3());
  51917. let start = drag.intersectionStart;
  51918. let dir = new Vector4(...handle.alignment, 0).applyMatrix4(this.scene.matrixWorld);
  51919. let end = new Vector3().addVectors(start, dir);
  51920. let line = new Line3(start.clone(), end.clone());
  51921. drag.line = line;
  51922. let camOnLine = line.closestPointToPoint(camera.position, false, new Vector3());
  51923. let normal = new Vector3().subVectors(camera.position, camOnLine);
  51924. let plane = new Plane().setFromNormalAndCoplanarPoint(normal, drag.intersectionStart);
  51925. drag.dragPlane = plane;
  51926. drag.pivot = drag.intersectionStart;
  51927. }else {
  51928. handle = drag.handle;
  51929. }
  51930. this.dragging = true;
  51931. {
  51932. let pointer = this.viewer.inputHandler.pointer;
  51933. let domElement = this.viewer.renderer.domElement;
  51934. let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
  51935. let I = ray.intersectPlane(drag.dragPlane, new Vector3());
  51936. if (I) {
  51937. let iOnLine = drag.line.closestPointToPoint(I, false, new Vector3());
  51938. let diff = new Vector3().subVectors(iOnLine, drag.pivot);
  51939. for (let selection of this.selection) {
  51940. selection.position.add(diff);
  51941. selection.dispatchEvent({
  51942. type: "position_changed",
  51943. object: selection
  51944. });
  51945. }
  51946. drag.pivot = drag.pivot.add(diff);
  51947. }
  51948. }
  51949. }
  51950. dropTranslationHandle(e){
  51951. this.dragging = false;
  51952. this.setActiveHandle(null);
  51953. }
  51954. dropScaleHandle(e){
  51955. this.dragging = false;
  51956. this.setActiveHandle(null);
  51957. }
  51958. dragScaleHandle(e){
  51959. let drag = e.drag;
  51960. let handle = this.activeHandle;
  51961. let camera = this.viewer.scene.getActiveCamera();
  51962. if(!drag.intersectionStart){
  51963. drag.intersectionStart = drag.location;
  51964. drag.objectStart = drag.object.getWorldPosition(new Vector3());
  51965. drag.handle = handle;
  51966. let start = drag.intersectionStart;
  51967. let dir = new Vector4(...handle.alignment, 0).applyMatrix4(this.scene.matrixWorld);
  51968. let end = new Vector3().addVectors(start, dir);
  51969. let line = new Line3(start.clone(), end.clone());
  51970. drag.line = line;
  51971. let camOnLine = line.closestPointToPoint(camera.position, false, new Vector3());
  51972. let normal = new Vector3().subVectors(camera.position, camOnLine);
  51973. let plane = new Plane().setFromNormalAndCoplanarPoint(normal, drag.intersectionStart);
  51974. drag.dragPlane = plane;
  51975. drag.pivot = drag.intersectionStart;
  51976. //Utils.debugSphere(viewer.scene.scene, drag.pivot, 0.05);
  51977. }else {
  51978. handle = drag.handle;
  51979. }
  51980. this.dragging = true;
  51981. {
  51982. let pointer = this.viewer.inputHandler.pointer;
  51983. let domElement = this.viewer.renderer.domElement;
  51984. let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
  51985. let I = ray.intersectPlane(drag.dragPlane, new Vector3());
  51986. if (I) {
  51987. let iOnLine = drag.line.closestPointToPoint(I, false, new Vector3());
  51988. let direction = handle.alignment.reduce( (a, v) => a + v, 0);
  51989. let toObjectSpace = this.selection[0].matrixWorld.clone().invert();
  51990. let iOnLineOS = iOnLine.clone().applyMatrix4(toObjectSpace);
  51991. let pivotOS = drag.pivot.clone().applyMatrix4(toObjectSpace);
  51992. let diffOS = new Vector3().subVectors(iOnLineOS, pivotOS);
  51993. let dragDirectionOS = diffOS.clone().normalize();
  51994. if(iOnLine.distanceTo(drag.pivot) === 0){
  51995. dragDirectionOS.set(0, 0, 0);
  51996. }
  51997. let dragDirection = dragDirectionOS.dot(new Vector3(...handle.alignment));
  51998. let diff = new Vector3().subVectors(iOnLine, drag.pivot);
  51999. let diffScale = new Vector3(...handle.alignment).multiplyScalar(diff.length() * direction * dragDirection);
  52000. let diffPosition = diff.clone().multiplyScalar(0.5);
  52001. for (let selection of this.selection) {
  52002. //xzw 改:否则不跟手
  52003. let diffScale_ = diffScale.clone().divide(selection.boundingBox.getSize(new Vector3));
  52004. selection.scale.add(diffScale_);
  52005. //selection.scale.add(diffScale);
  52006. selection.scale.x = Math.max(0.1, selection.scale.x);
  52007. selection.scale.y = Math.max(0.1, selection.scale.y);
  52008. selection.scale.z = Math.max(0.1, selection.scale.z);
  52009. selection.position.add(diffPosition);
  52010. selection.dispatchEvent({
  52011. type: "position_changed",
  52012. object: selection
  52013. });
  52014. selection.dispatchEvent({
  52015. type: "scale_changed",
  52016. object: selection
  52017. });
  52018. }
  52019. drag.pivot.copy(iOnLine);
  52020. //Utils.debugSphere(viewer.scene.scene, drag.pivot, 0.05);
  52021. }
  52022. }
  52023. }
  52024. setActiveHandle(handle){
  52025. if(this.dragging){
  52026. return;
  52027. }
  52028. if(this.activeHandle === handle){
  52029. return;
  52030. }
  52031. this.activeHandle = handle;
  52032. if(handle === null){
  52033. for(let handleName of Object.keys(this.handles)){
  52034. let handle = this.handles[handleName];
  52035. handle.node.setOpacity(0);
  52036. }
  52037. }
  52038. if(!hideFocusHandles){
  52039. for(let handleName of Object.keys(this.focusHandles)){
  52040. let handle = this.focusHandles[handleName];
  52041. if(this.activeHandle === handle){
  52042. handle.node.setOpacity(1.0);
  52043. }else {
  52044. handle.node.setOpacity(OpaWhenNotSelect);
  52045. }
  52046. }
  52047. }
  52048. for(let handleName of Object.keys(this.translationHandles)){
  52049. let handle = this.translationHandles[handleName];
  52050. if(this.activeHandle === handle){
  52051. handle.node.setOpacity(1.0);
  52052. }else {
  52053. handle.node.setOpacity(OpaWhenNotSelect);
  52054. }
  52055. }
  52056. for(let handleName of Object.keys(this.rotationHandles)){
  52057. let handle = this.rotationHandles[handleName];
  52058. //if(this.activeHandle === handle){
  52059. // handle.node.setOpacity(1.0);
  52060. //}else{
  52061. // handle.node.setOpacity(OpaWhenNotSelect)
  52062. //}
  52063. handle.node.setOpacity(OpaWhenNotSelect);
  52064. }
  52065. for(let handleName of Object.keys(this.scaleHandles)){
  52066. let handle = this.scaleHandles[handleName];
  52067. if(this.activeHandle === handle){
  52068. handle.node.setOpacity(1.0);
  52069. if(!hideFocusHandles){
  52070. let relatedFocusHandle = this.focusHandles[handle.name.replace("scale", "focus")];
  52071. let relatedFocusNode = relatedFocusHandle.node;
  52072. relatedFocusNode.setOpacity(OpaWhenNotSelect);
  52073. }
  52074. for(let translationHandleName of Object.keys(this.translationHandles)){
  52075. let translationHandle = this.translationHandles[translationHandleName];
  52076. translationHandle.node.setOpacity(OpaWhenNotSelect);
  52077. }
  52078. //let relatedTranslationHandle = this.translationHandles[
  52079. // handle.name.replace("scale", "translation").replace(/[+-]/g, "")];
  52080. //let relatedTranslationNode = relatedTranslationHandle.node;
  52081. //relatedTranslationNode.setOpacity(OpaWhenNotSelect);
  52082. }else {
  52083. handle.node.setOpacity(OpaWhenNotSelect);
  52084. }
  52085. }
  52086. if(handle){
  52087. handle.node.setOpacity(1.0);
  52088. }
  52089. }
  52090. update () {
  52091. if(this.selection.length === 1){
  52092. this.scene.visible = true;
  52093. this.scene.updateMatrix();
  52094. this.scene.updateMatrixWorld();
  52095. let selected = this.selection[0];
  52096. let world = selected.matrixWorld;
  52097. let camera = this.viewer.scene.getActiveCamera();
  52098. let domElement = this.viewer.renderer.domElement;
  52099. let pointer = this.viewer.inputHandler.pointer;
  52100. let center = selected.boundingBox.getCenter(new Vector3()).clone().applyMatrix4(selected.matrixWorld);
  52101. this.scene.scale.copy(selected.boundingBox.getSize(new Vector3()).multiply(selected.scale));
  52102. this.scene.position.copy(center);
  52103. this.scene.rotation.copy(selected.rotation);
  52104. this.scene.updateMatrixWorld();
  52105. {
  52106. // adjust rotation handles
  52107. if(!this.dragging){
  52108. let tWorld = this.scene.matrixWorld;
  52109. let tObject = tWorld.clone().invert();
  52110. let camObjectPos = camera.getWorldPosition(new Vector3()).applyMatrix4(tObject);
  52111. let x = this.rotationHandles["rotation.x"].node.rotation;
  52112. let y = this.rotationHandles["rotation.y"].node.rotation;
  52113. let z = this.rotationHandles["rotation.z"].node.rotation;
  52114. x.order = "ZYX";
  52115. y.order = "ZYX";
  52116. let above = camObjectPos.z > 0;
  52117. let below = !above;
  52118. let PI_HALF = Math.PI / 2;
  52119. if(above){
  52120. if(camObjectPos.x > 0 && camObjectPos.y > 0){
  52121. x.x = 1 * PI_HALF;
  52122. y.y = 3 * PI_HALF;
  52123. z.z = 0 * PI_HALF;
  52124. }else if(camObjectPos.x < 0 && camObjectPos.y > 0){
  52125. x.x = 1 * PI_HALF;
  52126. y.y = 2 * PI_HALF;
  52127. z.z = 1 * PI_HALF;
  52128. }else if(camObjectPos.x < 0 && camObjectPos.y < 0){
  52129. x.x = 2 * PI_HALF;
  52130. y.y = 2 * PI_HALF;
  52131. z.z = 2 * PI_HALF;
  52132. }else if(camObjectPos.x > 0 && camObjectPos.y < 0){
  52133. x.x = 2 * PI_HALF;
  52134. y.y = 3 * PI_HALF;
  52135. z.z = 3 * PI_HALF;
  52136. }
  52137. }else if(below){
  52138. if(camObjectPos.x > 0 && camObjectPos.y > 0){
  52139. x.x = 0 * PI_HALF;
  52140. y.y = 0 * PI_HALF;
  52141. z.z = 0 * PI_HALF;
  52142. }else if(camObjectPos.x < 0 && camObjectPos.y > 0){
  52143. x.x = 0 * PI_HALF;
  52144. y.y = 1 * PI_HALF;
  52145. z.z = 1 * PI_HALF;
  52146. }else if(camObjectPos.x < 0 && camObjectPos.y < 0){
  52147. x.x = 3 * PI_HALF;
  52148. y.y = 1 * PI_HALF;
  52149. z.z = 2 * PI_HALF;
  52150. }else if(camObjectPos.x > 0 && camObjectPos.y < 0){
  52151. x.x = 3 * PI_HALF;
  52152. y.y = 0 * PI_HALF;
  52153. z.z = 3 * PI_HALF;
  52154. }
  52155. }
  52156. }
  52157. // adjust scale of components
  52158. for(let handleName of Object.keys(this.handles)){
  52159. let handle = this.handles[handleName];
  52160. let node = handle.node;
  52161. let handlePos = node.getWorldPosition(new Vector3());
  52162. let distance = handlePos.distanceTo(camera.position);
  52163. let pr = Utils.projectedRadius(1, camera, distance, domElement.clientWidth, domElement.clientHeight);
  52164. let ws = node.parent.getWorldScale(new Vector3());
  52165. let s = (ScaleRatio / pr);
  52166. let scale = new Vector3(s, s, s).divide(ws);
  52167. let rot = new Matrix4().makeRotationFromEuler(node.rotation); //需要使用到旋转,所以我把设置scale的移到旋转后了,否则在视图上下旋转的分界线处rotateHandel会被拉长从而闪烁。
  52168. let rotInv = rot.clone().invert();
  52169. scale.applyMatrix4(rotInv);
  52170. scale.x = Math.abs(scale.x);
  52171. scale.y = Math.abs(scale.y);
  52172. scale.z = Math.abs(scale.z);
  52173. node.scale.copy(scale);
  52174. }
  52175. {
  52176. let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
  52177. let raycaster = new Raycaster(ray.origin, ray.direction);
  52178. raycaster.layers.enableAll();//add
  52179. let intersects = raycaster.intersectObjects(this.pickVolumes.filter(v => v.visible), true);
  52180. if(intersects.length > 0){
  52181. let I = intersects[0];
  52182. let handleName = I.object.handle;
  52183. this.setActiveHandle(this.handles[handleName]);
  52184. }else {
  52185. this.setActiveHandle(null);
  52186. }
  52187. }
  52188. //
  52189. for(let handleName of Object.keys(this.scaleHandles)){
  52190. let handle = this.handles[handleName];
  52191. let node = handle.node;
  52192. let alignment = handle.alignment;
  52193. }
  52194. }
  52195. }else {
  52196. this.scene.visible = false;
  52197. }
  52198. }
  52199. };
  52200. /*
  52201. note:
  52202. transformationTool.scene会跟随选中物体,其scale就是boundingbox的大小。因此transformationTool.frame这个框也会跟着缩放
  52203. */
  52204. class VolumeTool extends EventDispatcher{
  52205. constructor (viewer) {
  52206. super();
  52207. this.viewer = viewer;
  52208. this.renderer = viewer.renderer;
  52209. this.addEventListener('start_inserting_volume', e => {
  52210. this.viewer.dispatchEvent({
  52211. type: 'cancel_insertions'
  52212. });
  52213. });
  52214. this.scene = new Scene();
  52215. this.scene.name = 'scene_volume';
  52216. this.viewer.inputHandler.registerInteractiveScene(this.scene);
  52217. this.onRemove = e => {
  52218. this.scene.remove(e.volume);
  52219. };
  52220. this.onAdd = e => {
  52221. this.scene.add(e.volume);
  52222. };
  52223. for(let volume of viewer.scene.volumes){
  52224. this.onAdd({volume: volume});
  52225. }
  52226. this.viewer.inputHandler.addEventListener('delete', e => {
  52227. let volumes = e.selection.filter(e => (e instanceof Volume));
  52228. volumes.forEach(e => this.viewer.scene.removeVolume(e));
  52229. });
  52230. viewer.addEventListener("update", this.update.bind(this));
  52231. viewer.addEventListener("render.pass.scene", e => this.render(e));
  52232. viewer.addEventListener("scene_changed", this.onSceneChange.bind(this));
  52233. viewer.scene.addEventListener('volume_added', this.onAdd);
  52234. viewer.scene.addEventListener('volume_removed', this.onRemove);
  52235. }
  52236. onSceneChange(e){
  52237. if(e.oldScene){
  52238. e.oldScene.removeEventListeners('volume_added', this.onAdd);
  52239. e.oldScene.removeEventListeners('volume_removed', this.onRemove);
  52240. }
  52241. e.scene.addEventListener('volume_added', this.onAdd);
  52242. e.scene.addEventListener('volume_removed', this.onRemove);
  52243. }
  52244. startInsertion (args = {}) {
  52245. let volume;
  52246. if(args.type){
  52247. volume = new args.type();
  52248. }else {
  52249. volume = new BoxVolume();
  52250. }
  52251. volume.clip = args.clip || false;
  52252. volume.name = args.name || 'Volume';
  52253. this.dispatchEvent({
  52254. type: 'start_inserting_volume',
  52255. volume: volume
  52256. });
  52257. this.viewer.scene.addVolume(volume);
  52258. //this.scene.add(volume);
  52259. let cancel = {
  52260. callback: null
  52261. };
  52262. let drag = e => {
  52263. let camera = this.viewer.scene.getActiveCamera();
  52264. var I = e.intersectPoint;
  52265. if (I) {
  52266. volume.position.copy(I.location);
  52267. let wp = volume.getWorldPosition(new Vector3()).applyMatrix4(camera.matrixWorldInverse);
  52268. // let pp = new THREE.Vector4(wp.x, wp.y, wp.z).applyMatrix4(camera.projectionMatrix);
  52269. let w = Math.abs((wp.z / 5));
  52270. volume.scale.set(w, w, w);
  52271. }
  52272. };
  52273. let drop = e => {
  52274. volume.removeEventListener('drag', drag);
  52275. volume.removeEventListener('drop', drop);
  52276. cancel.callback();
  52277. };
  52278. cancel.callback = e => {
  52279. volume.removeEventListener('drag', drag);
  52280. volume.removeEventListener('drop', drop);
  52281. this.viewer.removeEventListener('cancel_insertions', cancel.callback);
  52282. };
  52283. volume.addEventListener('drag', drag);
  52284. volume.addEventListener('drop', drop);
  52285. this.viewer.addEventListener('cancel_insertions', cancel.callback);
  52286. this.viewer.inputHandler.startDragging(volume);
  52287. return volume;
  52288. }
  52289. update(){
  52290. if (!this.viewer.scene) {
  52291. return;
  52292. }
  52293. let camera = this.viewer.scene.getActiveCamera();
  52294. let renderAreaSize = this.viewer.renderer.getSize(new Vector2$1());
  52295. let clientWidth = renderAreaSize.width;
  52296. let clientHeight = renderAreaSize.height;
  52297. let volumes = this.viewer.scene.volumes;
  52298. for (let volume of volumes) {
  52299. }
  52300. }
  52301. render(params){
  52302. const renderer = this.viewer.renderer;
  52303. const oldTarget = renderer.getRenderTarget();
  52304. if(params.renderTarget){
  52305. renderer.setRenderTarget(params.renderTarget);
  52306. }
  52307. renderer.render(this.scene, this.viewer.scene.getActiveCamera());
  52308. renderer.setRenderTarget(oldTarget);
  52309. }
  52310. }
  52311. class Compass{
  52312. constructor(viewer){
  52313. this.viewer = viewer;
  52314. this.visible = false;
  52315. this.dom = this.createElement();
  52316. viewer.addEventListener("update", () => {
  52317. const direction = viewer.scene.view.direction.clone();
  52318. direction.z = 0;
  52319. direction.normalize();
  52320. const camera = viewer.scene.getActiveCamera();
  52321. const p1 = camera.getWorldPosition(new Vector3());
  52322. const p2 = p1.clone().add(direction);
  52323. const projection = viewer.getProjection();
  52324. const azimuth = Utils.computeAzimuth(p1, p2, projection);
  52325. this.dom.css("transform", `rotateZ(${-azimuth}rad)`);
  52326. });
  52327. this.dom.click( () => {
  52328. viewer.setTopView();
  52329. });
  52330. const renderArea = $(viewer.renderArea);
  52331. renderArea.append(this.dom);
  52332. this.setVisible(this.visible);
  52333. }
  52334. setVisible(visible){
  52335. this.visible = visible;
  52336. const value = visible ? "" : "none";
  52337. this.dom.css("display", value);
  52338. }
  52339. isVisible(){
  52340. return this.visible;
  52341. }
  52342. createElement(){
  52343. const style = `style="position: absolute; top: 10px; right: 10px; z-index: 10000; width: 64px;"`;
  52344. const img = $(`<img src="${Potree.resourcePath}/images/compas.svg" ${style} />`);
  52345. return img;
  52346. }
  52347. };
  52348. class PotreeRenderer {
  52349. constructor (viewer) {
  52350. this.viewer = viewer;
  52351. this.renderer = viewer.renderer;
  52352. {
  52353. let dummyScene = new Scene();
  52354. let geometry = new SphereGeometry(0.001, 2, 2);
  52355. let mesh = new Mesh(geometry, new MeshBasicMaterial());
  52356. mesh.position.set(36453, 35163, 764712);
  52357. dummyScene.add(mesh);
  52358. this.dummyMesh = mesh;
  52359. this.dummyScene = dummyScene;
  52360. }
  52361. }
  52362. clearTargets(params){//add
  52363. const viewer = this.viewer;
  52364. const {renderer} = viewer;
  52365. const oldTarget = renderer.getRenderTarget();
  52366. if(params.target){//add
  52367. renderer.setRenderTarget( params.target);
  52368. renderer.clear();
  52369. }
  52370. if(params.rtEDL){
  52371. renderer.setRenderTarget( params.rtEDL);
  52372. renderer.clear();
  52373. }else {
  52374. renderer.setRenderTarget( this.rtEDL );
  52375. renderer.clear( true, true, true );
  52376. }
  52377. /* renderer.setRenderTarget( this.rtRegular );
  52378. renderer.clear( true, true, false ); */
  52379. renderer.setRenderTarget(oldTarget);
  52380. }
  52381. clear(params={}){
  52382. let {viewer, renderer} = this;
  52383. // render skybox
  52384. if(viewer.background === "skybox"){
  52385. renderer.setClearColor(0xff0000, 1);
  52386. }else if(viewer.background === "gradient"){
  52387. renderer.setClearColor(0x00ff00, 1);
  52388. }else if(viewer.background === "black"){
  52389. renderer.setClearColor(0x000000, 1);
  52390. }else if(viewer.background === "white"){
  52391. renderer.setClearColor(0xFFFFFF, 1);
  52392. }else {
  52393. renderer.setClearColor(0x000000, 0);
  52394. }
  52395. params.target || renderer.clear();
  52396. renderer.clear();
  52397. this.clearTargets(params);
  52398. }
  52399. render(params={}){
  52400. let {viewer, renderer} = this;
  52401. const camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
  52402. viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
  52403. const renderAreaSize = renderer.getSize(new Vector2$1());
  52404. const width = params.width ? params.width : params.viewport ? params.viewport[2] : renderAreaSize.x;
  52405. const height = params.height ? params.height : params.viewport ? params.viewport[3] : renderAreaSize.y;
  52406. // render skybox
  52407. if(viewer.background === "skybox"){
  52408. viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
  52409. viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
  52410. viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
  52411. viewer.skybox.parent.rotation.x = 0;
  52412. viewer.skybox.parent.updateMatrixWorld();
  52413. viewer.skybox.camera.updateProjectionMatrix();
  52414. renderer.render(viewer.skybox.scene, viewer.skybox.camera);
  52415. }else if(viewer.background === "gradient"){
  52416. if(params.target){//add
  52417. renderer.setRenderTarget(params.target);
  52418. renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
  52419. renderer.setRenderTarget(null);
  52420. }else {
  52421. renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
  52422. }
  52423. }
  52424. for(let pointcloud of this.viewer.scene.pointclouds){
  52425. const {material} = pointcloud;
  52426. material.useEDL = false;
  52427. }
  52428. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, params.target || null, {
  52429. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof Potree.SphereVolume)),
  52430. });
  52431. // render scene
  52432. viewer.dispatchEvent({type: "render.pass.scene",viewer: viewer});
  52433. renderer.setRenderTarget(params.target ? params.target : null);//add
  52434. renderer.render(viewer.scene.scene, camera);
  52435. renderer.render(viewer.scene.sceneOverlay, camera);// add 透明贴图层
  52436. renderer.clearDepth();
  52437. viewer.transformationTool.update();
  52438. if(!params.target){
  52439. //测量线
  52440. viewer.dispatchEvent({type: "render.pass.perspective_overlay", viewer: viewer, camera});
  52441. viewer.renderer.render(viewer.overlay, camera);//从 viewer.renderDefault搬过来,为了reticule不遮住测量线
  52442. }
  52443. viewer.clippingTool.update();
  52444. renderer.render(viewer.clippingTool.sceneMarker, viewer.scene.cameraScreenSpace); //viewer.scene.cameraScreenSpace);
  52445. renderer.render(viewer.clippingTool.sceneVolume, camera);
  52446. renderer.render(viewer.controls.sceneControls, camera);
  52447. viewer.renderer.render(viewer.transformationTool.scene, camera);
  52448. //viewer.renderer.render(viewer.transformationTool.scene, camera);
  52449. // renderer.render(viewer.controls.sceneControls, camera);
  52450. // renderer.render(viewer.clippingTool.sceneVolume, camera);
  52451. // renderer.render(viewer.transformationTool.scene, camera);
  52452. // renderer.setViewport(width - viewer.navigationCube.width,
  52453. // height - viewer.navigationCube.width,
  52454. // viewer.navigationCube.width, viewer.navigationCube.width);
  52455. // renderer.render(viewer.navigationCube, viewer.navigationCube.camera);
  52456. // renderer.setViewport(0, 0, width, height);
  52457. viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
  52458. }
  52459. }
  52460. const copyShader = {
  52461. uniforms: {
  52462. tDiffuse: {
  52463. type: "t",
  52464. value: null
  52465. },
  52466. opacity: {
  52467. type: "f",
  52468. value: 1
  52469. }
  52470. },
  52471. vertexShader: `
  52472. varying vec2 vUv;
  52473. void main() {
  52474. vUv = uv;
  52475. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  52476. }
  52477. `,
  52478. fragmentShader: `
  52479. uniform float opacity;
  52480. uniform sampler2D tDiffuse;
  52481. varying vec2 vUv;
  52482. void main() {
  52483. vec4 texel = texture2D( tDiffuse, vUv );
  52484. gl_FragColor = opacity * texel;
  52485. }
  52486. `
  52487. };
  52488. class EDLRenderer{//Eye-Dome Lighting 眼罩照明
  52489. constructor(viewer){
  52490. this.viewer = viewer;
  52491. this.edlMaterial = null;
  52492. //this.rtRegular;
  52493. this.rtEDLs = new Map;
  52494. this.gl = viewer.renderer.getContext();
  52495. //反正也没用到,注释了:
  52496. //this.shadowMap = new PointCloudSM(this.viewer.pRenderer);
  52497. viewer.addEventListener('resize',this.resize.bind(this));
  52498. this.initEDL(viewer);
  52499. }
  52500. initEDL(viewer){
  52501. if (this.edlMaterial != null) {
  52502. return;
  52503. }
  52504. this.edlMaterial = new EyeDomeLightingMaterial();
  52505. this.edlMaterial.depthTest = true;
  52506. this.edlMaterial.depthWrite = true;
  52507. this.edlMaterial.transparent = true;
  52508. /* this.rtRegular = new THREE.WebGLRenderTarget(viewer.mainViewport.resolution2.x, viewer.mainViewport.resolution2.y, {
  52509. minFilter: THREE.NearestFilter,
  52510. magFilter: THREE.NearestFilter,
  52511. format: THREE.RGBAFormat,
  52512. depthTexture: new THREE.DepthTexture(undefined, undefined, THREE.UnsignedIntType)
  52513. });
  52514. */
  52515. /* let copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
  52516. this.copyMaterial = new THREE.ShaderMaterial( {
  52517. uniforms: copyUniforms,
  52518. vertexShader: copyShader.vertexShader,
  52519. fragmentShader: copyShader.fragmentShader,
  52520. //premultipliedAlpha: true,
  52521. transparent: true,
  52522. //blending: THREE.AdditiveBlending,
  52523. depthTest: false,
  52524. depthWrite: false
  52525. }); */
  52526. };
  52527. resize(e ){
  52528. if(Features.EXT_DEPTH.isSupported()){
  52529. let viewport = e.viewport;
  52530. this.getRtEDL(viewport).setSize(viewport.resolution2.x, viewport.resolution2.y);
  52531. }
  52532. }
  52533. clearTargets(params={}){
  52534. const viewer = this.viewer;
  52535. const {renderer} = viewer;
  52536. const oldTarget = renderer.getRenderTarget();
  52537. if(params.target){//add
  52538. renderer.setRenderTarget( params.target);
  52539. renderer.clear();
  52540. }
  52541. if(Features.EXT_DEPTH.isSupported()){
  52542. if(params.rtEDL){
  52543. renderer.setRenderTarget( params.rtEDL);
  52544. renderer.clear();
  52545. }else {
  52546. var rtEDL = this.getRtEDL(params.viewport);
  52547. if(rtEDL){
  52548. renderer.setRenderTarget( rtEDL );
  52549. renderer.clear( true, true, true );
  52550. }
  52551. }
  52552. }
  52553. //renderer.setRenderTarget( this.rtRegular );
  52554. //renderer.clear( true, true, false );
  52555. renderer.setRenderTarget(oldTarget);
  52556. }
  52557. getRtEDL(viewport){//根据不同viewport返回rtEDL的texture
  52558. if(!viewport){
  52559. console.warn('getRtEDL没传viewport!!!! !!!!!!!!!!');
  52560. viewport = viewer.mainViewport;
  52561. }
  52562. var rtEDL = this.rtEDLs.get(viewport);
  52563. if(!rtEDL){
  52564. if(Features.EXT_DEPTH.isSupported()){
  52565. rtEDL = new WebGLRenderTarget(viewport.resolution2.x, viewport.resolution2.y, {
  52566. minFilter: NearestFilter,
  52567. magFilter: NearestFilter,
  52568. format: RGBAFormat,
  52569. type: FloatType,
  52570. depthTexture: new DepthTexture(undefined, undefined, UnsignedIntType)
  52571. });
  52572. //注: 部分手机在resize时会崩溃,经检验去掉rtEDL的resize可以解决,所以更应该注释掉这个
  52573. this.rtEDLs.set(viewport, rtEDL);
  52574. }
  52575. }
  52576. return rtEDL
  52577. }
  52578. renderShadowMap(visiblePointClouds, camera, lights){
  52579. const {viewer} = this;
  52580. const doShadows = lights.length > 0 && !(lights[0].disableShadowUpdates);
  52581. if(doShadows){
  52582. let light = lights[0];
  52583. this.shadowMap.setLight(light);
  52584. let originalAttributes = new Map();
  52585. for(let pointcloud of viewer.scene.pointclouds){
  52586. // TODO IMPORTANT !!! check
  52587. originalAttributes.set(pointcloud, pointcloud.material.activeAttributeName);
  52588. pointcloud.material.disableEvents();
  52589. pointcloud.material.activeAttributeName = "depth";
  52590. //pointcloud.material.pointColorType = PointColorType.DEPTH;
  52591. }
  52592. this.shadowMap.render(viewer.scene.scenePointCloud, camera);
  52593. for(let pointcloud of visiblePointClouds){
  52594. let originalAttribute = originalAttributes.get(pointcloud);
  52595. // TODO IMPORTANT !!! check
  52596. pointcloud.material.activeAttributeName = originalAttribute;
  52597. pointcloud.material.enableEvents();
  52598. }
  52599. viewer.shadowTestCam.updateMatrixWorld();
  52600. viewer.shadowTestCam.matrixWorldInverse.copy(viewer.shadowTestCam.matrixWorld).invert();
  52601. viewer.shadowTestCam.updateProjectionMatrix();
  52602. }
  52603. }
  52604. render(params={}){
  52605. /*
  52606. 渲染顺序:
  52607. 底层:背景 -> skybox(也可中间)
  52608. 中间层(含有深度信息):1 点云、marker等mesh,
  52609. 2 测量线(现在被做成借用depthTex
  52610. 顶层:maginifier
  52611. magnifier的贴图渲染不需要顶层、中间层只需要点云。
  52612. */
  52613. const viewer = this.viewer;
  52614. let camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
  52615. const resolution = params.viewport ? params.viewport.resolution2 : this.viewer.renderer.getSize(new Vector2$1());
  52616. //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
  52617. let lights = [];
  52618. /* viewer.scene.scene.traverse(node => {
  52619. if(node.type === "SpotLight"){
  52620. lights.push(node);
  52621. }
  52622. }); */
  52623. viewer.renderer.setRenderTarget(params.target || null);
  52624. let background = params.background || viewer.background;
  52625. let backgroundOpacity = params.backgroundOpacity == void 0 ? viewer.backgroundOpacity : params.backgroundOpacity;//如果想完全透明,只需要backgroundOpacity为0
  52626. if(backgroundOpacity != 0){//绘制背景
  52627. if(background === "skybox"){
  52628. viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
  52629. viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
  52630. viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
  52631. viewer.skybox.parent.rotation.x = 0;
  52632. viewer.skybox.parent.updateMatrixWorld();
  52633. viewer.skybox.camera.updateProjectionMatrix();
  52634. viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera);
  52635. }else if(background === 'gradient'){
  52636. viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg);
  52637. viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
  52638. }else if(background === 'overlayColor'){//在不clear的前提下加一层背景色
  52639. viewer.scene.bg2.material.color.copy(params.backgroundColor);
  52640. viewer.scene.bg2.material.opacity = params.backgroundOpacity;
  52641. viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg2);
  52642. viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
  52643. }
  52644. }
  52645. //skybox 全景图
  52646. if(!params.magnifier){
  52647. viewer.setCameraLayers(camera, ['skybox']);
  52648. let useDepthTex;
  52649. if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex && Features.EXT_DEPTH.isSupported()){//渲染深度图
  52650. useDepthTex = true;
  52651. viewer.renderer.setRenderTarget(params.rtEDL || this.getRtEDL(params.viewport)); //将带有深度图的skybox画在rtEDL一下,这样就不需要绘制后边的点云了
  52652. viewer.renderer.render(viewer.scene.scene, camera);
  52653. viewer.renderer.setRenderTarget(params.target || null);
  52654. }
  52655. viewer.renderer.render(viewer.scene.scene, camera);
  52656. if(useDepthTex)return
  52657. }
  52658. if(viewer.scene.pointclouds.length == 0)return
  52659. //const visiblePointClouds = viewer.scene.pointclouds.filter(pc => pc.visible );
  52660. const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => viewer.getObjVisiByReason(pc,'datasetSelection') );
  52661. const showPointClouds = viewer.scene.pointclouds.some(e=>e.visible);
  52662. viewer.scene.pointclouds.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云)
  52663. e.oldVisi = e.visible;
  52664. if(viewer.getObjVisiByReason(e, 'datasetSelection') ) e.visible = true;
  52665. });
  52666. //pointcloud
  52667. viewer.setCameraLayers(camera, ['pointcloud']);
  52668. camera.layers.set(Potree.config.renderLayers.pointcloud);
  52669. //TODO adapt to multiple lights
  52670. //this.renderShadowMap(visiblePointClouds2, camera, lights); //???????
  52671. { //scenePointCloud COLOR & DEPTH PASS
  52672. for (let pointcloud of visiblePointClouds2) {
  52673. let material = pointcloud.material;
  52674. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new Vector3()).x;
  52675. material.fov = MathUtils.degToRad(camera.fov);
  52676. /* material.screenWidth = width;
  52677. material.screenHeight = height; */
  52678. material.resolution = resolution;
  52679. material.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z);
  52680. material.near = camera.near;
  52681. material.far = camera.far;
  52682. material.uniforms.octreeSize.value = octreeSize;
  52683. if(viewer.useEDL && Potree.settings.displayMode != 'showPanos'){
  52684. /* material.weighted = false;
  52685. material.useLogarithmicDepthBuffer = false; */
  52686. material.useEDL = true;
  52687. //material.fakeEDL = false; //add
  52688. }else {
  52689. material.useEDL = false;
  52690. //material.fakeEDL = true; //add 使也输出深度
  52691. }
  52692. }
  52693. if(Features.EXT_DEPTH.isSupported() && !params.dontRenderRtEDL){
  52694. //借用rtEDL存储深度信息
  52695. viewer.renderer.setRenderTarget(params.rtEDL || this.getRtEDL(params.viewport)/* this.rtEDL */);
  52696. //pointDensity已经使用的是panorama模式,在画面边缘点云会稀疏,遮挡效果差
  52697. /* if(Potree.settings.displayMode == "showPanos"){ //还原成点云模式的材质,且可能要更大些,因点云变稀疏
  52698. var matBefore = {
  52699. pointSizeType : new Map(),
  52700. size : new Map(),
  52701. usePanoMap : new Map(),
  52702. }
  52703. for (let pointcloud of visiblePointClouds2) {
  52704. matBefore.usePanoMap.set(pointcloud, pointcloud.material.usePanoMap)
  52705. //matBefore.pointSizeType.set(pointcloud, pointcloud.material.pointSizeType)
  52706. matBefore.size.set(pointcloud, pointcloud.temp.pointSize)
  52707. //pointcloud.material.pointSizeType = Potree.config.material.pointSizeType //不能修改这项,因为是define,会卡。
  52708. //pointcloud.changePointSize(pointcloud.temp.pointSize * (1+Potree.config.material.sizeAddAtPanoRtEDL))
  52709. //pointcloud.changePointSize(Potree.config.material.sizeAtPanoRtEDL, true)
  52710. pointcloud.material.usePanoMap = false //禁止使用absolutePanoramaSize大小
  52711. }
  52712. } */
  52713. //渲染scenePointCloud到rtEDL
  52714. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, params.rtEDL || this.getRtEDL(params.viewport), {
  52715. shadowMaps: lights.length > 0 ? [this.shadowMap] : null,
  52716. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  52717. transparent: false,
  52718. });
  52719. //test
  52720. /* {
  52721. viewer.objs.traverse((obj)=>{
  52722. if(obj.material){
  52723. obj.material = obj.depthMat
  52724. }
  52725. })
  52726. viewer.setCameraLayers(camera, ['sceneObjects'])
  52727. viewer.renderer.render(viewer.scene.scene, camera)
  52728. viewer.objs.traverse((obj)=>{
  52729. if(obj.material){
  52730. obj.material = obj.standardMat
  52731. }
  52732. })
  52733. } */
  52734. /* if(Potree.settings.displayMode == "showPanos"){
  52735. for (let pointcloud of visiblePointClouds2) {
  52736. //pointcloud.material.pointSizeType = matBefore.pointSizeType.get(pointcloud)
  52737. pointcloud.material.usePanoMap = matBefore.usePanoMap.get(pointcloud)
  52738. //pointcloud.changePointSize(matBefore.size.get(pointcloud))
  52739. }
  52740. } */
  52741. }
  52742. }
  52743. //渲染到rtEDL完毕
  52744. viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer/* , renderTarget: this.rtRegular */});
  52745. viewer.renderer.setRenderTarget(params.target || null);
  52746. if(!params.magnifier)viewer.scene.pointclouds.forEach(e=>{//放大镜显示点云
  52747. e.visible = e.oldVisi;
  52748. });
  52749. //设置edlMaterial
  52750. if(viewer.useEDL && showPointClouds /* || params.magnifier */) {
  52751. //Features.EXT_DEPTH不支持的话不会到这一块
  52752. const uniforms = this.edlMaterial.uniforms;
  52753. //if(viewer.useEDL){
  52754. /* uniforms.screenWidth.value = width;
  52755. uniforms.screenHeight.value = height; */
  52756. uniforms.resolution.value.copy(resolution);
  52757. uniforms.edlStrength.value = viewer.edlStrength;
  52758. uniforms.radius.value = viewer.edlRadius;
  52759. uniforms.useEDL.value = 1;//add
  52760. /* }else{
  52761. uniforms.useEDL.value = 0;//add
  52762. } */
  52763. let proj = camera.projectionMatrix;
  52764. let projArray = new Float32Array(16);
  52765. projArray.set(proj.elements);
  52766. uniforms.uProj.value = projArray;
  52767. uniforms.uEDLColor.value = (params.rtEDL || this.getRtEDL(params.viewport)).texture;
  52768. //uniforms.uEDLDepth.value = (params.rtEDL || this.getRtEDL(params.viewport)).depthTexture; //其实没用到
  52769. uniforms.opacity.value = viewer.edlOpacity; // HACK
  52770. Utils.screenPass.render(viewer.renderer, this.edlMaterial, params.target);
  52771. }else {
  52772. //渲染点云 (直接用rtEDL上的会失去抗锯齿)
  52773. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, null , {
  52774. shadowMaps: lights.length > 0 ? [this.shadowMap] : null,
  52775. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume))
  52776. });
  52777. }
  52778. //viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
  52779. viewer.scene.pointclouds.forEach(e=>{
  52780. e.visible = e.oldVisi;
  52781. });
  52782. }
  52783. }
  52784. class HQSplatRenderer{
  52785. //rtAttribute 估计需要给magnifer复制一份
  52786. constructor(viewer){
  52787. this.viewer = viewer;
  52788. this.depthMaterials = new Map();
  52789. this.attributeMaterials = new Map();
  52790. this.normalizationMaterial = null;
  52791. this.rtDepth = null;
  52792. this.rtAttribute = null;
  52793. this.gl = viewer.renderer.getContext();
  52794. this.initialized = false;
  52795. viewer.addEventListener('resize',this.resize.bind(this));
  52796. }
  52797. init(){
  52798. if (this.initialized) {
  52799. return;
  52800. }
  52801. this.normalizationMaterial = new NormalizationMaterial();
  52802. this.normalizationMaterial.depthTest = true;
  52803. this.normalizationMaterial.depthWrite = true;
  52804. this.normalizationMaterial.transparent = true;
  52805. this.normalizationEDLMaterial = new NormalizationEDLMaterial();
  52806. this.normalizationEDLMaterial.depthTest = true;
  52807. this.normalizationEDLMaterial.depthWrite = true;
  52808. this.normalizationEDLMaterial.transparent = true;
  52809. this.rtDepth = new WebGLRenderTarget(1024, 1024, {
  52810. minFilter: NearestFilter,
  52811. magFilter: NearestFilter,
  52812. format: RGBAFormat,
  52813. type: FloatType,
  52814. depthTexture: new DepthTexture(undefined, undefined, UnsignedIntType)
  52815. });
  52816. this.rtAttribute = new WebGLRenderTarget(1024, 1024, {
  52817. minFilter: NearestFilter,
  52818. magFilter: NearestFilter,
  52819. format: RGBAFormat,
  52820. type: FloatType,
  52821. depthTexture: this.rtDepth.depthTexture,
  52822. });
  52823. this.initialized = true;
  52824. };
  52825. resize(e/* width, height */){
  52826. this.rtDepth.setSize(e.canvasWidth, e.canvasHeight);
  52827. this.rtAttribute.setSize(e.canvasWidth, e.canvasHeight);
  52828. }
  52829. clearTargets(params){
  52830. const viewer = this.viewer;
  52831. const {renderer} = viewer;
  52832. const oldTarget = renderer.getRenderTarget();
  52833. if(params.target){//add
  52834. renderer.setRenderTarget( params.target);
  52835. renderer.clear();
  52836. }
  52837. renderer.setClearColor(0x000000, 0);
  52838. renderer.setRenderTarget( this.rtDepth );
  52839. renderer.clear( true, true, true );
  52840. renderer.setRenderTarget( this.rtAttribute );
  52841. renderer.clear( true, true, true );
  52842. renderer.setRenderTarget(oldTarget);
  52843. }
  52844. clear(params={}){
  52845. this.init();
  52846. const {renderer, background} = this.viewer;
  52847. if(background === "skybox"){
  52848. renderer.setClearColor(0x000000, 0);
  52849. } else if (background === 'gradient') {
  52850. renderer.setClearColor(0x000000, 0);
  52851. } else if (background === 'black') {
  52852. renderer.setClearColor(0x000000, 1);
  52853. } else if (background === 'white') {
  52854. renderer.setClearColor(0xFFFFFF, 1);
  52855. } else {
  52856. renderer.setClearColor(0x000000, 0);
  52857. }
  52858. params.target || renderer.clear();
  52859. this.clearTargets(params);
  52860. }
  52861. render(params={}) {
  52862. this.init();
  52863. const viewer = this.viewer;
  52864. const camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
  52865. const {width, height} = params.width ? params : this.viewer.renderer.getSize(new Vector2$1());
  52866. viewer.renderer.setRenderTarget(params.target||null);
  52867. viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
  52868. //params.target || this.resize(width, height);
  52869. const visiblePointClouds = viewer.scene.pointclouds.filter(pc => pc.visible);
  52870. const originalMaterials = new Map();
  52871. for(let pointcloud of visiblePointClouds){
  52872. originalMaterials.set(pointcloud, pointcloud.material);
  52873. if(!this.attributeMaterials.has(pointcloud)){
  52874. let attributeMaterial = new PointCloudMaterial$1();
  52875. this.attributeMaterials.set(pointcloud, attributeMaterial);
  52876. }
  52877. if(!this.depthMaterials.has(pointcloud)){
  52878. let depthMaterial = new PointCloudMaterial$1();
  52879. depthMaterial.setDefine("depth_pass", "#define hq_depth_pass");
  52880. depthMaterial.setDefine("use_edl", "#define use_edl");
  52881. this.depthMaterials.set(pointcloud, depthMaterial);
  52882. }
  52883. }
  52884. { // DEPTH PASS
  52885. for (let pointcloud of visiblePointClouds) {
  52886. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new Vector3()).x;
  52887. let material = originalMaterials.get(pointcloud);
  52888. let depthMaterial = this.depthMaterials.get(pointcloud);
  52889. depthMaterial.size = material.size;
  52890. depthMaterial.minSize = material.minSize;
  52891. depthMaterial.maxSize = material.maxSize;
  52892. depthMaterial.pointSizeType = material.pointSizeType;
  52893. depthMaterial.visibleNodesTexture = material.visibleNodesTexture;
  52894. depthMaterial.weighted = false;
  52895. depthMaterial.screenWidth = width;
  52896. depthMaterial.shape = PointShape.CIRCLE;
  52897. depthMaterial.screenHeight = height;
  52898. depthMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
  52899. depthMaterial.uniforms.octreeSize.value = octreeSize;
  52900. depthMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
  52901. depthMaterial.classification = material.classification;
  52902. depthMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
  52903. depthMaterial.classificationTexture.needsUpdate = true;
  52904. depthMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
  52905. depthMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
  52906. depthMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
  52907. depthMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
  52908. depthMaterial.clipTask = material.clipTask;
  52909. depthMaterial.clipMethod = material.clipMethod;
  52910. depthMaterial.setClipBoxes(material.clipBoxes);
  52911. depthMaterial.setClipPolygons(material.clipPolygons);
  52912. pointcloud.material = depthMaterial;
  52913. }
  52914. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, (params.rtEDL || this.rtDepth), {
  52915. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  52916. });
  52917. }
  52918. { // ATTRIBUTE PASS
  52919. for (let pointcloud of visiblePointClouds) {
  52920. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new Vector3()).x;
  52921. let material = originalMaterials.get(pointcloud);
  52922. let attributeMaterial = this.attributeMaterials.get(pointcloud);
  52923. attributeMaterial.size = material.size;
  52924. attributeMaterial.minSize = material.minSize;
  52925. attributeMaterial.maxSize = material.maxSize;
  52926. attributeMaterial.pointSizeType = material.pointSizeType;
  52927. attributeMaterial.activeAttributeName = material.activeAttributeName;
  52928. attributeMaterial.visibleNodesTexture = material.visibleNodesTexture;
  52929. attributeMaterial.weighted = true;
  52930. attributeMaterial.screenWidth = width;
  52931. attributeMaterial.screenHeight = height;
  52932. attributeMaterial.shape = PointShape.CIRCLE;
  52933. attributeMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
  52934. attributeMaterial.uniforms.octreeSize.value = octreeSize;
  52935. attributeMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
  52936. attributeMaterial.classification = material.classification;
  52937. attributeMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
  52938. attributeMaterial.classificationTexture.needsUpdate = true;
  52939. attributeMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
  52940. attributeMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
  52941. attributeMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
  52942. attributeMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
  52943. attributeMaterial.elevationGradientRepeat = material.elevationGradientRepeat;
  52944. attributeMaterial.elevationRange = material.elevationRange;
  52945. attributeMaterial.gradient = material.gradient;
  52946. attributeMaterial.matcap = material.matcap;
  52947. attributeMaterial.intensityRange = material.intensityRange;
  52948. attributeMaterial.intensityGamma = material.intensityGamma;
  52949. attributeMaterial.intensityContrast = material.intensityContrast;
  52950. attributeMaterial.intensityBrightness = material.intensityBrightness;
  52951. attributeMaterial.rgbGamma = material.rgbGamma;
  52952. attributeMaterial.rgbContrast = material.rgbContrast;
  52953. attributeMaterial.rgbBrightness = material.rgbBrightness;
  52954. attributeMaterial.weightRGB = material.weightRGB;
  52955. attributeMaterial.weightIntensity = material.weightIntensity;
  52956. attributeMaterial.weightElevation = material.weightElevation;
  52957. attributeMaterial.weightRGB = material.weightRGB;
  52958. attributeMaterial.weightClassification = material.weightClassification;
  52959. attributeMaterial.weightReturnNumber = material.weightReturnNumber;
  52960. attributeMaterial.weightSourceID = material.weightSourceID;
  52961. attributeMaterial.color = material.color;
  52962. attributeMaterial.clipTask = material.clipTask;
  52963. attributeMaterial.clipMethod = material.clipMethod;
  52964. attributeMaterial.setClipBoxes(material.clipBoxes);
  52965. attributeMaterial.setClipPolygons(material.clipPolygons);
  52966. pointcloud.material = attributeMaterial;
  52967. }
  52968. let gl = this.gl;
  52969. //viewer.renderer.setRenderTarget(null);
  52970. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, this.rtAttribute, {
  52971. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  52972. //material: this.attributeMaterial,
  52973. blendFunc: [gl.SRC_ALPHA, gl.ONE],
  52974. //depthTest: false,
  52975. depthWrite: false
  52976. });
  52977. }
  52978. for(let [pointcloud, material] of originalMaterials){
  52979. pointcloud.material = material;
  52980. }
  52981. if(viewer.background === "skybox"){
  52982. viewer.renderer.setClearColor(0x000000, 0);
  52983. viewer.renderer.clear();
  52984. viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
  52985. viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
  52986. viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
  52987. viewer.skybox.parent.rotation.x = 0;
  52988. viewer.skybox.parent.updateMatrixWorld();
  52989. viewer.skybox.camera.updateProjectionMatrix();
  52990. viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera);
  52991. } else if (viewer.background === 'gradient') {
  52992. viewer.renderer.setClearColor(0x000000, 0);
  52993. viewer.renderer.clear();
  52994. viewer.renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
  52995. } else if (viewer.background === 'black') {
  52996. viewer.renderer.setClearColor(0x000000, 1);
  52997. viewer.renderer.clear();
  52998. } else if (viewer.background === 'white') {
  52999. viewer.renderer.setClearColor(0xFFFFFF, 1);
  53000. viewer.renderer.clear();
  53001. } else {
  53002. viewer.renderer.setClearColor(0x000000, 0);
  53003. viewer.renderer.clear();
  53004. }
  53005. { // NORMALIZATION PASS
  53006. let normalizationMaterial = this.useEDL ? this.normalizationEDLMaterial : this.normalizationMaterial;
  53007. if(this.useEDL){
  53008. normalizationMaterial.uniforms.edlStrength.value = viewer.edlStrength;
  53009. normalizationMaterial.uniforms.radius.value = viewer.edlRadius;
  53010. normalizationMaterial.uniforms.screenWidth.value = width;
  53011. normalizationMaterial.uniforms.screenHeight.value = height;
  53012. normalizationMaterial.uniforms.uEDLMap.value = (params.rtEDL || this.rtDepth).texture;
  53013. }
  53014. normalizationMaterial.uniforms.uWeightMap.value = this.rtAttribute.texture;
  53015. normalizationMaterial.uniforms.uDepthMap.value = this.rtAttribute.depthTexture;
  53016. Utils.screenPass.render(viewer.renderer, normalizationMaterial);
  53017. }
  53018. viewer.renderer.render(viewer.scene.scene, camera);
  53019. viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer});
  53020. viewer.renderer.render(viewer.scene.sceneOverlay, camera);// add 透明贴图层
  53021. viewer.renderer.clearDepth();
  53022. viewer.transformationTool.update();
  53023. if(!params.target){
  53024. //测量线
  53025. viewer.dispatchEvent({type: "render.pass.perspective_overlay",viewer: viewer, camera});
  53026. viewer.renderer.render(viewer.overlay, camera);//从 viewer.renderDefault搬过来,为了reticule不遮住测量线
  53027. }
  53028. viewer.renderer.render(viewer.controls.sceneControls, camera);
  53029. viewer.renderer.render(viewer.clippingTool.sceneVolume, camera);
  53030. viewer.renderer.render(viewer.transformationTool.scene, camera);
  53031. viewer.renderer.setViewport(width - viewer.navigationCube.width,
  53032. height - viewer.navigationCube.width,
  53033. viewer.navigationCube.width, viewer.navigationCube.width);
  53034. viewer.renderer.render(viewer.navigationCube, viewer.navigationCube.camera);
  53035. viewer.renderer.setViewport(0, 0, width, height);
  53036. viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
  53037. viewer.renderer.setRenderTarget(null);
  53038. }
  53039. }
  53040. let sid = 0;
  53041. class View extends EventDispatcher{
  53042. constructor () {
  53043. super();
  53044. this.position = new Vector3(0, 0, 0);
  53045. this.yaw = 0;//Math.PI / 4; // = 4dkk lon + 90
  53046. this._pitch = 0;//-Math.PI / 4; //上下旋转 = 4dkk lat
  53047. this.radius = 1;
  53048. this.maxPitch = Math.PI / 2;
  53049. this.minPitch = -Math.PI / 2;
  53050. this.sid = sid++;
  53051. this.LookTransition = 'LookTransition'+this.sid;
  53052. }
  53053. //add------
  53054. applyToCamera(camera){
  53055. camera.position.copy(this.position);
  53056. camera.rotation.copy(this.rotation);
  53057. camera.updateMatrix();
  53058. camera.updateMatrixWorld();
  53059. //camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
  53060. }
  53061. get rotation(){
  53062. var rotation = new Euler;
  53063. rotation.order = "ZXY";
  53064. rotation.x = Math.PI / 2 + this.pitch;
  53065. rotation.z = this.yaw;
  53066. return rotation
  53067. }
  53068. set rotation(rotation){
  53069. //因为 rotation的y不一定是0 , 所以不能直接逆着写。
  53070. this.direction = new Vector3(0,0,-1).applyEuler(rotation);
  53071. }
  53072. copy(a){
  53073. Common.CopyClassObject(this, a);
  53074. }
  53075. clone () {
  53076. /* let c = new View();
  53077. c.yaw = this.yaw;
  53078. c._pitch = this.pitch;
  53079. c.radius = this.radius;
  53080. c.maxPitch = this.maxPitch;
  53081. c.minPitch = this.minPitch;
  53082. return c; */
  53083. return Common.CloneClassObject(this)
  53084. }
  53085. //----------
  53086. get pitch () {
  53087. return this._pitch;
  53088. }
  53089. set pitch (angle) {
  53090. this._pitch = Math.max(Math.min(angle, this.maxPitch), this.minPitch);
  53091. }
  53092. get direction () {
  53093. let dir = new Vector3(0, 1, 0);
  53094. dir.applyAxisAngle(new Vector3(1, 0, 0), this.pitch);
  53095. dir.applyAxisAngle(new Vector3(0, 0, 1), this.yaw);
  53096. return dir;
  53097. }
  53098. set direction (dir) {
  53099. //if(dir.x === dir.y){
  53100. if(dir.x === 0 && dir.y === 0){
  53101. this.pitch = Math.PI / 2 * Math.sign(dir.z);
  53102. }else {
  53103. let yaw = Math.atan2(dir.y, dir.x) - Math.PI / 2;
  53104. let pitch = Math.atan2(dir.z, Math.sqrt(dir.x * dir.x + dir.y * dir.y));
  53105. this.yaw = yaw;
  53106. this.pitch = pitch;
  53107. }
  53108. }
  53109. lookAt(t){//setPivot
  53110. let V;
  53111. if(arguments.length === 1){
  53112. V = new Vector3().subVectors(t, this.position);
  53113. }else if(arguments.length === 3){
  53114. V = new Vector3().subVectors(new Vector3(...arguments), this.position);
  53115. }
  53116. let radius = V.length();
  53117. let dir = V.normalize();
  53118. this.radius = radius;
  53119. this.direction = dir;
  53120. }
  53121. getPivot () {
  53122. return new Vector3().addVectors(this.position, this.direction.multiplyScalar(this.radius));
  53123. }
  53124. getSide () {
  53125. let side = new Vector3(1, 0, 0);
  53126. side.applyAxisAngle(new Vector3(0, 0, 1), this.yaw);
  53127. return side;
  53128. }
  53129. /* pan (x, y) {
  53130. let dir = new THREE.Vector3(0, 1, 0);
  53131. dir.applyAxisAngle(new THREE.Vector3(1, 0, 0), this.pitch);
  53132. dir.applyAxisAngle(new THREE.Vector3(0, 0, 1), this.yaw);
  53133. // let side = new THREE.Vector3(1, 0, 0);
  53134. // side.applyAxisAngle(new THREE.Vector3(0, 0, 1), this.yaw);
  53135. let side = this.getSide();
  53136. let up = side.clone().cross(dir);
  53137. let pan = side.multiplyScalar(x).add(up.multiplyScalar(y));
  53138. this.position = this.position.add(pan);
  53139. // this.target = this.target.add(pan);
  53140. } */
  53141. pan (x, y) { //发现pan其实就是translate
  53142. this.translate(x, 0, y);
  53143. }
  53144. translate (x, y, z) {
  53145. let dir = new Vector3(0, 1, 0);
  53146. dir.applyAxisAngle(new Vector3(1, 0, 0), this.pitch);
  53147. dir.applyAxisAngle(new Vector3(0, 0, 1), this.yaw);
  53148. let side = new Vector3(1, 0, 0);
  53149. side.applyAxisAngle(new Vector3(0, 0, 1), this.yaw);
  53150. let up = side.clone().cross(dir);
  53151. let t = side.multiplyScalar(x)
  53152. .add(dir.multiplyScalar(y))
  53153. .add(up.multiplyScalar(z));
  53154. if(this.fixZWhenPan) t.setZ(0); //在水平面上平移
  53155. this.position = this.position.add(t);
  53156. this.restrictPos();
  53157. }
  53158. translateWorld (x, y, z) {
  53159. this.position.x += x;
  53160. this.position.y += y;
  53161. this.position.z += z;
  53162. this.restrictPos();
  53163. }
  53164. restrictPos(){//add
  53165. if(this.limitBound){
  53166. this.position.clamp(this.limitBound.min, this.limitBound.max);
  53167. }
  53168. }
  53169. setCubeView(dir) {
  53170. switch(dir) {
  53171. case "front":
  53172. this.yaw = 0;
  53173. this.pitch = 0;
  53174. break;
  53175. case "back":
  53176. this.yaw = Math.PI;
  53177. this.pitch = 0;
  53178. break;
  53179. case "left":
  53180. this.yaw = -Math.PI / 2;
  53181. this.pitch = 0;
  53182. break;
  53183. case "right":
  53184. this.yaw = Math.PI / 2;
  53185. this.pitch = 0;
  53186. break;
  53187. case "top":
  53188. this.yaw = 0;
  53189. this.pitch = -Math.PI / 2;
  53190. break;
  53191. case "bottom":
  53192. this.yaw = -Math.PI;
  53193. this.pitch = Math.PI / 2;
  53194. break;
  53195. }
  53196. }
  53197. isFlying(){
  53198. return transitions.getById(this.LookTransition).length > 0
  53199. }
  53200. cancelFlying(){//外界只能通过这个来cancel
  53201. transitions.cancelById(this.LookTransition, true );
  53202. }
  53203. setView( info = {}){
  53204. // position, target, duration = 0, callback = null, onUpdate = null, Easing='', cancelFun
  53205. this.cancelFlying();
  53206. let done = ()=>{
  53207. if(endTarget){
  53208. this.lookAt(endTarget); //compute radius for orbitcontrol
  53209. }else if(endQuaternion){
  53210. this.rotation = new Euler().setFromQuaternion(endQuaternion);
  53211. }
  53212. let f = ()=>{
  53213. info.callback && info.callback();
  53214. this.dispatchEvent('flyingDone');
  53215. };
  53216. if(info.duration){
  53217. setTimeout(f,1);//延迟是为了使isFlying先为false
  53218. }else {
  53219. f(); //有的需要迅速执行回调
  53220. }
  53221. };
  53222. let endPosition = new Vector3().copy(info.position);
  53223. const startPosition = this.position.clone();
  53224. const startTarget = this.getPivot();
  53225. let startQuaternion = math.getQuaFromPosAim(startPosition,startTarget);
  53226. let endTarget = null, endQuaternion ;
  53227. if(info.target ){
  53228. endTarget = new Vector3().copy(info.target);
  53229. endQuaternion = math.getQuaFromPosAim(endPosition,endTarget);
  53230. }else if(info.quaternion){
  53231. endQuaternion = info.quaternion.clone();
  53232. }
  53233. if(!info.duration){
  53234. this.position.copy(endPosition);
  53235. this.restrictPos();
  53236. info.onUpdate && info.onUpdate(1);
  53237. done();
  53238. }else {
  53239. transitions.start(lerp.vector(this.position, endPosition, (pos, progress)=>{
  53240. let t = progress;
  53241. if(endQuaternion){
  53242. let quaternion = (new Quaternion()).copy(startQuaternion);
  53243. lerp.quaternion(quaternion, endQuaternion)(progress),
  53244. this.rotation = new Euler().setFromQuaternion(quaternion);
  53245. }
  53246. this.restrictPos();
  53247. info.onUpdate && info.onUpdate(t);//add
  53248. }), info.duration, done, 0, info.Easing ? easing[info.Easing] : easing.easeInOutSine /*easeInOutQuad */,null, this.LookTransition, info.cancelFun);
  53249. }
  53250. }
  53251. //平移Ortho相机
  53252. moveOrthoCamera(viewport, info, duration, easeName){//boundSize优先于endZoom。
  53253. let camera = viewport.camera;
  53254. let startZoom = camera.zoom;
  53255. let endPosition = info.endPosition;
  53256. let boundSize = info.boundSize;
  53257. let endZoom = info.endZoom;
  53258. let margin = info.margin || {x:0,y:0};/* 200 */ //像素
  53259. if(info.bound){//需要修改boundSize以适应相机的旋转,当相机不在xy水平面上朝向z时
  53260. endPosition = endPosition || info.bound.getCenter(new Vector3());
  53261. let matrixRot = new Matrix4().makeRotationFromEuler(this.rotation).invert();
  53262. let boundingBox = info.bound.clone().applyMatrix4(matrixRot);
  53263. boundSize = boundingBox.getSize(new Vector3());
  53264. }
  53265. if(boundSize && boundSize.x == 0 && boundSize.y == 0){
  53266. boundSize.set(1,1); //避免infinity
  53267. }
  53268. this.setView({ position:endPosition, duration,
  53269. callback:()=>{//done
  53270. },
  53271. onUpdate:(progress)=>{
  53272. if(boundSize || endZoom){
  53273. if(boundSize){
  53274. let aspect = boundSize.x / boundSize.y;
  53275. let w, h;
  53276. if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
  53277. h = boundSize.y;
  53278. endZoom = (viewport.resolution.y - margin.x) / h; //注意,要在resolution不为0时执行
  53279. }else {
  53280. w = boundSize.x;
  53281. endZoom = (viewport.resolution.x - margin.y) / w;
  53282. }
  53283. //onUpdate时更新endzoom是因为画布大小可能更改
  53284. }
  53285. camera.zoom = endZoom * progress + startZoom * (1 - progress);
  53286. camera.updateProjectionMatrix();
  53287. }
  53288. },
  53289. Easing:easeName
  53290. });
  53291. }
  53292. zoomOrthoCamera(camera, endZoom, pointer, duration, onProgress){//定点缩放
  53293. let startZoom = camera.zoom;
  53294. let pointerPos = new Vector3(pointer.x, pointer.y,0.5);
  53295. transitions.start(( progress)=>{
  53296. let oldPos = pointerPos.clone().unproject(camera);
  53297. camera.zoom = endZoom * progress + startZoom * (1 - progress);
  53298. camera.updateProjectionMatrix();
  53299. let newPos = pointerPos.clone().unproject(camera);
  53300. //定点缩放, 恢复一下鼠标所在位置的位置改变量
  53301. let moveVec = new Vector3().subVectors(newPos, oldPos);
  53302. camera.position.sub(moveVec);
  53303. this.position.copy(camera.position);
  53304. onProgress && onProgress();
  53305. } , duration, null/* done */, 0, easing.easeInOutSine, null, "zoomInView"/* , info.cancelFun */);
  53306. }
  53307. };
  53308. /*
  53309. z
  53310. |
  53311. |
  53312. |
  53313. |
  53314. x <-------| 中心为点云position加boudingbox中心
  53315. /
  53316. /
  53317. y
  53318. */
  53319. var lineLen$1 = 2, stemLen = 4, arrowLen = 2, lineDisToStem = 5;
  53320. var opacity = 0.5;
  53321. class Axis extends Object3D {// 坐标轴
  53322. constructor (position) {
  53323. super();
  53324. this.getArrow();
  53325. this.createArrows();
  53326. //this.position.copy(position) 点云的中心点就是在(0,0,0)
  53327. //this.scale.set(2,2,2)
  53328. }
  53329. getArrow(){
  53330. var arrowGroup = new Object3D();
  53331. var line = LineDraw.createLine([new Vector3, new Vector3(0,0,lineLen$1)]);
  53332. var stem = new Mesh(new BoxGeometry(0.3, 0.3, stemLen));
  53333. stem.position.set(0,0,lineLen$1+lineDisToStem+stemLen/2);
  53334. var arrow = new Mesh(new CylinderBufferGeometry( 0, 0.6, arrowLen, 12, 1, false ));//radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2
  53335. arrow.position.set(0,0,lineLen$1+lineDisToStem+stemLen + arrowLen/2);
  53336. arrow.rotation.set(Math.PI/2,0,0);
  53337. arrowGroup.add(stem);
  53338. arrowGroup.add(line);
  53339. arrowGroup.add(arrow);
  53340. this.arrowGroup = arrowGroup;
  53341. }
  53342. createArrows(){
  53343. var material = new MeshBasicMaterial({color:"#00d7df",side:2,transparent:true,opacity:0.8, depthWrite:false});
  53344. let axis = Object.keys(Potree.config.axis);
  53345. axis.forEach((axisText)=>{
  53346. let color = Potree.config.axis[axisText].color;
  53347. var group = this.arrowGroup.clone();
  53348. group.children.forEach(e=>{
  53349. e.material = e.material.clone();
  53350. /* e.material.opacity = opacity
  53351. e.material.transparent = true */
  53352. e.material.color.set(color);
  53353. });
  53354. var label = this.createLabel(axisText, color);
  53355. label.position.set(0, 0, lineLen$1 + stemLen + arrowLen + lineDisToStem + 3);
  53356. group.add(label);
  53357. if(axisText == 'y'){
  53358. group.rotation.x = -Math.PI / 2;
  53359. }else if(axisText == 'x'){
  53360. group.rotation.y = Math.PI / 2;
  53361. }
  53362. this.add(group);
  53363. });
  53364. }
  53365. createLabel(text,color){
  53366. var canvas = document.createElement("canvas");
  53367. var context = canvas.getContext("2d");
  53368. canvas.width = 256,
  53369. canvas.height = 256;
  53370. var fontSize = 120;
  53371. context.fillStyle = color; //"#00ffee";
  53372. context.font = "normal " + fontSize + "px 微软雅黑";
  53373. var textWidth = context.measureText(text).width;
  53374. context.clearRect(0,0,canvas.width,canvas.height);
  53375. context.fillText(text, (canvas.width - textWidth) / 2 , (canvas.height + fontSize) / 2);
  53376. var tex = new Texture(canvas);
  53377. tex.needsUpdate = true;
  53378. tex.minFilter = NearestFilter;//防止边缘发黑
  53379. tex.magFilter = NearestFilter;//防止边缘发黑
  53380. var sprite = new Sprite(new SpriteMaterial({
  53381. map: tex , // depthWrite:false,
  53382. }));
  53383. sprite.renderOrder = 1;//防止在透明后还是出现白矩形挡住其他mesh
  53384. sprite.scale.set(3,3,3);
  53385. return sprite
  53386. }
  53387. }
  53388. class Scene$1 extends EventDispatcher{
  53389. constructor(){
  53390. super();
  53391. this.annotations = new Annotation();
  53392. this.scene = new Scene();
  53393. //this.sceneBG = new THREE.Scene(); //用来放skybox
  53394. //this.sceneOverlay = new THREE.Scene();
  53395. this.scenePointCloud = new Scene();
  53396. this.cameraP = new PerspectiveCamera(this.fov, 1, Potree.config.view.near, Potree.config.view.near);
  53397. this.cameraO = new OrthographicCamera(-1, 1, 1, -1, Potree.config.view.near, Potree.settings.cameraFar);
  53398. this.cameraP.limitFar = true;//add
  53399. this.cameraVR = new PerspectiveCamera();
  53400. this.cameraBG = new Camera();
  53401. this.cameraScreenSpace = new OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
  53402. this.cameraMode = CameraMode.PERSPECTIVE;
  53403. this.overrideCamera = null;
  53404. this.pointclouds = [];
  53405. this.measurements = [];
  53406. this.profiles = [];
  53407. this.volumes = [];
  53408. this.polygonClipVolumes = [];
  53409. this.cameraAnimations = [];
  53410. this.orientedImages = [];
  53411. this.images360 = [];
  53412. this.geopackages = [];
  53413. this.fpControls = null;
  53414. this.orbitControls = null;
  53415. this.earthControls = null;
  53416. this.geoControls = null;
  53417. this.deviceControls = null;
  53418. this.inputHandler = null;
  53419. this.view = new View();
  53420. this.directionalLight = null;
  53421. this.initialize();
  53422. //-------------
  53423. this.axisArrow = new Axis();
  53424. this.scene.add(this.axisArrow);
  53425. if(!Potree.settings.isDebug)this.axisArrow.visible = false;
  53426. viewer.setObjectLayers(this.axisArrow, 'bothMapAndScene' );
  53427. }
  53428. estimateHeightAt (position) {
  53429. let height = null;
  53430. let fromSpacing = Infinity;
  53431. for (let pointcloud of this.pointclouds) {
  53432. if (pointcloud.root.geometryNode === undefined) {
  53433. continue;
  53434. }
  53435. let pHeight = null;
  53436. let pFromSpacing = Infinity;
  53437. let lpos = position.clone().sub(pointcloud.position);
  53438. lpos.z = 0;
  53439. let ray = new Ray(lpos, new Vector3(0, 0, 1));
  53440. let stack = [pointcloud.root];
  53441. while (stack.length > 0) {
  53442. let node = stack.pop();
  53443. let box = node.getBoundingBox();
  53444. let inside = ray.intersectBox(box);
  53445. if (!inside) {
  53446. continue;
  53447. }
  53448. let h = node.geometryNode.mean.z +
  53449. pointcloud.position.z +
  53450. node.geometryNode.boundingBox.min.z;
  53451. if (node.geometryNode.spacing <= pFromSpacing) {
  53452. pHeight = h;
  53453. pFromSpacing = node.geometryNode.spacing;
  53454. }
  53455. for (let index of Object.keys(node.children)) {
  53456. let child = node.children[index];
  53457. if (child.geometryNode) {
  53458. stack.push(node.children[index]);
  53459. }
  53460. }
  53461. }
  53462. if (height === null || pFromSpacing < fromSpacing) {
  53463. height = pHeight;
  53464. fromSpacing = pFromSpacing;
  53465. }
  53466. }
  53467. return height;
  53468. }
  53469. getBoundingBox(pointclouds = this.pointclouds){
  53470. let box = new Box3();
  53471. this.scenePointCloud.updateMatrixWorld(true);
  53472. this.referenceFrame.updateMatrixWorld(true);
  53473. for (let pointcloud of pointclouds) {
  53474. pointcloud.updateMatrixWorld(true);
  53475. let pointcloudBox = pointcloud.pcoGeometry.tightBoundingBox ? pointcloud.pcoGeometry.tightBoundingBox : pointcloud.boundingBox;
  53476. let boxWorld = Utils.computeTransformedBoundingBox(pointcloudBox, pointcloud.matrixWorld);
  53477. box.union(boxWorld);
  53478. }
  53479. return box;
  53480. }
  53481. addPointCloud (pointcloud) {
  53482. this.pointclouds.push(pointcloud);
  53483. this.scenePointCloud.add(pointcloud);
  53484. this.dispatchEvent({
  53485. type: 'pointcloud_added',
  53486. pointcloud: pointcloud
  53487. });
  53488. }
  53489. //add:
  53490. removePointCloud (pointcloud) {
  53491. let index = this.pointclouds.indexOf(pointcloud);
  53492. if(index == -1)return
  53493. this.pointclouds.splice(index, 1);
  53494. this.scenePointCloud.remove(pointcloud);
  53495. pointcloud.panos.forEach(pano=>{
  53496. pano.dispose();
  53497. });
  53498. }
  53499. addVolume (volume) {
  53500. this.volumes.push(volume);
  53501. this.dispatchEvent({
  53502. 'type': 'volume_added',
  53503. 'scene': this,
  53504. 'volume': volume
  53505. });
  53506. }
  53507. addOrientedImages(images){
  53508. this.orientedImages.push(images);
  53509. this.scene.add(images.node);
  53510. this.dispatchEvent({
  53511. 'type': 'oriented_images_added',
  53512. 'scene': this,
  53513. 'images': images
  53514. });
  53515. };
  53516. removeOrientedImages(images){
  53517. let index = this.orientedImages.indexOf(images);
  53518. if (index > -1) {
  53519. this.orientedImages.splice(index, 1);
  53520. this.dispatchEvent({
  53521. 'type': 'oriented_images_removed',
  53522. 'scene': this,
  53523. 'images': images
  53524. });
  53525. }
  53526. };
  53527. add360Images(images){
  53528. this.images360.push(images);
  53529. this.scene.add(images.node);
  53530. //this.sceneOverlay.add(images.node);//add
  53531. this.dispatchEvent({
  53532. 'type': '360_images_added',
  53533. 'scene': this,
  53534. 'images': images
  53535. });
  53536. }
  53537. remove360Images(images){
  53538. let index = this.images360.indexOf(images);
  53539. if (index > -1) {
  53540. this.images360.splice(index, 1);
  53541. this.dispatchEvent({
  53542. 'type': '360_images_removed',
  53543. 'scene': this,
  53544. 'images': images
  53545. });
  53546. }
  53547. }
  53548. addGeopackage(geopackage){
  53549. this.geopackages.push(geopackage);
  53550. this.scene.add(geopackage.node);
  53551. this.dispatchEvent({
  53552. 'type': 'geopackage_added',
  53553. 'scene': this,
  53554. 'geopackage': geopackage
  53555. });
  53556. };
  53557. removeGeopackage(geopackage){
  53558. let index = this.geopackages.indexOf(geopackage);
  53559. if (index > -1) {
  53560. this.geopackages.splice(index, 1);
  53561. this.dispatchEvent({
  53562. 'type': 'geopackage_removed',
  53563. 'scene': this,
  53564. 'geopackage': geopackage
  53565. });
  53566. }
  53567. };
  53568. removeVolume (volume) {
  53569. let index = this.volumes.indexOf(volume);
  53570. if (index > -1) {
  53571. this.volumes.splice(index, 1);
  53572. this.dispatchEvent({
  53573. 'type': 'volume_removed',
  53574. 'scene': this,
  53575. 'volume': volume
  53576. });
  53577. }
  53578. };
  53579. addCameraAnimation(animation) {
  53580. this.cameraAnimations.push(animation);
  53581. this.dispatchEvent({
  53582. 'type': 'camera_animation_added',
  53583. 'scene': this,
  53584. 'animation': animation
  53585. });
  53586. };
  53587. removeCameraAnimation(animation){
  53588. let index = this.cameraAnimations.indexOf(animation);
  53589. if (index > -1) {
  53590. this.cameraAnimations.splice(index, 1);
  53591. this.dispatchEvent({
  53592. 'type': 'camera_animation_removed',
  53593. 'scene': this,
  53594. 'animation': animation
  53595. });
  53596. }
  53597. };
  53598. addPolygonClipVolume(volume){
  53599. this.polygonClipVolumes.push(volume);
  53600. this.dispatchEvent({
  53601. "type": "polygon_clip_volume_added",
  53602. "scene": this,
  53603. "volume": volume
  53604. });
  53605. };
  53606. removePolygonClipVolume(volume){
  53607. let index = this.polygonClipVolumes.indexOf(volume);
  53608. if (index > -1) {
  53609. this.polygonClipVolumes.splice(index, 1);
  53610. this.dispatchEvent({
  53611. "type": "polygon_clip_volume_removed",
  53612. "scene": this,
  53613. "volume": volume
  53614. });
  53615. }
  53616. };
  53617. addMeasurement(measurement){
  53618. measurement.lengthUnit = this.lengthUnit;
  53619. measurement.lengthUnitDisplay = this.lengthUnitDisplay;
  53620. this.measurements.push(measurement);
  53621. this.dispatchEvent({
  53622. 'type': 'measurement_added',
  53623. 'scene': this,
  53624. 'measurement': measurement
  53625. });
  53626. };
  53627. removeMeasurement (measurement) {
  53628. let index = this.measurements.indexOf(measurement);
  53629. if (index > -1) {
  53630. this.measurements.splice(index, 1);
  53631. this.dispatchEvent({
  53632. 'type': 'measurement_removed',
  53633. 'scene': this,
  53634. 'measurement': measurement
  53635. });
  53636. }
  53637. }
  53638. addProfile (profile) {
  53639. this.profiles.push(profile);
  53640. this.dispatchEvent({
  53641. 'type': 'profile_added',
  53642. 'scene': this,
  53643. 'profile': profile
  53644. });
  53645. }
  53646. removeProfile (profile) {
  53647. let index = this.profiles.indexOf(profile);
  53648. if (index > -1) {
  53649. this.profiles.splice(index, 1);
  53650. this.dispatchEvent({
  53651. 'type': 'profile_removed',
  53652. 'scene': this,
  53653. 'profile': profile
  53654. });
  53655. }
  53656. }
  53657. removeAllMeasurements () {
  53658. while (this.measurements.length > 0) {
  53659. this.removeMeasurement(this.measurements[0]);
  53660. }
  53661. while (this.profiles.length > 0) {
  53662. this.removeProfile(this.profiles[0]);
  53663. }
  53664. while (this.volumes.length > 0) {
  53665. this.removeVolume(this.volumes[0]);
  53666. }
  53667. }
  53668. removeAllClipVolumes(){
  53669. let clipVolumes = this.volumes.filter(volume => volume.clip === true);
  53670. for(let clipVolume of clipVolumes){
  53671. this.removeVolume(clipVolume);
  53672. }
  53673. while(this.polygonClipVolumes.length > 0){
  53674. this.removePolygonClipVolume(this.polygonClipVolumes[0]);
  53675. }
  53676. }
  53677. getActiveCamera() {
  53678. return viewer.mainViewport.camera
  53679. if(this.overrideCamera){
  53680. return this.overrideCamera;
  53681. }
  53682. if(this.cameraMode === CameraMode.PERSPECTIVE){
  53683. return this.cameraP;
  53684. }else if(this.cameraMode === CameraMode.ORTHOGRAPHIC){
  53685. return this.cameraO;
  53686. }else if(this.cameraMode === CameraMode.VR){
  53687. return this.cameraVR;
  53688. }
  53689. return null;
  53690. }
  53691. initialize(){
  53692. this.referenceFrame = new Object3D();
  53693. this.referenceFrame.matrixAutoUpdate = false;
  53694. this.scenePointCloud.add(this.referenceFrame);
  53695. if(window.axisYup){
  53696. }else {
  53697. this.cameraP.up.set(0, 0, 1);
  53698. this.cameraO.up.set(0, 0, 1);
  53699. }
  53700. this.cameraP.position.set(1000, 1000, 1000);
  53701. this.cameraO.position.set(1000, 1000, 1000);
  53702. //this.camera.rotation.y = -Math.PI / 4;
  53703. //this.camera.rotation.x = -Math.PI / 6;
  53704. this.cameraScreenSpace.lookAt(new Vector3(0, 0, 0), new Vector3(0, 0, -1), new Vector3(0, 1, 0));
  53705. this.directionalLight = new DirectionalLight( 0xffffff, 0.5 );
  53706. this.directionalLight.position.set( 10, 10, 10 );
  53707. this.directionalLight.lookAt( new Vector3(0, 0, 0));
  53708. this.scenePointCloud.add( this.directionalLight );
  53709. let light = new AmbientLight( 0x555555 ); // soft white light
  53710. this.scenePointCloud.add( light );
  53711. //add:------给空间模型的box 或其他obj------
  53712. /* let light2 = new THREE.AmbientLight( 16777215, 1 );
  53713. viewer.setObjectLayers(light2, 'bothMapAndScene')
  53714. this.scene.add(light2)
  53715. let light3 = new THREE.DirectionalLight( 16777215, 1);
  53716. light3.position.set( 10, 10, 10 );
  53717. light3.lookAt( new THREE.Vector3(0, 0, 0));
  53718. viewer.setObjectLayers(light3, 'bothMapAndScene')
  53719. this.scene.add(light3) */
  53720. //--------------------------------------------
  53721. { // background
  53722. let texture = Utils.createBackgroundTexture(512, 512);
  53723. texture.minFilter = texture.magFilter = NearestFilter;
  53724. texture.minFilter = texture.magFilter = LinearFilter;
  53725. let bg = new Mesh(
  53726. new PlaneBufferGeometry(2, 2, 1),
  53727. new MeshBasicMaterial({
  53728. map: texture
  53729. })
  53730. );
  53731. bg.material.depthTest = false;
  53732. bg.material.depthWrite = false;
  53733. bg.name = 'bg';
  53734. //this.sceneBG.add(bg);
  53735. this.scene.add(bg);
  53736. bg.layers.set(Potree.config.renderLayers.bg);
  53737. }
  53738. { // background color
  53739. let bg2 = new Mesh(
  53740. new PlaneBufferGeometry(2, 2, 1),
  53741. new MeshBasicMaterial({
  53742. transparent : true
  53743. })
  53744. );
  53745. bg2.material.depthTest = false;
  53746. bg2.material.depthWrite = false;
  53747. bg2.name = 'bg2';
  53748. this.scene.add(bg2);
  53749. bg2.layers.set(Potree.config.renderLayers.bg2);
  53750. this.bg2 = bg2;
  53751. }
  53752. // { // lights
  53753. // {
  53754. // let light = new THREE.DirectionalLight(0xffffff);
  53755. // light.position.set(10, 10, 1);
  53756. // light.target.position.set(0, 0, 0);
  53757. // this.scene.add(light);
  53758. // }
  53759. // {
  53760. // let light = new THREE.DirectionalLight(0xffffff);
  53761. // light.position.set(-10, 10, 1);
  53762. // light.target.position.set(0, 0, 0);
  53763. // this.scene.add(light);
  53764. // }
  53765. // {
  53766. // let light = new THREE.DirectionalLight(0xffffff);
  53767. // light.position.set(0, -10, 20);
  53768. // light.target.position.set(0, 0, 0);
  53769. // this.scene.add(light);
  53770. // }
  53771. // }
  53772. }
  53773. /* switchBg(type){//add
  53774. let bg,;
  53775. if(type == 'gradient'){
  53776. bg
  53777. }else if(type == 'overlayColor'){
  53778. }
  53779. } */
  53780. addAnnotation(position, args = {}){
  53781. if(position instanceof Array){
  53782. args.position = new Vector3().fromArray(position);
  53783. } else if (position.x != null) {
  53784. args.position = position;
  53785. }
  53786. let annotation = new Annotation(args);
  53787. this.annotations.add(annotation);
  53788. return annotation;
  53789. }
  53790. getAnnotations () {
  53791. return this.annotations;
  53792. };
  53793. removeAnnotation(annotationToRemove) {
  53794. this.annotations.remove(annotationToRemove);
  53795. }
  53796. };
  53797. // http://epsg.io/
  53798. //see http://openlayers.org/
  53799. proj4.defs([
  53800. ['UTM10N', '+proj=utm +zone=10 +ellps=GRS80 +datum=NAD83 +units=m +no_defs'],
  53801. ['EPSG:6339', '+proj=utm +zone=10 +ellps=GRS80 +units=m +no_defs'],
  53802. ['EPSG:6340', '+proj=utm +zone=11 +ellps=GRS80 +units=m +no_defs'],
  53803. ['EPSG:6341', '+proj=utm +zone=12 +ellps=GRS80 +units=m +no_defs'],
  53804. ['EPSG:6342', '+proj=utm +zone=13 +ellps=GRS80 +units=m +no_defs'],
  53805. ['EPSG:6343', '+proj=utm +zone=14 +ellps=GRS80 +units=m +no_defs'],
  53806. ['EPSG:6344', '+proj=utm +zone=15 +ellps=GRS80 +units=m +no_defs'],
  53807. ['EPSG:6345', '+proj=utm +zone=16 +ellps=GRS80 +units=m +no_defs'],
  53808. ['EPSG:6346', '+proj=utm +zone=17 +ellps=GRS80 +units=m +no_defs'],
  53809. ['EPSG:6347', '+proj=utm +zone=18 +ellps=GRS80 +units=m +no_defs'],
  53810. ['EPSG:6348', '+proj=utm +zone=19 +ellps=GRS80 +units=m +no_defs'],
  53811. ['EPSG:26910', '+proj=utm +zone=10 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53812. ['EPSG:26911', '+proj=utm +zone=11 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53813. ['EPSG:26912', '+proj=utm +zone=12 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53814. ['EPSG:26913', '+proj=utm +zone=13 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53815. ['EPSG:26914', '+proj=utm +zone=14 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53816. ['EPSG:26915', '+proj=utm +zone=15 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53817. ['EPSG:26916', '+proj=utm +zone=16 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53818. ['EPSG:26917', '+proj=utm +zone=17 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53819. ['EPSG:26918', '+proj=utm +zone=18 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53820. ['EPSG:26919', '+proj=utm +zone=19 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '],
  53821. ]);
  53822. class MapView{
  53823. constructor (viewer) {
  53824. this.viewer = viewer;
  53825. this.webMapService = 'WMTS';
  53826. this.mapProjectionName = 'EPSG:3857'; //navvis也是这个
  53827. this.mapProjection = proj4.defs(this.mapProjectionName);
  53828. this.sceneProjection = null;
  53829. this.extentsLayer = null;
  53830. this.cameraLayer = null;
  53831. this.toolLayer = null;
  53832. this.sourcesLayer = null;
  53833. this.sourcesLabelLayer = null;
  53834. this.images360Layer = null;
  53835. this.enabled = false;
  53836. this.createAnnotationStyle = (text) => {
  53837. return [
  53838. new ol.style.Style({
  53839. image: new ol.style.Circle({
  53840. radius: 10,
  53841. stroke: new ol.style.Stroke({
  53842. color: [255, 255, 255, 0.5],
  53843. width: 2
  53844. }),
  53845. fill: new ol.style.Fill({
  53846. color: [0, 0, 0, 0.5]
  53847. })
  53848. })
  53849. })
  53850. ];
  53851. };
  53852. this.createLabelStyle = (text) => {
  53853. let style = new ol.style.Style({
  53854. image: new ol.style.Circle({
  53855. radius: 6,
  53856. stroke: new ol.style.Stroke({
  53857. color: 'white',
  53858. width: 2
  53859. }),
  53860. fill: new ol.style.Fill({
  53861. color: 'green'
  53862. })
  53863. }),
  53864. text: new ol.style.Text({
  53865. font: '12px helvetica,sans-serif',
  53866. text: text,
  53867. fill: new ol.style.Fill({
  53868. color: '#000'
  53869. }),
  53870. stroke: new ol.style.Stroke({
  53871. color: '#fff',
  53872. width: 2
  53873. })
  53874. })
  53875. });
  53876. return style;
  53877. };
  53878. }
  53879. showSources (show) {
  53880. this.sourcesLayer.setVisible(show);
  53881. this.sourcesLabelLayer.setVisible(show);
  53882. }
  53883. init () {
  53884. if(typeof ol === "undefined"){
  53885. return;
  53886. }
  53887. this.elMap = $('#potree_map');
  53888. this.elMap.draggable({ handle: $('#potree_map_header') });
  53889. this.elMap.resizable();
  53890. this.elTooltip = $(`<div style="position: relative; z-index: 100"></div>`);
  53891. this.elMap.append(this.elTooltip);
  53892. let extentsLayer = this.getExtentsLayer();
  53893. let cameraLayer = this.getCameraLayer();
  53894. this.getToolLayer();
  53895. let sourcesLayer = this.getSourcesLayer();
  53896. this.images360Layer = this.getImages360Layer();
  53897. this.getSourcesLabelLayer();
  53898. this.getAnnotationsLayer();
  53899. let mousePositionControl = new ol.control.MousePosition({
  53900. coordinateFormat: ol.coordinate.createStringXY(5),
  53901. projection: 'EPSG:4326',
  53902. undefinedHTML: '&nbsp;'
  53903. });
  53904. let _this = this;
  53905. let DownloadSelectionControl = function (optOptions) {
  53906. let options = optOptions || {};
  53907. // TOGGLE TILES
  53908. let btToggleTiles = document.createElement('button');
  53909. btToggleTiles.innerHTML = 'T';
  53910. btToggleTiles.addEventListener('click', () => {
  53911. let visible = sourcesLayer.getVisible();
  53912. _this.showSources(!visible);
  53913. }, false);
  53914. btToggleTiles.style.float = 'left';
  53915. btToggleTiles.title = 'show / hide tiles';
  53916. // DOWNLOAD SELECTED TILES
  53917. let link = document.createElement('a');
  53918. link.href = '#';
  53919. link.download = 'list.txt';
  53920. link.style.float = 'left';
  53921. let button = document.createElement('button');
  53922. button.innerHTML = 'D';
  53923. link.appendChild(button);
  53924. let handleDownload = (e) => {
  53925. let features = selectedFeatures.getArray();
  53926. let url = [document.location.protocol, '//', document.location.host, document.location.pathname].join('');
  53927. if (features.length === 0) {
  53928. alert('No tiles were selected. Select area with ctrl + left mouse button!');
  53929. e.preventDefault();
  53930. e.stopImmediatePropagation();
  53931. return false;
  53932. } else if (features.length === 1) {
  53933. let feature = features[0];
  53934. if (feature.source) {
  53935. let cloudjsurl = feature.pointcloud.pcoGeometry.url;
  53936. let sourceurl = new URL(url + '/../' + cloudjsurl + '/../source/' + feature.source.name);
  53937. link.href = sourceurl.href;
  53938. link.download = feature.source.name;
  53939. }
  53940. } else {
  53941. let content = '';
  53942. for (let i = 0; i < features.length; i++) {
  53943. let feature = features[i];
  53944. if (feature.source) {
  53945. let cloudjsurl = feature.pointcloud.pcoGeometry.url;
  53946. let sourceurl = new URL(url + '/../' + cloudjsurl + '/../source/' + feature.source.name);
  53947. content += sourceurl.href + '\n';
  53948. }
  53949. }
  53950. let uri = 'data:application/octet-stream;base64,' + btoa(content);
  53951. link.href = uri;
  53952. link.download = 'list_of_files.txt';
  53953. }
  53954. };
  53955. button.addEventListener('click', handleDownload, false);
  53956. // assemble container
  53957. let element = document.createElement('div');
  53958. element.className = 'ol-unselectable ol-control';
  53959. element.appendChild(link);
  53960. element.appendChild(btToggleTiles);
  53961. element.style.bottom = '0.5em';
  53962. element.style.left = '0.5em';
  53963. element.title = 'Download file or list of selected tiles. Select tile with left mouse button or area using ctrl + left mouse.';
  53964. ol.control.Control.call(this, {
  53965. element: element,
  53966. target: options.target
  53967. });
  53968. };
  53969. ol.inherits(DownloadSelectionControl, ol.control.Control);
  53970. this.map = new ol.Map({
  53971. controls: ol.control.defaults({
  53972. attributionOptions: ({
  53973. collapsible: false
  53974. })
  53975. }).extend([
  53976. // this.controls.zoomToExtent,
  53977. new DownloadSelectionControl(),
  53978. mousePositionControl
  53979. ]),
  53980. layers: [
  53981. new ol.layer.Tile({source: new ol.source.OSM()}),
  53982. this.toolLayer,
  53983. this.annotationsLayer,
  53984. this.sourcesLayer,
  53985. this.sourcesLabelLayer,
  53986. this.images360Layer,
  53987. extentsLayer,
  53988. cameraLayer
  53989. ],
  53990. target: 'potree_map_content',
  53991. view: new ol.View({
  53992. center: this.olCenter,
  53993. zoom: 9
  53994. })
  53995. });
  53996. // DRAGBOX / SELECTION
  53997. this.dragBoxLayer = new ol.layer.Vector({
  53998. source: new ol.source.Vector({}),
  53999. style: new ol.style.Style({
  54000. stroke: new ol.style.Stroke({
  54001. color: 'rgba(0, 0, 255, 1)',
  54002. width: 2
  54003. })
  54004. })
  54005. });
  54006. this.map.addLayer(this.dragBoxLayer);
  54007. let select = new ol.interaction.Select();
  54008. this.map.addInteraction(select);
  54009. let selectedFeatures = select.getFeatures();
  54010. let dragBox = new ol.interaction.DragBox({
  54011. condition: ol.events.condition.platformModifierKeyOnly
  54012. });
  54013. this.map.addInteraction(dragBox);
  54014. // this.map.on('pointermove', evt => {
  54015. // let pixel = evt.pixel;
  54016. // let feature = this.map.forEachFeatureAtPixel(pixel, function (feature) {
  54017. // return feature;
  54018. // });
  54019. // // console.log(feature);
  54020. // // this.elTooltip.css("display", feature ? '' : 'none');
  54021. // this.elTooltip.css('display', 'none');
  54022. // if (feature && feature.onHover) {
  54023. // feature.onHover(evt);
  54024. // // overlay.setPosition(evt.coordinate);
  54025. // // tooltip.innerHTML = feature.get('name');
  54026. // }
  54027. // });
  54028. this.map.on('click', evt => {
  54029. let pixel = evt.pixel;
  54030. let feature = this.map.forEachFeatureAtPixel(pixel, function (feature) {
  54031. return feature;
  54032. });
  54033. if (feature && feature.onClick) {
  54034. feature.onClick(evt);
  54035. }
  54036. });
  54037. dragBox.on('boxend', (e) => {
  54038. // features that intersect the box are added to the collection of
  54039. // selected features, and their names are displayed in the "info"
  54040. // div
  54041. let extent = dragBox.getGeometry().getExtent();
  54042. this.getSourcesLayer().getSource().forEachFeatureIntersectingExtent(extent, (feature) => {
  54043. selectedFeatures.push(feature);
  54044. });
  54045. });
  54046. // clear selection when drawing a new box and when clicking on the map
  54047. dragBox.on('boxstart', (e) => {
  54048. selectedFeatures.clear();
  54049. });
  54050. this.map.on('click', () => {
  54051. selectedFeatures.clear();
  54052. });
  54053. this.viewer.addEventListener('scene_changed', e => {
  54054. this.setScene(e.scene);
  54055. });
  54056. this.onPointcloudAdded = e => {
  54057. this.load(e.pointcloud);
  54058. };
  54059. this.on360ImagesAdded = e => {
  54060. this.addImages360(e.images);
  54061. };
  54062. this.onAnnotationAdded = e => {
  54063. if (!this.sceneProjection) {
  54064. return;
  54065. }
  54066. let annotation = e.annotation;
  54067. let position = annotation.position;
  54068. let mapPos = this.toMap.forward([position.x, position.y]);
  54069. let feature = new ol.Feature({
  54070. geometry: new ol.geom.Point(mapPos),
  54071. name: annotation.title
  54072. });
  54073. feature.setStyle(this.createAnnotationStyle(annotation.title));
  54074. feature.onHover = evt => {
  54075. let coordinates = feature.getGeometry().getCoordinates();
  54076. let p = this.map.getPixelFromCoordinate(coordinates);
  54077. this.elTooltip.html(annotation.title);
  54078. this.elTooltip.css('display', '');
  54079. this.elTooltip.css('left', `${p[0]}px`);
  54080. this.elTooltip.css('top', `${p[1]}px`);
  54081. };
  54082. feature.onClick = evt => {
  54083. annotation.clickTitle();
  54084. };
  54085. this.getAnnotationsLayer().getSource().addFeature(feature);
  54086. };
  54087. this.setScene(this.viewer.scene);
  54088. }
  54089. setScene (scene) {
  54090. if (this.scene === scene) {
  54091. return;
  54092. };
  54093. if (this.scene) {
  54094. this.scene.removeEventListener('pointcloud_added', this.onPointcloudAdded);
  54095. this.scene.removeEventListener('360_images_added', this.on360ImagesAdded);
  54096. this.scene.annotations.removeEventListener('annotation_added', this.onAnnotationAdded);
  54097. }
  54098. this.scene = scene;
  54099. this.scene.addEventListener('pointcloud_added', this.onPointcloudAdded);
  54100. this.scene.addEventListener('360_images_added', this.on360ImagesAdded);
  54101. this.scene.annotations.addEventListener('annotation_added', this.onAnnotationAdded);
  54102. for (let pointcloud of this.viewer.scene.pointclouds) {
  54103. this.load(pointcloud);
  54104. }
  54105. this.viewer.scene.annotations.traverseDescendants(annotation => {
  54106. this.onAnnotationAdded({annotation: annotation});
  54107. });
  54108. for(let images of this.viewer.scene.images360){
  54109. this.on360ImagesAdded({images: images});
  54110. }
  54111. }
  54112. getExtentsLayer () {
  54113. if (this.extentsLayer) {
  54114. return this.extentsLayer;
  54115. }
  54116. this.gExtent = new ol.geom.LineString([[0, 0], [0, 0]]);
  54117. let feature = new ol.Feature(this.gExtent);
  54118. let featureVector = new ol.source.Vector({
  54119. features: [feature]
  54120. });
  54121. this.extentsLayer = new ol.layer.Vector({
  54122. source: featureVector,
  54123. style: new ol.style.Style({
  54124. fill: new ol.style.Fill({
  54125. color: 'rgba(255, 255, 255, 0.2)'
  54126. }),
  54127. stroke: new ol.style.Stroke({
  54128. color: '#0000ff',
  54129. width: 2
  54130. }),
  54131. image: new ol.style.Circle({
  54132. radius: 3,
  54133. fill: new ol.style.Fill({
  54134. color: '#0000ff'
  54135. })
  54136. })
  54137. })
  54138. });
  54139. return this.extentsLayer;
  54140. }
  54141. getAnnotationsLayer () {
  54142. if (this.annotationsLayer) {
  54143. return this.annotationsLayer;
  54144. }
  54145. this.annotationsLayer = new ol.layer.Vector({
  54146. source: new ol.source.Vector({
  54147. }),
  54148. style: new ol.style.Style({
  54149. fill: new ol.style.Fill({
  54150. color: 'rgba(255, 0, 0, 1)'
  54151. }),
  54152. stroke: new ol.style.Stroke({
  54153. color: 'rgba(255, 0, 0, 1)',
  54154. width: 2
  54155. })
  54156. })
  54157. });
  54158. return this.annotationsLayer;
  54159. }
  54160. getCameraLayer () {
  54161. if (this.cameraLayer) {
  54162. return this.cameraLayer;
  54163. }
  54164. // CAMERA LAYER
  54165. this.gCamera = new ol.geom.LineString([[0, 0], [0, 0], [0, 0], [0, 0]]);
  54166. let feature = new ol.Feature(this.gCamera);
  54167. let featureVector = new ol.source.Vector({
  54168. features: [feature]
  54169. });
  54170. this.cameraLayer = new ol.layer.Vector({
  54171. source: featureVector,
  54172. style: new ol.style.Style({
  54173. stroke: new ol.style.Stroke({
  54174. color: '#0000ff',
  54175. width: 2
  54176. })
  54177. })
  54178. });
  54179. return this.cameraLayer;
  54180. }
  54181. getToolLayer () {
  54182. if (this.toolLayer) {
  54183. return this.toolLayer;
  54184. }
  54185. this.toolLayer = new ol.layer.Vector({
  54186. source: new ol.source.Vector({
  54187. }),
  54188. style: new ol.style.Style({
  54189. fill: new ol.style.Fill({
  54190. color: 'rgba(255, 0, 0, 1)'
  54191. }),
  54192. stroke: new ol.style.Stroke({
  54193. color: 'rgba(255, 0, 0, 1)',
  54194. width: 2
  54195. })
  54196. })
  54197. });
  54198. return this.toolLayer;
  54199. }
  54200. getImages360Layer(){
  54201. if(this.images360Layer){
  54202. return this.images360Layer;
  54203. }
  54204. let style = new ol.style.Style({
  54205. image: new ol.style.Circle({
  54206. radius: 4,
  54207. stroke: new ol.style.Stroke({
  54208. color: [255, 0, 0, 1],
  54209. width: 2
  54210. }),
  54211. fill: new ol.style.Fill({
  54212. color: [255, 100, 100, 1]
  54213. })
  54214. })
  54215. });
  54216. let layer = new ol.layer.Vector({
  54217. source: new ol.source.Vector({}),
  54218. style: style,
  54219. });
  54220. this.images360Layer = layer;
  54221. return this.images360Layer;
  54222. }
  54223. getSourcesLayer () {
  54224. if (this.sourcesLayer) {
  54225. return this.sourcesLayer;
  54226. }
  54227. this.sourcesLayer = new ol.layer.Vector({
  54228. source: new ol.source.Vector({}),
  54229. style: new ol.style.Style({
  54230. fill: new ol.style.Fill({
  54231. color: 'rgba(0, 0, 150, 0.1)'
  54232. }),
  54233. stroke: new ol.style.Stroke({
  54234. color: 'rgba(0, 0, 150, 1)',
  54235. width: 1
  54236. })
  54237. })
  54238. });
  54239. return this.sourcesLayer;
  54240. }
  54241. getSourcesLabelLayer () {
  54242. if (this.sourcesLabelLayer) {
  54243. return this.sourcesLabelLayer;
  54244. }
  54245. this.sourcesLabelLayer = new ol.layer.Vector({
  54246. source: new ol.source.Vector({
  54247. }),
  54248. style: new ol.style.Style({
  54249. fill: new ol.style.Fill({
  54250. color: 'rgba(255, 0, 0, 0.1)'
  54251. }),
  54252. stroke: new ol.style.Stroke({
  54253. color: 'rgba(255, 0, 0, 1)',
  54254. width: 2
  54255. })
  54256. }),
  54257. minResolution: 0.01,
  54258. maxResolution: 20
  54259. });
  54260. return this.sourcesLabelLayer;
  54261. }
  54262. setSceneProjection (sceneProjection) {
  54263. this.sceneProjection = sceneProjection;
  54264. this.toMap = proj4(this.sceneProjection, this.mapProjection);
  54265. this.toScene = proj4(this.mapProjection, this.sceneProjection);
  54266. };
  54267. getMapExtent () {
  54268. let bb = this.viewer.getBoundingBox();
  54269. let bottomLeft = this.toMap.forward([bb.min.x, bb.min.y]);
  54270. let bottomRight = this.toMap.forward([bb.max.x, bb.min.y]);
  54271. let topRight = this.toMap.forward([bb.max.x, bb.max.y]);
  54272. let topLeft = this.toMap.forward([bb.min.x, bb.max.y]);
  54273. let extent = {
  54274. bottomLeft: bottomLeft,
  54275. bottomRight: bottomRight,
  54276. topRight: topRight,
  54277. topLeft: topLeft
  54278. };
  54279. return extent;
  54280. };
  54281. getMapCenter () {
  54282. let mapExtent = this.getMapExtent();
  54283. let mapCenter = [
  54284. (mapExtent.bottomLeft[0] + mapExtent.topRight[0]) / 2,
  54285. (mapExtent.bottomLeft[1] + mapExtent.topRight[1]) / 2
  54286. ];
  54287. return mapCenter;
  54288. };
  54289. updateToolDrawings () {
  54290. this.toolLayer.getSource().clear();
  54291. let profiles = this.viewer.profileTool.profiles;
  54292. for (let i = 0; i < profiles.length; i++) {
  54293. let profile = profiles[i];
  54294. let coordinates = [];
  54295. for (let j = 0; j < profile.points.length; j++) {
  54296. let point = profile.points[j];
  54297. let pointMap = this.toMap.forward([point.x, point.y]);
  54298. coordinates.push(pointMap);
  54299. }
  54300. let line = new ol.geom.LineString(coordinates);
  54301. let feature = new ol.Feature(line);
  54302. this.toolLayer.getSource().addFeature(feature);
  54303. }
  54304. let measurements = this.viewer.measuringTool.measurements;
  54305. for (let i = 0; i < measurements.length; i++) {
  54306. let measurement = measurements[i];
  54307. let coordinates = [];
  54308. for (let j = 0; j < measurement.points.length; j++) {
  54309. let point = measurement.points[j].position;
  54310. let pointMap = this.toMap.forward([point.x, point.y]);
  54311. coordinates.push(pointMap);
  54312. }
  54313. if (measurement.closed && measurement.points.length > 0) {
  54314. coordinates.push(coordinates[0]);
  54315. }
  54316. let line = new ol.geom.LineString(coordinates);
  54317. let feature = new ol.Feature(line);
  54318. this.toolLayer.getSource().addFeature(feature);
  54319. }
  54320. }
  54321. addImages360(images){
  54322. let transform = this.toMap.forward;
  54323. let layer = this.getImages360Layer();
  54324. for(let pano of images.panos){
  54325. let p = transform([pano.position.x, pano.position.y]);
  54326. let feature = new ol.Feature({
  54327. 'geometry': new ol.geom.Point(p),
  54328. });
  54329. feature.onClick = () => {
  54330. //images.focus(pano);
  54331. images.flyToPano({
  54332. pano
  54333. });
  54334. };
  54335. layer.getSource().addFeature(feature);
  54336. }
  54337. }
  54338. async load (pointcloud) {
  54339. if (!pointcloud) {
  54340. return;
  54341. }
  54342. /* if (!pointcloud.projection) {
  54343. return;
  54344. }
  54345. */
  54346. if (!this.sceneProjection) {
  54347. try {
  54348. this.setSceneProjection(proj4.defs("NAVVIS:TMERC") || pointcloud.projection);
  54349. }catch (e) {
  54350. console.log('Failed projection:', e);
  54351. if (pointcloud.fallbackProjection) {
  54352. try {
  54353. console.log('Trying fallback projection...');
  54354. this.setSceneProjection(pointcloud.fallbackProjection);
  54355. console.log('Set projection from fallback');
  54356. }catch (e) {
  54357. console.log('Failed fallback projection:', e);
  54358. return;
  54359. }
  54360. }else {
  54361. return;
  54362. };
  54363. }
  54364. }
  54365. let mapExtent = this.getMapExtent();
  54366. let mapCenter = this.getMapCenter();
  54367. let view = this.map.getView();
  54368. view.setCenter(mapCenter);
  54369. this.gExtent.setCoordinates([
  54370. mapExtent.bottomLeft,
  54371. mapExtent.bottomRight,
  54372. mapExtent.topRight,
  54373. mapExtent.topLeft,
  54374. mapExtent.bottomLeft
  54375. ]);
  54376. view.fit(this.gExtent, [300, 300], {
  54377. constrainResolution: false
  54378. });
  54379. if (pointcloud.pcoGeometry.type == 'ept'){
  54380. return;
  54381. }
  54382. let url = `${pointcloud.pcoGeometry.url}/../sources.json`;
  54383. //let response = await fetch(url);
  54384. fetch(url).then(async (response) => {
  54385. let data = await response.json();
  54386. let sources = data.sources;
  54387. for (let i = 0; i < sources.length; i++) {
  54388. let source = sources[i];
  54389. let name = source.name;
  54390. let bounds = source.bounds;
  54391. let mapBounds = {
  54392. min: this.toMap.forward([bounds.min[0], bounds.min[1]]),
  54393. max: this.toMap.forward([bounds.max[0], bounds.max[1]])
  54394. };
  54395. let mapCenter = [
  54396. (mapBounds.min[0] + mapBounds.max[0]) / 2,
  54397. (mapBounds.min[1] + mapBounds.max[1]) / 2
  54398. ];
  54399. let p1 = this.toMap.forward([bounds.min[0], bounds.min[1]]);
  54400. let p2 = this.toMap.forward([bounds.max[0], bounds.min[1]]);
  54401. let p3 = this.toMap.forward([bounds.max[0], bounds.max[1]]);
  54402. let p4 = this.toMap.forward([bounds.min[0], bounds.max[1]]);
  54403. // let feature = new ol.Feature({
  54404. // 'geometry': new ol.geom.LineString([p1, p2, p3, p4, p1])
  54405. // });
  54406. let feature = new ol.Feature({
  54407. 'geometry': new ol.geom.Polygon([[p1, p2, p3, p4, p1]])
  54408. });
  54409. feature.source = source;
  54410. feature.pointcloud = pointcloud;
  54411. this.getSourcesLayer().getSource().addFeature(feature);
  54412. feature = new ol.Feature({
  54413. geometry: new ol.geom.Point(mapCenter),
  54414. name: name
  54415. });
  54416. feature.setStyle(this.createLabelStyle(name));
  54417. this.sourcesLabelLayer.getSource().addFeature(feature);
  54418. }
  54419. }).catch(() => {
  54420. });
  54421. }
  54422. toggle () {
  54423. if (this.elMap.is(':visible')) {
  54424. this.elMap.css('display', 'none');
  54425. this.enabled = false;
  54426. } else {
  54427. this.elMap.css('display', 'block');
  54428. this.enabled = true;
  54429. }
  54430. }
  54431. update (delta) {
  54432. if (!this.sceneProjection) {
  54433. return;
  54434. }
  54435. let pm = $('#potree_map');
  54436. if (!this.enabled) {
  54437. return;
  54438. }
  54439. // resize
  54440. let mapSize = this.map.getSize();
  54441. let resized = (pm.width() !== mapSize[0] || pm.height() !== mapSize[1]);
  54442. if (resized) {
  54443. this.map.updateSize();
  54444. }
  54445. //
  54446. let camera = this.viewer.scene.getActiveCamera();
  54447. let scale = this.map.getView().getResolution();
  54448. let campos = camera.position;
  54449. let camdir = camera.getWorldDirection(new Vector3());
  54450. let sceneLookAt = camdir.clone().multiplyScalar(30 * scale).add(campos);
  54451. let geoPos = camera.position;
  54452. let geoLookAt = sceneLookAt;
  54453. let mapPos = new Vector2$1().fromArray(this.toMap.forward([geoPos.x, geoPos.y]));
  54454. let mapLookAt = new Vector2$1().fromArray(this.toMap.forward([geoLookAt.x, geoLookAt.y]));
  54455. let mapDir = new Vector2$1().subVectors(mapLookAt, mapPos).normalize();
  54456. mapLookAt = mapPos.clone().add(mapDir.clone().multiplyScalar(30 * scale));
  54457. let mapLength = mapPos.distanceTo(mapLookAt);
  54458. let mapSide = new Vector2$1(-mapDir.y, mapDir.x);
  54459. let p1 = mapPos.toArray();
  54460. let p2 = mapLookAt.clone().sub(mapSide.clone().multiplyScalar(0.3 * mapLength)).toArray();
  54461. let p3 = mapLookAt.clone().add(mapSide.clone().multiplyScalar(0.3 * mapLength)).toArray();
  54462. this.gCamera.setCoordinates([p1, p2, p3, p1]);
  54463. }
  54464. get sourcesVisible () {
  54465. return this.getSourcesLayer().getVisible();
  54466. }
  54467. set sourcesVisible (value) {
  54468. this.getSourcesLayer().setVisible(value);
  54469. }
  54470. }
  54471. let texLoader$1 = new TextureLoader();
  54472. texLoader$1.crossOrigin = "anonymous";
  54473. let createErrorMaterial = function() {
  54474. var t = new MeshBasicMaterial({
  54475. transparent: !0,
  54476. depthWrite: !1,
  54477. depthTest: !0,
  54478. opacity: 1,
  54479. side: DoubleSide
  54480. });
  54481. return t.color = new Color(3355443),
  54482. t
  54483. };
  54484. let tempVector = new Vector3, //sharedata
  54485. face1 = new Face3(0,1,2),
  54486. face2 = new Face3(2,3,0),
  54487. errorMaterial = createErrorMaterial(),
  54488. uv00 = new Vector2$1(0,0),
  54489. uv01 = new Vector2$1(0,1),
  54490. uv10 = new Vector2$1(1,0),
  54491. uv11 = new Vector2$1(1,1),
  54492. face1UV = [uv00, uv10, uv11],
  54493. face2UV = [uv11, uv01, uv00];
  54494. const HALF_WORLD_SIZE = 21e6;
  54495. const MAX_VERTICAL_DIST = 2;
  54496. const MAX_VERTICAL_DIST_TO_BEST = 1;
  54497. //高德坐标拾取工具 : https://lbs.amap.com/tools/picker
  54498. class MapLayer extends EventDispatcher{ // 包括了 MapLayerBase SceneLayer
  54499. constructor(viewer_, viewport){
  54500. super();
  54501. this.sceneGroup = new Object3D;
  54502. this.sceneGroup.name = "MapLayer";
  54503. this.loadingInProgress = 0;
  54504. this.maps = [];
  54505. this.frustum = new Frustum;
  54506. this.frustumMatrix = new Matrix4;
  54507. this.tileColor = /* i && i.tileColor ? i.tileColor : */new Color(16777215);
  54508. this.viewport = viewport;
  54509. this.changeViewer(viewer_);
  54510. //添加地图
  54511. var map = new TiledMapOpenStreetMap(this, this.tileColor );
  54512. this.addMap(map);
  54513. //map.setEnable(false)
  54514. /* this.on('needUpdate',()=>{
  54515. this.mapLayer.update()
  54516. })
  54517. */
  54518. }
  54519. addMapEntity(data, datasetId){
  54520. if(!data || !data[0]){
  54521. Potree.Log('平面图无数据','red');
  54522. return
  54523. }
  54524. var floorplan = new TiledMapFromEntity(this, this.tileColor, data[0] );//[0]?
  54525. if(floorplan){
  54526. floorplan.name += "_"+ datasetId;
  54527. this.addMap(floorplan);
  54528. floorplan.updateProjection();
  54529. floorplan.updateObjectGroup();
  54530. let visible = false;
  54531. if(datasetId in Potree.settings.floorplanEnables){
  54532. visible = Potree.settings.floorplanEnables[datasetId];
  54533. }else {
  54534. visible = Potree.settings.floorplanEnable;
  54535. }
  54536. if(visible){
  54537. this.needUpdate = true;
  54538. }else {
  54539. floorplan.setEnable(false);
  54540. }
  54541. this.dispatchEvent({type:'floorplanLoaded', floorplan});
  54542. }
  54543. return floorplan
  54544. }
  54545. getFloorplan(datasetId){
  54546. return this.maps.find(e=>e.name == 'floorplan'+"_"+ datasetId )
  54547. }
  54548. addMap(t){
  54549. this.maps.push(t);
  54550. //this.view.invalidateScene()
  54551. this.needUpdate = true;
  54552. }
  54553. removeMap(t){
  54554. var e = this.maps.indexOf(t);
  54555. if(e >= 0){
  54556. t.removeFromSceneGroup(this.sceneGroup);
  54557. this.maps.splice(e, 1);
  54558. }
  54559. /* this.view.invalidateScene() */
  54560. this.needUpdate = true;
  54561. this.viewer.dispatchEvent({
  54562. type:'content_changed'
  54563. });
  54564. }
  54565. changeViewer(viewer_){//add
  54566. this.viewer = viewer_;
  54567. }
  54568. initProjection(){
  54569. this.maps.forEach(map=>{
  54570. map.updateProjection();
  54571. map.updateObjectGroup();
  54572. });
  54573. }
  54574. visibilityChanged(){
  54575. if (!this.visible)
  54576. for (var t = 0, e = this.maps; t < e.length; t++){
  54577. e[t].removeFromSceneGroup(this.sceneGroup);
  54578. }
  54579. }
  54580. onAfterRenderViewport(e){
  54581. var n = this;
  54582. /* this.isVisibleInViewport(e) && (this.updateTimer || this.loadingInProgress || (this.updateTimer = window.setTimeout((function(){
  54583. n.update(e).then((function (t){
  54584. t && n.loadComplete.emit(!0)
  54585. }
  54586. )).catch(u.handleWarning)
  54587. }
  54588. ), 100))) */
  54589. }
  54590. update(){
  54591. this.needUpdate = false;
  54592. if(this.disabled || !this.maps.find(e=>!e.disabled) || !this.maps.find(e=>e.objectGroup.visible) )return //add
  54593. var e, n, i, r, o;
  54594. this.updateTimer = void 0,
  54595. e = this.viewport.camera,
  54596. n = e.projectionMatrix.clone(),
  54597. n.elements[0] /= 1.5,
  54598. n.elements[5] /= 1.5,
  54599. this.frustumMatrix.multiplyMatrices(n, e.matrixWorldInverse),
  54600. this.frustum.setFromProjectionMatrix(this.frustumMatrix),
  54601. this.frustum.planes[4].setComponents(0, 0, 0, 0),
  54602. this.frustum.planes[5].setComponents(0, 0, 0, 0),
  54603. i = !0;
  54604. for (r = 0; r < this.maps.length; r++){
  54605. var map = this.maps[r];
  54606. i = map.update(this.frustum, this.sceneGroup) && i;
  54607. }
  54608. return [2, i]
  54609. }
  54610. getAttributions(){
  54611. for (var t = {}, e = 0, n = this.maps; e < n.length; e++){
  54612. n[e].fillAttributions(t);
  54613. }
  54614. return t
  54615. }
  54616. updateProjection(){
  54617. for (var t = 0, e = this.maps; t < e.length; t++){
  54618. var n = e[t];
  54619. n.clearProjection(),
  54620. n.updateObjectGroup();
  54621. }
  54622. }
  54623. }
  54624. class TiledMapBase extends EventDispatcher{
  54625. constructor(/* t, */name, mapLayer, tileColor, projection){
  54626. super();
  54627. this.name = name;
  54628. //this.TransformService = t,
  54629. this.mapLayer = mapLayer,
  54630. this.tileColor = tileColor,
  54631. this.bias = 0;
  54632. this.zIndex = -1;
  54633. this.objectGroup = new Object3D;
  54634. this.objectGroup.name = name;
  54635. this.objectGroupAdded = !1,
  54636. this.baseTile = new MapTile(this,/* this.mapLayer, */this.objectGroup,this.tileColor),
  54637. this.isTileVisibleBox = new Box3,
  54638. this.isTileVisibleVec = new Vector3;
  54639. this.projection = projection;
  54640. this._zoomLevel = 0;//1-20
  54641. }
  54642. get zoomLevel(){
  54643. return this._zoomLevel
  54644. }
  54645. set zoomLevel(zoomLevel){
  54646. if(this._zoomLevel != zoomLevel){
  54647. this._zoomLevel = zoomLevel;
  54648. //this.dispatchEvent('zoomLevelChange',zoomLevel)
  54649. //if(this.name == 'map')console.log(zoomLevel,viewer.mapViewer.camera.zoom)
  54650. }
  54651. }
  54652. updateObjectGroup(){
  54653. this.position && this.objectGroup.position.copy(this.position),
  54654. this.quaternion && this.objectGroup.quaternion.copy(this.quaternion),
  54655. this.objectGroup.updateMatrixWorld(!0);
  54656. }
  54657. updateProjection(){
  54658. //this.transformMapToLocal || (this.transformMapToLocal = this.TransformService.getTransform(this.projection, this.TransformService.crsLocal))
  54659. if(!this.transformMapToLocal){
  54660. if(proj4.defs("NAVVIS:TMERC")){
  54661. if(this.projection == "EPSG:4550"){
  54662. this.transformMapToLocal = {
  54663. forward:(e)=>{
  54664. var a = viewer.transform.lonlatTo4550.inverse(e);
  54665. return viewer.transform.lonlatToLocal.forward(a)
  54666. },
  54667. };
  54668. }else {
  54669. this.transformMapToLocal = proj4(this.projection, "NAVVIS:TMERC");
  54670. }
  54671. //this.transformMapToLocal = proj4(this.projection, "NAVVIS:TMERC")
  54672. }
  54673. }
  54674. }
  54675. setEnable(enable){//add
  54676. if(!this.disabled == enable)return
  54677. if(enable){
  54678. console.log('setEnable',true);
  54679. }
  54680. this.disabled = !enable;
  54681. viewer.updateVisible(this.objectGroup, 'setEnable', enable);
  54682. if(!enable){
  54683. this.baseTile.remove();
  54684. }else {
  54685. this.mapLayer.needUpdate = true;
  54686. }
  54687. this.mapLayer.viewer.dispatchEvent({
  54688. type:'content_changed'
  54689. });
  54690. }
  54691. /* clearProjection(){
  54692. this.transformMapToLocal = void 0,
  54693. this.projection.name !== this.TransformService.NAVVIS_LOCAL && this.baseTile.remove()
  54694. } */
  54695. update(e, n){
  54696. var unavailable = (this.disabled || !this.objectGroup.visible);//地图即使不显示也要获得zoomlevel
  54697. if(this.name != 'map' && unavailable)return
  54698. this.updateProjection();
  54699. if(!this.transformMapToLocal)return
  54700. if (!this.isTileVisible(new Vector3(0,0,0), this.mapSizeM, e))
  54701. return this.removeFromSceneGroup(n), !0;
  54702. let viewport = this.mapLayer.viewport;
  54703. var i = new Vector3(-.5 * this.mapSizeM,0,0);
  54704. i.applyMatrix4(this.objectGroup.matrixWorld),
  54705. i.project(viewport.camera);
  54706. var o = new Vector3(.5 * this.mapSizeM,0,0);
  54707. o.applyMatrix4(this.objectGroup.matrixWorld),
  54708. o.project(viewport.camera);
  54709. var a = viewport.resolution.x
  54710. , s = viewport.resolution.y;
  54711. if (a <= 0 || s <= 0 || isNaN(i.x) || isNaN(o.x)) return !1;
  54712. i.sub(o),
  54713. i.x *= a / 2,
  54714. i.y *= s / 2;
  54715. var c = this.tileSizePx / i.length()
  54716. , level = Math.ceil(-Math.log(c) / Math.log(2) - this.bias);
  54717. level = Math.max(level, 0);
  54718. level = Math.min(level, void 0 === this.maxDepth ? 1 / 0 : this.maxDepth);
  54719. this.zoomLevel = level;//add
  54720. //console.log(level)
  54721. if(!unavailable){
  54722. this.addToSceneGroup(n);
  54723. return this.baseTile.update(this, e, level, this.mapSizeM, 0, 0, "")
  54724. }
  54725. }
  54726. isTileVisible(e, n, i){
  54727. if (n > HALF_WORLD_SIZE) return !0;
  54728. var r = .5 * n;
  54729. this.transformMapToLocal.forward(e);
  54730. this.isTileVisibleBox.makeEmpty();
  54731. this.isTileVisibleVec.set(e.x - r, e.y - r, e.z).applyMatrix4(this.objectGroup.matrixWorld);
  54732. this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec);
  54733. this.isTileVisibleVec.set(e.x - r, e.y + r, e.z).applyMatrix4(this.objectGroup.matrixWorld);
  54734. this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec);
  54735. this.isTileVisibleVec.set(e.x + r, e.y - r, e.z).applyMatrix4(this.objectGroup.matrixWorld);
  54736. this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec);
  54737. this.isTileVisibleVec.set(e.x + r, e.y + r, e.z).applyMatrix4(this.objectGroup.matrixWorld);
  54738. this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec);
  54739. return i.intersectsBox(this.isTileVisibleBox)
  54740. }
  54741. addToSceneGroup(t){
  54742. this.objectGroupAdded || (t.add(this.objectGroup),
  54743. this.objectGroupAdded = !0);
  54744. }
  54745. removeFromSceneGroup(t){
  54746. this.baseTile.remove(),
  54747. this.objectGroupAdded && (t.remove(this.objectGroup),
  54748. this.objectGroupAdded = !1);
  54749. }
  54750. }
  54751. class MapTile{
  54752. constructor(map,/* t, */ e, n){
  54753. this.map = map;
  54754. //this.mapLayer = t,
  54755. this.objectGroup = e,
  54756. this.tileColor = n,
  54757. this.meshAdded = !1,
  54758. this.textureLoaded = !1,
  54759. this.children = [];
  54760. }
  54761. update(e, n, i, r, o, a, s){
  54762. return !!this.doesNotContainTilesToBeDisplayed(e) || (0 === i ? this.updateTile(e, r, o, a) : this.updateSubTiles(e, n, i, r, o, a, s))
  54763. }
  54764. doesNotContainTilesToBeDisplayed(t){
  54765. return t.tilePresenceMap && t.tilePresenceMap.empty
  54766. }
  54767. updateTile(t, e, n, i){
  54768. if(!this.mesh){
  54769. this.createTileObject(t, e, n, i);
  54770. }
  54771. if(!this.meshAdded){
  54772. this.objectGroup.add(this.mesh);
  54773. this.meshAdded = !0;
  54774. }
  54775. if(this.textureLoaded){
  54776. this.removeChildren();
  54777. }
  54778. return this.textureLoaded
  54779. }
  54780. updateSubTiles(entity, n, level, o, a, s, c){
  54781. for (var l = !0, u = [-.25 * o, .25 * o, -.25 * o, .25 * o], d = [.25 * o, .25 * o, -.25 * o, -.25 * o], p = 0; p < 4; ++p){
  54782. var h = c + p.toString(10);
  54783. //一级(512):0 1 2 3分别为左上、右上、左下、右下。二级(1024)就是把一级的每一块分裂,如00 01 02 03分别是0的左上、右上、左下、右下……
  54784. /* if(entity.name == 'floorplan'){
  54785. console.log(1)
  54786. } */
  54787. if (!entity.tilePresenceMap || entity.tilePresenceMap[h]){
  54788. //去掉判断,直接显示
  54789. var f = a + u[p]
  54790. , m = s + d[p];
  54791. tempVector.set(f, m, 0);
  54792. if (entity.isTileVisible(tempVector, .5 * o, n)){
  54793. this.children[p] || (this.children[p] = new MapTile(this.map, this.objectGroup,this.tileColor));
  54794. l = this.children[p].update(entity, n, level - 1, .5 * o, f, m, h) && l;
  54795. } else {
  54796. if (this.children[p]){
  54797. this.children[p].remove();
  54798. delete this.children[p];
  54799. }
  54800. }
  54801. }
  54802. }
  54803. return l && this.removeObject3D(),
  54804. l
  54805. }
  54806. createTileObject(t, e, n, a){
  54807. var s = this;
  54808. this.mesh = this.createMesh(t.transformMapToLocal, e, n, a),
  54809. this.textureLoaded = !1;
  54810. var c = t.mapSizeM / e
  54811. , l = Math.log(c) / Math.log(2)
  54812. , u = n / e + .5 * (c - 1)
  54813. , d = -a / e + .5 * (c - 1)
  54814. , p = t.getTileUrl(Math.round(l), Math.round(u), Math.round(d));
  54815. viewer.setObjectLayers(this.mesh, 'map' );
  54816. this.mesh.renderOrder = -(1e6 - l - 100 * (t.zIndex || 0));
  54817. var h = this.mesh.material;
  54818. var loadDone = ()=>{
  54819. this.map.mapLayer.loadingInProgress--;
  54820. if(this.map.mapLayer.loadingInProgress == 0){
  54821. this.map.mapLayer.dispatchEvent('loadDone');
  54822. }
  54823. };
  54824. h.map = texLoader$1.load(p, (tex)=>{
  54825. if(this.mesh){//如果还要显示的话
  54826. this.textureLoaded = true;
  54827. this.mesh.material.opacity = 1;
  54828. //this.mapLayer.view.invalidateScene()
  54829. this.map.mapLayer.viewer.dispatchEvent({
  54830. type:'content_changed'
  54831. });
  54832. this.map.mapLayer.needUpdate = true; //表示还要继续update(以removeChildren)
  54833. }else {
  54834. tex.dispose();
  54835. }
  54836. loadDone();
  54837. } , void 0, (()=>{//error
  54838. this.textureLoaded = !0;
  54839. if(this.mesh){
  54840. this.mesh.material.dispose(); //o.disposeMeshMaterial(this.mesh)
  54841. this.mesh.material = errorMaterial;
  54842. //this.map.mapLayer.view.invalidateScene())
  54843. this.map.mapLayer.viewer.dispatchEvent({
  54844. type:'content_changed'
  54845. });
  54846. }
  54847. loadDone();
  54848. }));
  54849. h.map.anisotropy = 0,
  54850. h.map.generateMipmaps = !1,
  54851. h.map.minFilter = LinearFilter,
  54852. h.map.magFilter = LinearFilter,
  54853. this.map.mapLayer.loadingInProgress++;
  54854. }
  54855. createMesh(t, e, n, o){
  54856. var a = new Geometry;
  54857. return tempVector.set(n - e / 2, o - e / 2, 0),
  54858. a.vertices.push(new Vector3().copy(t.forward(tempVector))),
  54859. tempVector.set(n + e / 2, o - e / 2, 0),
  54860. a.vertices.push(new Vector3().copy(t.forward(tempVector))),
  54861. tempVector.set(n + e / 2, o + e / 2, 0),
  54862. a.vertices.push(new Vector3().copy(t.forward(tempVector))),
  54863. tempVector.set(n - e / 2, o + e / 2, 0),
  54864. a.vertices.push(new Vector3().copy(t.forward(tempVector))),
  54865. a.faces.push(face1),
  54866. a.faces.push(face2),
  54867. a.faceVertexUvs[0].push(face1UV),
  54868. a.faceVertexUvs[0].push(face2UV),
  54869. new Mesh(a,this.createMaterial())
  54870. }
  54871. createMaterial(){
  54872. var t = new MeshBasicMaterial({
  54873. transparent: !0,
  54874. depthWrite: !1,
  54875. depthTest: !0,
  54876. opacity: 0,
  54877. side: DoubleSide
  54878. });
  54879. return t.color = this.tileColor ? this.tileColor : new Color(16777215),
  54880. t
  54881. }
  54882. remove(){
  54883. this.removeObject3D(),
  54884. this.removeChildren();
  54885. }
  54886. removeObject3D(){
  54887. if (this.mesh){
  54888. if (this.objectGroup.remove(this.mesh),
  54889. this.textureLoaded){
  54890. var t = this.mesh.material.map;
  54891. t && t.dispose();
  54892. }
  54893. this.mesh.material.dispose(); //o.disposeMeshMaterial(this.mesh),
  54894. this.mesh.geometry.dispose();
  54895. this.mesh = void 0;
  54896. }
  54897. this.meshAdded = !1,
  54898. this.textureLoaded = !1;
  54899. }
  54900. removeChildren(){
  54901. for (var t = 0, e = this.children; t < e.length; t++){
  54902. var n = e[t];
  54903. n && (n.removeObject3D(),
  54904. n.removeChildren());
  54905. }
  54906. this.children.length = 0;
  54907. }
  54908. }
  54909. proj4.defs("EPSG:3857", "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs");
  54910. //这里地图世界的中心是不是lon:0,lat:0
  54911. class TiledMapOpenStreetMap extends TiledMapBase{
  54912. constructor(mapLayer, tileColor){
  54913. super('map', mapLayer, tileColor, /* "EPSG:4550" */ "EPSG:3857" ); //EPSG projection
  54914. //this.baseUrl = "https://wprd03.is.autonavi.com/appmaptile?style=7&x=${x}&y=${y}&z=${z}",
  54915. //this.baseUrl = "https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=${x}&y=${y}&z=${z}" //最高只到18 level
  54916. this.baseUrl = "https://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&style=7&x=${x}&y=${y}&z=${z}"; //最高只到19
  54917. this.attribution = "© PopSmart, © 高德地图",
  54918. this.tileSizePx = 256;
  54919. this.mapSizeM = 40075017;
  54920. this.maxDepth = 19;//20
  54921. this.bias = 0.5;
  54922. }
  54923. getTileUrl(t, e, n){
  54924. return this.baseUrl.replace(/\${z}/, t.toString(10)).replace(/\${x}/, e.toString(10)).replace(/\${y}/, n.toString(10))
  54925. }
  54926. fillAttributions(t){
  54927. t[this.attribution] = {
  54928. score: 50
  54929. };
  54930. }
  54931. }
  54932. class TiledMapFromEntity extends TiledMapBase{
  54933. constructor(mapLayer, tileColor, data){
  54934. super('floorplan', mapLayer, tileColor, "NAVVIS:TMERC" /* "EPSG:3857" *//* "WGS84" */); //直接就是本地坐标,没有projec
  54935. let entity = this.tiledMapEntity = this.fillFromData(data);
  54936. let time = entity.updateTime || entity.createTime;
  54937. this.tileSizePx = entity.tileSizePx,
  54938. this.mapSizeM = entity.mapSizeM,
  54939. this.maxDepth = entity.maxDepth;
  54940. this.postStamp = time ? time.replace(/[^0-9]/ig,'') : (new Date).getTime();
  54941. //this.projection = n.crsLocal,
  54942. this.zIndex = 0,
  54943. this.tilePresenceMap = this.decodeBitStream(this.tiledMapEntity.quadtree); //包含tile分裂信息,如果写错了会造成tile显示不全
  54944. }
  54945. fillFromData(e){
  54946. let data = {};
  54947. data.id = e.id;
  54948. data.globalLocation = Potree.Utils.VectorFactory.fromArray3(e.location),
  54949. data.orientation = Potree.Utils.QuaternionFactory.fromArray(e.orientation);
  54950. if(Potree.fileServer){
  54951. data.filePath = `${Potree.settings.urls.prefix}${e.file_path}`;
  54952. }else {
  54953. data.filePath = `${Potree.settings.urls.prefix}/data/${Potree.settings.number}/${e.file_path}`;
  54954. }
  54955. //if(!data.filePath.includes('building_1'))data.filePath = data.filePath.replace('building','building_1')//暂时
  54956. data.fileName = '$DEPTH/$X/$Y.png',//e.file_name,
  54957. data.type = e.type,
  54958. data.mapSizeM = e.map_size_m,
  54959. data.tileSizePx = e.tile_size_px,
  54960. data.maxDepth = e.max_depth,
  54961. data.quadtree = e.quadtree,
  54962. data.floorId = e.floor_id,
  54963. data.bundleId = e.bundle_id;
  54964. //this.computeLocalCoordinates()
  54965. return data
  54966. }
  54967. computeLocalCoordinates(){
  54968. if(proj4.defs("NAVVIS:TMERC")){
  54969. this.tiledMapEntity.location = new Vector3().copy(viewer.transform.lonlatToLocal.forward(this.tiledMapEntity.globalLocation));
  54970. }
  54971. }
  54972. updateProjection() {
  54973. super.updateProjection();
  54974. if(!this.position){
  54975. this.computeLocalCoordinates();
  54976. }
  54977. /* this.projection = this.TransformService.crsLocal,
  54978. t.prototype.updateProjection.call(this) */
  54979. }
  54980. get position(){
  54981. return this.tiledMapEntity.location
  54982. /* enumerable: !0,
  54983. configurable: !0 */
  54984. }
  54985. get quaternion(){
  54986. return this.tiledMapEntity.orientation
  54987. /* enumerable: !0,
  54988. configurable: !0 */
  54989. }
  54990. getTileUrl(t, e, n) {
  54991. var i = (this.tiledMapEntity.filePath + "/" + this.tiledMapEntity.fileName).replace(/\$DEPTH/g, t.toString(10)).replace(/\$X/g, e.toString(10)).replace(/\$Y/g, n.toString(10));
  54992. return i += "?t=" + this.postStamp
  54993. //this.RestService.addAuthorizationQueryParameter(i) //????
  54994. }
  54995. fillAttributions(t) {
  54996. t.NavVis = {
  54997. score: 100
  54998. };
  54999. }
  55000. decodeBitStream(t) {
  55001. if (!t)
  55002. return {
  55003. empty: !0
  55004. };
  55005. for (var e = {}, n = [e], i = 0; i < t.length; i++) {
  55006. var r = n.shift()
  55007. , o = parseInt(t.substr(i, 1), 16);
  55008. if (1 & o) {
  55009. var a = {};
  55010. r[0] = a,
  55011. n.push(a);
  55012. }
  55013. 2 & o && (a = {},
  55014. r[1] = a,
  55015. n.push(a)),
  55016. 4 & o && (a = {},
  55017. r[2] = a,
  55018. n.push(a)),
  55019. 8 & o && (a = {},
  55020. r[3] = a,
  55021. n.push(a));
  55022. }
  55023. var s = {
  55024. empty: !0
  55025. };
  55026. return this.computeHashes(s, e, ""),
  55027. s
  55028. }
  55029. computeHashes(t, e, n) {
  55030. for (var i = 0; i < 4; i++)
  55031. e[i] && (t[n + i.toString(10)] = !0,
  55032. t.empty = !1,
  55033. this.computeHashes(t, e[i], n + i.toString(10)));
  55034. }
  55035. }
  55036. /* {
  55037. "bundle_id": 1, //t-CwfhfqJ
  55038. "file_name": "$DEPTH/$X/$Y.png",
  55039. "file_path": "data/bundle_t-CwfhfqJ/building_1/map_tiles/11",
  55040. "floor_id": 11,
  55041. "id": 1,
  55042. "location": [
  55043. 113.5957510575092,
  55044. 22.366605927999239,
  55045. 0.0
  55046. ],
  55047. "map_size_m": 61.44,
  55048. "max_depth": 3,
  55049. "orientation": [
  55050. 0.7071067811865476,
  55051. 0.0,
  55052. 0.0,
  55053. 0.7071067811865475
  55054. ],
  55055. "quadtree": "fe5f7c7fcffff7f53",
  55056. "sceneCode": "t-CwfhfqJ",
  55057. "tile_size_px": 256,
  55058. "type": "TILED_PYRAMID"
  55059. }
  55060. */
  55061. var MathLight = {};
  55062. MathLight.RADIANS_PER_DEGREE = Math.PI / 180;
  55063. MathLight.DEGREES_PER_RADIAN = 180 / Math.PI;
  55064. MathLight.Vector3 = function(e, t, i) {
  55065. this.x = e || 0,
  55066. this.y = t || 0,
  55067. this.z = i || 0;
  55068. };
  55069. MathLight.Matrix4 = function() {
  55070. this.elements = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
  55071. arguments.length > 0 && console.error("MathLight.Matrix4: the constructor no longer reads arguments. use .set() instead.");
  55072. };
  55073. MathLight.Matrix4.prototype = {
  55074. identity: function() {
  55075. return this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1),
  55076. this
  55077. },
  55078. copy: function(e) {
  55079. return this.elements.set(e.elements),
  55080. this
  55081. },
  55082. applyToVector3: function(e) {
  55083. var t = e.x
  55084. , i = e.y
  55085. , n = e.z
  55086. , r = this.elements;
  55087. return e.x = r[0] * t + r[4] * i + r[8] * n + r[12],
  55088. e.y = r[1] * t + r[5] * i + r[9] * n + r[13],
  55089. e.z = r[2] * t + r[6] * i + r[10] * n + r[14],
  55090. this
  55091. },
  55092. getInverse: function(e, t) {
  55093. var i = this.elements
  55094. , n = e.elements
  55095. , r = n[0]
  55096. , o = n[1]
  55097. , a = n[2]
  55098. , s = n[3]
  55099. , l = n[4]
  55100. , c = n[5]
  55101. , h = n[6]
  55102. , u = n[7]
  55103. , d = n[8]
  55104. , p = n[9]
  55105. , f = n[10]
  55106. , g = n[11]
  55107. , m = n[12]
  55108. , v = n[13]
  55109. , A = n[14]
  55110. , y = n[15]
  55111. , C = p * A * u - v * f * u + v * h * g - c * A * g - p * h * y + c * f * y
  55112. , I = m * f * u - d * A * u - m * h * g + l * A * g + d * h * y - l * f * y
  55113. , E = d * v * u - m * p * u + m * c * g - l * v * g - d * c * y + l * p * y
  55114. , b = m * p * h - d * v * h - m * c * f + l * v * f + d * c * A - l * p * A
  55115. , w = r * C + o * I + a * E + s * b;
  55116. if (0 === w) {
  55117. var _ = "MathLight.Matrix4.getInverse(): can't invert matrix, determinant is 0";
  55118. if (t)
  55119. throw new Error(_);
  55120. return console.warn(_),
  55121. this.identity()
  55122. }
  55123. var T = 1 / w;
  55124. return i[0] = C * T,
  55125. i[1] = (v * f * s - p * A * s - v * a * g + o * A * g + p * a * y - o * f * y) * T,
  55126. i[2] = (c * A * s - v * h * s + v * a * u - o * A * u - c * a * y + o * h * y) * T,
  55127. i[3] = (p * h * s - c * f * s - p * a * u + o * f * u + c * a * g - o * h * g) * T,
  55128. i[4] = I * T,
  55129. i[5] = (d * A * s - m * f * s + m * a * g - r * A * g - d * a * y + r * f * y) * T,
  55130. i[6] = (m * h * s - l * A * s - m * a * u + r * A * u + l * a * y - r * h * y) * T,
  55131. i[7] = (l * f * s - d * h * s + d * a * u - r * f * u - l * a * g + r * h * g) * T,
  55132. i[8] = E * T,
  55133. i[9] = (m * p * s - d * v * s - m * o * g + r * v * g + d * o * y - r * p * y) * T,
  55134. i[10] = (l * v * s - m * c * s + m * o * u - r * v * u - l * o * y + r * c * y) * T,
  55135. i[11] = (d * c * s - l * p * s - d * o * u + r * p * u + l * o * g - r * c * g) * T,
  55136. i[12] = b * T,
  55137. i[13] = (d * v * a - m * p * a + m * o * f - r * v * f - d * o * A + r * p * A) * T,
  55138. i[14] = (m * c * a - l * v * a - m * o * h + r * v * h + l * o * A - r * c * A) * T,
  55139. i[15] = (l * p * a - d * c * a + d * o * h - r * p * h - l * o * f + r * c * f) * T,
  55140. this
  55141. },
  55142. makeRotationFromQuaternion: function(e) {
  55143. var t = this.elements
  55144. , i = e.x
  55145. , n = e.y
  55146. , r = e.z
  55147. , o = e.w
  55148. , a = i + i
  55149. , s = n + n
  55150. , l = r + r
  55151. , c = i * a
  55152. , h = i * s
  55153. , u = i * l
  55154. , d = n * s
  55155. , p = n * l
  55156. , f = r * l
  55157. , g = o * a
  55158. , m = o * s
  55159. , v = o * l;
  55160. return t[0] = 1 - (d + f),
  55161. t[4] = h - v,
  55162. t[8] = u + m,
  55163. t[1] = h + v,
  55164. t[5] = 1 - (c + f),
  55165. t[9] = p - g,
  55166. t[2] = u - m,
  55167. t[6] = p + g,
  55168. t[10] = 1 - (c + d),
  55169. t[3] = 0,
  55170. t[7] = 0,
  55171. t[11] = 0,
  55172. t[12] = 0,
  55173. t[13] = 0,
  55174. t[14] = 0,
  55175. t[15] = 1,
  55176. this
  55177. }
  55178. };
  55179. MathLight.Quaternion = function(e, t, i, n) {
  55180. this._x = e || 0,
  55181. this._y = t || 0,
  55182. this._z = i || 0,
  55183. this._w = void 0 !== n ? n : 1;
  55184. };
  55185. MathLight.Quaternion.prototype = {
  55186. get x() {
  55187. return this._x
  55188. },
  55189. set x(e) {
  55190. this._x = e;
  55191. },
  55192. get y() {
  55193. return this._y
  55194. },
  55195. set y(e) {
  55196. this._y = e;
  55197. },
  55198. get z() {
  55199. return this._z
  55200. },
  55201. set z(e) {
  55202. this._z = e;
  55203. },
  55204. get w() {
  55205. return this._w
  55206. },
  55207. set w(e) {
  55208. this._w = e;
  55209. },
  55210. copy: function(e) {
  55211. this._x = e.x,
  55212. this._y = e.y,
  55213. this._z = e.z,
  55214. this._w = e.w;
  55215. },
  55216. inverse: function() {
  55217. return this.conjugate().normalize()
  55218. },
  55219. conjugate: function() {
  55220. return this._x *= -1,
  55221. this._y *= -1,
  55222. this._z *= -1,
  55223. this
  55224. },
  55225. length: function() {
  55226. return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w)
  55227. },
  55228. normalize: function() {
  55229. var e = this.length();
  55230. return 0 === e ? (this._x = 0,
  55231. this._y = 0,
  55232. this._z = 0,
  55233. this._w = 1) : (e = 1 / e,
  55234. this._x = this._x * e,
  55235. this._y = this._y * e,
  55236. this._z = this._z * e,
  55237. this._w = this._w * e),
  55238. this
  55239. },
  55240. setFromAxisAngle: function(e, t) {
  55241. var i = t / 2
  55242. , n = Math.sin(i);
  55243. return this._x = e.x * n,
  55244. this._y = e.y * n,
  55245. this._z = e.z * n,
  55246. this._w = Math.cos(i),
  55247. this
  55248. },
  55249. setFromUnitVectors: function() {
  55250. var e, t, i = 1e-6;
  55251. return function(n, o) {
  55252. return void 0 === e && (e = new MathLight.Vector3),
  55253. t = MathLight.dot(n, o) + 1,
  55254. t < i ? (t = 0,
  55255. Math.abs(n.x) > Math.abs(n.z) ? MathLight.setVector(e, -n.y, n.x, 0) : MathLight.setVector(e, 0, -n.z, n.y)) : MathLight.cross(n, o, e),
  55256. this._x = e.x,
  55257. this._y = e.y,
  55258. this._z = e.z,
  55259. this._w = t,
  55260. this.normalize()
  55261. }
  55262. }(),
  55263. multiply: function(e) {
  55264. return this.multiplyQuaternions(this, e)
  55265. },
  55266. premultiply: function(e) {
  55267. return this.multiplyQuaternions(e, this)
  55268. },
  55269. multiplyQuaternions: function(e, t) {
  55270. var i = e._x
  55271. , n = e._y
  55272. , r = e._z
  55273. , o = e._w
  55274. , a = t._x
  55275. , s = t._y
  55276. , l = t._z
  55277. , c = t._w;
  55278. return this._x = i * c + o * a + n * l - r * s,
  55279. this._y = n * c + o * s + r * a - i * l,
  55280. this._z = r * c + o * l + i * s - n * a,
  55281. this._w = o * c - i * a - n * s - r * l,
  55282. this
  55283. }
  55284. };
  55285. MathLight.convertWorkshopVector = function(e) {
  55286. return new MathLight.Vector3(-e.x,e.y,e.z)
  55287. };
  55288. MathLight.convertWorkshopQuaternion = function(e) {
  55289. return new MathLight.Quaternion(-e.x,e.y,e.z,-e.w).multiply(new MathLight.Quaternion(Math.sqrt(2) / 2,Math.sqrt(2) / 2,0,0))
  55290. };
  55291. MathLight.convertWorkshopOrthoZoom = function(e) {
  55292. //return e === -1 ? -1 : e / 16 * ($('#player').width() / $('#player').height()) / n.workshopApsect
  55293. return e === -1 ? -1 : e * ($("#player").width() / $("#player").height()) ;
  55294. };
  55295. MathLight.convertWorkshopPanoramaQuaternion = function(e) {
  55296. return new MathLight.Quaternion(e.x,-e.y,-e.z,e.w).normalize().multiply((new MathLight.Quaternion).setFromAxisAngle(new MathLight.Vector3(0,1,0), 270 * MathLight.RADIANS_PER_DEGREE))
  55297. };
  55298. MathLight.normalize = function(e) {
  55299. var t = e.x * e.x + e.y * e.y + e.z * e.z
  55300. , i = Math.sqrt(t);
  55301. e.x /= i,
  55302. e.y /= i,
  55303. e.z /= i;
  55304. };
  55305. MathLight.dot = function(e, t) {
  55306. return e.x * t.x + e.y * t.y + e.z * t.z
  55307. };
  55308. MathLight.cross = function(e, t, i) {
  55309. var n = e.x
  55310. , r = e.y
  55311. , o = e.z;
  55312. i.x = r * t.z - o * t.y,
  55313. i.y = o * t.x - n * t.z,
  55314. i.z = n * t.y - r * t.x;
  55315. };
  55316. MathLight.setVector = function(e, t, i, n) {
  55317. e.x = t,
  55318. e.y = i,
  55319. e.z = n;
  55320. };
  55321. MathLight.copyVector = function(e, t) {
  55322. t.x = e.x,
  55323. t.y = e.y,
  55324. t.z = e.z;
  55325. };
  55326. MathLight.addVector = function(e, t) {
  55327. e.x += t.x,
  55328. e.y += t.y,
  55329. e.z += t.z;
  55330. };
  55331. MathLight.subVector = function(e, t) {
  55332. e.x -= t.x,
  55333. e.y -= t.y,
  55334. e.z -= t.z;
  55335. };
  55336. MathLight.applyQuaternionToVector = function(e, t) {
  55337. var i = t.x
  55338. , n = t.y
  55339. , r = t.z
  55340. , o = e.x
  55341. , a = e.y
  55342. , s = e.z
  55343. , l = e.w
  55344. , c = l * i + a * r - s * n
  55345. , h = l * n + s * i - o * r
  55346. , u = l * r + o * n - a * i
  55347. , d = -o * i - a * n - s * r;
  55348. t.x = c * l + d * -o + h * -s - u * -a,
  55349. t.y = h * l + d * -a + u * -o - c * -s,
  55350. t.z = u * l + d * -s + c * -a - h * -o;
  55351. };
  55352. MathLight.angleBetweenVectors = function(e, t) {
  55353. return Math.acos(MathLight.dot(e, t))
  55354. };
  55355. var cameraLight = {
  55356. clampVFOV: function(currentFov, maxHFov, width, height) {//限制currentFov, 使之造成的横向fov不大于指定值maxHFov
  55357. var r = cameraLight.getHFOVFromVFOV(currentFov, width, height);
  55358. return r > maxHFov ? cameraLight.getVFOVFromHFOV(maxHFov, width, height) : currentFov
  55359. },
  55360. getHFOVForCamera: function(camera, getRad) {
  55361. return cameraLight.getHFOVByScreenPrecent(camera.fov, camera.aspect, getRad)
  55362. },
  55363. //add
  55364. getHFOVByScreenPrecent: function(fov, percent, getRad) { //当fov为占比百分百时,percent代表在屏幕上从中心到边缘的占比
  55365. let rad = 2 * Math.atan(percent * Math.tan(fov * MathLight.RADIANS_PER_DEGREE / 2));
  55366. if(getRad)return rad
  55367. else return rad * MathLight.DEGREES_PER_RADIAN;
  55368. }
  55369. };
  55370. /**
  55371. * @author mschuetz / http://mschuetz.at
  55372. *
  55373. * adapted from THREE.OrbitControls by
  55374. *
  55375. * @author qiao / https://github.com/qiao
  55376. * @author mrdoob / http://mrdoob.com
  55377. * @author alteredq / http://alteredqualia.com/
  55378. * @author WestLangley / http://github.com/WestLangley
  55379. * @author erich666 / http://erichaines.com
  55380. *
  55381. *
  55382. *
  55383. */
  55384. class FirstPersonControls extends EventDispatcher {
  55385. constructor (viewer, viewport) {
  55386. super();
  55387. this.viewer = viewer;
  55388. this.renderer = viewer.renderer;
  55389. this.scene = viewer.scene;
  55390. this.rotationSpeed = 200;
  55391. this.moveSpeed = 10;
  55392. this.setCurrentViewport({hoverViewport:viewport, force:true}); //this.currentViewport = viewport
  55393. this.keys = {
  55394. FORWARD: ['W'.charCodeAt(0), 38],
  55395. BACKWARD: ['S'.charCodeAt(0), 40],
  55396. LEFT: ['A'.charCodeAt(0), 37],
  55397. RIGHT: ['D'.charCodeAt(0), 39],
  55398. UP: ['Q'.charCodeAt(0)],
  55399. DOWN: ['E'.charCodeAt(0)],
  55400. //SHIFT : [16],
  55401. ALT : [18],
  55402. Rotate_LEFT : ['L'.charCodeAt(0)],
  55403. Rotate_RIGHT : ['J'.charCodeAt(0)],
  55404. Rotate_UP : ['K'.charCodeAt(0)],
  55405. Rotate_DOWN : ['I'.charCodeAt(0)],
  55406. };
  55407. this.fadeFactor = 20;
  55408. this.yawDelta = 0;
  55409. this.pitchDelta = 0;
  55410. this.translationDelta = new Vector3(0, 0, 0);
  55411. this.translationWorldDelta = new Vector3(0, 0, 0);
  55412. this.tweens = [];
  55413. this.dollyStart = new Vector2$1;
  55414. this.dollyEnd = new Vector2$1;
  55415. //this.enableChangePos = true
  55416. this.viewer.addEventListener('camera_changed',(e)=>{
  55417. this.setFPCMoveSpeed(e.viewport);
  55418. });
  55419. let drag = (e) => {
  55420. if(!this.enabled)return
  55421. let viewport = e.dragViewport;
  55422. if(!viewport)return
  55423. let camera = viewport.camera;
  55424. let mode;
  55425. if(e.isTouch){
  55426. if(e.touches.length == 1){
  55427. mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan';
  55428. }else if(e.touches.length == 2){
  55429. mode = 'scale';
  55430. }else {
  55431. mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'pan' : 'scale';
  55432. }
  55433. }else {
  55434. //mode = e.buttons === Buttons.LEFT && (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
  55435. mode = e.buttons === Buttons.LEFT && camera.type != 'OrthographicCamera' ? 'rotate' : 'pan';
  55436. }
  55437. //console.log('mode ', mode )
  55438. let moveSpeed = this.currentViewport.getMoveSpeed();
  55439. if (e.drag.startHandled === undefined) {///???????
  55440. e.drag.startHandled = true;
  55441. this.dispatchEvent({type: 'start'});
  55442. }
  55443. if (mode.includes('rotate')) {//旋转
  55444. //来自panoramaControl updateRotation
  55445. if(!this.pointerDragStart){
  55446. return this.pointerDragStart = e.pointer.clone()
  55447. }
  55448. let view = this.scene.view;
  55449. if(Potree.settings.rotAroundPoint && this.intersectStart && this.canMovePos(viewport) && !viewer.images360.isAtPano() && !this.viewer.inputHandler.pressedKeys[17]){//定点旋转: 以当前intersect的点为target旋转,不改点在屏幕中的位置
  55450. let distance = camera.position.distanceTo(this.intersectStart.location); //不按下ctrl的话
  55451. //按照orbitControl的方式旋转:
  55452. let rotationSpeed = 2.5;
  55453. this.yawDelta -= e.drag.pointerDelta.x * rotationSpeed;
  55454. this.pitchDelta += e.drag.pointerDelta.y * rotationSpeed;
  55455. //先更新一下相机:
  55456. this.update();
  55457. view.applyToCamera(camera);
  55458. //然后得到新的相机角度下,原先点在屏幕中的位置所对应的3d点现在的坐标。只需要平移一下新旧坐标差值即可。
  55459. let newPointerDir = viewer.inputHandler.getMouseDirection(this.intersectStart.pointer).direction.clone().multiplyScalar(distance);
  55460. let pivot = new Vector3().addVectors(camera.position, newPointerDir); //新的3d点
  55461. let moveVec = new Vector3().subVectors(pivot, this.intersectStart.location);
  55462. this.translationWorldDelta.copy(moveVec.negate());
  55463. //立即更新下,防止因update和此drag频率不同而打滑。
  55464. this.update();
  55465. view.applyToCamera(camera);
  55466. }else {
  55467. let _matrixWorld = camera.matrixWorld;
  55468. camera.matrixWorld = new Matrix4;//unproject 前先把相机置于原点
  55469. var e1 = new Vector3(this.pointerDragStart.x,this.pointerDragStart.y,-1).unproject(camera)
  55470. , t = new Vector3(e.pointer.x,e.pointer.y,-1).unproject(camera)
  55471. , i = Math.sqrt(e1.x * e1.x + e1.z * e1.z)
  55472. , n = Math.sqrt(t.x * t.x + t.z * t.z)
  55473. , o = Math.atan2(e1.y, i)
  55474. , a = Math.atan2(t.y, n);
  55475. this.pitchDelta += o - a; //上下旋转
  55476. e1.y = 0,
  55477. t.y = 0;
  55478. var s = Math.acos(e1.dot(t) / e1.length() / t.length());
  55479. if(!isNaN(s)){
  55480. var yawDelta = s; //左右旋转
  55481. this.pointerDragStart.x > e.pointer.x && (yawDelta *= -1);
  55482. this.yawDelta += yawDelta;
  55483. }
  55484. //console.log('rotate:', this.pitchDelta, e.pointer.toArray(), this.pointerDragStart.toArray())
  55485. this.pointerDragStart.copy(e.pointer);
  55486. camera.matrixWorld = _matrixWorld ;
  55487. }
  55488. }
  55489. if (mode.includes('pan')) {//平移
  55490. if(!this.canMovePos(viewport)){
  55491. return
  55492. }
  55493. if(camera.type == "OrthographicCamera"){
  55494. //console.log(e.drag.pointerDelta, e.pointer, e.drag.end)
  55495. let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera );//最近一次移动向量
  55496. let pointclouds;
  55497. let Alignment = window.viewer.modules.Alignment;
  55498. let MergeEditor = window.viewer.modules.MergeEditor;
  55499. let handleState = Alignment.handleState;
  55500. let a = e.buttons === Buttons.LEFT && viewport.alignment && handleState && viewport.alignment[handleState];
  55501. if(Potree.settings.editType == 'pano'){//右键平移视图、左键操作点云
  55502. let PanoEditor = window.viewer.modules.PanoEditor;
  55503. if(a && PanoEditor.selectedPano){
  55504. if(!PanoEditor.selectedGroup || !PanoEditor.checkIfAllLinked({group:PanoEditor.selectedGroup}) ){
  55505. if(handleState == 'translate' && ( e.drag.intersectStart.pointclouds && Common.getMixedSet(PanoEditor.selectedClouds, e.drag.intersectStart.pointclouds).length || PanoEditor.selectedPano.hovered)//拖拽到点云上 或 circle
  55506. || handleState == 'rotate' )
  55507. {
  55508. pointclouds = PanoEditor.selectedClouds;
  55509. }
  55510. }else {
  55511. PanoEditor.dispatchEvent('needToDisConnect');
  55512. console.warn('选中的漫游点连通了整个数据集,不允许移动');
  55513. }
  55514. }
  55515. if(!pointclouds && e.buttons === Buttons.LEFT && viewport.alignment.rotateSide){
  55516. return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x)
  55517. }
  55518. }else if(Potree.settings.editType == 'merge'){
  55519. if(e.buttons === Buttons.LEFT && viewport.alignment && viewport.alignment.rotateSide){
  55520. return MergeEditor.rotateSideCamera(-e.drag.pointerDelta.x)
  55521. }
  55522. }else {
  55523. /* if(Alignment.selectedClouds && Alignment.selectedClouds.length){
  55524. pointclouds = a && e.drag.intersectStart.pointclouds && Common.getMixedSet(Alignment.selectedClouds, e.drag.intersectStart.pointclouds).length && Alignment.selectedClouds
  55525. }else{ */
  55526. pointclouds = a && e.drag.intersectStart.pointcloud && [e.drag.intersectStart.pointcloud];
  55527. //}
  55528. }
  55529. if(pointclouds){
  55530. this.dispatchEvent({
  55531. type : "transformPointcloud",
  55532. intersectPoint: e.intersectPoint.orthoIntersect,
  55533. intersectStart: e.drag.intersectStart.orthoIntersect,
  55534. moveVec,
  55535. pointclouds,
  55536. camera
  55537. });
  55538. }else {
  55539. this.translationWorldDelta.add(moveVec.negate());
  55540. }
  55541. }else {
  55542. if(e.drag.intersectStart){//如果拖拽着点云
  55543. if(e.drag.z == void 0){//拖拽开始
  55544. let pointerStartPos2d = e.drag.intersectStart.location.clone().project(camera);//识别到的点云点的位置
  55545. e.drag.z = pointerStartPos2d.z; //记录z,保持拖拽物体到屏幕距离不变,所以z深度不变
  55546. e.drag.projectionMatrixInverse = camera.projectionMatrixInverse.clone();
  55547. //防止吸附到最近点上(因为鼠标所在位置并非识别到的点云点的位置,需要得到鼠标所在位置的3d坐标。)
  55548. let pointerStartPos2dReal = new Vector3(this.pointerDragStart.x,this.pointerDragStart.y, e.drag.z);
  55549. e.drag.translateStartPos = pointerStartPos2dReal.clone().unproject(camera);
  55550. /* this.viewer.dispatchEvent({
  55551. type: 'dragPanBegin',
  55552. projectionMatrixInverse : e.drag.projectionMatrixInverse
  55553. }); */
  55554. //console.log('开始拖拽', e.pointer.clone())
  55555. }
  55556. //拖拽的过程中将projectionMatrixInverse替换成开始拖拽时的,因为near、far一直在变,会导致unproject计算出的3d坐标改变很大而闪烁。
  55557. var _projectionMatrixInverse = camera.projectionMatrixInverse;
  55558. camera.projectionMatrixInverse = e.drag.projectionMatrixInverse;
  55559. let newPos2d = new Vector3(e.pointer.x,e.pointer.y, e.drag.z );
  55560. let newPos3d = newPos2d.clone().unproject(camera);
  55561. let moveVec = newPos3d.clone().sub( e.drag.translateStartPos /* e.drag.intersectStart.location */ );//移动相机,保持鼠标下的位置永远不变,所以用鼠标下的新位置减去鼠标下的原始位置
  55562. camera.projectionMatrixInverse = _projectionMatrixInverse;
  55563. this.translationWorldDelta.copy(moveVec.negate()); //这里没法用add,原因未知,会跳动
  55564. //console.log('pan 1', this.translationWorldDelta.clone())
  55565. //四指松开剩三指时会偏移一下,暂不知道哪里的问题,或许跟开头防止点云吸附有关?
  55566. }else { //如果鼠标没有找到和点云的交点,就假设移动整个模型(也可以去扩大范围寻找最近点云)
  55567. /* let center = viewer.scene.pointclouds[0].position;
  55568. let radius = camera.position.distanceTo(center);
  55569. let ratio = radius * Math.tan(THREE.Math.degToRad(camera.fov)/2) / 1000 */
  55570. /* let speed = this.currentViewport.getMoveSpeed()
  55571. if(FirstPersonControls.boundPlane){
  55572. speed = FirstPersonControls.boundPlane.distanceToPoint(this.currentViewport.position)
  55573. speed = Math.max(1 , speed)
  55574. } */
  55575. let lastIntersect = viewport.lastIntersect ? (viewport.lastIntersect.location || viewport.lastIntersect) : viewer.bound.center; //该viewport的最近一次鼠标和点云的交点
  55576. let speed = camera.position.distanceTo(lastIntersect);
  55577. let fov = cameraLight.getHFOVForCamera(camera, true);
  55578. let ratio = speed * Math.tan(fov/2);
  55579. this.translationDelta.x -= e.drag.pointerDelta.x * ratio;
  55580. this.translationDelta.z -= e.drag.pointerDelta.y * ratio;
  55581. //console.log('pan2', e.drag.pointerDelta)
  55582. }
  55583. }
  55584. this.useAttenuation = false;
  55585. }
  55586. if(mode.includes('scale')){
  55587. this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  55588. //if(!this.dollyStart)return
  55589. var scale = this.dollyEnd.length() / this.dollyStart.length();
  55590. //console.log('scale ',scale)
  55591. let pointer = new Vector2$1().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
  55592. dolly({
  55593. pointer,
  55594. scale, camera
  55595. });
  55596. this.dollyStart.copy(this.dollyEnd);
  55597. }
  55598. //最好按ctrl可以变为dollhouse的那种旋转
  55599. };
  55600. let drop = e => {
  55601. if(!this.enabled)return
  55602. this.dispatchEvent({type: 'end'});
  55603. };
  55604. let dolly = (e={})=>{
  55605. if(Potree.settings.displayMode == 'showPanos' && this.currentViewport == viewer.mainViewport/* this.currentViewport.unableChangePos */){//全景时
  55606. this.dispatchEvent({type:'dollyStopCauseUnable',delta:e.delta, scale:e.scale});
  55607. return
  55608. }
  55609. let camera = e.camera;
  55610. if(camera.type == "OrthographicCamera"){
  55611. let ratio;
  55612. if(e.delta != void 0){//滚轮缩放
  55613. if(e.delta == 0){//mac
  55614. return
  55615. }else if (e.delta < 0) {
  55616. ratio = 0.9;
  55617. } else if (e.delta > 0) {
  55618. ratio = 1.1;
  55619. }
  55620. }else {
  55621. ratio = e.scale; //触屏缩放
  55622. }
  55623. let zoom = camera.zoom * ratio;
  55624. let limit = camera.zoomLimit;
  55625. if(limit) zoom = MathUtils.clamp(zoom, limit.min,limit.max );
  55626. let pointerPos = new Vector3(e.pointer.x, e.pointer.y,0.5);
  55627. let oldPos = pointerPos.clone().unproject(camera);
  55628. if(camera.zoom != zoom){
  55629. camera.zoom = zoom;
  55630. camera.updateProjectionMatrix();
  55631. }
  55632. let newPos = pointerPos.clone().unproject(camera);
  55633. //定点缩放, 恢复一下鼠标所在位置的位置改变量
  55634. let moveVec = new Vector3().subVectors(newPos,oldPos);
  55635. this.translationWorldDelta.add(moveVec.negate());
  55636. this.useAttenuation = false;
  55637. }else {
  55638. let speed , direction;
  55639. if(e.delta != void 0){//滚轮缩放
  55640. speed = this.currentViewport.getMoveSpeed() * 15;
  55641. //var direction = this.currentViewport.view.direction.clone();
  55642. direction = this.viewer.inputHandler.getMouseDirection().direction; //定点缩放
  55643. if(e.delta == 0){//mac
  55644. return
  55645. }else if (e.delta < 0) {
  55646. speed *= -1;
  55647. }
  55648. }else {
  55649. const constantDis = this.currentViewport.getMoveSpeed() * 200; //constantDis = 10;//常量系数,当放大一倍时前进的距离。可以调整
  55650. speed = (e.scale-1)*constantDis; //触屏缩放
  55651. //pointer = new THREE.Vector2().addVectors().multiplyScalar(0.5);//两个指头的中心点
  55652. direction = this.viewer.inputHandler.getMouseDirection(e.pointer).direction; //定点缩放
  55653. }
  55654. this.useAttenuation = true;
  55655. var vec = direction.multiplyScalar(speed );
  55656. this.translationWorldDelta.copy(vec);
  55657. }
  55658. };
  55659. let scroll = (e) => {
  55660. if(!this.enabled)return
  55661. this.setCurrentViewport(e);
  55662. e.camera = e.hoverViewport.camera;
  55663. dolly(e);
  55664. };
  55665. let dblclick = (e) => {
  55666. if(!this.enabled)return
  55667. if(!Potree.settings.dblToFocusPoint)return;//调试时才可双击
  55668. if(Potree.settings.displayMode == 'showPointCloud'/* !viewer.images360.isAtPano() */) this.zoomToLocation(e.mouse);
  55669. };
  55670. this.viewer.addEventListener('global_drag', drag);
  55671. /* this.viewer.addEventListener('global_touchmove', (e)=>{
  55672. if(!this.enabled)return
  55673. if(e.touches.length>1){//单指的就触发上一句
  55674. //console.log('global_touchmove' )
  55675. drag(e)
  55676. }
  55677. }); */
  55678. this.viewer.addEventListener('global_drop', drop);
  55679. this.viewer.addEventListener('global_mousewheel', scroll);
  55680. this.viewer.addEventListener('global_dblclick', dblclick);
  55681. let prepareScale = (e)=>{//触屏的scale
  55682. this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  55683. };
  55684. let prepareRotate = (e)=>{
  55685. this.pointerDragStart = e.pointer.clone();
  55686. this.intersectStart = e.intersectPoint && e.intersectPoint.location && {
  55687. location : e.intersectPoint.location,
  55688. pointer : e.intersectPoint.location.clone().project(e.dragViewport.camera) //intersect点在屏幕中的位置
  55689. };
  55690. //console.log('prepareRotate' )
  55691. };
  55692. let preparePan = (e)=>{//触屏的pan点云 还是会偏移
  55693. this.pointerDragStart = e.pointer.clone();
  55694. e.drag.z = void 0; //清空
  55695. drag(e); //触屏点击时更新的pointer直接用一次drag
  55696. //console.log('preparePan ' )
  55697. };
  55698. this.viewer.addEventListener('global_mousedown'/* 'startDragging' */, (e)=>{
  55699. if(!this.enabled)return
  55700. this.setCurrentViewport(e);
  55701. prepareRotate(e);
  55702. });
  55703. //注意,每次增减指头都会修改pointer,需要更新下状态
  55704. this.viewer.addEventListener('global_touchstart', (e)=>{
  55705. if(!this.enabled)return
  55706. if(e.touches.length==2){//只监听开头两个指头
  55707. prepareScale(e);
  55708. }else if(e.touches.length>=3){
  55709. preparePan(e);
  55710. }
  55711. });
  55712. this.viewer.addEventListener('global_touchend', (e)=>{
  55713. if(!this.enabled)return
  55714. if(e.touches.length==2){//停止平移,开始scale
  55715. prepareScale(e);
  55716. }else if(e.touches.length==1){//停止scale,开始rotate
  55717. prepareRotate(e);
  55718. }else if(e.touches.length>=3){//重新准备下平移(因为抬起的指头可能包含平移使用的数据),否则抬起时漂移
  55719. preparePan(e);
  55720. }
  55721. });
  55722. /* this.viewer.addEventListener('enableChangePos', (e)=>{
  55723. if(!this.enabled)return
  55724. this.enableChangePos = e.canLeavePano
  55725. }) */
  55726. }
  55727. canMovePos(viewport){
  55728. if(viewport == viewer.mainViewport && (Potree.settings.displayMode == 'showPanos'
  55729. || viewer.images360.bumping || viewer.images360.latestToPano))return false
  55730. else return true
  55731. }
  55732. setEnable(enabled){
  55733. this.enabled = enabled;
  55734. }
  55735. setFPCMoveSpeed(viewport){
  55736. if(viewport.camera.type == 'OrthographicCamera'){
  55737. let s = 1 / viewport.camera.zoom;
  55738. viewport.setMoveSpeed(s);
  55739. }else {
  55740. if(viewport == viewer.mainViewport && FirstPersonControls.boundPlane){
  55741. let s = FirstPersonControls.boundPlane.distanceToPoint(viewer.mainViewport.view.position);
  55742. s = Math.sqrt(s) / 10;
  55743. s = Math.max(FirstPersonControls.standardSpeed , s);
  55744. s *= Potree.config.moveSpeedAdujust;
  55745. viewer.setMoveSpeed(s);
  55746. }
  55747. }
  55748. }
  55749. setCurrentViewport(o={}){//add
  55750. if(!this.enabled && !o.force )return
  55751. if(o.hoverViewport && this.currentViewport != o.hoverViewport ){
  55752. this.currentViewport = o.hoverViewport;
  55753. //this.viewer.setMoveSpeed(this.currentViewport.radius/100);
  55754. this.setFPCMoveSpeed(this.currentViewport);
  55755. }
  55756. if(this.currentViewport.camera.type == 'OrthographicCamera'){
  55757. this.lockElevationOri = true;
  55758. this.lockRotation = true;
  55759. }else {
  55760. this.lockElevationOri = false;
  55761. this.lockRotation = false;
  55762. }
  55763. }
  55764. setScene (scene) {
  55765. this.scene = scene;
  55766. }
  55767. stop(){
  55768. this.yawDelta = 0;
  55769. this.pitchDelta = 0;
  55770. this.translationDelta.set(0, 0, 0);
  55771. }
  55772. zoomToLocation(mouse){
  55773. if(!this.enabled)return
  55774. let camera = this.scene.getActiveCamera();
  55775. /* let I = Utils.getMousePointCloudIntersection(
  55776. mouse,
  55777. camera,
  55778. this.viewer,
  55779. this.scene.pointclouds); */
  55780. var I = this.viewer.inputHandler.intersectPoint;
  55781. if (!I) {
  55782. return;
  55783. }
  55784. let targetRadius = 0;
  55785. {
  55786. let minimumJumpDistance = 0.2;
  55787. let domElement = this.renderer.domElement;
  55788. let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer, camera);
  55789. let {origin, direction} = this.viewer.inputHandler.getMouseDirection();
  55790. let raycaster = new Raycaster();
  55791. raycaster.ray.set(origin, direction);
  55792. let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
  55793. let nodes2 = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, raycaster.ray);
  55794. let lastNode = nodes[nodes.length - 1];
  55795. let radius = lastNode.getBoundingSphere(new Sphere()).radius;
  55796. targetRadius = Math.min(this.scene.view.radius, radius);
  55797. targetRadius = Math.max(minimumJumpDistance, targetRadius);
  55798. }
  55799. let d = this.scene.view.direction.multiplyScalar(-1);
  55800. let cameraTargetPosition = new Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
  55801. // TODO Unused: let controlsTargetPosition = I.location;
  55802. let animationDuration = 600;
  55803. let easing = TWEEN.Easing.Quartic.Out;
  55804. { // animate
  55805. let value = {x: 0};
  55806. let tween = new TWEEN.Tween(value).to({x: 1}, animationDuration);
  55807. tween.easing(easing);
  55808. this.tweens.push(tween);
  55809. let startPos = this.scene.view.position.clone();
  55810. let targetPos = cameraTargetPosition.clone();
  55811. let startRadius = this.scene.view.radius;
  55812. let targetRadius = cameraTargetPosition.distanceTo(I.location);
  55813. tween.onUpdate(() => {
  55814. let t = value.x;
  55815. this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
  55816. this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
  55817. this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
  55818. this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
  55819. this.viewer.setMoveSpeed(this.scene.view.radius / 2.5);
  55820. });
  55821. tween.onComplete(() => {
  55822. this.tweens = this.tweens.filter(e => e !== tween);
  55823. });
  55824. tween.start();
  55825. }
  55826. }
  55827. update (delta=1) {
  55828. if(!this.enabled)return
  55829. //console.log('update')
  55830. let view = this.currentViewport.view;
  55831. { // cancel move animations on user input
  55832. let changes = [ this.yawDelta,
  55833. this.pitchDelta,
  55834. this.translationDelta.length(),
  55835. this.translationWorldDelta.length() ];
  55836. let changeHappens = changes.some(e => Math.abs(e) > 0.001);
  55837. if (changeHappens && this.tweens.length > 0) {
  55838. this.tweens.forEach(e => e.stop());
  55839. this.tweens = [];
  55840. }
  55841. }
  55842. { // accelerate while input is given
  55843. let ih = this.viewer.inputHandler;
  55844. let moveForward = this.keys.FORWARD.some(e => ih.pressedKeys[e]);
  55845. let moveBackward = this.keys.BACKWARD.some(e => ih.pressedKeys[e]);
  55846. let moveLeft = this.keys.LEFT.some(e => ih.pressedKeys[e]);
  55847. let moveRight = this.keys.RIGHT.some(e => ih.pressedKeys[e]);
  55848. let moveUp = this.keys.UP.some(e => ih.pressedKeys[e]);
  55849. let moveDown = this.keys.DOWN.some(e => ih.pressedKeys[e]);
  55850. let rotateLeft = this.keys.Rotate_LEFT.some(e => ih.pressedKeys[e]);
  55851. let rotateRight = this.keys.Rotate_RIGHT.some(e => ih.pressedKeys[e]);
  55852. let rotateUp = this.keys.Rotate_UP.some(e => ih.pressedKeys[e]);
  55853. let rotateDown = this.keys.Rotate_DOWN.some(e => ih.pressedKeys[e]);
  55854. this.lockElevation = this.lockElevationOri || this.keys.ALT.some(e => ih.pressedKeys[e]);
  55855. if(!this.lockRotation){
  55856. if(rotateLeft){
  55857. this.yawDelta -= 0.01;
  55858. }else if(rotateRight){
  55859. this.yawDelta += 0.01;
  55860. }
  55861. if(rotateUp){
  55862. this.pitchDelta -= 0.01;
  55863. }else if(rotateDown){
  55864. this.pitchDelta += 0.01;
  55865. }
  55866. }
  55867. if(this.canMovePos(this.currentViewport) && !this.lockKey){
  55868. if(this.lockElevation){
  55869. let dir = view.direction;
  55870. dir.z = 0;
  55871. dir.normalize();
  55872. if (moveForward && moveBackward) {
  55873. this.translationWorldDelta.set(0, 0, 0);
  55874. } else if (moveForward) {
  55875. this.translationWorldDelta.copy(dir.multiplyScalar(this.currentViewport.getMoveSpeed()));
  55876. } else if (moveBackward) {
  55877. this.translationWorldDelta.copy(dir.multiplyScalar(-this.currentViewport.getMoveSpeed()));
  55878. }
  55879. }else {
  55880. if (moveForward && moveBackward) {
  55881. this.translationDelta.y = 0;
  55882. } else if (moveForward) {
  55883. this.translationDelta.y = this.currentViewport.getMoveSpeed();
  55884. } else if (moveBackward) {
  55885. this.translationDelta.y = -this.currentViewport.getMoveSpeed();
  55886. }
  55887. }
  55888. if (moveLeft && moveRight) {
  55889. this.translationDelta.x = 0;
  55890. } else if (moveLeft) {
  55891. this.translationDelta.x = -this.currentViewport.getMoveSpeed();
  55892. } else if (moveRight) {
  55893. this.translationDelta.x = this.currentViewport.getMoveSpeed();
  55894. }
  55895. if (moveUp && moveDown) {
  55896. this.translationWorldDelta.z = 0;
  55897. } else if (moveUp) {
  55898. this.translationWorldDelta.z = this.currentViewport.getMoveSpeed();
  55899. } else if (moveDown) {
  55900. this.translationWorldDelta.z = -this.currentViewport.getMoveSpeed();
  55901. }
  55902. if(moveUp || moveDown || moveForward || moveBackward){
  55903. this.useAttenuation = false;
  55904. }
  55905. }
  55906. }
  55907. { // apply rotation
  55908. let yaw = view.yaw;
  55909. let pitch = view.pitch;
  55910. yaw += this.yawDelta; /* * delta; */
  55911. pitch += this.pitchDelta;/* * delta; */
  55912. view.yaw = yaw;
  55913. view.pitch = pitch;
  55914. this.yawDelta = 0;
  55915. this.pitchDelta = 0;
  55916. }
  55917. if(this.translationWorldDelta.length()>0) {
  55918. // console.log('translationDelta')
  55919. }
  55920. { // apply translation
  55921. view.translate(
  55922. this.translationDelta.x, /* * delta, */
  55923. this.translationDelta.y, /* * delta, */
  55924. this.translationDelta.z, /* * delta */
  55925. );
  55926. this.translationDelta.set(0,0,0);
  55927. //if(this.translationWorldDelta.length())console.log(translationWorldDelta)
  55928. view.translateWorld(
  55929. this.translationWorldDelta.x /* * delta */,
  55930. this.translationWorldDelta.y /* * delta */,
  55931. this.translationWorldDelta.z /* * delta */
  55932. );
  55933. //this.translationWorldDelta.set(0,0,0)
  55934. }
  55935. { // set view target according to speed
  55936. //view.radius = 1 * this.currentViewport.getMoveSpeed();
  55937. /* if(viewer.bound) view.radius = view.position.distanceTo(viewer.bound.center)
  55938. let speed = view.radius/100;
  55939. this.viewer.setMoveSpeed(speed); */
  55940. //this.setMoveSpeed()
  55941. }
  55942. if(this.useAttenuation){ //只有滚轮缩放时开启
  55943. let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
  55944. /*this.yawDelta *= attenuation;
  55945. this.pitchDelta *= attenuation;
  55946. this.translationDelta.multiplyScalar(attenuation);*/
  55947. this.translationWorldDelta.multiplyScalar(attenuation);
  55948. }else {
  55949. this.translationWorldDelta.set(0,0,0);
  55950. }
  55951. }
  55952. };
  55953. class Viewport{
  55954. constructor( view, camera, prop={}){//目前不支持换camera
  55955. this.left = prop.left;
  55956. this.bottom = prop.bottom;
  55957. this.width = prop.width;
  55958. this.height = prop.height;
  55959. this.name = prop.name;
  55960. this.view = view;
  55961. this.camera = camera;
  55962. this.active = true;
  55963. this.unableChangePos = false;
  55964. this.noPointcloud;
  55965. //this.keys = [...] firstPersonCtl....
  55966. this.resolution = new Vector2$1;
  55967. this.resolution2 = new Vector2$1;
  55968. this.offset = new Vector2$1; //viewportOffset 范围从0-整个画布的像素
  55969. this.extraEnableLayers = prop.extraEnableLayers || [];//额外可展示的层
  55970. this.cameraLayers = prop.cameraLayers;
  55971. this.pixelRatio = prop.pixelRatio; //如果规定pixelRatio的话要传,这样就覆盖devicePicelRatio, 如magnifier
  55972. }
  55973. clone(){
  55974. return Common.CloneClassObject(this)
  55975. }
  55976. getMoveSpeed(){
  55977. return this.moveSpeed
  55978. }
  55979. setMoveSpeed(e){
  55980. this.moveSpeed = e;
  55981. }
  55982. layersAdd(name){
  55983. this.extraEnableLayers.includes(name) || this.extraEnableLayers.push(name);
  55984. }
  55985. layersRemove(name){
  55986. let index = this.extraEnableLayers.indexOf(name);
  55987. if(index > -1){
  55988. this.extraEnableLayers.splice(index, 1);
  55989. }
  55990. }
  55991. cameraChanged() {
  55992. var copy = ()=>{
  55993. this.previousState = {
  55994. projectionMatrix: this.camera.projectionMatrix.clone(),//worldMatrix在this.control时归零了所以不用了吧,用position和qua也一样
  55995. position: this.camera.position.clone(),
  55996. quaternion: this.camera.quaternion.clone()
  55997. };
  55998. };
  55999. let projectionChanged = true;
  56000. let positionChanged = true;
  56001. let quaternionChanged = true;
  56002. let getChanged = ()=>{
  56003. return {
  56004. projectionChanged,positionChanged,quaternionChanged,
  56005. changed:projectionChanged || positionChanged || quaternionChanged
  56006. }
  56007. };
  56008. if (this.previousState){
  56009. projectionChanged = !this.camera.projectionMatrix.equals(this.previousState.projectionMatrix);
  56010. positionChanged = !this.camera.position.equals(this.previousState.position);
  56011. quaternionChanged = !this.camera.quaternion.equals(this.previousState.quaternion);
  56012. }
  56013. copy();
  56014. return getChanged()
  56015. }
  56016. setResolution(w,h, wholeW=0, wholeH=0){
  56017. this.resolution.set(w,h);//是client的width height
  56018. this.resolution2.copy(this.resolution).multiplyScalar(this.pixelRatio || window.devicePixelRatio);
  56019. this.offset.set(wholeW,wholeH).multiply(new Vector2$1(this.left,this.bottom)).multiplyScalar(window.devicePixelRatio);
  56020. }
  56021. }
  56022. /**
  56023. * @author mschuetz / http://mschuetz.at
  56024. *
  56025. *
  56026. */
  56027. class InputHandler extends EventDispatcher {
  56028. constructor (viewer,scene) {
  56029. super();
  56030. this.viewer = viewer;
  56031. this.renderer = viewer.renderer;
  56032. this.domElement = this.renderer.domElement;
  56033. this.enabled = true;
  56034. this.scene = scene;
  56035. this.interactiveScenes = [];
  56036. this.interactiveObjects = new Set();
  56037. this.inputListeners = [];
  56038. this.blacklist = new Set();
  56039. this.drag = null;
  56040. this.mouse = new Vector2$1(0, 0);
  56041. //add:
  56042. this.pointer = new Vector2$1(0, 0); //交互点的屏幕坐标,有别于DOM坐标,在此存放NDC坐标。(NDC,三维常用坐标系,二维坐标,整个屏幕映射范围(-1,1),屏幕中心为原点,+Y朝上,+X朝右)
  56043. this.mouseDownMouse = new Vector2$1(0, 0);
  56044. this.selection = [];
  56045. this.hoveredElements = [];
  56046. this.pressedKeys = {};
  56047. this.wheelDelta = 0;
  56048. this.speed = 1;
  56049. this.logMessages = false;
  56050. if (this.domElement.tabIndex === -1) {
  56051. this.domElement.tabIndex = 2222;
  56052. }
  56053. this.lastPointerUpTime = 0;
  56054. this.touches = [];
  56055. this.hoverViewport = viewer.viewports[0];
  56056. this.domElement.addEventListener('contextmenu', (event) => { event.preventDefault(); }, false);
  56057. this.domElement.addEventListener('click', this.onMouseClick.bind(this), false);
  56058. this.domElement.addEventListener('mousedown', this.onMouseDown.bind(this), false);
  56059. window.addEventListener('mouseup', this.onMouseUp.bind(this), false);
  56060. this.domElement.addEventListener('mousemove', this.onMouseMove.bind(this), false);
  56061. //add
  56062. /* this.domElement.addEventListener("pointerout", this.onMouseUp.bind(this)),
  56063. this.domElement.addEventListener("pointercancel", this.onMouseUp.bind(this)),
  56064. */
  56065. this.domElement.addEventListener('mousewheel', this.onMouseWheel.bind(this), false);
  56066. this.domElement.addEventListener('DOMMouseScroll', this.onMouseWheel.bind(this), false); // Firefox
  56067. //this.domElement.addEventListener('dblclick', this.onDoubleClick.bind(this)); //因为双击时间间隔是跟随系统的所以不好判断
  56068. this.domElement.addEventListener('keydown', this.onKeyDown.bind(this));
  56069. window.addEventListener('keyup', this.onKeyUp.bind(this));
  56070. //window.addEventListener('focus',()=>{
  56071. window.addEventListener('blur',this.onKeyUp.bind(this)); //add
  56072. this.domElement.addEventListener('touchstart', this.onTouchStart.bind(this));
  56073. this.domElement.addEventListener('touchend', this.onTouchEnd.bind(this));
  56074. this.domElement.addEventListener('touchmove', this.onTouchMove.bind(this));
  56075. {
  56076. this.addEventListener('isMeasuring',(e)=>{
  56077. //console.log('isMeasuring',e.v,e.cause)
  56078. this.isMeasuring = e.v;
  56079. });
  56080. }
  56081. }
  56082. /* addInputListener (listener) {
  56083. this.inputListeners.push(listener);
  56084. }
  56085. removeInputListener (listener) {
  56086. this.inputListeners = this.inputListeners.filter(e => e !== listener);
  56087. }
  56088. getSortedListeners(){
  56089. return this.inputListeners.sort( (a, b) => {
  56090. let ia = (a.importance !== undefined) ? a.importance : 0;
  56091. let ib = (b.importance !== undefined) ? b.importance : 0;
  56092. return ib - ia;
  56093. });
  56094. } */
  56095. //统一跟第一个触碰的viewport相同
  56096. updateTouchesInfo(e){
  56097. var viewport, pointer, camera;
  56098. let oldTouches = this.touches;
  56099. let changedTouches = Array.from(e.changedTouches);
  56100. let touches = Array.from(e.touches);
  56101. this.touches = touches.map(touch=>{
  56102. let touch_ = oldTouches.find(a=>a.touch.identifier == touch.identifier);
  56103. let pointer = touch_ && touch_.pointer; //复制原先的值
  56104. return {
  56105. touch, pointer,
  56106. }
  56107. });
  56108. if(e.touches.length > 0){
  56109. let newTouches = touches.filter(e=>!
  56110. oldTouches.some(a=>a.touch.identifier == e.identifier) && !changedTouches.some(a=>a.identifier == e.identifier)
  56111. ); //从按钮处划过时e.touches中会出现this.touches和changedTouches中都没有的identifier
  56112. if(newTouches.length>0){
  56113. console.warn('has new',newTouches.map(e=>e.identifier));
  56114. }
  56115. newTouches.concat(changedTouches).forEach(touch=>{ //修改changedTouches的
  56116. let touch_ = this.touches.find(a=>a.touch.identifier == touch.identifier);
  56117. if(touch_){
  56118. let a = this.getPointerInViewport(touch.pageX, touch.pageY, this.dragViewport||viewport, new Vector2$1);
  56119. touch_.pointer = a.pointer.clone();
  56120. viewport = a.viewport; camera = a.camera;
  56121. }
  56122. });
  56123. //使用当前touches的平均
  56124. if(e.touches.length > 1){
  56125. let pageX = Common.average(e.touches, "pageX");
  56126. let pageY = Common.average(e.touches, "pageY");
  56127. let a = this.getPointerInViewport(pageX, pageY, viewport, new Vector2$1);
  56128. this.pointer.copy(a.pointer);
  56129. //console.log('updateTouchesInfo', this.pointer.clone())
  56130. }else {
  56131. this.pointer = this.touches[0].pointer.clone(); //更新,使用当前touches中的第一个
  56132. }
  56133. /* if(this.touches.find(e=>!e.pointer)){
  56134. console.error(' touches has no pointer', oldTouches.map(e=>e.touch.identifier),
  56135. Array.from(e.touches).map(e=>e.identifier), Array.from(e.changedTouches).map(e=>e.identifier) )
  56136. } */
  56137. //console.log(this.touches)
  56138. //console.log('更新pointer1',this.pointer.toArray())
  56139. return {viewport, camera/* , pointer:this.pointer */}
  56140. }
  56141. }
  56142. onTouchStart (e) {
  56143. if (this.logMessages) console.log(this.constructor.name + ': onTouchStart');
  56144. e.preventDefault();
  56145. /* if (e.touches.length === 1 || !this.drag) { //!this.drag代表一次性下了两个指头
  56146. let rect = this.domElement.getBoundingClientRect();
  56147. let x = e.touches[0].pageX
  56148. let y = e.touches[0].pageY
  56149. this.dealPointerDown(x,y,e,true)
  56150. }else{
  56151. this.updateTouchesInfo(e)
  56152. this.drag.end.copy(this.pointer)
  56153. } */
  56154. this.dealPointerDown(e,true);
  56155. this.viewer.dispatchEvent($.extend(
  56156. this.getEventDesc(e,true),
  56157. {
  56158. type: 'global_' + e.type,
  56159. changedTouches: e.changedTouches
  56160. }
  56161. ));
  56162. /* console.log('targetTouches :', Array.from(e.targetTouches).map(e=>'| identifier: '+ e.identifier),
  56163. 'changedTouches :', Array.from(e.changedTouches).map(e=>'| identifier: '+ e.identifier)
  56164. ) */
  56165. //console.log('')
  56166. }
  56167. onTouchMove (e) {
  56168. if (this.logMessages) console.log(this.constructor.name + ': onTouchMove');
  56169. e.preventDefault();
  56170. /* if (e.touches.length === 1) {
  56171. let rect = this.domElement.getBoundingClientRect();
  56172. let x = e.touches[0].pageX;
  56173. let y = e.touches[0].pageY;
  56174. }else{
  56175. this.updateTouchesInfo(e)
  56176. this.drag.pointerDelta.subVectors(this.pointer, this.drag.end)
  56177. this.drag.end.copy(this.pointer)
  56178. }
  56179. */
  56180. this.dealPointerMove(e, true);
  56181. this.viewer.dispatchEvent($.extend(
  56182. this.getEventDesc(e,true),
  56183. {
  56184. type: 'global_' + e.type,
  56185. changedTouches: e.changedTouches
  56186. }
  56187. ));
  56188. /* console.log('targetTouches :', Array.from(e.targetTouches).map(e=>'| identifier: '+ e.identifier),
  56189. 'changedTouches :', Array.from(e.changedTouches).map(e=>'| identifier: '+ e.identifier)
  56190. ) */
  56191. }
  56192. onTouchEnd (e) {
  56193. if (this.logMessages) console.log(this.constructor.name + ': onTouchEnd');
  56194. e.preventDefault();
  56195. //console.log('onTouchEnd')
  56196. this.updateTouchesInfo(e);
  56197. /* if (e.touches.length === 0) {
  56198. let rect = this.domElement.getBoundingClientRect();
  56199. let x = e.changedTouches[0].pageX //万一一次松开两个指头的怎么办
  56200. let y = e.changedTouches[0].pageY
  56201. this.dealPointerUp(x,y,e,true)
  56202. }else {
  56203. this.drag.end.copy(this.pointer)
  56204. } */
  56205. this.dealPointerUp(e,true);
  56206. this.viewer.dispatchEvent($.extend(
  56207. this.getEventDesc(e,true),
  56208. {
  56209. type: 'global_' + e.type,
  56210. }
  56211. ));
  56212. //console.log('touchend length '+e.touches.length, this.touches.length)
  56213. }
  56214. onKeyDown (e) {
  56215. if (this.logMessages) console.log(this.constructor.name + ': onKeyDown');
  56216. // DELETE
  56217. if (e.keyCode === KeyCodes.DELETE && this.selection.length > 0) {
  56218. this.dispatchEvent({
  56219. type: 'delete',
  56220. selection: this.selection
  56221. });
  56222. this.deselectAll();
  56223. }
  56224. this.dispatchEvent({
  56225. type: 'keydown',
  56226. keyCode: e.keyCode,
  56227. event: e
  56228. });
  56229. // for(let l of this.getSortedListeners()){
  56230. // l.dispatchEvent({
  56231. // type: "keydown",
  56232. // keyCode: e.keyCode,
  56233. // event: e
  56234. // });
  56235. // }
  56236. this.pressedKeys[e.keyCode] = true;
  56237. // e.preventDefault();
  56238. }
  56239. onKeyUp (e) {
  56240. if (this.logMessages) console.log(this.constructor.name + ': onKeyUp');
  56241. if(e.keyCode != void 0){
  56242. delete this.pressedKeys[e.keyCode];
  56243. }else {
  56244. this.pressedKeys = {};
  56245. }
  56246. e.preventDefault();
  56247. }
  56248. onDoubleClick (e) {
  56249. if (this.logMessages) console.log(this.constructor.name + ': onDoubleClick');
  56250. let consumed = false;
  56251. for (let hovered of this.hoveredElements) {
  56252. if (hovered._listeners && hovered._listeners['dblclick']) {
  56253. hovered.object.dispatchEvent({
  56254. type: 'dblclick',
  56255. mouse: this.mouse,
  56256. object: hovered.object
  56257. });
  56258. consumed = true;
  56259. break;
  56260. }
  56261. }
  56262. if (!consumed) {
  56263. /* for (let inputListener of this.getSortedListeners()) {
  56264. inputListener. */this.viewer.dispatchEvent({
  56265. type: 'global_dblclick',
  56266. mouse: this.mouse,
  56267. object: null
  56268. });
  56269. //}
  56270. }
  56271. this.needSingleClick = false;//add
  56272. e.preventDefault();
  56273. }
  56274. onMouseClick (e) {
  56275. if (this.logMessages) console.log(this.constructor.name + ': onMouseClick');
  56276. e.preventDefault();
  56277. }
  56278. dealPointerDown(e,isTouch){
  56279. e.preventDefault();
  56280. //重新获取一下pointer, 因点击了浏览器的按钮展开列表时 move回来不会触发onmousemove,所以pointer是旧的
  56281. if(isTouch){
  56282. var { camera, viewport } = this.updateTouchesInfo(e);
  56283. if(this.drag){
  56284. //因为触屏在按下前缺少pointermove所以要更新下
  56285. this.drag.end = this.pointer.clone();
  56286. }
  56287. }else {
  56288. var { camera, viewport } = this.getPointerInViewport(e.clientX, e.clientY );
  56289. }
  56290. this.dragViewport = this.hoverViewport = viewport;
  56291. if(isTouch){
  56292. this.hoveredElements = this.getHoveredElements();
  56293. this.intersectPoint = this.getIntersect(viewport);
  56294. this.intersect = this.getWholeIntersect();
  56295. }
  56296. if(!viewport)return
  56297. if(!isTouch || e.touches.length == 1){
  56298. let consumed = false;
  56299. let consume = () => { return consumed = true; };
  56300. //if (this.hoveredElements.length === 0) {
  56301. this.viewer.dispatchEvent($.extend(
  56302. this.getEventDesc(e,isTouch),
  56303. {
  56304. type: 'global_mousedown'
  56305. }
  56306. ));
  56307. for(let hovered of this.hoveredElements){
  56308. let object = hovered.object;
  56309. object.dispatchEvent({
  56310. type: 'mousedown',
  56311. viewer: this.viewer,
  56312. consume: consume
  56313. });
  56314. if(consumed){
  56315. break;
  56316. }
  56317. }
  56318. }
  56319. if (!this.drag) {
  56320. let target = (isTouch||e.button == MOUSE.LEFT) && this.hoveredElements.find(el => (//只有左键能拖拽
  56321. el.object._listeners &&
  56322. el.object._listeners['drag'] &&
  56323. el.object._listeners['drag'].length > 0));
  56324. if (target) {
  56325. this.startDragging(target.object, {location: target.point});
  56326. } else {
  56327. this.startDragging(null);
  56328. }
  56329. }
  56330. this.drag.intersectStart = this.intersectPoint;
  56331. this.mouseDownMouse = this.mouse.clone();
  56332. this.pointerDownTime = Date.now();
  56333. }
  56334. onMouseDown (e) {
  56335. if (this.logMessages) console.log(this.constructor.name + ': onMouseDown');
  56336. this.dealPointerDown(e);
  56337. }
  56338. getWholeIntersect(hoveredElements, intersectPoint){//add
  56339. hoveredElements = hoveredElements || this.hoveredElements;
  56340. intersectPoint = intersectPoint || this.intersectPoint;
  56341. if(Potree.settings.intersectOnObjs && hoveredElements[0] && hoveredElements[0].object.isModel){
  56342. return {//模拟点云的intersectPoint的结构写法
  56343. hoveredElement : hoveredElements[0] ,
  56344. location: hoveredElements[0].point,
  56345. point: {normal: hoveredElements[0].face.normal },
  56346. distance: hoveredElements[0].distance,
  56347. object: hoveredElements[0].object
  56348. }
  56349. }else return intersectPoint
  56350. }
  56351. getEventDesc(e,isTouch){//搜集dispatchEvent要给的一般数据
  56352. let o = {
  56353. viewer: this.viewer,
  56354. mouse: this.mouse,
  56355. pointer:this.pointer,
  56356. drag :this.drag,
  56357. isTouch,
  56358. dragViewport : this.dragViewport,
  56359. hoverViewport: this.hoverViewport,
  56360. // button: isTouch ? 0 : e.button,
  56361. intersectPoint:this.intersectPoint,
  56362. hoveredElement: this.hoveredElements[0],
  56363. intersect: this.intersect//this.getWholeIntersect() , //可能包含mesh上的,针对融合页面
  56364. };
  56365. if(e){
  56366. o.isAtDomElement = e.target == this.domElement;
  56367. }
  56368. if(isTouch){
  56369. o.touches = this.touches;
  56370. }else if(e){
  56371. o.button = e.button;
  56372. o.buttons = e.buttons;
  56373. }
  56374. return o;
  56375. }
  56376. dealPointerUp(e,isTouch){
  56377. if(!this.drag){// 在canvas外mousedown
  56378. return
  56379. }
  56380. this.drag.end.copy(this.pointer);
  56381. if(isTouch && e.touches.length >= 1){
  56382. return
  56383. }
  56384. let now = Date.now();
  56385. if (this.logMessages) console.log(this.constructor.name + ': onMouseUp');
  56386. e.preventDefault();
  56387. let pressDistance = this.mouseDownMouse.distanceTo(this.mouse);
  56388. let pressTime = now - this.pointerDownTime;
  56389. let noMovement = this.drag.pointerDelta.length() == 0;//this.getNormalizedDrag().length() === 0;
  56390. let consumed = false;
  56391. let consume = () => { return consumed = true; };
  56392. //if (this.hoveredElements.length === 0) {
  56393. /* for (let inputListener of this.getSortedListeners()) {
  56394. inputListener */this.viewer.dispatchEvent($.extend(
  56395. this.getEventDesc(e,isTouch),
  56396. {
  56397. type: 'global_mouseup',
  56398. pressDistance,
  56399. consume,
  56400. }
  56401. ));
  56402. /* if(consumed){//??
  56403. break;
  56404. } */
  56405. //}
  56406. //}
  56407. if (this.hoveredElements.length > 0) {
  56408. let hovered = this.hoveredElements
  56409. .map(e => e.object)
  56410. .find(e => (e._listeners && e._listeners['mouseup']));
  56411. if(hovered){
  56412. hovered.dispatchEvent({
  56413. type: 'mouseup',
  56414. viewer: this.viewer,
  56415. consume: consume
  56416. });
  56417. }
  56418. }
  56419. if (this.drag) {
  56420. //拖拽结束
  56421. if (this.drag.object/* && e.button == THREE.MOUSE.LEFT */) {//add LEFT
  56422. if (this.logMessages) console.log(`${this.constructor.name}: drop ${this.drag.object.name}`);
  56423. this.drag.object.dispatchEvent($.extend(
  56424. this.getEventDesc(e,isTouch),
  56425. {
  56426. type: 'drop',
  56427. pressDistance,
  56428. }
  56429. ));
  56430. } else {
  56431. this.viewer.dispatchEvent($.extend(
  56432. this.getEventDesc(e,isTouch),
  56433. {
  56434. type: 'global_drop',
  56435. pressDistance
  56436. }
  56437. ));
  56438. }
  56439. // check for a click
  56440. if(pressDistance < Potree.config.clickMaxDragDis && pressTime<Potree.config.clickMaxPressTime){
  56441. let clickElement;
  56442. if(this.hoveredElements){
  56443. clickElement = this.hoveredElements.find(e=>e.object._listeners['click']);
  56444. if(clickElement){
  56445. if (this.logMessages) console.log(`${this.constructor.name}: click ${clickObject.name}`);
  56446. clickElement.object.dispatchEvent($.extend(
  56447. this.getEventDesc(e,isTouch),
  56448. {
  56449. type: 'click',
  56450. pressDistance
  56451. }
  56452. ));
  56453. }
  56454. }
  56455. let desc = this.getEventDesc(e,isTouch);
  56456. //if(!clickElement){
  56457. this.viewer.dispatchEvent($.extend(
  56458. desc,
  56459. {
  56460. type: 'global_click',
  56461. pressDistance
  56462. }
  56463. ));
  56464. //}
  56465. //增加 单击:
  56466. this.needSingleClick = true;
  56467. setTimeout(()=>{
  56468. if(this.needSingleClick){
  56469. this.viewer.dispatchEvent($.extend(
  56470. desc,
  56471. {
  56472. type: 'global_single_click',
  56473. pressDistance,
  56474. clickElement
  56475. }
  56476. ));
  56477. }
  56478. }, Potree.config.doubleClickTime+1);
  56479. //自行执行双击:
  56480. if(now - this.lastClickTime < this.doubleClickTime){
  56481. this.onDoubleClick(e);
  56482. }
  56483. this.lastClickTime = now;
  56484. }
  56485. this.drag = null;
  56486. }
  56487. this.dragViewport = null;
  56488. if(!consumed && !this.fixSelection){
  56489. if (e.button === MOUSE.LEFT) {
  56490. if (noMovement) {
  56491. let selectable = this.hoveredElements
  56492. .find(el => el.object._listeners && el.object._listeners['select']);
  56493. if (selectable) {
  56494. selectable = selectable.object;
  56495. if (this.isSelected(selectable)) {
  56496. this.selection
  56497. .filter(e => e !== selectable)
  56498. .forEach(e => this.toggleSelection(e));
  56499. } else {
  56500. this.deselectAll();
  56501. this.toggleSelection(selectable);
  56502. }
  56503. } else {
  56504. this.deselectAll();
  56505. }
  56506. }
  56507. } else if ((e.button === MOUSE.RIGHT) && noMovement) {
  56508. this.deselectAll();
  56509. }
  56510. }
  56511. }
  56512. onMouseUp (e) {
  56513. this.dealPointerUp( e );
  56514. }
  56515. getPointerInViewport(clientX, clientY, viewForceAt, pointer ){
  56516. let rect = this.domElement.getBoundingClientRect();
  56517. let x = clientX - rect.left;
  56518. let y = clientY - rect.top;
  56519. let camera;
  56520. let viewport;
  56521. pointer = pointer ||this.pointer;
  56522. //if(this.viewer.viewports || viewForceAt){
  56523. var getDimension = (view)=>{
  56524. var left = Math.ceil(this.domElement.clientWidth * view.left)
  56525. , bottom = Math.ceil(this.domElement.clientHeight * view.bottom)
  56526. , width = Math.ceil(this.domElement.clientWidth * view.width)
  56527. , height = Math.ceil(this.domElement.clientHeight * view.height)
  56528. , top = this.domElement.clientHeight - bottom - height;
  56529. return {left, bottom, width, height, top}
  56530. };
  56531. var getView = (view, left, bottom, width, height, top)=>{
  56532. this.mouse.set(x-left, y - top );
  56533. Utils.convertScreenPositionToNDC(pointer, this.mouse, width, height);
  56534. //console.log('更新pointer2',this.pointer.toArray())
  56535. camera = view.camera;
  56536. viewport = view;
  56537. };
  56538. if(viewForceAt){
  56539. let {left, bottom, width, height, top} = getDimension(viewForceAt);
  56540. getView(viewForceAt, left, bottom, width, height, top);
  56541. }else {
  56542. var length = this.viewer.viewports.length;
  56543. //var getif = false
  56544. for(var i=0;i<length;i++){
  56545. var view = this.viewer.viewports[i];
  56546. if(!view.active)continue
  56547. var {left, bottom, width, height, top} = getDimension(view);
  56548. if(x >= left && x <= left + width && y >= top && y <= top + height){
  56549. getView(view, left, bottom, width, height, top);
  56550. //getif = true
  56551. break;
  56552. }
  56553. }
  56554. }
  56555. return {
  56556. camera, viewport, pointer
  56557. }
  56558. }
  56559. ifBlockedByIntersect(point, margin=0, usePointcloud, cameraPos, pickWindowSize, pano){//某点是否被遮挡(不允许camera修改位置, 因为depthTex不好置换)
  56560. if(cameraPos){
  56561. usePointcloud = true; //只有使用点云才允许换位置
  56562. }
  56563. let intersectPoint = this.getIntersect(this.hoverViewport, true, pickWindowSize, null, usePointcloud, {point, cameraPos, pano});
  56564. let cameraPos_ = (!usePointcloud && pano) ? pano.position : (cameraPos||this.hoverViewport.view.position);
  56565. if(intersectPoint && intersectPoint.distance+margin <= point.distanceTo(cameraPos_)){
  56566. return intersectPoint //被遮挡
  56567. }
  56568. //点云模式,对没加载出的点云不准确。 尤其是需要修改相机位置时,因临时修改并不能使点云加载。
  56569. }
  56570. getIntersect(viewport, onlyGetIntersect, pickWindowSize, dontIntersectPointcloud, usePointcloud, prop={}){
  56571. let intersectPoint;
  56572. let camera = viewport.camera;
  56573. if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex && !usePointcloud && !this.isMeasuring && viewport == viewer.mainViewport ){
  56574. let raycaster;
  56575. /* if(prop.point){
  56576. raycaster = new THREE.Raycaster()
  56577. var dir = new THREE.Vector3().subVectors(prop.point, camera.position).normalize()
  56578. raycaster.set(camera.position, dir) //var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
  56579. } */
  56580. let intersect;
  56581. if(prop.point){
  56582. let cameraPos = prop.pano ? prop.pano.position : camera.position;
  56583. let dir = new Vector3().subVectors(prop.point, cameraPos).normalize();
  56584. intersect = {dir};
  56585. }else {
  56586. intersect = Utils.getIntersect(camera, [viewer.images360.cube], this.pointer, raycaster);
  56587. }
  56588. intersectPoint = viewer.images360.depthSampler.sample(intersect, prop.pano, !!prop.point); //可能不准确, 因pano可能未加载depthTex
  56589. }else {
  56590. if(prop.point){
  56591. prop.cameraPos && camera.position.copy(prop.cameraPos);
  56592. camera.lookAt(prop.point);
  56593. camera.updateMatrixWorld();
  56594. prop.pointer = this.pointer.clone();
  56595. prop.mouse = this.mouse.clone();
  56596. this.pointer.set(0,0); //画布中心
  56597. this.mouse.set(Math.round(viewport.resolution.x/2), Math.round(viewport.resolution.y/2));
  56598. }
  56599. intersectPoint = (viewport.noPointcloud || dontIntersectPointcloud)? null : Utils.getMousePointCloudIntersection(
  56600. viewport,
  56601. this.mouse,
  56602. this.pointer,
  56603. camera,
  56604. this.viewer,
  56605. this.viewer.scene.pointclouds,
  56606. {pickClipped: true, isMeasuring: this.isMeasuring, pickWindowSize, cameraChanged: !!prop.point }
  56607. );
  56608. //恢复
  56609. if(prop.point){
  56610. viewport.view.applyToCamera(camera);
  56611. this.pointer.copy(prop.pointer);
  56612. this.mouse.copy(prop.mouse);
  56613. }
  56614. }
  56615. //console.log(viewport.name , intersectPoint && intersectPoint.location )
  56616. if(viewport.camera.type == 'OrthographicCamera'/* == 'mapViewport' */){
  56617. let pos3d = new Vector3(this.pointer.x,this.pointer.y,-1).unproject(viewport.camera); //z:-1朝外
  56618. if(!intersectPoint){
  56619. intersectPoint = {};
  56620. }
  56621. intersectPoint.orthoIntersect = pos3d.clone();
  56622. }
  56623. if(onlyGetIntersect){
  56624. return intersectPoint
  56625. }
  56626. if (intersectPoint) {
  56627. if(viewer.showCoordType){ //显示坐标位置时
  56628. let pos = intersectPoint.point.position.toArray();
  56629. if(viewer.showCoordType == "local"){
  56630. }else if(viewer.showCoordType == "lonlat"){
  56631. pos = viewer.transform.lonlatToLocal.inverse(pos);
  56632. }else {
  56633. pos = viewer.transform.lonlatToLocal.inverse(pos);
  56634. pos = viewer.transform.lonlatTo4550.forward(pos);
  56635. }
  56636. viewer.dispatchEvent({
  56637. type : "coordinateChange", pos
  56638. });
  56639. }
  56640. }
  56641. //console.log('getIntersect', !!intersectPoint)
  56642. this.intersectPoint = intersectPoint;
  56643. intersectPoint && (this.hoverViewport.lastIntersect = intersectPoint);
  56644. return intersectPoint
  56645. }
  56646. onMouseMove (e) {
  56647. return this.dealPointerMove( e )
  56648. }
  56649. dealPointerMove(e, isTouch){
  56650. if(isTouch){
  56651. var { camera, viewport } = this.updateTouchesInfo(e);
  56652. }else {
  56653. var { camera, viewport } = this.getPointerInViewport(e.clientX, e.clientY, this.dragViewport);
  56654. }
  56655. this.hoverViewport = viewport;
  56656. if(!viewport)return//刚变化viewport时会找不到
  56657. let isFlying = this.viewer.viewports.some(e=>e.view.isFlying());
  56658. let intersectPoint;
  56659. if(e.onlyGetIntersect || !this.drag || this.drag.object || viewport.alignment ){ //没有拖拽物体,但按下鼠标了的话,不intersect
  56660. let dontIntersectPointcloud = this.drag && viewport.alignment && Potree.settings.editType == 'pano' || isFlying;/* viewer.images360.flying */ // flying 时可能卡顿
  56661. //console.log('dontIntersectPointcloud',dontIntersectPointcloud)
  56662. intersectPoint = this.getIntersect(viewport, e.onlyGetIntersect, e.pickWindowSize, dontIntersectPointcloud, e.whichPointcloud); //数据集多的时候卡顿
  56663. //console.log('intersectPoint', intersectPoint)
  56664. }
  56665. if(e.onlyGetIntersect){
  56666. if(Potree.settings.intersectOnObjs){
  56667. let hoveredElements = this.getHoveredElements(); //应该不用发送mouseover事件吧
  56668. let intersect = this.getWholeIntersect(hoveredElements, intersectPoint);
  56669. return intersect
  56670. }
  56671. return intersectPoint
  56672. }
  56673. e.preventDefault();
  56674. /* if(intersectPoint && intersectPoint.pointcloud){
  56675. console.log(intersectPoint.pointcloud.name)
  56676. } */
  56677. if (this.drag) {//有拖拽(不一定拖拽了物体, 也不一定按下了鼠标)
  56678. this.drag.mouse = isTouch ? 1 : e.buttons;
  56679. //add:
  56680. //this.drag.pointer = this.pointer.clone();
  56681. //this.drag.hoverViewport = this.hoverViewport
  56682. this.drag.pointerDelta.subVectors(this.pointer, this.drag.end);
  56683. this.drag.end.copy(this.pointer);
  56684. if (this.drag.object && (e.buttons == Buttons.NONE || !this.drag.notPressMouse )){//如果是本不需要按鼠标的拖拽,但按下了鼠标,就不执行这段(改为拖拽场景,如添加测量时突然拖拽画面)
  56685. if (this.logMessages) console.log(this.constructor.name + ': drag: ' + this.drag.object.name);
  56686. this.drag.object.dispatchEvent($.extend(
  56687. this.getEventDesc(e,isTouch),
  56688. {
  56689. type: 'drag', //拖拽物体
  56690. }
  56691. ));
  56692. } else {
  56693. if (this.logMessages) console.log(this.constructor.name + ': drag: ');
  56694. let dragConsumed = false;
  56695. this.viewer.dispatchEvent($.extend(
  56696. this.getEventDesc(e,isTouch),
  56697. {
  56698. type: 'global_drag', //拖拽画面
  56699. consume: () => {dragConsumed = true;}
  56700. }
  56701. ));
  56702. }
  56703. }
  56704. if(!isTouch || e.touches.length == 1){
  56705. if((!this.drag || this.drag.notPressMouse || Potree.settings.intersectOnObjs && this.drag.object) && !isFlying){
  56706. /* let blacklist = this.drag && this.drag */
  56707. let hoveredElements = this.getHoveredElements( );
  56708. if(hoveredElements.length > 0){
  56709. let names = hoveredElements.map(h => h.object.name).join(", ");
  56710. if (this.logMessages) console.log(`${this.constructor.name}: onMouseMove; hovered: '${names}'`);
  56711. }
  56712. let curr = hoveredElements.map(a => a.object).find(a => true);//只取第一个
  56713. let prev = this.lastMouseoverElement; //this.hoveredElements.map(a => a.object).find(a => true);
  56714. if(curr !== prev){
  56715. if(curr){
  56716. if (this.logMessages) console.log(`${this.constructor.name}: mouseover: ${curr.name}`);
  56717. curr.dispatchEvent({
  56718. type: 'mouseover',
  56719. object: curr,
  56720. });
  56721. }
  56722. if(prev){
  56723. if (this.logMessages) console.log(`${this.constructor.name}: mouseleave: ${prev.name}`);
  56724. prev.dispatchEvent({
  56725. type: 'mouseleave',
  56726. object: prev,
  56727. });
  56728. }
  56729. this.lastMouseoverElement = curr;
  56730. }
  56731. if(hoveredElements.length > 0){
  56732. let object = hoveredElements
  56733. .map(e => e.object)
  56734. .find(e => (e._listeners && e._listeners['mousemove']));
  56735. if(object){
  56736. object.dispatchEvent({
  56737. type: 'mousemove',
  56738. object: object
  56739. });
  56740. }
  56741. }
  56742. this.hoveredElements = hoveredElements;
  56743. }
  56744. this.intersect = this.getWholeIntersect();
  56745. this.viewer.dispatchEvent($.extend(
  56746. this.getEventDesc(e,isTouch),
  56747. {
  56748. type: 'global_mousemove',
  56749. }
  56750. ));
  56751. }
  56752. }
  56753. onMouseWheel(e){
  56754. if(!this.enabled) return;
  56755. if(this.logMessages) console.log(this.constructor.name + ": onMouseWheel");
  56756. e.preventDefault();
  56757. let delta = 0;
  56758. if (e.wheelDelta !== undefined) { // WebKit / Opera / Explorer 9
  56759. delta = e.wheelDelta;
  56760. } else if (e.detail !== undefined) { // Firefox
  56761. delta = -e.detail;
  56762. }
  56763. let ndelta = Math.sign(delta);
  56764. // this.wheelDelta += Math.sign(delta);
  56765. if(!this.hoverViewport){//调试手机版时会无
  56766. var { viewport } = this.getPointerInViewport(e.clientX, e.clientY );
  56767. this.hoverViewport = viewport;
  56768. }
  56769. if (this.hoveredElement) {
  56770. this.hoveredElement.object.dispatchEvent($.extend(
  56771. this.getEventDesc(e,isTouch),
  56772. {
  56773. type: 'mousewheel',
  56774. delta: ndelta,
  56775. object: this.hoveredElement.object
  56776. }
  56777. ));
  56778. } else {
  56779. this.viewer.dispatchEvent($.extend(
  56780. this.getEventDesc(e),
  56781. {
  56782. type: 'global_mousewheel',
  56783. delta: ndelta,
  56784. }
  56785. ));
  56786. }
  56787. }
  56788. startDragging (object, args = null) {
  56789. let name = object ? object.name : "no name";
  56790. if (this.logMessages) console.log(`${this.constructor.name}: startDragging: '${name}'`);
  56791. this.drag = {
  56792. start: this.pointer.clone(),
  56793. end: this.pointer.clone(),
  56794. pointerDelta: new Vector2$1(0, 0),
  56795. object: object,
  56796. hoverViewport: this.hoverViewport, //会变化
  56797. dragViewport: this.hoverViewport, //不变
  56798. };
  56799. if (args) {
  56800. for (let key of Object.keys(args)) {
  56801. this.drag[key] = args[key];
  56802. }
  56803. }
  56804. if(object){
  56805. object.dispatchEvent($.extend(
  56806. this.getEventDesc(),
  56807. {
  56808. type: 'startDragging'
  56809. }
  56810. ));
  56811. }
  56812. }
  56813. /* getMousePointCloudIntersection (mouse) {
  56814. return Utils.getMousePointCloudIntersection(
  56815. this.mouse,
  56816. this.scene.getActiveCamera(),
  56817. this.viewer,
  56818. this.scene.pointclouds);
  56819. } */
  56820. toggleSelection (object) {
  56821. let oldSelection = this.selection;
  56822. let index = this.selection.indexOf(object);
  56823. if (index === -1) {
  56824. this.selection.push(object);
  56825. object.dispatchEvent({
  56826. type: 'select'
  56827. });
  56828. } else {
  56829. this.selection.splice(index, 1);
  56830. object.dispatchEvent({
  56831. type: 'deselect'
  56832. });
  56833. }
  56834. this.dispatchEvent({
  56835. type: 'selection_changed',
  56836. oldSelection: oldSelection,
  56837. selection: this.selection
  56838. });
  56839. }
  56840. deselect(object){
  56841. let oldSelection = this.selection;
  56842. let index = this.selection.indexOf(object);
  56843. if(index >= 0){
  56844. this.selection.splice(index, 1);
  56845. object.dispatchEvent({
  56846. type: 'deselect'
  56847. });
  56848. this.dispatchEvent({
  56849. type: 'selection_changed',
  56850. oldSelection: oldSelection,
  56851. selection: this.selection
  56852. });
  56853. }
  56854. }
  56855. deselectAll () {
  56856. for (let object of this.selection) {
  56857. object.dispatchEvent({
  56858. type: 'deselect'
  56859. });
  56860. }
  56861. let oldSelection = this.selection;
  56862. if (this.selection.length > 0) {
  56863. this.selection = [];
  56864. this.dispatchEvent({
  56865. type: 'selection_changed',
  56866. oldSelection: oldSelection,
  56867. selection: this.selection
  56868. });
  56869. }
  56870. }
  56871. isSelected (object) {
  56872. let index = this.selection.indexOf(object);
  56873. return index !== -1;
  56874. }
  56875. registerInteractiveObject(object){
  56876. this.interactiveObjects.add(object);
  56877. }
  56878. removeInteractiveObject(object){
  56879. this.interactiveObjects.delete(object);
  56880. }
  56881. registerInteractiveScene (scene) {
  56882. let index = this.interactiveScenes.indexOf(scene);
  56883. if (index === -1) {
  56884. this.interactiveScenes.push(scene);
  56885. }
  56886. }
  56887. unregisterInteractiveScene (scene) {
  56888. let index = this.interactiveScenes.indexOf(scene);
  56889. if (index > -1) {
  56890. this.interactiveScenes.splice(index, 1);
  56891. }
  56892. }
  56893. getHoveredElement () {
  56894. let hoveredElements = this.getHoveredElements();
  56895. if (hoveredElements.length > 0) {
  56896. return hoveredElements[0];
  56897. } else {
  56898. return null;
  56899. }
  56900. }
  56901. getHoveredElements () {
  56902. let scenes = this.hoverViewport.interactiveScenes || this.interactiveScenes.concat(this.scene);
  56903. let interactableListeners = ['mouseup', 'mousemove', 'mouseover', 'mouseleave', 'drag', 'drop', 'click', 'select', 'deselect'];
  56904. let interactables = [];
  56905. for (let scene of scenes) {
  56906. scene.traverseVisible(node => {//检测加了侦听的object
  56907. if (node._listeners && node.visible && (Potree.settings.intersectOnObjs || !this.blacklist.has(node))) {
  56908. let hasInteractableListener = interactableListeners.filter((e) => {
  56909. return node._listeners[e] !== undefined;
  56910. }).length > 0;
  56911. if (hasInteractableListener) {
  56912. interactables.push(node);
  56913. }
  56914. }
  56915. });
  56916. }
  56917. let camera = this.hoverViewport.camera;
  56918. let ray = Utils.mouseToRay(this.pointer, camera );
  56919. let raycaster = new Raycaster();
  56920. raycaster.ray.set(ray.origin, ray.direction);
  56921. raycaster.camera = camera; //add
  56922. if(camera.type == "OrthographicCamera"){//使无论多远,threshold区域都是一样宽的
  56923. raycaster.params.Line.threshold = 20/camera.zoom;
  56924. }else {
  56925. raycaster.params.Line.threshold = 0.2;
  56926. }
  56927. raycaster.params.Line2 = {threshold :20 }; //拓宽的lineWidth
  56928. //raycaster.layers.enableAll()//add
  56929. viewer.setCameraLayers(raycaster, //设置能识别到的layers(如空间模型里只有mapViewer能识别到marker)
  56930. ['sceneObjects','mapObjects','measure', 'transformationTool'],
  56931. this.hoverViewport && this.hoverViewport.extraEnableLayers
  56932. );
  56933. viewer.dispatchEvent( {type:'raycaster', viewport: this.hoverViewport});//add
  56934. let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true); //原本是false 检测不到children
  56935. if(this.intersectPoint && this.intersectPoint.distance != void 0){//add
  56936. intersections = intersections.filter(e=>{
  56937. let material = e.object.material;
  56938. return (material.depthTest == false || material.depthWrite == false) && !material.useDepth //!material.depthTestWhenPick
  56939. || ( material instanceof DepthBasicMaterial ? e.distance < this.intersectPoint.distance + material.uniforms.occlusionDistance.value : e.distance < this.intersectPoint.distance )
  56940. });
  56941. }
  56942. intersections = intersections.map(e=>{//add 转化为interactables
  56943. var object = e.object;
  56944. do{
  56945. if(interactables.includes(object)) {
  56946. e.oriObject = e.object;
  56947. e.object = object;
  56948. break
  56949. }
  56950. object = object.parent;
  56951. }while(object)
  56952. return e
  56953. });
  56954. //add for测量线,在检测到sphere时优先选中sphere而非线
  56955. intersections = intersections.sort(function(a,b){return b.object.renderOrder-a.object.renderOrder}); // 降序
  56956. //console.log('getHoveredElement ', intersections)
  56957. return intersections;
  56958. }
  56959. /* setScene (scene) {
  56960. this.deselectAll();
  56961. this.scene = scene;
  56962. } */
  56963. update (delta) {
  56964. }
  56965. /*getNormalizedDrag () {
  56966. if (!this.drag) {
  56967. return new THREE.Vector2(0, 0);
  56968. }
  56969. let diff = new THREE.Vector2().subVectors(this.drag.end, this.drag.start);
  56970. diff.x = diff.x / this.domElement.clientWidth;
  56971. diff.y = diff.y / this.domElement.clientHeight;
  56972. return diff;
  56973. }
  56974. getNormalizedLastDrag () {
  56975. if (!this.drag) {
  56976. return new THREE.Vector2(0, 0);
  56977. }
  56978. let mouseDelta = this.drag.mouseDelta.clone();
  56979. mouseDelta.x = mouseDelta.x / this.domElement.clientWidth;
  56980. mouseDelta.y = mouseDelta.y / this.domElement.clientHeight;
  56981. return mouseDelta;
  56982. } */
  56983. getMouseDirection(pointer) {//add
  56984. pointer = pointer || this.pointer;
  56985. let camera = this.hoverViewport.camera;
  56986. var t = new Vector3(pointer.x, pointer.y, -1).unproject(camera),
  56987. i = new Vector3(pointer.x, pointer.y, 1).unproject(camera);
  56988. return {origin: t, direction:i.clone().sub(t).normalize() }
  56989. }
  56990. }
  56991. class ViewerBase extends EventDispatcher{
  56992. constructor(domElement, args = {}){
  56993. super();
  56994. this.name = args.name;
  56995. this.renderArea = domElement;
  56996. this.oldResolution = new Vector2$1();
  56997. this.screenSizeInfo = {
  56998. W:0, H:0, pixelRatio:1 , windowWidth:0, windowHeight:0
  56999. };
  57000. this.initContext(args);
  57001. this.addEventListener('content_changed', ()=>{//画面改变,需要渲染
  57002. this.needRender = true;
  57003. });
  57004. }
  57005. initContext(args){
  57006. //console.log(`initializing three.js ${THREE.REVISION}`);
  57007. let width = this.renderArea.clientWidth;
  57008. let height = this.renderArea.clientHeight;
  57009. let contextAttributes = {
  57010. alpha: true,
  57011. depth: true,
  57012. stencil: false,
  57013. antialias: true,
  57014. preserveDrawingBuffer: true,
  57015. powerPreference: "high-performance",
  57016. };
  57017. let canvas = document.createElement("canvas");
  57018. let context = canvas.getContext('webgl', contextAttributes );
  57019. this.renderer = new WebGLRenderer({
  57020. alpha: true, //支持透明
  57021. premultipliedAlpha: false,
  57022. canvas: canvas,
  57023. context: context,
  57024. });
  57025. this.renderer.sortObjects = true; //原先false 打开了renderOrder才奏效
  57026. //this.renderer.setSize(width, height);
  57027. this.renderer.autoClear = args.autoClear || false;
  57028. //args.clearColor = args.clearColor || '#aa0033'
  57029. args.clearColor && this.renderer.setClearColor(args.clearColor);
  57030. this.renderArea.appendChild(this.renderer.domElement);
  57031. this.renderer.domElement.tabIndex = '2222';
  57032. this.renderer.domElement.style.position = 'absolute';
  57033. this.renderer.domElement.addEventListener('mousedown', () => {
  57034. this.renderer.domElement.focus();
  57035. });
  57036. //this.renderer.domElement.focus();
  57037. // NOTE: If extension errors occur, pass the string into this.renderer.extensions.get(x) before enabling
  57038. // enable frag_depth extension for the interpolation shader, if available
  57039. let gl = this.renderer.getContext();
  57040. gl.getExtension('EXT_frag_depth');
  57041. gl.getExtension('WEBGL_depth_texture');
  57042. gl.getExtension('WEBGL_color_buffer_float'); // Enable explicitly for more portability, EXT_color_buffer_float is the proper name in WebGL 2
  57043. if(gl.createVertexArray == null){
  57044. let extVAO = gl.getExtension('OES_vertex_array_object');
  57045. if(!extVAO){
  57046. throw new Error("OES_vertex_array_object extension not supported");
  57047. }
  57048. gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
  57049. gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
  57050. }
  57051. /* let oldClear = gl.clear;
  57052. gl.clear = (bits)=>{
  57053. console.error('clear')
  57054. }
  57055. */
  57056. }
  57057. updateScreenSize(o={}) { //有可能需要让viewport来判断,当窗口大小不变但viewport大小变时
  57058. var render = false, ratio, w, h;
  57059. //记录应当render的大小
  57060. if (o.width != void 0 && o.height != void 0) {
  57061. w = o.width;
  57062. h = o.height;
  57063. render = true;
  57064. ratio = 1;
  57065. }else {
  57066. w = this.renderArea.clientWidth;
  57067. h = this.renderArea.clientHeight;
  57068. if(w !== this.screenSizeInfo.W || h !== this.screenSizeInfo.H || o.forceUpdateSize || this.screenSizeInfo.pixelRatio != window.devicePixelRatio){
  57069. this.screenSizeInfo.W = w;
  57070. this.screenSizeInfo.H = h;
  57071. render = true;
  57072. this.screenSizeInfo.pixelRatio = window.devicePixelRatio; //如果player放在小窗口了,也要监测devicePixelRatio,因为缩放时client宽高不会改变
  57073. //config.isMobile ? (ratio = Math.min(window.devicePixelRatio, 2)) : (ratio = window.devicePixelRatio)
  57074. ratio = window.devicePixelRatio;
  57075. }
  57076. }
  57077. if (render) {
  57078. this.setSize(w, h, ratio);
  57079. }
  57080. }
  57081. /* updateScreenSize(o={}) { //容易出错。。
  57082. var render = false, ratio, w, h;
  57083. //记录应当render的大小
  57084. if (o.width != void 0 && o.height != void 0) {
  57085. w = o.width
  57086. h = o.height
  57087. render = true
  57088. ratio = 1
  57089. }else {
  57090. w = this.renderArea.clientWidth;
  57091. h = this.renderArea.clientHeight
  57092. let refreshWin = ()=>{
  57093. this.screenSizeInfo.windowWidth = window.innerWidth
  57094. this.screenSizeInfo.windowHeight = window.innerHeight
  57095. }
  57096. let prepareToRender = ()=>{
  57097. w = this.renderArea.clientWidth;
  57098. h = this.renderArea.clientHeight
  57099. this.screenSizeInfo.W = w
  57100. this.screenSizeInfo.H = h
  57101. refreshWin() //render后才refreshWin
  57102. render = true
  57103. this.screenSizeInfo.pixelRatio = window.devicePixelRatio //如果player放在小窗口了,也要监测devicePixelRatio,因为缩放时client宽高不会改变
  57104. //config.isMobile ? (ratio = Math.min(window.devicePixelRatio, 2)) : (ratio = window.devicePixelRatio)
  57105. ratio = window.devicePixelRatio
  57106. //console.log('setSize11', w)
  57107. o.forceUpdateSize = false ;//防止再次render
  57108. }
  57109. let ifNeedUpdate = ()=>{
  57110. w = this.renderArea.clientWidth;
  57111. h = this.renderArea.clientHeight
  57112. return o.forceUpdateSize || w !== this.screenSizeInfo.W || h !== this.screenSizeInfo.H || this.screenSizeInfo.pixelRatio != window.devicePixelRatio
  57113. }
  57114. if(ifNeedUpdate()){
  57115. //当只有一个有效viewport时,且因为改变整个窗口大小而触发的话,延时
  57116. let canInterval = !o.forceUpdateSize && this.viewports.filter(e=>e.active).length==1 && (this.screenSizeInfo.windowWidth != window.innerWidth || this.screenSizeInfo.windowHeight != window.innerHeight )
  57117. if(canInterval){
  57118. Common.intervalTool.isWaiting('updateScreenSize', ()=>{ //延时update,防止崩溃 , 未到时间就拦截(第一次直接执行)
  57119. if(ifNeedUpdate()){
  57120. prepareToRender()
  57121. return true
  57122. }
  57123. }, 500)
  57124. }else{
  57125. //console.log('soon', window.innerWidth, this.screenSizeInfo.windowWidth)
  57126. prepareToRender()
  57127. }
  57128. }
  57129. }
  57130. if (render) {
  57131. this.setSize(w, h, ratio);
  57132. }
  57133. } */
  57134. setSize(width, height, devicePixelRatio, onlyForTarget){
  57135. //console.log('setSize', width)
  57136. if(!onlyForTarget){//onlyForTarget表示不更改当前renderer,只是为了rendertarget才要改变viewport
  57137. this.renderer.setSize(width, height, null, devicePixelRatio); // resize之后会自动clear(似乎因为setScissor ),所以一定要立刻绘制,所以setSize要在cameraChanged、update之前
  57138. }
  57139. this.composer && this.composer.setSize(width, height);
  57140. if(this.viewports){
  57141. this.viewports.forEach((view,i)=>{
  57142. if(!view.active)return
  57143. var width_ = width * view.width;
  57144. var height_ = height * view.height;
  57145. if(height_ == 0)return //avoid NAN
  57146. view.setResolution(Math.ceil(width_), Math.ceil(height_), width, height ); //本来应该是floor,但是这样奇数时会少一个像素,导致向左移一个像素且宽度少1。现在则多绘制1个像素,超出的1个像素应该不会绘制出来(但不知道其他地方是否有偏差,比如pick时)
  57147. let aspect = width_ / height_; //camera的参数精确些,不用视口的归整的resolution像素值,否则hasChange无法为true, 导致canvasResize了但map没update从而闪烁
  57148. view.camera.aspect = aspect;
  57149. if(view.camera.type == "OrthographicCamera"){
  57150. /* //不改宽度 同4dkk
  57151. var heightHalf = view.camera.right / aspect
  57152. view.camera.top = heightHalf
  57153. view.camera.bottom = -heightHalf */
  57154. //高宽都改 使大小不随视口大小改变 navvis (直接和视口大小一致即可,通过zoom来定大小)
  57155. view.camera.left = -width_/2;
  57156. view.camera.right = width_/2;
  57157. view.camera.bottom = -height_/2;
  57158. view.camera.top = height_/2;
  57159. }else {
  57160. }
  57161. view.camera.updateProjectionMatrix();
  57162. });
  57163. }
  57164. if(!onlyForTarget){//因为onlyForTarget不传递devicePixelRatio所以不发送了
  57165. this.emitResizeMsg({viewport:this.viewports[0], deviceRatio:devicePixelRatio});
  57166. }
  57167. }
  57168. emitResizeMsg(e){//切换viewport渲染时就发送一次, 通知一些材质更新resolution。
  57169. if(!e.viewport.resolution.equals(this.oldResolution)){
  57170. this.dispatchEvent($.extend(e, {type:'resize'}));
  57171. this.oldResolution.copy(e.viewport.resolution);
  57172. }
  57173. }
  57174. cameraChanged() {//判断相机是否改变
  57175. var changed = false;
  57176. /* if(this.needRender){
  57177. this.needRender = false
  57178. return true
  57179. } */
  57180. for(let i=0,j=this.viewports.length;i<j;i++){
  57181. let changeInfo = this.viewports[i].cameraChanged();
  57182. if(changeInfo.changed){
  57183. changed = true;
  57184. //if(!this.changeTime ||this.changeTime<100){
  57185. this.dispatchEvent({
  57186. type: "camera_changed",
  57187. camera: this.viewports[i].camera,
  57188. viewport : this.viewports[i],
  57189. changeInfo
  57190. });
  57191. //this.changeTime = (this.changeTime || 0) +1
  57192. //}
  57193. }
  57194. }
  57195. return changed
  57196. }
  57197. makeScreenshot( size, viewports, compressRatio){//暂时不要指定viewports渲染,但也可以
  57198. let {width, height} = size;
  57199. /* let oldBudget = Potree.pointBudget;
  57200. Potree.pointBudget = Math.max(10 * 1000 * 1000, 2 * oldBudget);
  57201. let result = Potree.updatePointClouds(this.scene.pointclouds, camera, size );
  57202. Potree.pointBudget = oldBudget;
  57203. this.dispatchEvent({ //resize everything such as lines targets
  57204. type: 'resize',
  57205. resolution: new THREE.Vector2(width,height),
  57206. });*/
  57207. let target = new WebGLRenderTarget(width, height, {
  57208. format: RGBAFormat,
  57209. });
  57210. this.setSize(width, height,1,true);
  57211. this.render({
  57212. target ,
  57213. //camera ,
  57214. viewports: viewports || this.viewports,
  57215. screenshot : true,
  57216. width ,
  57217. height,
  57218. resize :true //需要resize
  57219. });
  57220. let dataUrl = Potree.Utils.renderTargetToDataUrl(target, width, height, this.renderer, compressRatio);
  57221. /* let pixelCount = width * height;
  57222. let buffer = new Uint8Array(4 * pixelCount);
  57223. this.renderer.readRenderTargetPixels(target, 0, 0, width, height, buffer);
  57224. let dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio) */
  57225. target.dispose();
  57226. //resize back
  57227. //this.updateScreenSize({forceUpdateSize:true})
  57228. return {
  57229. width,
  57230. height,
  57231. dataUrl
  57232. };
  57233. }
  57234. }
  57235. const prefixVertex ="precision highp float;\nprecision highp int;\n\nuniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\n";
  57236. const prefixFragment ="precision highp float;\nprecision highp int;\n\nuniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n";
  57237. let shader = {
  57238. uniforms: {
  57239. opacity: {
  57240. type: "f",
  57241. value: 1
  57242. },
  57243. progress: {
  57244. type: "f",
  57245. value: 0
  57246. },
  57247. pano0Map: {
  57248. type: "t",
  57249. value: null
  57250. },
  57251. pano1Map: {
  57252. type: "t",
  57253. value: null
  57254. },
  57255. depthMap0: {
  57256. type: "t",
  57257. value: null
  57258. },
  57259. depthMap1: {
  57260. type: "t",
  57261. value: null
  57262. },
  57263. pano0Position: {
  57264. type: "v3",
  57265. value: new Vector3
  57266. },
  57267. pano0Matrix: {
  57268. type: "m4",
  57269. value: new Matrix4
  57270. },
  57271. pano1Position: {
  57272. type: "v3",
  57273. value: new Vector3
  57274. },
  57275. pano1Matrix: {
  57276. type: "m4",
  57277. value: new Matrix4
  57278. },
  57279. /* pano1Matrix2: {
  57280. type: "m4",
  57281. value: new THREE.Matrix4
  57282. },
  57283. */
  57284. inverseProjectionMatrix: {
  57285. value: new Matrix4
  57286. },
  57287. /* projectionMatrix:{//需要再写一遍吗
  57288. value: new THREE.Matrix4
  57289. }, */
  57290. viewport: {
  57291. value: new Vector4
  57292. },
  57293. //如 {x: 0, y: 0, z: 428, w: 969} xy应该是offset, zw是宽高
  57294. cameraHeight0: {
  57295. type: "f",
  57296. value: 1
  57297. },
  57298. cameraHeight1: {
  57299. type: "f",
  57300. value: 1
  57301. },
  57302. },
  57303. vertexShader: prefixVertex + `
  57304. uniform vec3 pano0Position;
  57305. uniform mat4 pano0Matrix;
  57306. uniform vec3 pano1Position;
  57307. uniform mat4 pano1Matrix;
  57308. //uniform mat4 pano1Matrix2;
  57309. varying vec2 vUv;
  57310. varying vec3 vWorldPosition0;
  57311. varying vec3 vWorldPosition1;
  57312. varying vec3 vWorldPosition12;
  57313. vec3 transformAxis( vec3 direction ) //navvis->4dkk
  57314. {
  57315. float y = direction.y;
  57316. direction.y = direction.z;
  57317. direction.z = -y;
  57318. return direction;
  57319. }
  57320. void main() {
  57321. vUv = uv;
  57322. vec4 worldPosition = modelMatrix * vec4(position, 1.0);
  57323. vec3 positionLocalToPanoCenter0 = worldPosition.xyz - pano0Position;
  57324. vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz;
  57325. vWorldPosition0.x *= -1.0;
  57326. vWorldPosition0 = transformAxis(vWorldPosition0);
  57327. vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position;
  57328. vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz;
  57329. vWorldPosition1.x *= -1.0;
  57330. vWorldPosition1 = transformAxis(vWorldPosition1);
  57331. /*
  57332. vec3 positionLocalToPanoCenter12 = worldPosition.xyz - pano1Position;
  57333. vWorldPosition12 = (vec4(positionLocalToPanoCenter12, 1.0) * pano1Matrix2).xyz;
  57334. vWorldPosition12.x *= -1.0;
  57335. vWorldPosition12 = transformAxis(vWorldPosition12);
  57336. */
  57337. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  57338. }
  57339. `,
  57340. fragmentShader: prefixFragment + `
  57341. #define PI 3.141592653
  57342. uniform float modelAlpha;
  57343. uniform float opacity;
  57344. uniform float progress;
  57345. uniform int blackout;
  57346. uniform vec3 pano0Position;
  57347. uniform vec3 pano1Position;
  57348. uniform float maxDistance;
  57349. uniform float minDistance;
  57350. uniform float minOpa;
  57351. uniform float cameraHeight0;
  57352. uniform float cameraHeight1;
  57353. /* uniform sampler2D pano0Map;
  57354. uniform sampler2D pano1Map; */
  57355. uniform samplerCube pano0Map;
  57356. uniform samplerCube pano1Map;
  57357. varying vec2 vUv;
  57358. varying vec3 vWorldPosition0;
  57359. varying vec3 vWorldPosition1;
  57360. //varying vec3 vWorldPosition12;
  57361. /* vec2 getSamplerCoord( vec3 direction )
  57362. {
  57363. direction = normalize(direction);
  57364. float tx=atan(direction.x,-direction.y)/(PI*2.0)+0.5;
  57365. float ty=acos(direction.z)/PI;
  57366. return vec2(tx,ty);
  57367. } */
  57368. vec2 getSamplerCoord2( vec3 direction )
  57369. {
  57370. direction = normalize(direction);
  57371. float tx=atan(direction.x,direction.z)/(PI*2.0)+0.5;
  57372. float ty=acos(direction.y)/PI;
  57373. return vec2(tx,ty);
  57374. }
  57375. #extension GL_EXT_frag_depth : enable
  57376. #if defined(GL_EXT_frag_depth) && defined(hasDepthTex)
  57377. uniform sampler2D depthMap0;
  57378. uniform sampler2D depthMap1;
  57379. uniform mat4 inverseProjectionMatrix;
  57380. uniform mat4 projectionMatrix;
  57381. uniform vec4 viewport;
  57382. vec2 getDepth(vec3 dir, sampler2D depthMap, float height, vec4 eyePos){
  57383. vec2 depthValue = vec2(0.0, 0.0);
  57384. vec2 uv2 = getSamplerCoord2(/* vWorldPosition12 */dir.xyz); //暂时只用基于目标漫游点的方向
  57385. uv2.x -= 0.25; //全景图和Cube的水平采样起始坐标相差90度,这里矫正 0.25 个采样偏移
  57386. vec4 depth = texture2D(depthMap, uv2);
  57387. //float distance = depth.r + 256. * (depth.g + 256. * depth.b);
  57388. //distance *= 255. * .001; // distance is now in meters
  57389. //更改
  57390. float distance = (depth.g + depth.r / 256.) * 255.; //为什么要乘以255
  57391. if(distance == 0.0){//漫游点底部识别不到的区域,给一个地板高度
  57392. if(uv2.y > 0.75)distance = height / dir.y;
  57393. else distance = 100000.0;//给个超级远的值
  57394. }
  57395. depthValue.x = distance;
  57396. // return r[1] + r[0] / 256
  57397. distance += .1; // add a safety margin
  57398. vec4 eyePos2 = vec4(normalize(eyePos.xyz) * distance, 1.);
  57399. vec4 clipPos2 = projectionMatrix * eyePos2;
  57400. vec4 ndcPos2 = clipPos2 * 1. / clipPos2.w;
  57401. depthValue.y = 0.5 * ((gl_DepthRange.far - gl_DepthRange.near) * ndcPos2.z
  57402. + gl_DepthRange.near + gl_DepthRange.far);
  57403. return depthValue;
  57404. }
  57405. //注:未加载好的话,depth为0,导致第一次漫游过去的时候许多mesh会立刻被遮挡,所以要确保加载完
  57406. #endif
  57407. void main()
  57408. {
  57409. /* vec2 samplerCoord0 = getSamplerCoord(vWorldPosition0.xyz);
  57410. vec2 samplerCoord1 = getSamplerCoord(vWorldPosition1.xyz);
  57411. vec4 colorFromPano0=texture2D(pano0Map,samplerCoord0);
  57412. vec4 colorFromPano1=texture2D(pano1Map,samplerCoord1); */
  57413. vec4 colorFromPano0 = vec4(0.0,0.0,0.0,0.0);
  57414. if(progress < 1.0){//通常是1
  57415. colorFromPano0=textureCube(pano0Map,vWorldPosition0.xyz);
  57416. }
  57417. vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1.xyz);
  57418. gl_FragColor=mix(colorFromPano0,colorFromPano1,progress);
  57419. //深度图修改深度
  57420. #if defined(GL_EXT_frag_depth) && defined(hasDepthTex)
  57421. vec4 ndcPos;
  57422. ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1.;
  57423. ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
  57424. (gl_DepthRange.far - gl_DepthRange.near);
  57425. ndcPos.w = 1.0;
  57426. vec4 clipPos = ndcPos / gl_FragCoord.w;
  57427. vec4 eyePos = inverseProjectionMatrix * clipPos;
  57428. vec2 depth0 = vec2(0.0,0.0);
  57429. if(progress < 1.0){
  57430. depth0 = getDepth(vWorldPosition0, depthMap0, cameraHeight0, eyePos);
  57431. }
  57432. vec2 depth1 = getDepth(vWorldPosition1, depthMap1, cameraHeight1, eyePos);
  57433. /* if(progress < 1.0 && depth1.x == 0.0 && depth0.x > 0.0){
  57434. gl_FragDepthEXT = depth0.y;
  57435. }else{ */
  57436. gl_FragDepthEXT = mix(depth0.y,depth1.y,progress);
  57437. //}
  57438. #endif
  57439. }
  57440. `
  57441. };
  57442. class ModelTextureMaterial extends RawShaderMaterial {
  57443. constructor( ){
  57444. let defines = {};
  57445. super({
  57446. fragmentShader: shader.fragmentShader,
  57447. vertexShader: shader.vertexShader,
  57448. uniforms: UniformsUtils.clone(shader.uniforms),
  57449. side:DoubleSide,
  57450. name: "ModelTextureMaterial",
  57451. defines
  57452. });
  57453. let setSize = (e)=>{
  57454. let viewport = e.viewport;
  57455. let viewportOffset = viewport.offset || new Vector2();
  57456. let resolution = viewport.resolution2;
  57457. this.uniforms.viewport.value.set(viewportOffset.x, viewportOffset.y, resolution.x, resolution.y);
  57458. };
  57459. let viewport = viewer.mainViewport;
  57460. setSize({viewport});
  57461. viewer.addEventListener('resize',(e)=>{
  57462. setSize(e);
  57463. });
  57464. //var supportExtDepth = !!Features.EXT_DEPTH.isSupported()
  57465. {
  57466. //add
  57467. viewer.addEventListener('camera_changed', (e)=>{
  57468. //this.uniforms.projectionMatrix.value.copy(e.camera.projectionMatrix)
  57469. this.uniforms.inverseProjectionMatrix.value.copy(e.camera.projectionMatrixInverse);
  57470. });
  57471. }
  57472. //-------------------------------------
  57473. }
  57474. /**
  57475. *
  57476. * @param {Panorama} pano0
  57477. * @param {Panorama} pano1
  57478. * @param {boolean} flag
  57479. 更新全景图的材质uniforms
  57480. */
  57481. setProjectedPanos(pano0, pano1, progressValue ){
  57482. progressValue!=void 0 && (this.uniforms.progress.value = progressValue);
  57483. //pano0.ensureSkyboxReadyForRender();
  57484. if(pano0){
  57485. this.uniforms.pano0Map.value = pano0.getSkyboxTexture();//pano0.texture
  57486. this.uniforms.pano0Position.value.copy(pano0.position);
  57487. this.uniforms.pano0Matrix.value.copy(pano0.panoMatrix/* pano0.mesh.matrixWorld */ );
  57488. this.uniforms.cameraHeight0.value = pano0.floorPosition.distanceTo(pano0.position);
  57489. //pano1.ensureSkyboxReadyForRender();
  57490. }
  57491. this.uniforms.pano1Map.value = pano1.getSkyboxTexture();//pano1.texture;
  57492. this.uniforms.pano1Position.value.copy(pano1.position);
  57493. this.uniforms.pano1Matrix.value.copy(pano1.panoMatrix /* pano1.mesh.matrixWorld */ );
  57494. this.uniforms.cameraHeight1.value = pano1.floorPosition.distanceTo(pano1.position);
  57495. this.pano0 = pano0;
  57496. this.pano1 = pano1;
  57497. this.updateDepthTex(pano0);
  57498. this.updateDepthTex(pano1);
  57499. //console.log('setProjectedPanos', pano0&&pano0.id, pano1&&pano1.id)
  57500. this.needsUpdate = true;
  57501. }
  57502. updateDepthTex(pano){
  57503. if( !Potree.settings.useDepthTex || !pano || !pano.depthTex || pano!=this.pano0 && pano!=this.pano1)return
  57504. //console.log('updateDepthTex', pano.id, this.pano0 && this.pano0.id, this.pano1 && this.pano1.id)
  57505. this.uniforms.depthMap0.value = this.pano0 && this.pano0.depthTex;
  57506. this.uniforms.depthMap1.value = this.pano1 && this.pano1.depthTex;
  57507. this.updateDepthTexEnable();
  57508. }
  57509. updateDepthTexEnable(){
  57510. let hasDepthTex = this.pano0 && this.pano1 && this.pano0.pointcloud.hasDepthTex && this.pano1.pointcloud.hasDepthTex; //暂时不知道一个有图一个没图怎么写所以
  57511. Common.addOrRemoveDefine(this, 'hasDepthTex', hasDepthTex?'add':'remove' );
  57512. }
  57513. /* EnableDepthTex(){//开启DepthTex
  57514. if(this.defines['hasDepthTex']){
  57515. return
  57516. }
  57517. this.defines['hasDepthTex'] = ''
  57518. this.needsUpdate = true;
  57519. } */
  57520. }
  57521. var TileUtils = {};
  57522. TileUtils.TILE_SIZE = 512,
  57523. TileUtils.FACES_PER_PANO = 6,
  57524. TileUtils.LocationOnTile = {
  57525. Center: 0,
  57526. UpperLeft: 1,
  57527. UpperRight: 2,
  57528. LowerRight: 3,
  57529. LowerLeft: 4
  57530. },
  57531. /*
  57532. * 获取某tile在cube中的方向 direction (向量起点在cube中心,终点在tile图的指定位置)。spherical通过先求uv,再直接得到dir
  57533. * @param {*} size 面分辨率
  57534. * @param {*} cubeFace 所在面
  57535. * @param {*} Center 在tile上的目标位置,默认为中心,其他位置就是四个顶点
  57536. * @param {*} c 似乎是在tile的缩进百分比,根据所在面的不同,分别向不同方向缩进,但都是向tile的中心
  57537. * @param {*} dir 所求方向
  57538. */
  57539. TileUtils.getTileVector = function() {//获取某tile在cube中的方向 direction (向量起点在cube中心,终点在tile图的中心)
  57540. return function(size, tileSize, cubeFace, tileX, tileY, Center, c, dir) {//c似乎是缩进百分比
  57541. Center = Center || TileUtils.LocationOnTile.Center;
  57542. //假设该cube边长为2:
  57543. var u = size / tileSize
  57544. , d = tileX / u;
  57545. tileY = -tileY + (u - 1);
  57546. var p = tileY / u
  57547. , f = tileSize / size
  57548. , g = 2 * f //一个tile的宽度 (乘以2是因为cube边长是2)
  57549. , m = g / 2
  57550. , v = 2 * d - 1 + m
  57551. , A = 2 * p - 1 + m;
  57552. switch (Center) {//计算在tile中指定位置带来的偏移
  57553. case TileUtils.LocationOnTile.UpperLeft: //1
  57554. v -= m,
  57555. A += m,
  57556. v += c * g; //似乎是向内缩进
  57557. break;
  57558. case TileUtils.LocationOnTile.UpperRight:
  57559. v += m,
  57560. A += m,
  57561. A -= c * g;
  57562. break;
  57563. case TileUtils.LocationOnTile.LowerRight:
  57564. v += m,
  57565. A -= m,
  57566. v -= c * g;
  57567. break;
  57568. case TileUtils.LocationOnTile.LowerLeft:
  57569. v -= m,
  57570. A -= m,
  57571. A += c * g;
  57572. break;
  57573. case TileUtils.LocationOnTile.Center: //0
  57574. }
  57575. switch (cubeFace) {
  57576. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  57577. MathLight.setVector(dir, -1, A, -v);
  57578. break;
  57579. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  57580. MathLight.setVector(dir, 1, A, v);
  57581. break;
  57582. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Y: //顶面
  57583. MathLight.setVector(dir, -v, 1, -A);
  57584. break;
  57585. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  57586. MathLight.setVector(dir, -v, -1, A);
  57587. break;
  57588. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  57589. MathLight.setVector(dir, -v, A, 1);
  57590. break;
  57591. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  57592. MathLight.setVector(dir, v, A, -1);
  57593. }
  57594. MathLight.normalize(dir);
  57595. }
  57596. }(),
  57597. /*
  57598. * 获取该tile在第几个面(简易装载法)
  57599. */
  57600. TileUtils.getFaceForTile = function(size, index) {//获取该tile在第几个面
  57601. var tileSize = TileUtils.TILE_SIZE;
  57602. size < TileUtils.TILE_SIZE && (tileSize = size);
  57603. var n = Math.floor(size / tileSize)
  57604. , sum = n * n; //得每个面tile总数
  57605. return Math.floor(index / sum)
  57606. }
  57607. ,
  57608. TileUtils.getTileLocation = function(size, t, result) {
  57609. var tileSize = TileUtils.TILE_SIZE;
  57610. size < TileUtils.TILE_SIZE && (tileSize = size);
  57611. var r = TileUtils.getFaceForTile(size, t)
  57612. , a = Math.floor(size / tileSize)
  57613. , s = a * a
  57614. , l = t - r * s;
  57615. result.tileX = l % a;
  57616. result.tileY = Math.floor(l / a);
  57617. result.face = r;
  57618. result.faceTileIndex = l;
  57619. return result
  57620. }
  57621. ,
  57622. /*
  57623. * 求size分辨率需要多少张tile
  57624. */
  57625. TileUtils.getTileCountForSize = function(e) {
  57626. if (e <= TileUtils.TILE_SIZE)
  57627. return TileUtils.FACES_PER_PANO;
  57628. var t = Math.floor(e / TileUtils.TILE_SIZE)
  57629. , i = t * t
  57630. , n = i * TileUtils.FACES_PER_PANO;
  57631. return n
  57632. }
  57633. ,
  57634. TileUtils.getRelativeDirection = function() {
  57635. var e = new MathLight.Matrix4
  57636. , t = new MathLight.Quaternion;
  57637. return function(i, n) {//i是pano.quaternion, n是camera的direction
  57638. t.copy(i),
  57639. t.inverse(),
  57640. e.makeRotationFromQuaternion(t),
  57641. e.applyToVector3(n),
  57642. MathLight.normalize(n);
  57643. }
  57644. }(),
  57645. /*
  57646. * 根据方向寻找合适的tile加载
  57647. */
  57648. TileUtils.matchingTilesInDirection = function() {
  57649. var e = new MathLight.Vector3
  57650. , t = new MathLight.Vector3(0,0,-1)
  57651. , i = new MathLight.Quaternion
  57652. , n = function(e, t) {
  57653. e.push({
  57654. face: t.face,
  57655. faceTileIndex: t.faceTileIndex,
  57656. tileX: t.tileX,
  57657. tileY: t.tileY
  57658. });
  57659. }
  57660. , a = function() {
  57661. var e = {
  57662. face: -1,
  57663. faceTileIndex: -1,
  57664. tileX: -1,
  57665. tileY: -1
  57666. };
  57667. return function(size, i, r) {
  57668. for (var a = TileUtils.getTileCountForSize(size), s = 0, l = 0; l < a; l++)
  57669. TileUtils.getTileLocation(size, l, e),
  57670. i && !i(e) || (s++,
  57671. r && n(r, e));
  57672. return s
  57673. }
  57674. }();
  57675. return function(pano, size, dir, hFov, vFov, result) {
  57676. var d = size < TileUtils.TILE_SIZE ? size : TileUtils.TILE_SIZE;
  57677. //TileUtils.getTileCountForSize(size);
  57678. if (!hFov && !vFov)
  57679. return a(size, null, result);
  57680. var p = !!vFov;
  57681. vFov = vFov || hFov,
  57682. vFov = Math.max(0, Math.min(vFov, 360)),
  57683. hFov = Math.max(0, Math.min(hFov, 360)),
  57684. MathLight.copyVector(dir, e),
  57685. TileUtils.getRelativeDirection(pano.quaternion4dkk, e);
  57686. if(p){//如果有vFov hFov
  57687. i.setFromUnitVectors(e, t);
  57688. var f = function(e) {
  57689. return TileUtils.isTileWithinFrustum(size, d, e.face, e.tileX, e.tileY, i, hFov, vFov)//在视野中的
  57690. };
  57691. return a(size, f, result)
  57692. }
  57693. var g = function(t) {//如果仅有hFov
  57694. return TileUtils.isTileWithinFOV(size, d, t.face, t.tileX, t.tileY, e, hFov)
  57695. };
  57696. return a(size, g, result)
  57697. }
  57698. }(),
  57699. /*
  57700. * 是否在屏幕范围内
  57701. */
  57702. TileUtils.isTileWithinFrustum = function() {
  57703. var e = new MathLight.Vector3
  57704. , t = 1e-5;
  57705. return function(i, n, a, s, l, c, h, u) {
  57706. for (var d = Math.tan(.5 * u * MathLight.RADIANS_PER_DEGREE), p = -d, f = Math.tan(.5 * h * MathLight.RADIANS_PER_DEGREE), g = -f, m = TileUtils.mapFaceToCubemapFace(a), v = 0, A = 0, y = 0, C = 0, I = 0, E = 0, b = TileUtils.LocationOnTile.Center; b <= TileUtils.LocationOnTile.LowerLeft; b++){
  57707. TileUtils.getTileVector(i, n, m, s, l, b, 0, e),//get e // size, tileSize, cubeFace, tileX, tileY, Center, c, dir
  57708. MathLight.applyQuaternionToVector(c, e);
  57709. if (e.z >= -t)//似乎是在相机背面
  57710. I++;
  57711. else {
  57712. var w = -1 / e.z
  57713. , _ = e.x * w
  57714. , T = e.y * w;
  57715. T > d ? v++ : T < p && A++, //这四种似乎代表在这个画框之外,如在左、在上、在下、在右
  57716. _ > f ? y++ : _ < g && C++,
  57717. E++;
  57718. }
  57719. }
  57720. return A !== E && v !== E && y !== E && C !== E //如果有一项和E相等代表要么是在相机背面要么是tile的四个顶点都画在画布的同一边,所以肯定不在画布上
  57721. }
  57722. }(),
  57723. /*
  57724. * 是否在FOV范围内
  57725. */
  57726. TileUtils.isTileWithinFOV = function() {
  57727. var e = new MathLight.Vector3
  57728. , t = new MathLight.Vector3(0,1,0)
  57729. , i = new MathLight.Vector3(1,0,0);
  57730. return function(panoSize, tileSize, face, tileX, tileY, direction, fov) {//direction是作用了pano.quaternion的camera.direction
  57731. var d = TileUtils.mapFaceToCubemapFace(face);
  57732. MathLight.cross(direction, t, i); //get i 好像没用到
  57733. TileUtils.getTileVector(panoSize, tileSize, d, tileX, tileY, TileUtils.LocationOnTile.Center, 0, e);
  57734. if (TileUtils.isWithinFOV(e, direction, fov, null))//先判断tile中心在不在FOV内
  57735. return !0;
  57736. for (var p = fov / 360, f = Math.floor(1 / p), g = 0, m = 0; m < f; m++) {
  57737. for (var v = TileUtils.LocationOnTile.UpperLeft; v <= TileUtils.LocationOnTile.LowerLeft; v++)
  57738. if (TileUtils.getTileVector(panoSize, tileSize, d, tileX, tileY, v, g, e),
  57739. TileUtils.isWithinFOV(e, direction, fov, null))
  57740. return !0;
  57741. g += p; //可能是考虑到有可能tile比fov覆盖了fov(虽然一般不可能,除非fov特别小),所以将tile分成若干段,取tile中的点再检测下
  57742. }
  57743. return !1
  57744. }
  57745. }(),
  57746. TileUtils.isWithinFOV = function() {
  57747. var e = new MathLight.Vector3
  57748. , t = new MathLight.Vector3;
  57749. return function(dir, cameraDir, fov, a) {
  57750. if (MathLight.copyVector(dir, t),
  57751. a) {
  57752. MathLight.copyVector(a, e),
  57753. MathLight.normalize(e);
  57754. var s = MathLight.dot(e, dir);
  57755. e.x *= s,
  57756. e.y *= s,
  57757. e.z *= s,
  57758. MathLight.subVector(t, e);
  57759. }
  57760. var l = fov / 2 * MathLight.RADIANS_PER_DEGREE
  57761. , c = Math.cos(l)
  57762. , h = MathLight.dot(t, cameraDir);
  57763. return h >= c
  57764. }
  57765. }(),
  57766. TileUtils.mapFaceToCubemapFace = function() {
  57767. var e = {
  57768. 0: GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  57769. 1: GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  57770. 2: GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_X,
  57771. 3: GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
  57772. 4: GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  57773. 5: GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
  57774. };
  57775. return function(t) {
  57776. return e[t]
  57777. }
  57778. }();
  57779. var texLoader$2 = new TextureLoader();
  57780. const labelProp = {
  57781. sizeInfo: {minSize : 200 , maxSize : 250, nearBound : 0.8, farBound : 10},
  57782. backgroundColor:{r: 255, g: 255, b: 255, a: 0.4 },
  57783. textColor:{r: 0, g: 0, b: 0, a: 1 },
  57784. borderRadius: 15,
  57785. renderOrder:10
  57786. };
  57787. let standardMarkerMat;
  57788. let markerTex;
  57789. let getMarerMat = function(){
  57790. if(!markerTex) {
  57791. markerTex = {
  57792. default:texLoader$2.load( Potree.resourcePath+'/textures/marker.png' ),
  57793. ring:texLoader$2.load( Potree.resourcePath+'/textures/marker2.png' )
  57794. };
  57795. markerTex.default.anisotropy = 4; // 各向异性过滤 .防止倾斜模糊
  57796. markerTex.ring.anisotropy = 4;
  57797. //有可能被点云遮住吗。
  57798. }
  57799. return new DepthBasicMaterial({opacity:0.7, side: DoubleSide , map:markerTex.default ,transparent:true,
  57800. clipDistance: 2, occlusionDistance:1, //不能设置太短,因为过渡时深度不准确
  57801. //depthTest: !!Potree.settings.useDepthTex,
  57802. useDepth: !!Potree.settings.useDepthTex
  57803. //改为DepthBasicMaterial是因为原Basic的材质过渡时会先隐藏后出现
  57804. })
  57805. };
  57806. //显示全景图时marker没有被遮挡,如果需要,要换成depthBasicMaterial 或者直接把skybox的深度修改(拿到深度贴图后更如此)
  57807. let planeGeo$1 = new PlaneBufferGeometry(0.2,0.2);
  57808. let sg = new SphereGeometry(0.1, 8, 8);
  57809. let smHovered = new MeshBasicMaterial({/* side: THREE.BackSide, */color: 0xff0000});
  57810. let sm = new MeshBasicMaterial({/* side: THREE.BackSide */});
  57811. var rot90 = new Quaternion().setFromAxisAngle(new Vector3(0,0,1), Math.PI/2 ); //使用的是刚好适合全景图的,给cube贴图需要转90°
  57812. //var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), -Math.PI/2 ); //4dkk->navvis
  57813. //var rot901 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), -Math.PI/2 ); //整张球幕图要旋转下
  57814. //rot90 = new THREE.Quaternion().multiplyQuaternions( rot901, rot90)
  57815. var old = null;
  57816. /*
  57817. 转成四维看看的axis:
  57818. var a = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)) 因为四维的要绕y转90
  57819. 这里的quaternion.multiply(a);
  57820. 先乘再换顺序 w : q.w, x:q.x , y:-q.z, z:q.y
  57821. */
  57822. //暂时直接用4dkkconsole输出的数据
  57823. class Panorama extends EventDispatcher{
  57824. constructor(o, images360){//file, time, longitude, latitude, altitude, course, pitch, roll
  57825. super();
  57826. this.id = o.id; //唯一标识
  57827. this.images360 = images360;
  57828. this.visible = true; //for viewer updateVisible
  57829. this.enabled = true;//是否可以走
  57830. this.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
  57831. //console.log('pano isVisible', this.id, e.visible)
  57832. viewer.updateVisible(this.marker, 'panoVisi', e.visible);
  57833. Potree.settings.showPanoMesh && (this.mesh.visible = e.visible);
  57834. if(e.reason == 'screenshot' || e.visible){
  57835. this.label && (this.label.visible = e.visible);//截图时隐藏下
  57836. }
  57837. viewer.updateVisible(this.label2, 'panoVisi', e.visible);
  57838. });
  57839. /*
  57840. 漫游点可见性:旧
  57841. level reason 类型
  57842. 2(最高)buildingChange(不在此楼层) unvisible
  57843. 1 modeIsShowPanos(漫游模式) visible //不记得为什么加这个了,所以重写
  57844. 0 pointcloudVisi(隐藏了数据集) unvisible
  57845. */
  57846. /*
  57847. 漫游点可见性:新
  57848. level reason 类型
  57849. 2(最高)buildingChange(不在此楼层) unvisible
  57850. 1 ifShowMarker(marker显示开关) unvisible
  57851. 0 pointcloudVisi(隐藏了数据集) unvisible
  57852. */
  57853. if(Potree.settings.editType == 'pano'){//漫游点拼合编辑
  57854. this.uuid = o.uuid; //因为有多个数据集 所以会重复
  57855. this.index = o.index; //下标, 用于visibles
  57856. this.panosData = o;
  57857. //数据中原本的位置朝向
  57858. this.dataPosition = new Vector3().copy(o.pose.translation);
  57859. this.dataQuaternion = new Quaternion().copy(o.pose.rotation);
  57860. this.dataRotation = new Euler().setFromQuaternion(this.dataQuaternion);
  57861. //因为位置朝向随着点云位置改变,所以直接运用到点云上,这里清零
  57862. this.originPosition = new Vector3(); //{x: 0, y: 0, z: 0}
  57863. this.quaternion = new Quaternion(); //{w: 0, x: 0, y: 0, z: 1}
  57864. //this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
  57865. this.visibles = o.visibles;
  57866. this.pointcloud = viewer.scene.pointclouds.find(e=>e.panoUuid == o.uuid);
  57867. this.pointcloud.panos.push(this);
  57868. const height = 1.4; //相机高度
  57869. this.originFloorPosition = this.originPosition.clone();
  57870. this.originFloorPosition.z -= height;
  57871. /* this.originPosition = new THREE.Vector3().copy(o.pose.translation) //{x: 0, y: 0, z: 0}
  57872. this.quaternion = new THREE.Quaternion().copy(o.pose.rotation) //{w: 0, x: 0, y: 0, z: 1}
  57873. //this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
  57874. this.visibles = o.visibles
  57875. this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.uuid)
  57876. this.pointcloud.panos.push(this)
  57877. const height = 1.5; //相机高度
  57878. this.originFloorPosition = this.originPosition.clone()
  57879. this.originFloorPosition.z -= height
  57880. */
  57881. }else {
  57882. this.originPosition = new Vector3().fromArray(o.dataset_location);
  57883. this.originFloorPosition = new Vector3().fromArray(o.dataset_floor_location);
  57884. this.originID = parseInt(o.file_id);//"file_id":"00022"对应是原本的4dkk的id --来自vision.txt
  57885. this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0];
  57886. this.pointcloud.panos.push(this);
  57887. this.sid = this.pointcloud.sceneCode + '|' + this.originID; //不会更改的标记
  57888. //全景图和Cube的水平采样起始坐标相差90度
  57889. /* if(from4dkk){
  57890. var qua = o.dataset_orientation
  57891. var quaternion = new THREE.Quaternion().fromArray(qua)
  57892. quaternion = new THREE.Quaternion().multiplyQuaternions(quaternion, rot901);//整张球幕图要旋转下 因为在4dkk里转过,还原。如果是tiles的不用
  57893. this.quaternion = new THREE.Quaternion(quaternion.x, -quaternion.z, quaternion.y, quaternion.w) //转化坐标
  57894. }else{ */
  57895. var qua = o.dataset_orientation;
  57896. qua = [qua[1], qua[2], qua[3], qua[0]];
  57897. this.quaternion = new Quaternion().fromArray(qua);
  57898. this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion);//4dkk内使用的quaternion
  57899. this.quaternion2 = this.quaternion.clone();
  57900. this.quaternion = new Quaternion().multiplyQuaternions(this.quaternion, rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
  57901. this.rotation4dkk = new Euler().setFromQuaternion(this.quaternion4dkk);
  57902. //}
  57903. //this.quaternion1 = Potree.Utils.QuaternionFactory.fromArray(o.dataset_orientation)
  57904. //同quaternion
  57905. //let xy = this.transform.forward([this.longitude, this.latitude]);
  57906. this.file = `https://4dkk.4dage.com/images/images${Potree.settings.number}/pan/high/${this.id}.jpg`;
  57907. }
  57908. this.rotation = new Euler().setFromQuaternion(this.quaternion);
  57909. this.build();
  57910. this.transformByPointcloud(); //初始化位移
  57911. {//tile
  57912. this.minimumTiledPanoLoaded = !1;
  57913. this.highestPartialTileRenderOpCompleted = 0;
  57914. this.highestFullTileRenderOpCompleted = 0;
  57915. this.shouldRedrawOnBaseLoaded = !1;
  57916. this.resolutionPromise = {};
  57917. this.tiledPanoRenderTarget = null;
  57918. this.zoomed = !1;
  57919. images360.panoRenderer.addEventListener(PanoRendererEvents.TileRenderSuccess, this.onTileRendered.bind(this));
  57920. images360.panoRenderer.addEventListener(PanoRendererEvents.PanoRenderComplete, this.onPanoRendered.bind(this));
  57921. images360.panoRenderer.addEventListener(PanoRendererEvents.TileRenderFailure, this.onTileRenderFail.bind(this));
  57922. images360.panoRenderer.addEventListener(PanoRendererEvents.UploadAttemptedForAllTiles, this.onUploadAttemptedForAllTiles.bind(this));
  57923. }
  57924. this.addEventListener('hoverOn', (e)=>{//from Map
  57925. if(!e.byMainView){
  57926. this.hoverOn(e);
  57927. }
  57928. });
  57929. this.addEventListener('hoverOff', (e)=>{
  57930. if(!e.byMainView){
  57931. this.hoverOff(e);
  57932. }
  57933. });
  57934. }
  57935. setEnable(enable){//是否可以走
  57936. viewer.updateVisible(this, 'isEnabled', enable); //令所有marker不可见
  57937. this.enabled = enable;
  57938. //如果当前在全景模式且在这个点,需要切换显示吗? 目前用不到
  57939. }
  57940. loadDepthImg(){
  57941. if(!this.pointcloud.hasDepthTex || this.depthTex || this.depthTexLoading)return
  57942. this.depthTexLoading = true;
  57943. let src = Potree.settings.number == 'SS-t-7DUfWAUZ3V' ? `${Potree.scriptPath}/data/${Potree.settings.number}/depthMap/${this.originID}.png`
  57944. : `https://laser-oss.4dkankan.com/testdata/${Potree.settings.number}/data/${Potree.settings.number}/depthmap/${this.originID}.png`;
  57945. let texture = texLoader$2.load( src, ()=>{
  57946. this.depthTex = texture;
  57947. this.images360.dispatchEvent({type:'loadedDepthImg', pano:this});
  57948. this.depthTexLoading = false;
  57949. });
  57950. texture.wrapS = RepeatWrapping;
  57951. texture.flipY = false;
  57952. texture.magFilter = LinearFilter;
  57953. texture.minFilter = LinearFilter;
  57954. }
  57955. build(){
  57956. /* let mesh = new THREE.Mesh(sg, sm);
  57957. mesh.scale.set(1, 1, 1);
  57958. mesh.material.transparent = true;
  57959. mesh.material.opacity = 0.75;
  57960. mesh.pano = this;
  57961. mesh.name = 'panoSphere'
  57962. mesh.addEventListener('mouseover',(e)=>{
  57963. mesh.material = smHovered
  57964. })
  57965. mesh.addEventListener('mouseleave',(e)=>{
  57966. mesh.material = sm
  57967. })
  57968. mesh.addEventListener('click',(e)=>{
  57969. this.images360.focusPano(this)
  57970. })
  57971. this.mesh = mesh;
  57972. if(!Potree.settings.showPanoMesh) mesh.visible = false
  57973. this.images360.node.add(mesh)
  57974. */
  57975. { // orientation
  57976. //var {course, pitch, roll} = this;
  57977. //mesh.quaternion.copy(this.quaternion)
  57978. //add
  57979. //var quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion, rot901);//改 为球目全
  57980. //quaternion.premultiply(rot90)
  57981. this.panoMatrix = new Matrix4().makeRotationFromQuaternion(this.quaternion);
  57982. this.oriPanoMatrix = this.panoMatrix.clone();
  57983. if(this.quaternion2)this.oriPanoMatrix2 = new Matrix4().makeRotationFromQuaternion(this.quaternion2);
  57984. //console.log(this.quaternion)
  57985. //this.quaternion = quaternion
  57986. }
  57987. let marker = new Mesh(planeGeo$1, getMarerMat() );
  57988. marker.up.set(0,0,1);
  57989. marker.lookAt(marker.up);
  57990. marker.scale.set(2,2,2);
  57991. this.addEventListener('changeMarkerTex',(e)=>{
  57992. marker.material.map = markerTex[e.name];
  57993. });
  57994. this.marker = marker;
  57995. if(Potree.settings.editType == 'pano'){
  57996. viewer.updateVisible(marker, 'panoEdit', false, 4);
  57997. }
  57998. this.images360.node.add(marker);
  57999. Potree.settings.isTest && this.createTextLabel();
  58000. this.createTextLabel2();
  58001. /* let mouseover = (e)=>{
  58002. if(!e.byMap){
  58003. pano.mapMarker.material = panoMarkerMats.selected
  58004. if(!e.byMainView) pano.dispatchEvent({type: "hoverOn", byMap:true})
  58005. this.needRender = true
  58006. }
  58007. }
  58008. let mouseleave = (e)=>{
  58009. if(!e.byMap){
  58010. pano.mapMarker.material = panoMarkerMats.default
  58011. if(!e.byMainView) pano.dispatchEvent({type: "hoverOff", byMap:true})
  58012. this.needRender = true
  58013. }
  58014. } */
  58015. marker.addEventListener('mouseover', this.hoverOn.bind(this));
  58016. marker.addEventListener('mouseleave', this.hoverOff.bind(this));
  58017. }
  58018. transformByPointcloud(){
  58019. let position = this.originPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);//也可以用datasetPosTransform算
  58020. let floorPosition = this.originFloorPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);
  58021. this.setPosition(position, floorPosition);
  58022. this.panoMatrix = new Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix );
  58023. //this.panoMatrix2 = Potree.Utils.datasetRotTransform({fromDataset:true, pointcloud:this.pointcloud, matrix:this.oriPanoMatrix, getMatrix:true}) //和上一行结果一样
  58024. //quaternion也变下
  58025. if(this.oriPanoMatrix2){
  58026. this.panoMatrix2 = new Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix2 );//供DepthImageSampler使用
  58027. this.panoMatrix2Inverse = this.panoMatrix2.clone().invert();
  58028. }
  58029. this.dispatchEvent('rePos');
  58030. }
  58031. setPosition(position, floorPosition){
  58032. this.position = position;
  58033. this.floorPosition = floorPosition;
  58034. //this.mesh.position.copy(this.position)
  58035. this.marker.position.copy(this.floorPosition);
  58036. this.marker.position.z+=0.04;//会被点云遮住
  58037. if(this.label){
  58038. if(Potree.settings.editType == 'pano'){
  58039. this.label.position.copy(this.position);
  58040. }else {
  58041. this.label.position.copy(this.floorPosition);
  58042. }
  58043. this.label.position.z+=0.14;
  58044. this.label.update();
  58045. }
  58046. if(this.label2){
  58047. if(Potree.settings.editType == 'pano'){
  58048. this.label2.position.copy(this.position);
  58049. }else {
  58050. this.label2.position.copy(this.floorPosition);
  58051. }
  58052. this.label2.position.copy(this.marker.position);
  58053. this.label2.update();
  58054. }
  58055. }
  58056. hoverOn(e={}) {
  58057. //console.log("hoverOn " + this.id )
  58058. transitions.start(lerp.property(this.marker.material, "opacity", 1), 250);
  58059. if(!e.byMap) this.dispatchEvent({type:'hoverOn', byMainView:true});
  58060. if(!e.byImages360) this.images360.dispatchEvent({type:'markerHover', hovered:true, pano:this});
  58061. }
  58062. hoverOff(e={}){
  58063. //console.log("hoverOff " + this.id )
  58064. transitions.start(lerp.property(this.marker.material, "opacity", 0.5), 250);
  58065. if(!e.byMap) this.dispatchEvent({type:'hoverOff', byMainView:true});
  58066. if(!e.byImages360) this.images360.dispatchEvent({type:'markerHover', hovered:false, pano:this});
  58067. }
  58068. setZoomed(zoomed){
  58069. this.zoomed = zoomed;
  58070. Potree.settings.displayMode == 'showPanos' && this.updateSkyboxForZoomLevel(); //放大后换成zoomTarget贴图
  58071. viewer.dispatchEvent({type:'panoSetZoom', zoomed});
  58072. }
  58073. enter(){
  58074. this.setZoomed(!1),
  58075. viewer.dispatchEvent({type:PanoramaEvents.Enter, oldPano:old, newPano:this } );
  58076. old = this;
  58077. //console.log("enter pano "+ this.id)
  58078. }
  58079. exit(){
  58080. /* if(this.tiled)
  58081. { */
  58082. this.clearWaitDeferreds();
  58083. this.minimumTiledPanoLoaded = !1;
  58084. this.tiledPanoRenderTarget = null;
  58085. this.setZoomed(!1);
  58086. this.images360.panoRenderer.deactivateTiledPano(this);
  58087. this.highestPartialTileRenderOpCompleted = 0;
  58088. this.highestFullTileRenderOpCompleted = 0;
  58089. /*}
  58090. else
  58091. {
  58092. this.solidSkybox.dispose();
  58093. this.solidSkybox.loaded = !1;
  58094. this.solidSkybox.version = 0;
  58095. } */
  58096. //console.log("exit pano "+ this.id)
  58097. viewer.dispatchEvent({type:PanoramaEvents.Exit, pano:this});
  58098. }
  58099. updateSkyboxForZoomLevel(){
  58100. if(this.minimumTiledPanoLoaded){
  58101. this.images360.updateProjectedPanos();
  58102. }
  58103. }
  58104. getSkyboxTexture(){
  58105. if(this.minimumTiledPanoLoaded)
  58106. {
  58107. if(this.zoomed && this.images360.qualityManager.maxRenderTargetSize > this.images360.qualityManager.maxNavPanoSize)//change 如果放大后和不放大都是2k就不用这个
  58108. {
  58109. return this.images360.panoRenderer.zoomRenderTarget.texture;
  58110. }
  58111. else
  58112. {
  58113. this.tiledPanoRenderTarget.texture.mapping = UVMapping;//add
  58114. return this.tiledPanoRenderTarget.texture;
  58115. }
  58116. }
  58117. else
  58118. {
  58119. return null;
  58120. }
  58121. }
  58122. isLoaded(e){
  58123. if (e && "string" == typeof e)
  58124. console.error("Wrong panoSize given to Panorama.isLoaded(); a tiled pano uses PanoSizeClass");
  58125. return !!this.minimumTiledPanoLoaded && (!e || this.highestFullTileRenderOpCompleted >= e)//改:原本是:this.highestPartialTileRenderOpCompleted >= e, 希望这代表全部加载完
  58126. }
  58127. getWaitDeferred(size){//获取不同size的tile贴图的promiss
  58128. var t = this.resolutionPromise[this.id];
  58129. t || (t = {}, this.resolutionPromise[this.id] = t);
  58130. var i = t[size];
  58131. return i || (i = {
  58132. deferred: $.Deferred(),
  58133. active: !1
  58134. },
  58135. t[size] = i),
  58136. i
  58137. }
  58138. clearWaitDeferreds(){
  58139. var e = this.resolutionPromise[this.id];
  58140. e || (e = {},
  58141. this.resolutionPromise[this.id] = e);
  58142. for (var t in e)
  58143. if (e.hasOwnProperty(t)) {
  58144. var i = e[t];
  58145. i.active = !1,
  58146. i.deferred = $.Deferred();
  58147. }
  58148. }
  58149. resetWaitDeferred(e){
  58150. var t = this.getWaitDeferred(e);
  58151. t.active = !1;
  58152. t.deferred = $.Deferred();
  58153. }
  58154. onTileRendered(ev){
  58155. ev.id === this.id && this.dispatchEvent({
  58156. type:PanoramaEvents.TileLoaded,
  58157. size:ev.panoSize, index:ev.tileIndex, count:ev.totalTiles
  58158. });
  58159. }
  58160. onPanoRendered(ev) {
  58161. if(ev.id === this.id)
  58162. {
  58163. this.minimumTiledPanoLoaded = !0;
  58164. this.updateSkyboxForZoomLevel();//更新贴图 setProjected
  58165. ev.panoSize > this.highestPartialTileRenderOpCompleted && (this.highestPartialTileRenderOpCompleted = ev.panoSize);//应该是更新最高获取到的Partial size
  58166. ev.updateFullComplete && ev.panoSize > this.highestFullTileRenderOpCompleted && (this.highestFullTileRenderOpCompleted = ev.panoSize); //应该是更新最高获取到的Full size
  58167. //this.dispatchEvent("load", ev.panoSize);
  58168. viewer.ifAllLoaded( this);
  58169. this.dispatchEvent({type:PanoramaEvents.LoadComplete, size:ev.panoSize, count:ev.totalTiles});
  58170. }
  58171. }
  58172. onTileRenderFail(ev) {
  58173. ev.id === this.id && this.dispatchEvent({type:PanoramaEvents.LoadFailed });
  58174. }
  58175. onUploadAttemptedForAllTiles(ev) {
  58176. if (ev.id === this.id) {
  58177. var n = this.images360.qualityManager.getPanoSize(PanoSizeClass.BASE);
  58178. if(ev.panoSize === n && this.shouldRedrawOnBaseLoaded) //shouldRedrawOnBaseLoaded一直是false。在4dkk里只有初始点在quickstart后变为true。
  58179. {
  58180. this.shouldRedrawOnBaseLoaded = !1;
  58181. this.panoRenderer.resetRenderStatus(this.id, !0, !1);
  58182. this.panoRenderer.renderPanoTiles(this.id, null, !0, !0);
  58183. }
  58184. }
  58185. }
  58186. createTextLabel(){
  58187. this.removeTextLabel();
  58188. this.label = new TextSprite(Object.assign({},
  58189. labelProp, {text: this.id }) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
  58190. );
  58191. this.images360.node.add(this.label);
  58192. this.floorPosition && this.label.position.copy(this.floorPosition);
  58193. }
  58194. createTextLabel2(){
  58195. let labelProp2 = {
  58196. //sizeInfo: {minSize : 200 , maxSize : 250, nearBound : 0.8, farBound : 10},
  58197. backgroundColor:{r: 255, g: 255, b: 255, a: 0 },
  58198. textColor:{r:255 , g: 255, b: 255, a: 1 },
  58199. textBorderColor:{r:30 , g:30, b: 30, a: 1 },
  58200. textBorderThick:3,
  58201. dontFixOrient:true,
  58202. renderOrder:10,
  58203. fontsize:30,
  58204. };
  58205. this.label2 = new TextSprite(Object.assign({},
  58206. labelProp2, {text: /* this.originID */ parseInt(this.id)+1 }) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
  58207. );
  58208. this.images360.node.add(this.label2);
  58209. this.floorPosition && this.label2.position.copy(this.floorPosition);
  58210. let s = 0.4;
  58211. this.label2.scale.set(s,s,s);
  58212. viewer.updateVisible(this.label2, 'notDisplay', false);
  58213. }
  58214. removeTextLabel(){
  58215. if(this.label){
  58216. this.label.parent.remove(this.label);
  58217. }
  58218. }
  58219. dispose(){
  58220. let i = viewer.images360.panos.indexOf(this);
  58221. if(i==-1)return
  58222. this.marker.parent.remove(this.marker);
  58223. this.removeTextLabel();
  58224. if(this.depthTex) this.depthTex.dispose();
  58225. viewer.images360.panos.splice(i,1);
  58226. this.dispatchEvent('dispose');
  58227. //删除tile贴图、depthTex等以后再写
  58228. }
  58229. };
  58230. Panorama.prototype.loadTiledPano = function() {
  58231. //var downloads = [] , t = [];
  58232. var downloaded = {} , eventAdded = {}, latestPartialRequest = {}; //每个pano对应一组这些
  58233. return function(size, dirs, fov, o, a, download) {
  58234. var dir = dirs.datasetsLocal.find(e=>e.datasetId == this.pointcloud.dataset_id).direction;
  58235. //var dir = dirs
  58236. null !== o && void 0 !== o || (o = !0),
  58237. null !== a && void 0 !== a || (a = !0);
  58238. var l = this.getWaitDeferred(size)
  58239. , c = l.deferred
  58240. , h = null
  58241. , u = null;
  58242. fov && ("number" == typeof fov ? h = fov : (h = fov.hFov, u = fov.vFov));
  58243. if (!this.isLoaded(size)) {
  58244. //console.log('loadTiledPano', this.id, size, fov)
  58245. if (!l.active) {
  58246. l.active = !0;
  58247. let name = this.id + ":" + size;
  58248. downloaded[name] = downloaded[name] || [];
  58249. /*
  58250. this.downloaded = downloaded
  58251. this.latestPartialRequest = latestPartialRequest
  58252. */
  58253. latestPartialRequest[name] = null;
  58254. if (fov) {
  58255. let tileArr = [];//add
  58256. var d = TileUtils.matchingTilesInDirection(this, size, dir, h, u, tileArr);
  58257. latestPartialRequest[name] = tileArr;
  58258. downloaded[name].forEach((e)=>{
  58259. let item = latestPartialRequest[name].find(a=>e.faceTileIndex == a.faceTileIndex && e.face == a.face);
  58260. if(item){
  58261. item.loaded = true;
  58262. }
  58263. });
  58264. if(!latestPartialRequest[name].some(e=>!e.loaded)){//所需要的全部加载成功
  58265. //let total = TileUtils.getTileCountForSize(size)
  58266. //this.onPanoRendered(this.id, size, total, !0);
  58267. c.resolve(size/* , total */);
  58268. this.resetWaitDeferred(size);
  58269. //console.log('该部分早已经加载好了'+size, this.id)
  58270. latestPartialRequest[name] = null;
  58271. }
  58272. //console.log("Loading partial pano: " + this.id + " with " + d + " tiles")
  58273. }
  58274. if(!eventAdded[this.id]) {
  58275. eventAdded[this.id] = !0;
  58276. this.addEventListener(PanoramaEvents.LoadComplete, function(ev/* e, t */) {//本次任务全部加载完毕
  58277. //console.warn('点位(可能部分)下载完成 ', 'id:'+this.id, 'size:'+ev.size )
  58278. var i = this.getWaitDeferred(ev.size).deferred;//"pending"为还未完成
  58279. i && "pending" === i.state() && this.highestPartialTileRenderOpCompleted >= ev.size && (i.resolve(ev.size, ev.count),
  58280. this.resetWaitDeferred(ev.size));//恢复active为false
  58281. }.bind(this));
  58282. this.addEventListener(PanoramaEvents.LoadFailed, function(ev) {
  58283. var t = this.getWaitDeferred(e).deferred;
  58284. t && "pending" === t.state() && this.highestPartialTileRenderOpCompleted >= ev.t && (t.reject(ev.t),
  58285. this.resetWaitDeferred(ev.t));//恢复active为false
  58286. }.bind(this));
  58287. this.addEventListener(PanoramaEvents.TileLoaded, function(ev/* t, i, n */) {//每张加载完时
  58288. //console.log('tileLoaded', 'id:'+this.id, 'size:'+ev.size, 'tileIndex:'+ev.index )
  58289. let tileIndex = ev.index;
  58290. let total = ev.count;
  58291. let size = ev.size;
  58292. let name = this.id + ":" + size;
  58293. downloaded[name] = downloaded[name] || []; //不是所有的加载都是从loadTiledPano获取的所以会有未定义的情况
  58294. let {faceTileIndex,face} = TileUtils.getTileLocation(size, tileIndex, {});
  58295. downloaded[name].push({faceTileIndex,face});
  58296. var r = this.getWaitDeferred(size).deferred;
  58297. if (r && "pending" === r.state()) {
  58298. r.notify(size, tileIndex, total);
  58299. if(latestPartialRequest[name]){
  58300. let item = latestPartialRequest[name].find(e=>e.faceTileIndex == faceTileIndex && e.face == face);
  58301. item && (item.loaded = true );
  58302. if(!latestPartialRequest[name].some(e=>!e.loaded)){//所需要的局部tiles全部加载成功
  58303. this.onPanoRendered(this.id, size, total, !0); //onPanoRendered还会触发 PanoramaEvents.LoadComplete
  58304. r.resolve(size, total);
  58305. this.resetWaitDeferred(size);
  58306. //console.log('该部分加载好了'+size, this.id)
  58307. latestPartialRequest[name] = null;
  58308. }
  58309. }
  58310. }
  58311. /* var r = this.getWaitDeferred(ev.size).deferred;
  58312. if (r && "pending" === r.state()) {
  58313. r.notify(ev.size, ev.index, ev.count);
  58314. var o = downloads[this.id + ":" + ev.size];
  58315. if(o){//如果有规定下载哪些tile,只需要下载这些tile则LoadComplete
  58316. o.tileCount++
  58317. if(o.tileCount === o.targetTileCount){//达到下载目标数
  58318. this.onPanoRendered(this.id, ev.size, ev.count, !0);
  58319. r.resolve(ev.size, ev.count);
  58320. this.resetWaitDeferred(ev.size)
  58321. }
  58322. }
  58323. } */
  58324. }.bind(this));
  58325. }
  58326. }
  58327. this.images360.tileDownloader.clearForceQueue(),
  58328. this.images360.tileDownloader.forceQueueTilesForPano(this, size, dir, h, u, download);
  58329. this.tiledPanoRenderTarget = this.images360.panoRenderer.activateTiledPano(this, this.images360.qualityManager.getMaxNavPanoSize(), o);
  58330. this.images360.panoRenderer.renderPanoTiles(this.id, dirs, a);
  58331. }else {
  58332. //console.log('早已经全加载好了' +size, this.id)
  58333. c.resolve(size);
  58334. }
  58335. return c.promise()
  58336. }
  58337. }();
  58338. class QualityManager {
  58339. constructor(e, t, i) {
  58340. this.maxNavPanoSize = -1;
  58341. this.maxZoomPanoSize = -1;
  58342. this.devicePixelDensity = e;
  58343. this.deviceScreenSize = t;
  58344. this.clientBandwidth = i;
  58345. this.panoSizeClassMap = {};
  58346. this.useHighResolutionPanos = !0; //是否能够使用2k及以上图
  58347. this.useUltraHighResolutionPanos = !1;
  58348. this.modelHasUltraHighPanos = !1;
  58349. this.qualityManager = this;
  58350. this.maxRenderTargetSize = browser.isMobile() ? 2048 : 4096; //add
  58351. this.init();
  58352. }
  58353. init(e ) {
  58354. //var metadata = store.getters['scene/metadata'] ;//有时候请求不到
  58355. //if(metadata.sceneSource == 11 || metadata.sceneScheme == 12){
  58356. /* if(config.tileClass == '1k'){
  58357. this.useHighResolutionPanos = false //xzw add 只加载1k
  58358. } */
  58359. this.buildPanoSizeClassMap(this.devicePixelDensity, this.deviceScreenSize, this.clientBandwidth);
  58360. this.ultraHighSize = this.getPanoSize(PanoSizeClass.ULTRAHIGH);
  58361. this.highSize = this.getPanoSize(PanoSizeClass.HIGH);
  58362. this.standardSize = this.getPanoSize(PanoSizeClass.STANDARD);
  58363. this.baseSize = this.getPanoSize(PanoSizeClass.BASE);
  58364. config$1.tiling.maxZoomPanoQuality && this.ultraHighSize <= config$1.tiling.maxZoomPanoQuality && (config$1.tiling.allowUltraHighResolution = !0);
  58365. this.highQualityThreshold = browser.valueFromHash("threshold2k", config$1.windowHeightHighQualityThreshold);
  58366. this.updateMaximums();
  58367. //e.on(ModelManagerEvents.ActiveModelChanged, this.onModelChanged.bind(this));
  58368. }
  58369. updateFromModel(e) {
  58370. //this.updateHighResolutionSettings(e)
  58371. this.updateUltraHighResolutionSettings(e);
  58372. }
  58373. /* updateHighResolutionSettings(e) {
  58374. this.useHighResolutionPanos = !0
  58375. this.updateMaximums()
  58376. } */
  58377. updateUltraHighResolutionSettings(e) {
  58378. if (config$1.tiling.allowUltraHighResolution && this.modelHasUltraHighPanos) {
  58379. this.useUltraHighResolutionPanos = !0;
  58380. } else {
  58381. this.useUltraHighResolutionPanos = !1;
  58382. }
  58383. this.updateMaximums();
  58384. }
  58385. enableUltraHighQualityMode() {
  58386. this.modelHasUltraHighPanos = !0;
  58387. this.updateUltraHighResolutionSettings(null);
  58388. }
  58389. ultraHighQualityModeEnabled() {
  58390. return this.modelHasUltraHighPanos
  58391. }
  58392. onModelChanged(e) {
  58393. this.updateFromModel(e.model),
  58394. this.updateMaximums();
  58395. }
  58396. updateMaximums() {
  58397. this.maxNavPanoSize = config$1.tiling.maxNavPanoQuality || this.detectMaxNavPanoSize(),
  58398. this.maxZoomPanoSize = config$1.tiling.maxZoomPanoQuality || this.detectMaxZoomPanoSize(),
  58399. this.maxZoomPanoSize < this.maxNavPanoSize && (this.maxNavPanoSize = this.maxZoomPanoSize);
  58400. }
  58401. buildPanoSizeClassMap() {
  58402. this.panoSizeClassMap[PanoSizeClass.BASE] = 512,
  58403. this.panoSizeClassMap[PanoSizeClass.STANDARD] = 1024,
  58404. this.panoSizeClassMap[PanoSizeClass.HIGH] = 2048,
  58405. this.panoSizeClassMap[PanoSizeClass.ULTRAHIGH] = 4096;
  58406. }
  58407. getPanoSize(e) {
  58408. return this.panoSizeClassMap[e]
  58409. }
  58410. getMaxPossiblePanoSize() {
  58411. return this.getPanoSize(PanoSizeClass.ULTRAHIGH)
  58412. }
  58413. getMaxPanoSize() {
  58414. return this.maxZoomPanoSize
  58415. }
  58416. getMaxNavPanoSize() {
  58417. return this.maxNavPanoSize
  58418. }
  58419. getMaxZoomPanoSize() {
  58420. return this.maxZoomPanoSize
  58421. }
  58422. detectMaxNavPanoSizeClass() {
  58423. //return this.useHighResolutionPanos ? browser.isMobile() ? PanoSizeClass.STANDARD : window.innerHeight < this.highQualityThreshold ? PanoSizeClass.STANDARD : PanoSizeClass.HIGH : PanoSizeClass.STANDARD
  58424. /* if(config.name == 'decor'){
  58425. return PanoSizeClass.STANDARD
  58426. }
  58427. return PanoSizeClass.HIGH */
  58428. switch(Potree.settings.navTileClass){
  58429. case '1k':
  58430. return PanoSizeClass.STANDARD;
  58431. break;
  58432. case '2k':
  58433. default:
  58434. return PanoSizeClass.HIGH;
  58435. }
  58436. }
  58437. detectMaxNavPanoSize() {
  58438. var e = this.detectMaxNavPanoSizeClass();
  58439. return this.getPanoSize(e)
  58440. }
  58441. detectMaxZoomPanoSize() {
  58442. if(this.zoomLevelResolution){
  58443. if(this.zoomLevelResolution == '4k' && this.useUltraHighResolutionPanos){
  58444. return this.getPanoSize(PanoSizeClass.ULTRAHIGH);
  58445. }else if(this.zoomLevelResolution == '1k' || !this.useHighResolutionPanos){
  58446. return this.getPanoSize(PanoSizeClass.STANDARD);
  58447. }else {
  58448. return this.getPanoSize(PanoSizeClass.HIGH);
  58449. }
  58450. }else {
  58451. if (this.useHighResolutionPanos) {
  58452. /* if (browser.isMobile()) {//手机版如果要2k的将这里去掉
  58453. if (settings.tiling.mobileHighQualityOverride) {
  58454. return this.getPanoSize(PanoSizeClass.HIGH);
  58455. } else {
  58456. return this.getPanoSize(PanoSizeClass.STANDARD);
  58457. }
  58458. } else */if (this.useUltraHighResolutionPanos ) {
  58459. return this.getPanoSize(PanoSizeClass.ULTRAHIGH);
  58460. } else {
  58461. return this.getPanoSize(PanoSizeClass.HIGH);
  58462. }
  58463. } else {
  58464. return this.getPanoSize(PanoSizeClass.STANDARD);
  58465. }
  58466. }
  58467. }
  58468. }
  58469. var h = Object.freeze({
  58470. None: 0,
  58471. DirectionalFOV: 1
  58472. });
  58473. var u = function () {
  58474. var e = function e(t, i) {
  58475. var n = e._panoSpaceDir,
  58476. r = e._fovThreshold,
  58477. o = e._fovThresholdNarrow,
  58478. a = Math.max(Math.min(n.dot(t.direction), 1), -1),
  58479. s = Math.max(Math.min(n.dot(i.direction), 1), -1);
  58480. return t._dot = a,
  58481. i._dot = s,
  58482. a >= r && s < r ? -1 : a < r && s >= r ? 1 : a >= o && s < o ? -1 : a < o && s >= o ? 1 : t.panoSize > i.panoSize ? 1 : i.panoSize > t.panoSize ? -1 : -(a - s)
  58483. };
  58484. return e._panoSpaceDir = new Vector3,
  58485. e._fovThreshold = -1,
  58486. e._fovThresholdNarrow = -1,
  58487. e
  58488. }();
  58489. class TilePrioritizer {//优先级处理序列
  58490. constructor(e,t, i, o, a) {
  58491. this.qualityManager = e;
  58492. this.maxNavQuality = this.qualityManager.getMaxNavPanoSize();
  58493. this.maxZoomQuality = this.qualityManager.getMaxZoomPanoSize();
  58494. this.baseSize = t;
  58495. this.standardSize = i;
  58496. this.highSize = o;
  58497. this.ultraHighSize = a;
  58498. this.priorityCriteria = new TilePrioritizer.PriorityCriteria(null, new Vector3(0, 0, 0), new Vector3(0, 0, -1), new Vector3(0, 0, -1));
  58499. }
  58500. updateCriteria(e, t, i, n) {//由player更新
  58501. this.priorityCriteria.pano = e,
  58502. this.priorityCriteria.cameraPosition.copy(t),
  58503. //this.priorityCriteria.cameraDir.copy(i),
  58504. this.priorityCriteria.cameraDirs = i;
  58505. this.priorityCriteria.upcomingPanos = n,
  58506. this.maxNavQuality = this.qualityManager.getMaxNavPanoSize(),
  58507. this.maxZoomQuality = this.qualityManager.getMaxZoomPanoSize();
  58508. }
  58509. canDownloadSize(e) {
  58510. return this.maxNavQuality >= e || this.maxZoomQuality >= e && this.zoomingActive
  58511. }
  58512. /* populateNeighborPanos(e, t, i) {
  58513. i = i || [],
  58514. i.length = 0;
  58515. var n = t.getNeighbours(e);
  58516. for (var r in n)
  58517. if (n.hasOwnProperty(r)) {
  58518. var o = t.get(r);
  58519. if(!o){
  58520. console.log(1)
  58521. }
  58522. i.push(o)
  58523. }
  58524. return i
  58525. } */
  58526. populateScoredPanos(e, t, i, dirs, a) {
  58527. i = i || [],
  58528. i.length = 0;
  58529. var s = [Images360.filters.inPanoDirection(e.position, dirs, TilePrioritizer.DIRECTION_SCORE_STRICTNESS), Images360.filters.not(e)],
  58530. l = [Images360.scoreFunctions.distanceSquared(e), Images360.scoreFunctions.direction(e.position, dirs)],
  58531. c = Common.sortByScore(t, s, l);
  58532. if (c)
  58533. for (var h = 0; h < c.length && h < a; h++) {
  58534. var u = c[h].item;
  58535. i.push(u);
  58536. }
  58537. return i
  58538. }
  58539. queueTilesForPanos(e, t, i, n, r) {
  58540. for (var o = 0, a = 0; a < t.length; a++) {
  58541. var s = t[a],
  58542. l = this.queueTilesForPano(e, i, s, n);
  58543. if (o += l > 0 ? 1 : 0,
  58544. r && o >= r)
  58545. break
  58546. }
  58547. return o
  58548. }
  58549. /* queueTilesInDirectionForPanos(e, t, i, n, r, o, a, s) {//没用到
  58550. for (var l = 0, c = 0; c < i.length; c++) {
  58551. var h = i[c],
  58552. u = this.queueTilesInDirectionForPano(e, t, h, n, o, a);
  58553. if (l += u > 0 ? 1 : 0,
  58554. s && l >= s)
  58555. break
  58556. }
  58557. return l
  58558. }
  58559. */
  58560. canIncludeDescriptor(e) {
  58561. return e.status !== DownloadStatus.Downloading && e.status !== DownloadStatus.Downloaded
  58562. }
  58563. canIncludePano(e, t) {
  58564. return !e.isLoaded(t)
  58565. }
  58566. getFOVDotThreshold(e) {
  58567. return Math.cos(MathUtils.degToRad(e / 2))
  58568. }
  58569. setZoomingActive(e) {
  58570. e !== this.zoomingActive && (this.zoomingActive = e);
  58571. }
  58572. }
  58573. TilePrioritizer.PriorityCriteria = function (e, t, i, n, o) {
  58574. this.pano = e,
  58575. this.cameraPosition = (new Vector3).copy(t),
  58576. //this.cameraDir = (new THREE.Vector3).copy(i),
  58577. this.cameraDirs = [], //
  58578. this.panoSpaceDir = (new Vector3).copy(n),
  58579. this.upcomingPanos = o,
  58580. this.copy = function (e) {
  58581. this.pano = e.pano,
  58582. this.cameraPosition.copy(e.cameraPosition),
  58583. //this.cameraDir.copy(e.cameraDir),
  58584. this.cameraDirs = e.cameraDirs;
  58585. this.panoSpaceDir.copy(e.panoSpaceDir),
  58586. this.upcomingPanos = o;
  58587. },
  58588. this.zoomingActive = !1;
  58589. };
  58590. TilePrioritizer.DIRECTIONAL_FOV = 180;
  58591. TilePrioritizer.DIRECTIONAL_FOV_NARROW = 120;
  58592. TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER = 6;
  58593. TilePrioritizer.MAX_SCORED_PANOS_TOADD = 2;
  58594. TilePrioritizer.MAX_UPCOMING_PANOS_TOADD = 3;
  58595. TilePrioritizer.DIRECTION_SCORE_STRICTNESS = .75;
  58596. TilePrioritizer.appendQueue = function (e, t) {
  58597. if (e && t)
  58598. for (var i = 0; i < t.length; i++){
  58599. e.push(t[i]);
  58600. //console.log(t[i])
  58601. }
  58602. };
  58603. TilePrioritizer.sortPanoTiles = function (descriptors, pano, dir) {
  58604. if(dir.datasetsLocal) dir = dir.datasetsLocal.find(e=>e.datasetId == pano.pointcloud.dataset_id).direction;//add
  58605. u._panoSpaceDir.copy(dir);
  58606. TileUtils.getRelativeDirection(pano.quaternion4dkk, u._panoSpaceDir); //应该是将dir根据quaternion转化下
  58607. u._fovThresholdNarrow = math.getFOVDotThreshold(TilePrioritizer.DIRECTIONAL_FOV_NARROW);
  58608. u._fovThreshold = math.getFOVDotThreshold(TilePrioritizer.DIRECTIONAL_FOV);
  58609. descriptors.sort(u);
  58610. };
  58611. TilePrioritizer.insertSortedPanoTile = function (e, t, pano, dir) {
  58612. if(dir.datasetsLocal) dir = dir.datasetsLocal.find(e=>e.datasetId == pano.pointcloud.dataset_id).direction;//add
  58613. u._panoSpaceDir.copy(dir),
  58614. TileUtils.getRelativeDirection(pano.quaternion4dkk, u._panoSpaceDir),
  58615. u._fovThresholdNarrow = math.getFOVDotThreshold(TilePrioritizer.DIRECTIONAL_FOV_NARROW),
  58616. u._fovThreshold = math.getFOVDotThreshold(TilePrioritizer.DIRECTIONAL_FOV);
  58617. for (var o = -1, a = 0; a < e.length; a++) {
  58618. var s = u(t, e[a]);
  58619. if (s <= 0) {
  58620. o = a;
  58621. break
  58622. }
  58623. }
  58624. if (o === -1)
  58625. e[e.length] = t;
  58626. else {
  58627. for (var h = e.length; h > o; h--)
  58628. e[h] = e[h - 1];
  58629. e[o] = t;
  58630. }
  58631. };
  58632. TilePrioritizer.prototype.filterDepthTex = function (panos ) {//仅下载depthTex
  58633. if(!Potree.settings.useDepthTex || !this.priorityCriteria.pano)return
  58634. let cameraDirLocals = this.priorityCriteria.cameraDirs.vectorForward;
  58635. let t = [];
  58636. //获得视野范围内的邻近点位序列t
  58637. this.populateScoredPanos(this.priorityCriteria.pano, panos, t, cameraDirLocals , TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER);
  58638. t.forEach(p=>p.loadDepthImg());
  58639. };
  58640. TilePrioritizer.prototype.filterAndPrioritize = function () {//挑选出优先加载的 pano和tile (有点复杂,没看很懂)
  58641. var e = [],
  58642. t = [],
  58643. i = [];
  58644. return function (queue, panos, tileDownloader) {
  58645. //this.populateNeighborPanos(this.priorityCriteria.pano, panos, e);
  58646. /* let cameraDirLocals = this.priorityCriteria.cameraDirs.map(e=>{ //add
  58647. var dataset = viewer.scene.pointclouds.find(u=>u.dataset_id == e.datasetId)
  58648. var matrix = new THREE.Matrix4().copy(dataset.rotateMatrix)
  58649. var direction = math.convertVector.YupToZup(e.direction)
  58650. return {
  58651. datasetId:e.datasetId,
  58652. direction: direction.clone().applyMatrix4(matrix)
  58653. }
  58654. }) */
  58655. let cameraDirLocals = this.priorityCriteria.cameraDirs.vectorForward;
  58656. //获得视野范围内的邻近点位序列t
  58657. this.populateScoredPanos(this.priorityCriteria.pano, panos, t, cameraDirLocals , TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER);
  58658. t.forEach(p=>p.loadDepthImg()); //add
  58659. var s = this.baseSize //512
  58660. ,
  58661. l = this.standardSize //1024
  58662. ,
  58663. c = this.highSize //2048
  58664. ,
  58665. h = this.ultraHighSize; //4096
  58666. this.queueTilesForPano(queue, tileDownloader, this.priorityCriteria.pano, s); //把当前pano的512下载了
  58667. if (this.priorityCriteria.upcomingPanos) {// 添加即将走到的点(之前用于导览路线)512 tiles
  58668. this.queueTilesForPanos(queue, this.priorityCriteria.upcomingPanos, tileDownloader, s, TilePrioritizer.MAX_UPCOMING_PANOS_TOADD);
  58669. }
  58670. i.length = 0;
  58671. //把当前pano角度范围内的tile按照分辨率从低到高加入队列
  58672. if (this.canDownloadSize(l)) {//1024如果在限制范围内的话
  58673. this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, l, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV_NARROW);
  58674. }
  58675. TilePrioritizer.sortPanoTiles(i, this.priorityCriteria.pano, this.priorityCriteria.cameraDirs); //排序
  58676. TilePrioritizer.appendQueue(queue, i);
  58677. //添加邻近点t 512的tiles
  58678. this.queueTilesForPanos(queue, t, tileDownloader, s, TilePrioritizer.MAX_SCORED_PANOS_TOADD);
  58679. i.length = 0;
  58680. //NARROW :
  58681. if (this.canDownloadSize(c)) {//2048
  58682. this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, c, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV_NARROW);
  58683. }
  58684. if (this.canDownloadSize(h)) {//4096
  58685. this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, h, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV_NARROW);
  58686. }
  58687. TilePrioritizer.sortPanoTiles(i, this.priorityCriteria.pano, this.priorityCriteria.cameraDirs);//排序
  58688. TilePrioritizer.appendQueue(queue, i);
  58689. i.length = 0;
  58690. if (this.canDownloadSize(l)) {//1024
  58691. this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, l, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV);
  58692. }
  58693. if (this.canDownloadSize(c)) {//2048
  58694. this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, c, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV);
  58695. }
  58696. if (this.canDownloadSize(h)) {//4096
  58697. this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, h, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV);
  58698. }
  58699. TilePrioritizer.sortPanoTiles(i, this.priorityCriteria.pano, this.priorityCriteria.cameraDirs);//排序
  58700. TilePrioritizer.appendQueue(queue, i);
  58701. this.queueTilesForPanos(queue, e, tileDownloader, s); // 如果前面有populateNeighborPanos的话,这步就是加neibour
  58702. }
  58703. }();
  58704. TilePrioritizer.prototype.queueTilesInDirectionForPano = function () {
  58705. var e = {
  58706. filter: h.DirectionalFOV,
  58707. direction: new Vector3,
  58708. fov: 60
  58709. },
  58710. t = new Vector3;
  58711. return function (i, n, pano, o, a, dirs, c) {
  58712. var dir = dirs.datasetsLocal.find(e=>e.datasetId == pano.pointcloud.dataset_id).direction;//add
  58713. //var dir = dirs
  58714. t.copy(dir);
  58715. TileUtils.getRelativeDirection(pano.quaternion4dkk, t);
  58716. e.direction.copy(t);
  58717. e.fov = c;
  58718. return this.filterAndQueueTileDownloadDescriptors(i, n, pano, o, e)
  58719. }
  58720. }();
  58721. TilePrioritizer.prototype.filterAndQueueTileDownloadDescriptors = function () {
  58722. var e = [];
  58723. return function (t, i, n, r, o) {
  58724. var a = i.getTileDownloadDescriptors(n, r);
  58725. e.length = 0,
  58726. this.filterTileDownloadDescriptors(n, a, e, o);
  58727. for (var s = 0, l = 0; l < e.length; l++) {
  58728. var c = e[l];
  58729. if (c) {
  58730. t.push(c);
  58731. s++;
  58732. }
  58733. }
  58734. return s
  58735. }
  58736. }();
  58737. TilePrioritizer.prototype.filterTileDownloadDescriptors = function () {
  58738. new Vector3;
  58739. return function (e, t, i, n) {
  58740. var r, o;
  58741. switch (n.filter) {
  58742. case h.DirectionalFOV:
  58743. for (r = 0; r < t.length; r++)
  58744. o = t[r],
  58745. TileUtils.isTileWithinFOV(o.panoSize, o.tileSize, o.face, o.tileX, o.tileY, n.direction, n.fov) && i.push(o);
  58746. break;
  58747. default:
  58748. for (r = 0; r < t.length; r++)
  58749. o = t[r],
  58750. i.push(o);
  58751. }
  58752. for (r = 0; r < i.length; r++)
  58753. o = i[r],
  58754. this.canIncludeDescriptor(o) || (i[r] = null);
  58755. }
  58756. }();
  58757. TilePrioritizer.prototype.queueTilesForPano = function () {
  58758. var e = {
  58759. filter: h.None
  58760. };
  58761. return function (t, i, n, r) {
  58762. return this.filterAndQueueTileDownloadDescriptors(t, i, n, r, e)
  58763. }
  58764. }();
  58765. /* TilePrioritizer.prototype.queueTilesForPanosInDirection = function () { //没用到
  58766. var e = new THREE.Vector3;
  58767. return function (t, i, n, r, o, a, s, l) {
  58768. for (var h = 0, u = 0; u < n.length; u++) {
  58769. var d = n[u];
  58770. e.copy(d.position),
  58771. e.sub(o),
  58772. e.normalize();
  58773. var p = Math.max(Math.min(a.dot(e), 1), -1),
  58774. f = c.getFOVDotThreshold(s);
  58775. if (p >= f) {
  58776. var g = this.queueTilesInDirectionForPano(t, i, d, r, o, a, s);
  58777. if (h += g > 0 ? 1 : 0,
  58778. l && h >= l)
  58779. break
  58780. }
  58781. }
  58782. return h
  58783. }
  58784. }() */
  58785. //import { i18n } from "@/lang/index"
  58786. // 媒体名称
  58787. /* export const mediaTypes = {
  58788. image: i18n.t("common.photo"),
  58789. video: i18n.t("common.video"),
  58790. audio: i18n.t("common.voice"),
  58791. } */
  58792. // 媒体扩展类型
  58793. const mediaMimes = {
  58794. image: ["jpg", "png", "jpeg", "bmp", "gif"],
  58795. audio: ["mp3", "aac", "ogg", "wav" /* , "m4a" */],
  58796. video: ["mp4", "mov", "quicktime", "webm" /* "rmvb", "wmv" */], //ios:mov
  58797. };
  58798. // 媒体大小显示(MB)
  58799. const mediaMaxSize = {
  58800. image: 10,
  58801. video: 20,
  58802. audio: 5,
  58803. };
  58804. /**
  58805. * 获取媒体扩展类型
  58806. * @param {Stirng} filename 文件名称
  58807. */
  58808. const getMime = filename => {
  58809. if (!filename || filename.indexOf(".") === -1) {
  58810. return ""
  58811. }
  58812. return filename
  58813. .split(".")
  58814. .pop()
  58815. .toLowerCase()
  58816. };
  58817. /**
  58818. * 在路径中获取文件名
  58819. * @param {*} path
  58820. */
  58821. const getFilename = path => {
  58822. const segment = (path || "").split("/");
  58823. return segment[segment.length - 1]
  58824. };
  58825. /**
  58826. * 检测媒体文件是否超过预设限制
  58827. * @param {String} type 媒体类型
  58828. * @param {Number} size 文件大小
  58829. */
  58830. const checkSizeLimit = (type, size) => {
  58831. size = size / 1024 / 1024;
  58832. return size <= mediaMaxSize[type]
  58833. };
  58834. const checkSizeLimitFree = (size, limit) => {
  58835. size = size / 1024 / 1024;
  58836. return size <= limit
  58837. };
  58838. /**
  58839. * 检测媒体类型
  58840. * @param {String} type 媒体类型
  58841. * @param {String} filename 文件名称
  58842. */
  58843. const checkMediaMime = (type, filename) => {
  58844. const mime = getMime(filename);
  58845. const find = mediaMimes[type];
  58846. if (!find) {
  58847. return false
  58848. }
  58849. return find.indexOf(mime) !== -1
  58850. };
  58851. const checkMediaMimeByAccept = (accept, filename) => {
  58852. let mime = getMime(filename);
  58853. let type = accept;
  58854. if (type && type.indexOf("jpg") == -1 && type.indexOf("jpeg") != -1) {
  58855. type += ",image/jpg";
  58856. }
  58857. return (type || "").indexOf(mime) != -1
  58858. };
  58859. const base64ToBlob = base64 => {
  58860. let arr = base64.split(","),
  58861. mime = arr[0].match(/:(.*?);/)[1],
  58862. bstr = atob(arr[1]),
  58863. n = bstr.length,
  58864. u8arr = new Uint8Array(n);
  58865. while (n--) {
  58866. u8arr[n] = bstr.charCodeAt(n);
  58867. }
  58868. return new Blob([u8arr], { type: mime })
  58869. };
  58870. const base64ToDataURL = base64 => {
  58871. return window.URL.createObjectURL(base64ToBlob(base64))
  58872. };
  58873. const blobToBase64 = function(blob) {
  58874. return new Promise(resolve => {
  58875. var reader = new FileReader();
  58876. reader.onload = function() {
  58877. resolve(reader.result);
  58878. };
  58879. reader.readAsDataURL(blob);
  58880. })
  58881. };
  58882. /*
  58883. * @Author: Rindy
  58884. * @Date: 2019-08-06 16:25:08
  58885. * @LastEditors: Rindy
  58886. * @LastEditTime: 2021-08-27 12:33:49
  58887. * @Description: Request
  58888. */
  58889. //import { $alert, $confirm, $loginTips } from "@/components/shared/message"
  58890. //import { $waiting } from "@/components/shared/loading"
  58891. //import { checkLogin } from "@/api"
  58892. //import { LoginDetector } from "@/core/starter"
  58893. //import { i18n } from "@/lang"
  58894. //import { password } from "@/utils/string"
  58895. //import store from "../Store"
  58896. // 空函数
  58897. const noop = function() {};
  58898. // 请求回调队列
  58899. let postQueue = [];
  58900. /**
  58901. * @property {number} NEXT - 继续执行
  58902. * @property {number} SUCCESS - 成功
  58903. * @property {number} EXCEPTION - 异常错误
  58904. * @property {number} FAILURE_CODE_3001 - 缺少必要参数
  58905. * @property {number} FAILURE_CODE_3002 - 访问异常
  58906. * @property {number} FAILURE_CODE_3003 - 非法访问
  58907. * @property {number} FAILURE_CODE_3004 - 用户未登录
  58908. * @property {number} FAILURE_CODE_3005 - 验证码已过期
  58909. * @property {number} FAILURE_CODE_3006 - 验证码错误
  58910. * @property {number} FAILURE_CODE_3007 - 昵称已存在
  58911. * @property {number} FAILURE_CODE_3008 - 该手机已被注册
  58912. * @property {number} FAILURE_CODE_3009 - 两次输入的密码不一致
  58913. * @property {number} FAILURE_CODE_3010 - 昵称长度错误
  58914. * @property {number} FAILURE_CODE_3011 - 密码长度错误
  58915. * @property {number} FAILURE_CODE_3012 - 昵称包含敏感词
  58916. * @property {number} FAILURE_CODE_3013 - 手机号码格式错误
  58917. * @property {number} FAILURE_CODE_3014 - 账号或密码不正确
  58918. * @property {number} FAILURE_CODE_3015 - 用户不存在
  58919. * @property {number} FAILURE_CODE_3016 - 您没有权限,请联系管理员
  58920. * @property {number} FAILURE_CODE_3017 - 空文件
  58921. * @property {number} FAILURE_CODE_3018 - 需要上传或使用的文件不存在
  58922. * @property {number} FAILURE_CODE_5010 - 找不到该场景对应的相机
  58923. * @property {number} FAILURE_CODE_5012 - 数据不正常
  58924. * @property {number} FAILURE_CODE_5014 - 无权操作该场景
  58925. * @property {number} FAILURE_CODE_5005 - 场景不存在
  58926. */
  58927. const statusCode = {
  58928. NEXT: -999,
  58929. SUCCESS: 0,
  58930. EXCEPTION: -1,
  58931. FAILURE_CODE_3001: 3001,
  58932. FAILURE_CODE_3002: 3002,
  58933. FAILURE_CODE_3003: 3003,
  58934. FAILURE_CODE_3004: 3004,
  58935. FAILURE_CODE_3005: 3005,
  58936. FAILURE_CODE_3006: 3006,
  58937. FAILURE_CODE_3007: 3007,
  58938. FAILURE_CODE_3008: 3008,
  58939. FAILURE_CODE_3009: 3009,
  58940. FAILURE_CODE_3010: 3010,
  58941. FAILURE_CODE_3011: 3011,
  58942. FAILURE_CODE_3012: 3012,
  58943. FAILURE_CODE_3013: 3013,
  58944. FAILURE_CODE_3014: 3014,
  58945. FAILURE_CODE_3015: 3015,
  58946. FAILURE_CODE_3016: 3016,
  58947. FAILURE_CODE_3017: 3017,
  58948. FAILURE_CODE_3018: 3018,
  58949. FAILURE_CODE_5010: 5010,
  58950. FAILURE_CODE_5012: 5012,
  58951. FAILURE_CODE_5014: 5014,
  58952. FAILURE_CODE_5005: 5005,
  58953. };
  58954. /**
  58955. * 获取Token
  58956. * @function
  58957. */
  58958. function getToken() {
  58959. var urlToken = browser.urlHasValue("token", true);
  58960. if (urlToken) {
  58961. // 设置token共享给用户中心
  58962. localStorage.setItem("token", urlToken);
  58963. }
  58964. return urlToken || localStorage.getItem("token") || ""
  58965. }
  58966. /**
  58967. * 根据状态码的结果处理后续操作
  58968. * @function
  58969. * @param {number} code - 状态码
  58970. * @param {function} callback - 回调
  58971. */
  58972. function statusCodesHandler(code, callback) {
  58973. if (code == statusCode.EXCEPTION) {
  58974. return $alert({ content: i18n.t("tips.exception") })
  58975. }
  58976. if (
  58977. code == statusCode.FAILURE_CODE_3002 ||
  58978. code == statusCode.FAILURE_CODE_3003 ||
  58979. code == statusCode.FAILURE_CODE_3004
  58980. ) {
  58981. callback(code);
  58982. return showLoginTips()
  58983. }
  58984. if (code == statusCode.FAILURE_CODE_3001) {
  58985. callback(code);
  58986. return $alert({ content: i18n.t("tips.params_notfound") })
  58987. }
  58988. if (code == statusCode.FAILURE_CODE_3017) {
  58989. callback(code);
  58990. return $alert({ content: i18n.t("tips.file_notfound") })
  58991. }
  58992. if (code == statusCode.FAILURE_CODE_5005) {
  58993. /* if (!config.isEdit) {
  58994. return (location.href = config.pages.NotFound)
  58995. } */
  58996. callback(code);
  58997. return $alert({ content: i18n.t("tips.scene_notfound") })
  58998. }
  58999. if (code == statusCode.FAILURE_CODE_5010) {
  59000. callback(code);
  59001. return $alert({ content: i18n.t("tips.camera_notfound") })
  59002. }
  59003. if (code == statusCode.FAILURE_CODE_5012) {
  59004. callback(code);
  59005. return $alert({ content: i18n.t("tips.data_error") })
  59006. }
  59007. if (code == statusCode.FAILURE_CODE_5014) {
  59008. callback(code);
  59009. return $alert({ content: i18n.t("tips.auth_deny") })
  59010. }
  59011. return statusCode.NEXT
  59012. }
  59013. $.ajaxSetup({
  59014. headers: {},
  59015. beforeSend: function(xhr) {
  59016. const token = getToken();
  59017. if (token) {
  59018. xhr.setRequestHeader("token", token);
  59019. } else if (!token && this.url.indexOf("isLogin") != -1) {
  59020. showLoginTips();
  59021. }
  59022. /* if (config.oem == "localshow") {
  59023. // 本地版本兼容当前目录
  59024. if (this.url.indexOf("http") == -1 && this.url.indexOf("/") == 0) {
  59025. this.url = this.url.substr(1)
  59026. }
  59027. } */
  59028. // if(this.url.indexOf('http')==-1 && this.url.indexOf('/') !=0){
  59029. // this.url = '/'+this.url
  59030. // }
  59031. },
  59032. error: function(xhr, status, error) {
  59033. // 出错时默认的处理函数
  59034. if (this.url.indexOf("/scene.json") != -1 && xhr.status == 404) {
  59035. return $alert({ content: i18n.t("tips.scene_notfound") })
  59036. } else if (this.type === "POST") {
  59037. return $alert({ content: i18n.t("tips.network_error") })
  59038. }
  59039. },
  59040. success: function(result) {},
  59041. complete: function() {
  59042. // Post类型请求无论成功或失败都关闭等待提示
  59043. if (this.type === "POST") {
  59044. http.__loading && $waiting.hide();
  59045. }
  59046. http.__loading = true;
  59047. },
  59048. });
  59049. /**
  59050. * @namespace http
  59051. * @type {Object}
  59052. */
  59053. const http = {
  59054. statusCode,
  59055. __loading: true,
  59056. __request(xhr, method, url, data, done, fail) {
  59057. if (typeof done != "function") {
  59058. done = noop;
  59059. }
  59060. if (typeof fail != "function") {
  59061. fail = noop;
  59062. }
  59063. xhr.done(result => {
  59064. if (typeof result.code !== "undefined") {
  59065. const flag = statusCodesHandler(result.code, function(code) {
  59066. // 需要登录的状态
  59067. if (
  59068. code == statusCode.FAILURE_CODE_3001 ||
  59069. code == statusCode.FAILURE_CODE_3002 ||
  59070. code == statusCode.FAILURE_CODE_3003 ||
  59071. code == statusCode.FAILURE_CODE_3004
  59072. ) {
  59073. if (url.indexOf("isLogin") == -1 && url.indexOf("openSceneBykey") == -1) {
  59074. postQueue.push(function() {
  59075. http[method](url, data, done, fail);
  59076. });
  59077. }
  59078. }
  59079. fail();
  59080. });
  59081. if (flag === statusCode.NEXT) {
  59082. done(result, result.code == 0);
  59083. }
  59084. } else {
  59085. done(result);
  59086. }
  59087. });
  59088. xhr.fail(fail);
  59089. xhr.always(() => (xhr = null));
  59090. return xhr
  59091. },
  59092. /**
  59093. * Get请求
  59094. * @param {String} url 请求地址
  59095. * @param {Object?} data 请求参数
  59096. * @param {Function?} done 成功回调
  59097. * @param {Function?} fail 失败回调
  59098. */
  59099. get(url, data = {}, done, fail) {
  59100. if (/\.json/.test(url)) {
  59101. // json文件格式自动调用getJson方法
  59102. return this.getJson(url, data, done, fail)
  59103. }
  59104. return this.__request($.get(url, data), "get", url, data, done, fail)
  59105. },
  59106. /**
  59107. * Get Blob请求
  59108. * @param {String} url 请求地址
  59109. * @param {Object?} data 请求参数
  59110. * @param {Function?} done 成功回调
  59111. * @param {Function?} fail 失败回调
  59112. */
  59113. getText(url, data = {}, done, fail) {
  59114. return this.__request(
  59115. $.ajax({
  59116. url: url,
  59117. dataType: "text",
  59118. }),
  59119. "getText",
  59120. url,
  59121. data,
  59122. done,
  59123. fail
  59124. )
  59125. },
  59126. /**
  59127. * GetJson请求 读取json文件数据
  59128. * @param {String} url 请求地址
  59129. * @param {Object?} data 请求参数
  59130. * @param {Function?} done 成功回调
  59131. * @param {Function?} fail 失败回调
  59132. */
  59133. getJson(url, data = {}, done, fail) {
  59134. return this.__request($.getJSON(url, data), "get", url, data, done, fail)
  59135. },
  59136. /**
  59137. * Get Blob请求
  59138. * @param {String} url 请求地址
  59139. * @param {Object?} data 请求参数
  59140. * @param {Function?} done 成功回调
  59141. * @param {Function?} fail 失败回调
  59142. */
  59143. getBlob(url, data = {}, done, fail) {
  59144. return this.__request(
  59145. $.ajax({
  59146. url: url,
  59147. dataType: "blob",
  59148. }),
  59149. "getBlob",
  59150. url,
  59151. data,
  59152. done,
  59153. fail
  59154. )
  59155. },
  59156. /**
  59157. * Get Arraybuffer请求
  59158. * @param {String} url 请求地址
  59159. * @param {Object?} data 请求参数
  59160. * @param {Function?} done 成功回调
  59161. * @param {Function?} fail 失败回调
  59162. */
  59163. getArraybuffer(url, data = {}, done, fail) {
  59164. return this.__request(
  59165. $.ajax({
  59166. url: url,
  59167. dataType: "arraybuffer",
  59168. }),
  59169. "getArraybuffer",
  59170. url,
  59171. data,
  59172. done,
  59173. fail
  59174. )
  59175. },
  59176. /**
  59177. * Post 请求
  59178. * @param {String} url 请求地址
  59179. * @param {Object?} data 请求参数
  59180. * @param {Function?} done 成功回调
  59181. * @param {Function?} fail 失败回调
  59182. */
  59183. post(url, data = {}, done, fail) {
  59184. if (url.indexOf("isLogin") == -1) {
  59185. http.__loading && $waiting.show();
  59186. }
  59187. return this.__request($.post(url, data), "post", url, data, done, fail)
  59188. },
  59189. /**
  59190. * PostJson 请求
  59191. * @param {String} url 请求地址
  59192. * @param {Object?} data 请求参数
  59193. * @param {Function?} done 成功回调
  59194. * @param {Function?} fail 失败回调
  59195. */
  59196. postJson(url, data = {}, done, fail) {
  59197. http.__loading && $waiting.show();
  59198. return this.__request(
  59199. $.ajax({
  59200. type: "POST",
  59201. url: url,
  59202. contentType: "application/json",
  59203. data: JSON.stringify(data),
  59204. }),
  59205. "postJson",
  59206. url,
  59207. data,
  59208. done,
  59209. fail
  59210. )
  59211. },
  59212. /**
  59213. * Post 表单 支持文件上传
  59214. * @param {String} url 请求地址
  59215. * @param {FormData?} formData 请求参数
  59216. * @param {Function?} done 成功回调
  59217. * @param {Function?} fail 失败回调
  59218. */
  59219. postForm(url, formData, done, fail, onProgress) {
  59220. if (typeof onProgress === "function") {
  59221. return this.__request(
  59222. $.ajax({
  59223. type: "POST",
  59224. url: url,
  59225. processData: false,
  59226. contentType: false,
  59227. data: formData,
  59228. xhr: function() {
  59229. const xhr = new XMLHttpRequest();
  59230. xhr.upload.addEventListener("progress", function(e) {
  59231. onProgress((e.loaded / e.total) * 100 + "%");
  59232. });
  59233. return xhr
  59234. },
  59235. }),
  59236. "postForm",
  59237. url,
  59238. formData,
  59239. done,
  59240. fail
  59241. )
  59242. } else {
  59243. http.__loading && $waiting.show();
  59244. return this.__request(
  59245. $.ajax({
  59246. type: "POST",
  59247. url: url,
  59248. processData: false,
  59249. contentType: false,
  59250. data: formData,
  59251. }),
  59252. "postForm",
  59253. url,
  59254. formData,
  59255. done,
  59256. fail
  59257. )
  59258. }
  59259. },
  59260. /**
  59261. * 加载图片
  59262. * @param {String} url 请求地址
  59263. * @param {Number?} retry 重试次数,默认为3
  59264. */
  59265. loadImage(url, retry = 3) {
  59266. const def = $.Deferred();
  59267. const img = new Image();
  59268. /* if (process.env.VUE_APP_REGION == "AWS" && url.indexOf("x-oss-process=image") != -1) {
  59269. var arr = url.split("?")
  59270. url = arr[0] + encodeURIComponent("?" + arr[1].replace(/\//g, "@"))
  59271. } */
  59272. const load = () => {
  59273. console.warn("Retrying load image: " + url);
  59274. this.loadImage(url, retry - 1)
  59275. .done(def.resolve.bind(def))
  59276. .progress(def.notify.bind(def))
  59277. .fail(def.reject.bind(def));
  59278. };
  59279. img.onerror = function() {
  59280. retry > 0 ? setTimeout(() => load(), 1e3) : def.reject(`[${url}]加载失败`);
  59281. };
  59282. img.onload = function() {
  59283. def.resolve(img);
  59284. };
  59285. img.crossOrigin = "anonymous";
  59286. img.src = url;
  59287. return def
  59288. },
  59289. /**
  59290. * 上传文件
  59291. * @param {String} url 请求地址
  59292. * @param {Object?} data 请求参数
  59293. * @param {Function?} done 成功回调
  59294. * @param {Function?} fail 失败回调
  59295. */
  59296. uploadFile(url, data = {}, done, fail, onProgress) {
  59297. const form = new FormData();
  59298. // if (file.needTransfer) { //ie和苹果都不支持dataURLtoFile得传送,所以只能用blob
  59299. // form.append("file", common.dataURLtoBlob(file.file), file.name || file.file.name);
  59300. // } else {
  59301. // form.append("file", file.file, file.name || file.file.name);
  59302. // }
  59303. for (let key in data) {
  59304. if (key == "file") {
  59305. form.append("file", data[key], data.filename || data[key].name);
  59306. } else if (key != "filename") {
  59307. form.append(key, data[key]);
  59308. }
  59309. }
  59310. return this.postForm(url, form, done, fail, onProgress)
  59311. },
  59312. /**
  59313. * 上传文件
  59314. * @param {String} url 请求地址
  59315. * @param {Object?} data 请求参数 {file:'base64 string',filename:'image.jpg',...}
  59316. * @param {Function?} done 成功回调
  59317. * @param {Function?} fail 失败回调
  59318. */
  59319. uploadBlobFile(url, data = {}, done, fail) {
  59320. const form = new FormData();
  59321. for (let key in data) {
  59322. if (key === "file") {
  59323. form.append("file", base64ToBlob(data.file), data.filename);
  59324. } else if (key != "filename") {
  59325. form.append(key, data[key]);
  59326. }
  59327. }
  59328. return this.postForm(url, form, done, fail)
  59329. },
  59330. };
  59331. window.downloaded = {};
  59332. window.startdownloads = [];
  59333. class TileDownloader extends EventDispatcher{
  59334. constructor( ) {
  59335. super();
  59336. this.panos = null;
  59337. this.retryMinimumTime = 1e4;
  59338. this.panoLoadCallbacks = {};
  59339. this.downloadDescriptors = {};
  59340. this.priorityQueue = [];
  59341. this.forceQueue = [];
  59342. this.activeDownloads = [];
  59343. this.tilePrioritizer = null;
  59344. this.refreshInterval = null;
  59345. this.processPriorityQueue = !1;
  59346. this.concurrentDownloads = 6;//e.concurrentDownloads || 1;
  59347. this.downloadTestResults = {};
  59348. this.freeze = Object.freeze({
  59349. Testing: 1,
  59350. Success: 2,
  59351. Fail: 3
  59352. });
  59353. this.visible = true; //add 借用viewer.updateVisible来判断是否start
  59354. viewer.addEventListener('pageVisible', (e)=>{//不可见时不refreshUpdateInterval
  59355. //console.log('visibilitychange:', state)
  59356. viewer.updateVisible(this, 'pageVisible', e.v);
  59357. this.judgeStart();
  59358. });
  59359. }
  59360. setPanoData(e, t /* , i */) {
  59361. this.panos = e,
  59362. this.imagePanos = t;
  59363. // this.panoGroupId = i
  59364. }
  59365. start() {
  59366. this.downloadCubeTex = true;
  59367. if(!Potree.settings.useDepthTex){
  59368. viewer.updateVisible(this,'pano', true );
  59369. this.judgeStart();
  59370. }else {
  59371. this.refreshInterval || this.judgeStart();
  59372. }
  59373. }
  59374. stop() {
  59375. this.downloadCubeTex = false;
  59376. if(!Potree.settings.useDepthTex){
  59377. viewer.updateVisible(this,'pano', false );
  59378. this.judgeStart();
  59379. }
  59380. }
  59381. judgeStart(){//add
  59382. if(this.visible){
  59383. //console.log('judgeStart true')
  59384. this.started = true;
  59385. this.refreshUpdateInterval(0);
  59386. }else {
  59387. //console.log('judgeStart false')
  59388. this.started = false;
  59389. window.clearTimeout(this.refreshInterval);
  59390. }
  59391. }
  59392. refreshUpdateInterval(e) {
  59393. e || (e = 0),
  59394. this.refreshInterval = window.setTimeout(function() {
  59395. var e = this.update();
  59396. e ? this.refreshUpdateInterval(TileDownloader.ACTIVE_REFRESH_DELAY) : this.refreshUpdateInterval(TileDownloader.IDLE_REFRESH_DELAY);
  59397. }
  59398. .bind(this), e);
  59399. }
  59400. update() {
  59401. if(this.downloadCubeTex){ //可以下载贴图
  59402. var e = this.forceQueue.length > 0;
  59403. this.processQueueForDownloading(this.forceQueue);
  59404. if (this.processPriorityQueue) {
  59405. this.queuePrioritizedTilesForPanos(this.panos);
  59406. this.priorityQueue.length > 0 && (e = !0);
  59407. this.processQueueForDownloading(this.priorityQueue);
  59408. }
  59409. return e
  59410. }else {//仅下载depthTex
  59411. this.tilePrioritizer.filterDepthTex(this.panos);
  59412. }
  59413. }
  59414. queuePrioritizedTilesForPanos(e) {
  59415. this.tilePrioritizer && (this.clearQueue(this.priorityQueue),
  59416. this.tilePrioritizer.filterAndPrioritize(this.priorityQueue, e, this),
  59417. this.clearFromQueue(this.priorityQueue, DownloadStatus.None, !0), //去除state为DownloadStatus.None的(可能是去除已经在下载的)
  59418. this.setStatusOrRemoveForAllDescriptors(this.priorityQueue, DownloadStatus.Queued));
  59419. }
  59420. clearQueue(e) {//停止下载并清空
  59421. this.setStatusForAllDescriptors(e, DownloadStatus.None),
  59422. e.length = 0;
  59423. }
  59424. clearForceQueue() {
  59425. this.clearQueue(this.forceQueue);
  59426. }
  59427. clearFromQueue(e, t, i) {
  59428. for (var n = 0; n < e.length; n++) {
  59429. var r = e[n];
  59430. r && (t === r.status && !i || t !== r.status && i) && (e[n] = null);
  59431. }
  59432. }
  59433. setStatusForAllDescriptors(e, t) {
  59434. for (var i = 0; i < e.length; i++) {
  59435. var n = e[i];
  59436. n && (n.status = t);
  59437. }
  59438. }
  59439. setStatusOrRemoveForAllDescriptors(e, t) {
  59440. for (var i = 0; i < e.length; i++) {
  59441. var n = e[i];
  59442. n && (n.status !== t ? n.status = t : e[i] = null);
  59443. }
  59444. }
  59445. getTileDownloadDescriptors(pano, size) {//获取该pano的该size的全部的tile的descriptor
  59446. var i = this.getAllTileDownloadDescriptorsForPano(pano),
  59447. n = i[size];
  59448. return n || (n = this.buildDownloadDescriptorArray(size),//创建的全部是空的
  59449. i[size] = n,
  59450. this.initTileDownloadDescriptors(n, pano, size)),//绑定到该pano size
  59451. n
  59452. }
  59453. getAllTileDownloadDescriptorsForPano(pano) {//新建空Descriptors
  59454. var t = this.downloadDescriptors[pano.id];
  59455. return t || (t = {},
  59456. this.downloadDescriptors[pano.id] = t),
  59457. t
  59458. }
  59459. processQueueForDownloading(e, t) {//执行下载任务
  59460. this.cleanupActiveDownloads();
  59461. if (this.activeDownloads.length < this.concurrentDownloads || t) {
  59462. var i = t ? e.length : this.concurrentDownloads - this.activeDownloads.length;
  59463. for (var n = 0, r = 0; n < i && e.length > 0; r++) {
  59464. var o = e.shift();
  59465. if(o){
  59466. //add 为了防止1024的在512前下载完,这里强行等待512下载完毕再开始下载
  59467. if(o.panoSize > 512 && !this.isPanoDownloaded(o.pano, 512) ){
  59468. //console.log('512的还没下载好呢!')
  59469. e.push(o);
  59470. break;//一般512的都是连续下载的,所以后面就都不是512了直接中断
  59471. }
  59472. this.startDownload(o);
  59473. n++;
  59474. }
  59475. }
  59476. }
  59477. }
  59478. testDownload(panoSize, tileSize, callback) {
  59479. var n = this.downloadTestResults[panoSize];
  59480. if (n)
  59481. return void(n === this.freeze.Success ? callback(!0) : n === this.freeze.Fail && callback(!1));
  59482. this.downloadTestResults[panoSize] = this.freeze.Testing;
  59483. var r = this.panos[0],
  59484. o = this.getTileUrl({pano:r, panoSize, tileSize, tileIndex:0} /* r.id, panoSize, tileSize, 0 */),
  59485. a = function(t) {
  59486. this.downloadTestResults[panoSize] = this.freeze.Success,
  59487. callback(!0);
  59488. }
  59489. .bind(this),
  59490. s = function() {
  59491. this.downloadTestResults[panoSize] = this.freeze.Fail,
  59492. callback(!1);
  59493. }
  59494. .bind(this);
  59495. this.loadImage(o, 0, a, s);
  59496. }
  59497. startDownload(e) {//开始下载啦
  59498. //console.log('startDownload')
  59499. startdownloads.push(e);
  59500. e.status = DownloadStatus.Downloading;
  59501. var t = this.getTileUrl(e/* e.pano.id, e.panoSize, e.tileSize, e.tileIndex, e.pano.alignmentType */);//xzw add alignmentType
  59502. if(!t)return;
  59503. this.activeDownloads.push(e);
  59504. this.loadImage(t, TileDownloader.DOWNLOAD_RETRIES, this.downloadComplete.bind(this, e), this.downloadFailed.bind(this, e));
  59505. }
  59506. downloadFailed(e, t) {}
  59507. downloadComplete(e, t) {//下载成功时
  59508. //if (e.panoGroupId === this.panoGroupId) {
  59509. var i = this.getPanoLoadCallbacks(e.pano, e.panoSize);
  59510. e.status = DownloadStatus.Downloaded,
  59511. i && i.onProgress && i.onProgress(e.pano, e.panoSize);
  59512. var n = {
  59513. panoId: e.pano.id,
  59514. image: t,
  59515. tileSize: e.tileSize,
  59516. panoSize: e.panoSize,
  59517. tileIndex: e.tileIndex,
  59518. faceTileIndex: e.faceTileIndex,
  59519. totalTiles: e.totalTiles,
  59520. face: e.face,
  59521. tileX: e.tileX,
  59522. tileY: e.tileY,
  59523. direction: e.direction
  59524. };
  59525. downloaded[e.pano.id] || (downloaded[e.pano.id]={512:[],1024:[],2048:[]});
  59526. downloaded[e.pano.id][e.panoSize] || (downloaded[e.pano.id][e.panoSize] = []);
  59527. downloaded[e.pano.id][e.panoSize].push(e);
  59528. if(e.panoSize != 512 && downloaded[e.pano.id][512].length<6){
  59529. console.warn('没下完');
  59530. }
  59531. e.image = t,
  59532. this.dispatchEvent({type:TileDownloaderEvents.TileDownloadSuccess, desc:n} );
  59533. this.isPanoDownloaded(e.pano, e.panoSize) && (n = {
  59534. panoId: e.pano.id,
  59535. tileSize: e.tileSize,
  59536. panoSize: e.panoSize
  59537. },
  59538. this.dispatchEvent({type:TileDownloaderEvents.PanoDownloadComplete, desc:n}),
  59539. i && i.onLoad && i.onLoad(e.pano, e.panoSize));
  59540. //}
  59541. }
  59542. isPanoDownloaded(e, t) {
  59543. var i = this.getTileDownloadDescriptors(e, t);
  59544. if (i.length <= 0)
  59545. return !1;
  59546. for (var n = 0; n < i.length; n++) {
  59547. var r = i[n];
  59548. if (r.status !== DownloadStatus.Downloaded)
  59549. return !1
  59550. }
  59551. return !0
  59552. }
  59553. setPanoLoadCallbacks(e, t, i, n, r) {
  59554. var o = e.id + ":" + this.qualityManager.getPanoSize(t);
  59555. this.panoLoadCallbacks[o] = {
  59556. onLoad: i,
  59557. onFail: n,
  59558. onProgress: r
  59559. };
  59560. }
  59561. getPanoLoadCallbacks(e, t) {
  59562. var i = e.id + ":" + t;
  59563. return this.panoLoadCallbacks[i]
  59564. }
  59565. buildDownloadDescriptorArray(e) {
  59566. for (var t = TileUtils.getTileCountForSize(e), i = [], n = 0; n < t; n++) {
  59567. var r = this.buildDownloadDescriptor();
  59568. i.push(r);
  59569. }
  59570. return i
  59571. }
  59572. buildDownloadDescriptor() {//Descriptor!
  59573. var e = {
  59574. panoGroupId: null,
  59575. pano: null,
  59576. panoSize: -1,
  59577. tileSize: -1,
  59578. tileIndex: -1,
  59579. totalTiles: -1,
  59580. faceTileIndex: -1,
  59581. status: DownloadStatus.None,
  59582. url: null,
  59583. image: null,
  59584. direction: new Vector3, //该tile在cube中的方向
  59585. face: -1,
  59586. cubeFace: -1,
  59587. tileX: -1,
  59588. tileY: -1
  59589. };
  59590. return e
  59591. }
  59592. initTileDownloadDescriptors(e, t, i) {
  59593. for (var n = 0; n < e.length; n++) {
  59594. var r = e[n];
  59595. this.initTileDownloadDescriptor(r, t, i, n);
  59596. }
  59597. }
  59598. initTileDownloadDescriptor(desc, pano, size, index) {
  59599. var r = size >= TileUtils.TILE_SIZE ? TileUtils.TILE_SIZE : size;
  59600. desc.face = TileUtils.getFaceForTile(size, index);//根据顺序得到的face的index
  59601. desc.cubeFace = TileUtils.mapFaceToCubemapFace(desc.face);//为了贴图而转化的face index
  59602. //desc.panoGroupId = this.panoGroupId;//就是场景号
  59603. desc.pano = pano;
  59604. desc.panoSize = size;
  59605. desc.tileSize = r; //瓦片图size 512
  59606. desc.tileIndex = index;
  59607. desc.totalTiles = TileUtils.getTileCountForSize(size);
  59608. desc.status = DownloadStatus.None;
  59609. desc.image = null;
  59610. TileUtils.getTileLocation(desc.panoSize, desc.tileIndex, desc);//得到该tile在这个face中的具体位置(tileX等)
  59611. TileUtils.getTileVector(desc.panoSize, desc.tileSize, desc.cubeFace, desc.tileX, desc.tileY, TileUtils.LocationOnTile.Center, 0, desc.direction);
  59612. }
  59613. getTiles(d, sceneNum){
  59614. return `${Potree.settings.urls.prefix3}/images/images${sceneNum}/${d}`
  59615. }
  59616. loadImage(e, t, i, n) {
  59617. //自己修改了ajax,把getImage改成了loadImg
  59618. http.loadImage(e, t).then(function(e) {
  59619. i(e);
  59620. }).fail(n);
  59621. }
  59622. }
  59623. TileDownloader.prototype.forceQueueTilesForPano = function() {//根据条件开始加载tile
  59624. var e = [],
  59625. t = [];
  59626. return function(pano, size, dir, hFov, vFov, download) {
  59627. e.length = 0;
  59628. for (var u = this.getTileDownloadDescriptors(pano, size), d = 0; d < u.length; d++) {
  59629. var p = u[d];
  59630. p.status !== DownloadStatus.None && p.status !== DownloadStatus.Queued || e.push(p);
  59631. }
  59632. if (dir && e.length > 0) {
  59633. TilePrioritizer.sortPanoTiles(e, pano, dir); //按最佳方向排序e
  59634. t.length = 0;
  59635. TileUtils.matchingTilesInDirection(pano, size, dir, hFov, vFov, t);//得到在符合视野标准的集合t
  59636. for (var f = 0, g = function(e) {
  59637. return e.face === m.face && e.faceTileIndex === m.faceTileIndex
  59638. }; f < e.length;) { //过滤掉不符合角度要求的
  59639. var m = e[f],
  59640. v = t.findIndex(g);
  59641. v < 0 ? e.splice(f, 1) : f++;
  59642. }
  59643. }
  59644. for (var A = 0; A < e.length; A++){
  59645. this.forceQueue.push(e[A]); //装载
  59646. }
  59647. /* if(e.length){
  59648. console.log(e)
  59649. } */
  59650. this.setStatusForAllDescriptors(this.forceQueue, DownloadStatus.ForceQueued);
  59651. this.clearFromQueue(this.priorityQueue, DownloadStatus.ForceQueued, !1);
  59652. download && this.processQueueForDownloading(this.forceQueue, !0);
  59653. }
  59654. }();
  59655. TileDownloader.prototype.cleanupActiveDownloads = function() {
  59656. var e = [];
  59657. return function() {
  59658. e.length = 0;
  59659. for (var t = 0; t < this.activeDownloads.length; t++) {
  59660. var i = this.activeDownloads[t];
  59661. i.status !== DownloadStatus.Downloaded && i.status !== DownloadStatus.Failed && e.push(i);
  59662. }
  59663. this.activeDownloads.length = 0,
  59664. this.activeDownloads.push.apply(this.activeDownloads, e);
  59665. }
  59666. }();
  59667. TileDownloader.prototype.getTileUrl = function() {
  59668. var e = {
  59669. 256: "256",
  59670. 512: "512",
  59671. 1024: "1k",
  59672. 2048: "2k",
  59673. 4096: "4k"
  59674. },
  59675. t = {
  59676. face: -1,
  59677. faceTileIndex: -1,
  59678. tileX: -1,
  59679. tileY: -1
  59680. };
  59681. return function(o={} ) {
  59682. var id = o.pano.originID, ////////
  59683. panoSize = o.panoSize,
  59684. tileSize = o.tileSize,
  59685. tileIndex = o.tileIndex,
  59686. sceneCode = o.pano.pointcloud.sceneCode;
  59687. var metadata = {sceneScheme:10};
  59688. TileUtils.getTileLocation(panoSize, tileIndex, t);
  59689. var s = Math.floor(panoSize / tileSize),
  59690. l = s * s,
  59691. h = Math.floor(tileIndex / l),
  59692. u = "",
  59693. d = '', g = '';
  59694. if(Potree.settings.isLocal){//原始规则
  59695. //1 === config.tiling.customCompression && (u = "_" + config.tiling["q" + e[panoSize]]);
  59696. //1 === o.tiling.customCompression && (u = "_" + o.tiling["q" + e[n]]);
  59697. d = "tiles/" + id + "/" + e[panoSize] + u + "_face" + h + "_" + t.tileX + "_" + t.tileY + ".jpg";
  59698. d = this.getTiles(d, sceneCode);
  59699. g = "?";
  59700. }else {//阿里云oss的规则 if (metadata.sceneScheme == 10)
  59701. d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=';
  59702. if (e[panoSize] == '512') {
  59703. d += 'image/resize,h_512';
  59704. } else {
  59705. //4k的图,移动端是1k,pc端是2k,放大才是4k
  59706. if (e[panoSize] == '1k' || e[panoSize] == '2k') { //https://4dkk.4dage.com/images/imagesx4iqYDG3/tiles/4k/122_skybox0.jpg?x-oss-process=image/resize,m_lfit,w_1024/crop,w_512,h_512,x_511,y_0
  59707. d += 'image/resize,m_lfit,w_' + panoSize + '/crop,w_512,h_512,';
  59708. } else {
  59709. d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=image/crop,w_512,h_512,';
  59710. }
  59711. //起始位置
  59712. if (t.tileX == 0) {
  59713. d += 'x_0,';
  59714. } else {
  59715. d += 'x_' + (512 * t.tileX - 1) + ',';
  59716. }
  59717. if (t.tileY == 0) {
  59718. d += 'y_0';
  59719. } else {
  59720. d += 'y_' + (512 * t.tileY - 1);
  59721. }
  59722. }
  59723. d = this.getTiles(d, sceneCode);
  59724. g = "&";
  59725. }
  59726. d += g + 'time='+o.pano.pointcloud.timeStamp; //加后缀
  59727. return d;
  59728. }
  59729. }();
  59730. TileDownloader.tilegen = true;
  59731. TileDownloader.IDLE_REFRESH_DELAY = 500;
  59732. TileDownloader.ACTIVE_REFRESH_DELAY = 16;
  59733. TileDownloader.DOWNLOAD_RETRIES = 4;
  59734. function Node$1(e, t) {
  59735. this.tree = e, //所属树(TileTree)
  59736. this.parent = t,
  59737. this.children = [],
  59738. this.id = ++u$1;
  59739. }
  59740. function o(e, t, i, r, a, s, l, h) {
  59741. if (e) {
  59742. l = l || TileTree.TraversalType.PreOrder;
  59743. var u = r * c + i;
  59744. if (l === TileTree.TraversalType.PreOrder && (a && a(e, t, u, i, r),
  59745. s && s.push(e)),
  59746. e.children && 0 !== e.children.length) {
  59747. for (var d = r * c, p = i * c, f = 0; f < c; f++)
  59748. for (var g = 0; g < c; g++)
  59749. o(e.children[g * c + f], t + 1, p + f, d + g, a, s, l, h);
  59750. l === TileTree.TraversalType.PostOrder && (a && a(e, t, u, i, r),
  59751. s && s.push(e));
  59752. }
  59753. }
  59754. }
  59755. function Plant(seed) {
  59756. seed.root = Branch(seed, null, 0);
  59757. }
  59758. function Branch(seed, parent, level) {
  59759. if (level > seed.levels)
  59760. return null;
  59761. var node = new Node$1(seed, parent);
  59762. seed.allNodes.push(node);
  59763. for (var o = 0; o < h$1; o++)
  59764. node.children[o] = Branch(seed, node, level + 1);
  59765. return node
  59766. }
  59767. function l(parent, t, level, n, r) {
  59768. if (!parent)
  59769. return null;
  59770. if (0 === level)
  59771. return parent;
  59772. if (!parent.children || 0 === parent.children.length)
  59773. return null;
  59774. var o = Math.pow(c, level),
  59775. a = o / c,
  59776. s = n % a,
  59777. h = r % a,
  59778. u = Math.floor(r / a),
  59779. d = Math.floor(n / a),
  59780. p = u * c + d,
  59781. f = parent.children[p];
  59782. return l(f, t + 1, level - 1, s, h)
  59783. }
  59784. /* cube每个面都有一个分层树 用于代表瓦片图的细分?
  59785. 树4096的分为三层,每层有4个子节点。(最后一层的四个子节点都是null)
  59786. */
  59787. var c = 2,
  59788. h$1 = c * c; //4个子节点
  59789. var u$1 = 0;
  59790. class TileTree {
  59791. constructor(e, t) {
  59792. this.levels = t,
  59793. this.tileSize = e,
  59794. this.root = null,
  59795. this.allNodes = [],
  59796. Plant(this);
  59797. }
  59798. getSubNode(e, t, i) {
  59799. (!t || e < this.tileSize) && (t = 0),
  59800. (!i || e < this.tileSize) && (i = 0),
  59801. e < this.tileSize && (e = this.tileSize);
  59802. var level = TileTree.getLevelCountForSize(this.tileSize, e),
  59803. o = l(this.root, 0, level, t, i);
  59804. return o
  59805. }
  59806. breadthFirst(e) {//广度优先搜索
  59807. e = e || {};
  59808. var t = !!e.nullLevelEnd,
  59809. i = e.maxLevel,
  59810. n = e.minLevel,
  59811. r = e.callback,
  59812. o = e.saveVisited,
  59813. a = [],
  59814. s = {},
  59815. l = 0,
  59816. c = 0;
  59817. for (a.push(this.root),
  59818. a.push(s); a.length > 0 && !(i && l > i);) {
  59819. var h = a.shift();
  59820. if (h === s)
  59821. (!n || l >= n) && (r && t && r(null),
  59822. o && t && o.push(null)),
  59823. a.length > 0 && a.push(s),
  59824. l++,
  59825. c = 0;
  59826. else {
  59827. if (h.children)
  59828. for (var u = 0; u < h.children.length; u++) {
  59829. var d = h.children[u];
  59830. d && a.push(h.children[u]);
  59831. }
  59832. var p = this.getFaceIndexFromNode(h);
  59833. (!n || l >= n) && (r && r(h, l, p),
  59834. o && o.push(h)),
  59835. c++;
  59836. }
  59837. }
  59838. }
  59839. getFaceIndexFromNode(e) {
  59840. if (!e)
  59841. return -1;
  59842. for (var t = 1, i = e, n = 0, r = 0;;) {
  59843. var o = i.parent;
  59844. if (!o)
  59845. break;
  59846. for (var a = -1, s = 0; s < o.children.length; s++)
  59847. o.children[s] === i && (a = s);
  59848. var l = a % c,
  59849. h = Math.floor(a / c);
  59850. n = l * t + n,
  59851. r = h * t + r,
  59852. t *= c,
  59853. i = o;
  59854. }
  59855. return r * t + n
  59856. }
  59857. depthFirst(e, t, i) {
  59858. o(this.root, 0, 0, 0, e, t, i, this.tileSize);
  59859. }
  59860. }
  59861. TileTree.TraversalType = Object.freeze({
  59862. PreOrder: 0,
  59863. PostOrder: 1
  59864. });
  59865. TileTree.getLevelCountForSize = function(tileSize, size) {//512->0 2024->1
  59866. var i = 0;
  59867. for (size < tileSize && (size = tileSize);;) {
  59868. if (size /= c,
  59869. size < tileSize)
  59870. break;
  59871. i++;
  59872. }
  59873. return i
  59874. };
  59875. TileTree.getSizeForLevel = function(e, t) {
  59876. return Math.pow(c, t) * e
  59877. };
  59878. function createDescriptor() {
  59879. var e = {
  59880. renderTarget: null,
  59881. inUse: !1,
  59882. size: -1,
  59883. pano: null
  59884. };
  59885. return e
  59886. }
  59887. function c$1() {
  59888. if (!this.uploadIntervalCancelled) {
  59889. if (this.overlayTilesLoaded || !this.usingTileOverlay) {
  59890. b = !0,
  59891. this.updateUploadQueue(this.maxNonBaseUploadsPerFrame, this.maxBaseUploadsPerFrame),
  59892. this.peekNextFromUploadQueue() ? this.refreshUploadInterval(w) : this.uploadInterval = null;
  59893. } else {
  59894. this.refreshUploadInterval(this.uploadIntervalDelay);
  59895. }
  59896. }
  59897. }
  59898. var b = !1,
  59899. w = config$1.tiling.uploadIntervalDelay,
  59900. _ = config$1.tiling.initialIntervalDelay,
  59901. T = config$1.tiling.maxNonBaseUploadsPerFrame,
  59902. x$1 = config$1.tiling.maxBaseUploadsPerFrame,
  59903. S = {
  59904. Base: 0,
  59905. Remaining: 1
  59906. };/* ,
  59907. M = []; */
  59908. class PanoRenderer extends EventDispatcher{
  59909. constructor(viewer, tileDownloader, qualityManager) {
  59910. super();
  59911. this.tileDirectory = {};
  59912. this.activeRenderTargetDescriptors = {};
  59913. this.activePanos = [];
  59914. this.panoLODDescriptors = {};
  59915. this.panoDescriptors = {};
  59916. this.tileTrees = {};
  59917. this.forceQueue = [];
  59918. this.uploadQueues = {};
  59919. this.uploadInterval = null;
  59920. this.uploadIntervalCancelled = !1;
  59921. this.usingTileOverlay = !1;
  59922. this.overlayTilesLoaded = !1;
  59923. this.overlayTileBase = null;
  59924. this.overlayTilesBasic = {};
  59925. this.overlayTilesEnhanced = {};
  59926. this.zoomRenderTarget = null; //用于缩放的rendertarget
  59927. this.zoomPano = null;
  59928. this.zoomingActive = !1;
  59929. this.zoomPanoId = null;
  59930. this.zoomPanoRenderingDisabled = !1;
  59931. this.direction = [];//new THREE.Vector3;
  59932. this.maxBaseUploadsPerFrame = x$1;
  59933. this.maxNonBaseUploadsPerFrame = T;
  59934. this.M = [];//move M to here 似乎列表里会有两个
  59935. this.viewer = viewer;
  59936. this.tileDownloader = tileDownloader;
  59937. this.qualityManager = qualityManager;
  59938. this.initTime = performance.now();
  59939. this.bindEvents();
  59940. }
  59941. getActivePanoTextures(e) {
  59942. e = e || [];
  59943. for (var t = 0; t < M.length; t++) {
  59944. var i = M[t];
  59945. i.renderTarget && i.renderTarget.texture && e.push(i.renderTarget.texture);
  59946. }
  59947. }
  59948. hasQueuedTiles() {
  59949. var e = this.peekNextFromUploadQueue();
  59950. return null !== e && void 0 !== e
  59951. }
  59952. getActiveRenderTargetDescriptor(e) {
  59953. return this.activeRenderTargetDescriptors[e]
  59954. }
  59955. setActiveRenderTargetDescriptor(e, t) {
  59956. this.activeRenderTargetDescriptors[e] = t;
  59957. }
  59958. bindEvents() {
  59959. this.tileDownloader.addEventListener(TileDownloaderEvents.TileDownloadSuccess, this.onTileDownloaded.bind(this));
  59960. }
  59961. enableUltraHighQualityMode(e) {
  59962. if(config$1.tileClass == "2k"||config$1.tileClass == "1k")return this.enableHighQuality(e)//xzw add 濡傛灉鏈€澶氬彧瑕?k鐨勮瘽
  59963. if (!this.qualityManager.ultraHighQualityModeEnabled()) {
  59964. var t = this.qualityManager.getPanoSize(PanoSizeClass.ULTRAHIGH);
  59965. this.tileDownloader.testDownload(t, TileUtils.TILE_SIZE, function (t) {
  59966. t && (this.qualityManager.enableUltraHighQualityMode(),
  59967. this.setupZoomRenderTarget(),
  59968. e());
  59969. }
  59970. .bind(this));
  59971. }
  59972. }
  59973. activateTiledPano(pano, size, i) {
  59974. i && this.clearAllQueuedUploads();
  59975. for (var n = 0; n < TileUtils.FACES_PER_PANO; n++)
  59976. this.initTileTree(pano.id, n, this.qualityManager.getMaxPossiblePanoSize()); //得到this.tileTrees[pano.id],arr[6]
  59977. this.linkAllTilesAndNodes(pano);
  59978. var r = this.getActiveRenderTargetDescriptor(pano.id),
  59979. l = size;
  59980. l > this.qualityManager.getMaxNavPanoSize() && (l = this.qualityManager.getMaxNavPanoSize());
  59981. if ( !r || l !== r.size) {
  59982. r && this.deactiveDescripor(r.renderTarget);
  59983. r = this.activeDescripor(l);
  59984. if (!r) {
  59985. var ren = this.initTiledPano(l, !1);
  59986. r = this.initDescriptor(ren.width);
  59987. r.renderTarget = ren;
  59988. }
  59989. r.pano = pano;
  59990. this.resetPanoDescriptor(pano.id);
  59991. this.resetPanoLODDescriptors(pano.id);
  59992. this.resetRenderStatus(pano.id, !0, !0);
  59993. }
  59994. this.setActiveRenderTargetDescriptor(pano.id, r);
  59995. var h = i ? 0 : 1;
  59996. this.updateActivePanos(pano, h);
  59997. //console.log(`index:${this.viewer.index} ${r.renderTarget.texture.id} ${pano.id}`)
  59998. return r.renderTarget
  59999. }
  60000. deactivateTiledPano(e) {
  60001. var t = this.getActiveRenderTargetDescriptor(e.id);
  60002. if(this.isRenderTargetDescriptorValid(t)){
  60003. this.deactiveDescripor(t.renderTarget);
  60004. this.setActiveRenderTargetDescriptor(e.id, null);
  60005. }
  60006. var i = this.getUploadQueueForPano(e.id);
  60007. this.clearUploadQueue(i);
  60008. this.updateActivePanos();
  60009. }
  60010. getActivePanoCount() {
  60011. return this.activePanos.length
  60012. }
  60013. resetRenderStatus(e, t, i, n) {
  60014. var r = null;
  60015. n && (r = TileTree.getLevelCountForSize(TileUtils.TILE_SIZE, n) + 1);
  60016. for (var o = function (e, n, r, o) {
  60017. i && (n.tile.zoomUploaded = !1),
  60018. t && (n.tile.uploaded = !1);
  60019. }, a = 0; a < TileUtils.FACES_PER_PANO; a++) {
  60020. var s = this.getTileTree(e, a);
  60021. s.breadthFirst({
  60022. callback: o.bind(this, a),
  60023. minLevel: r
  60024. });
  60025. }
  60026. }
  60027. copyBaseRenderStatusToZoomed(e) {
  60028. for (var t = TileTree.getLevelCountForSize(TileUtils.TILE_SIZE, this.qualityManager.getMaxNavPanoSize()), i = function (e, t, i, n) {
  60029. t.tile.zoomUploaded = t.tile.uploaded,
  60030. t.zoomCovered = t.covered;
  60031. }, n = 0; n < TileUtils.FACES_PER_PANO; n++) {
  60032. var r = this.getTileTree(e, n);
  60033. r.breadthFirst({
  60034. callback: i.bind(this, n),
  60035. maxLevel: t
  60036. });
  60037. }
  60038. }
  60039. isRenderTargetDescriptorValid(e) {
  60040. return e && e.renderTarget
  60041. }
  60042. isPanoActive(e) {
  60043. var t = this.getActiveRenderTargetDescriptor(e);
  60044. return this.isRenderTargetDescriptorValid(t)
  60045. }
  60046. isPanoZoomed(e) {
  60047. return this.zoomingActive && this.zoomPanoId === e
  60048. }
  60049. initTileTree(e, t, i) {
  60050. var n = this.tileTrees[e];
  60051. n || (n = [],
  60052. this.tileTrees[e] = n);
  60053. var r = n[t];
  60054. if (!r) {
  60055. var o = TileTree.getLevelCountForSize(TileUtils.TILE_SIZE, i);
  60056. r = new TileTree(TileUtils.TILE_SIZE, o),
  60057. n[t] = r;
  60058. }
  60059. }
  60060. getTileTree(e, t) {
  60061. var i = this.tileTrees[e];
  60062. if (!i)
  60063. console.error("PanoRenderer.getTileTree() -> Tree array not yet initialized!");
  60064. var n = i[t];
  60065. if (!n)
  60066. console.error("PanoRenderer.getTileTree() -> Tree not yet initialized!");
  60067. return n
  60068. }
  60069. /*
  60070. * 创建tile的renderTarget, 包括pano.tiledPanoRenderTarget和zoomRenderTarget
  60071. * @param {number} size 当前的panoSize,每个面的分辨率
  60072. */
  60073. initTiledPano(size, t) {//创建 RenderTargetCube
  60074. var renderer = this.viewer.renderer;
  60075. var renderTarget, texture;
  60076. renderTarget = new WebGLCubeRenderTarget(size,{ //THREE.WebGLRenderTargetCube(size, size, {
  60077. stencilBuffer: !1
  60078. });
  60079. texture = new CubeTexture([]);
  60080. texture.image = [null, null, null, null, null, null];
  60081. texture.flipY = !0,
  60082. texture.format = RGBAFormat;
  60083. t ? (texture.generateMipmaps = !0,
  60084. texture.magFilter = LinearFilter,
  60085. texture.minFilter = LinearMipMapLinearFilter)
  60086. : (texture.generateMipmaps = !1,
  60087. texture.magFilter = LinearFilter,
  60088. texture.minFilter = LinearFilter);
  60089. renderer.setRenderTarget(renderTarget);
  60090. renderer.setRenderTarget(null);
  60091. var o = renderer.properties.get(texture);
  60092. o.__image__webglTextureCube = o.__webglTexture;
  60093. //window.tex[r.id] = {texture:r, index:this.viewer.index }
  60094. return renderTarget
  60095. }
  60096. getUploadQueueForPano(e) {
  60097. var t = this.uploadQueues[e];
  60098. return t || (t = [],
  60099. this.uploadQueues[e] = t),
  60100. t
  60101. }
  60102. isTileUploaded(e) {
  60103. return this.isPanoZoomed(e.panoId) ? e.zoomUploaded : e.uploaded
  60104. }
  60105. setUploaded(e, t) {
  60106. this.isPanoZoomed(e.panoId) ? e.zoomUploaded = t : e.uploaded = t;
  60107. }
  60108. queueTileUpload(e, t, i) {
  60109. var n = this.getActiveRenderTargetDescriptor(e.panoId);
  60110. if (this.isRenderTargetDescriptorValid(n) && e.downloaded && !this.isTileUploaded(e) && (!e.uploadQueued || i)
  60111. && (!(e.panoSize > this.qualityManager.getMaxNavPanoSize())|| this.zoomingActive)) {
  60112. var r = this.getUploadQueueForPano(e.panoId);
  60113. if(i){
  60114. this.uploadTile(e, !1);//提交
  60115. }else {
  60116. if(this.shoulPushToFrontOfQueue(e)){//如果是512的优先
  60117. this.forceQueue.push(e);
  60118. }else {
  60119. if(t && this.direction){
  60120. TilePrioritizer.insertSortedPanoTile(r, e, n.pano, this.direction);
  60121. }else r.push(e);
  60122. }
  60123. e.uploadQueued = !0;
  60124. this.uploadInterval || this.uploadIntervalCancelled || this.refreshUploadInterval(0);
  60125. }
  60126. }
  60127. }
  60128. shoulPushToFrontOfQueue(e) {
  60129. return 0 === TileTree.getLevelCountForSize(TileUtils.TILE_SIZE, e.panoSize)
  60130. }
  60131. getTopUploadQueue() {
  60132. for (var e = null, t = null, i = S.Base; i <= S.Remaining; i++)
  60133. for (var n = 0; n < this.activePanos.length; n++)
  60134. if (e = this.activePanos[n],
  60135. t = this.getUploadQueueForPano(e.id),
  60136. t.length > 0)
  60137. switch (i) {
  60138. case S.Base:
  60139. if (0 === t[0].level)
  60140. return t;
  60141. break;
  60142. case S.Remaining:
  60143. return t
  60144. }
  60145. return null
  60146. }
  60147. peekNextFromUploadQueue() {
  60148. if (this.forceQueue.length > 0)
  60149. return this.forceQueue[0];
  60150. var e = this.getTopUploadQueue();
  60151. return e && e.length > 0 ? e[0] : null
  60152. }
  60153. clearAllQueuedUploads() {
  60154. this.clearAllUploadQueues(null, 0);
  60155. }
  60156. clearAllQueuedUploadsForPano(e) {
  60157. this.clearAllUploadQueues(e, 0);
  60158. }
  60159. clearAllUploadQueues(e, t) {
  60160. if (e)
  60161. this.clearUploadQueue(this.getUploadQueueForPano(e), t),
  60162. this.clearUploadQueue(this.forceQueue, t, e);
  60163. else {
  60164. for (var i = 0; i < this.activePanos.length; i++) {
  60165. var n = this.activePanos[i];
  60166. this.clearUploadQueue(this.getUploadQueueForPano(n.id), t);
  60167. }
  60168. this.clearUploadQueue(this.forceQueue, t);
  60169. }
  60170. }
  60171. clearUploadQueue(e, t, i) {
  60172. void 0 !== t && null !== t || (t = 0);
  60173. for (var n = 0; n < e.length;) {
  60174. var r = e[n];
  60175. (!i || i && i === r.tile.panoId) && r.level >= t ? (r.uploadQueued = !1,
  60176. e.splice(n, 1)) : n++;
  60177. }
  60178. //若报错, r.tile.panoId改为 r.panoId
  60179. }
  60180. updateUploadQueue(maxNPF,maxPF/* e, t */) {//参数是 maxNonBaseUploadsPerFrame and maxBaseUploadsPerFrame, 优先上传512
  60181. maxNPF || (maxNPF = 1);
  60182. for (var i = 0, n = 0;;) {
  60183. let old = this.forceQueue.slice(0);
  60184. if (n >= maxPF || i >= maxNPF)
  60185. break;
  60186. var r = this.getNextFromUploadQueue();
  60187. if (!r)
  60188. break;
  60189. //r.panoSize <2048 && console.log('panoId', r.panoId, 'panoSize', r.panoSize , old)
  60190. 0 !== r.level ? i++ : n++;
  60191. if (!(r.panoSize > this.qualityManager.getMaxNavPanoSize()) || this.zoomingActive) {
  60192. var o = this.getActiveRenderTargetDescriptor(r.panoId);
  60193. this.isRenderTargetDescriptorValid(o) && this.uploadTile(r, r.forceUpload);
  60194. }
  60195. }
  60196. }
  60197. updateDirection(e) {
  60198. if (e = e || this.direction) {
  60199. this.direction = e;
  60200. for (var t = 0; t < this.activePanos.length; t++) {
  60201. var i = this.activePanos[t],
  60202. n = this.getUploadQueueForPano(i.id);
  60203. TilePrioritizer.sortPanoTiles(n, i, this.direction);
  60204. }
  60205. }
  60206. }
  60207. anyUploaded(e) {
  60208. if (!e)
  60209. return !1;
  60210. if (e.tile && this.isTileUploaded(e.tile))
  60211. return !0;
  60212. if (e.children)
  60213. for (var t = 0; t < e.children.length; t++) {
  60214. var i = e.children[t];
  60215. if (this.anyUploaded(i))
  60216. return !0
  60217. }
  60218. return !1
  60219. }
  60220. setNodeCovered(e, t) {
  60221. this.isPanoZoomed(e.tile.panoId) ? e.zoomCovered = t : e.covered = t;
  60222. }
  60223. isNodeCovered(e) {
  60224. return !!e && (this.isPanoZoomed(e.tile.panoId) ? e.zoomCovered : e.covered)
  60225. }
  60226. addCoverageForNode(e) {
  60227. if (this.setNodeCovered(e, !0),
  60228. e.parent && e.covered) {
  60229. var t = e.parent;
  60230. this.nodeSubcovered(t) && this.addCoverageForNode(t, !0);
  60231. }
  60232. }
  60233. calcFullCoverage(e) {
  60234. var t = !1;
  60235. if (e.children)
  60236. for (var i = 0; i < e.children.length; i++) {
  60237. var n = e.children[i];
  60238. t = t || this.calcFullCoverage(n);
  60239. }
  60240. e.covered = e.tile.uploaded || t;
  60241. }
  60242. nodeSubcovered(e) {
  60243. if (!e.children)
  60244. return !1;
  60245. for (var t = 0; t < e.children.length; t++)
  60246. if (!e.children[t] || !this.isNodeCovered(e.children[t]))
  60247. return !1;
  60248. return !0
  60249. }
  60250. resetPanoDescriptor(e) {
  60251. this.getPanoDescriptor(e);
  60252. }
  60253. getPanoDescriptor(e) {
  60254. var t = this.panoDescriptors[e];
  60255. return t || (t = {},
  60256. this.panoDescriptors[e] = t),
  60257. t
  60258. }
  60259. resetPanoLODDescriptors(e) {
  60260. var t = this.getPanoLODDescriptors(e);
  60261. for (var i in t)
  60262. if (t.hasOwnProperty(i)) {
  60263. var n = t[i];
  60264. n.uploadCount = 0,
  60265. n.uploadAttempts = 0;
  60266. n.uploaded = [];
  60267. }
  60268. }
  60269. getPanoLODDescriptor(e, t) {
  60270. var i = this.getPanoLODDescriptors(e),
  60271. n = i[t];
  60272. return n || (n = {
  60273. uploadCount: 0,
  60274. uploadAttempts: 0,
  60275. uploaded:[],//add
  60276. },
  60277. i[t] = n),
  60278. n
  60279. }
  60280. getPanoLODDescriptors(e) {
  60281. var t = this.panoLODDescriptors[e];
  60282. return t || (t = {},
  60283. this.panoLODDescriptors[e] = t),
  60284. t
  60285. }
  60286. onTileDownloaded(o) {
  60287. var e = o.desc;
  60288. var t = TileTree.getLevelCountForSize(TileUtils.TILE_SIZE, e.panoSize),
  60289. i = this.getTileDirectoryEntry(e.panoId, e.face, t, e.faceTileIndex);
  60290. i.downloaded = !0;
  60291. i.image = e.image;
  60292. i.panoSize = e.panoSize;
  60293. i.tileX = e.tileX;
  60294. i.tileY = e.tileY;
  60295. i.totalTiles = e.totalTiles;
  60296. i.tileIndex = e.tileIndex;
  60297. i.faceTileIndex = e.faceTileIndex;
  60298. i.face = e.face;
  60299. i.cubeFace = TileUtils.mapFaceToCubemapFace(e.face);
  60300. i.panoId = e.panoId;
  60301. i.tileSize = e.tileSize;
  60302. i.direction = (new Vector3).copy(e.direction);
  60303. i.node = null;
  60304. i.level = TileTree.getLevelCountForSize(TileUtils.TILE_SIZE, i.panoSize);
  60305. if (this.isPanoActive(i.panoId)) {
  60306. var n = this.getTileTree(i.panoId, i.face);
  60307. var r = n.getSubNode(i.panoSize, i.tileX, i.tileY);
  60308. this.linkTileAndNode(i, r);
  60309. this.queueTileUpload(i, !0);
  60310. }
  60311. }
  60312. getTileDirectoryEntry(panoId, t, i, n) {
  60313. var r = this.tileDirectory[panoId];
  60314. r || (r = {}, this.tileDirectory[panoId] = r);
  60315. var o = 16384 * t + 1024 * i + n, //t:4096级别
  60316. a = r[o];
  60317. return a || (a = {
  60318. downloaded: !1,
  60319. uploaded: !1,
  60320. zoomUploaded: !1
  60321. },
  60322. r[o] = a),
  60323. a._key = panoId + ":" + t + ":" + i + ":" + n,//panoId : face : level : faceTileIndex
  60324. a._tileKey = o,
  60325. a
  60326. }
  60327. setZoomingActive(active, pano, i) {//设置当前正在zoom的pano
  60328. this.zoomPanoRenderingDisabled || active === this.zoomingActive && this.zoomPanoId === pano.id || (this.zoomingActive = active,
  60329. this.zoomPanoId = pano.id,
  60330. this.zoomingActive && (this.zoomPanoId !== pano.id || i) && this.updateZoomedPanoFromBase(pano));
  60331. }
  60332. updateZoomedPanoFromBase(pano) {//因更换pano所以将pano的rendertarget渲染到panoRenderer的zoomRenderTarget上
  60333. if (!this.zoomPanoRenderingDisabled && this.zoomRenderTarget) {
  60334. var t = this.getActiveRenderTargetDescriptor(pano.id);
  60335. if (t && t.renderTarget ) {
  60336. var i = Math.min(this.qualityManager.maxRenderTargetSize, this.qualityManager.getMaxZoomPanoSize()), //change
  60337. n = t.renderTarget,
  60338. r = t.size;
  60339. this.copyCubeMap(n.texture, this.zoomRenderTarget, r, r, i, i),
  60340. this.copyBaseRenderStatusToZoomed(pano.id);
  60341. }
  60342. }
  60343. }
  60344. add(e) {
  60345. this.M.push(e);
  60346. }
  60347. initDescriptor(size) {
  60348. var t = createDescriptor();
  60349. t.inUse = !0;
  60350. t.size = size;
  60351. this.add(t);
  60352. return t
  60353. }
  60354. activeDescripor(e) {
  60355. for (var t = 0; t < this.M.length; t++) {
  60356. var i = this.M[t];
  60357. if (!i.inUse && i.size === e){
  60358. i.inUse = !0;
  60359. return i
  60360. }
  60361. }
  60362. return null
  60363. }
  60364. deactiveDescripor(e) {
  60365. for (var t = 0; t < this.M.length; t++) {
  60366. var i = this.M[t];
  60367. if (i.renderTarget === e){
  60368. i.inUse = !1;
  60369. return !0
  60370. }
  60371. }
  60372. return !1
  60373. }
  60374. enableHighQuality(e){//xzw add 如果最多只要2k图的话enableUltraHighQualityMode替换成这个
  60375. if (!this.qualityManager.highQualityModeStarted) {
  60376. this.setupZoomRenderTarget();
  60377. e();
  60378. //this.qualityManager.updateHighResolutionSettings(e)////////?
  60379. this.qualityManager.highQualityModeStarted = true;
  60380. }
  60381. }
  60382. linkTileAndNode(e, t) {
  60383. t.tile = e,
  60384. e.node = t;
  60385. }
  60386. linkAllTilesAndNodes(e) {
  60387. var t = function (t, i, n, r, o) {
  60388. var a = this.getTileDirectoryEntry(e.id, i, r, o);
  60389. this.linkTileAndNode(a, n);
  60390. };
  60391. for (var i = 0; i < TileUtils.FACES_PER_PANO; i++) {
  60392. var n = this.getTileTree(e.id, i);
  60393. n.breadthFirst({
  60394. callback: t.bind(this, n, i)
  60395. });
  60396. }
  60397. }
  60398. //--------------sceneRenderer
  60399. initSizedTexture2D(e, t, i) {
  60400. var renderer = this.viewer.renderer,
  60401. o = renderer.getContext(),
  60402. a = renderer.state,
  60403. s = new Texture(null);
  60404. s.flipY = !1,
  60405. i !== !0 && (i = !1),
  60406. s.generateMipmaps = i;
  60407. var l = renderer.paramThreeToGL(s.format),
  60408. c = renderer.paramThreeToGL(s.type),
  60409. h = renderer.properties.get(s),
  60410. u = o.createTexture();
  60411. a.bindTexture(o.TEXTURE_2D, u),
  60412. o.pixelStorei(o.UNPACK_FLIP_Y_WEBGL, s.flipY),
  60413. o.texImage2D(o.TEXTURE_2D, 0, l, e, e, 0, l, c, null),
  60414. s.wrapS = t,
  60415. s.wrapT = t;
  60416. var d = renderer.paramThreeToGL(t);
  60417. return o.texParameteri(o.TEXTURE_2D, o.TEXTURE_WRAP_S, d),
  60418. o.texParameteri(o.TEXTURE_2D, o.TEXTURE_WRAP_T, d),
  60419. i ? (s.magFilter = LinearFilter,
  60420. s.minFilter = LinearMipMapLinearFilter,
  60421. o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MAG_FILTER, o.LINEAR),
  60422. o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MIN_FILTER, o.LINEAR_MIPMAP_NEAREST),
  60423. o.generateMipmap(o.TEXTURE_2D)) : (s.magFilter = LinearFilter,
  60424. s.minFilter = LinearFilter,
  60425. o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MAG_FILTER, o.LINEAR),
  60426. o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MIN_FILTER, o.LINEAR)),
  60427. a.bindTexture(o.TEXTURE_2D, null),
  60428. h.__webglTexture = u,
  60429. s
  60430. }
  60431. deallocateCubeTexture(e) {
  60432. var t = this.viewer.renderer,
  60433. i = t.getContext(),
  60434. renderer = t.properties.get(e);
  60435. i.deleteTexture(renderer.__image__webglTextureCube);
  60436. }
  60437. uploadTexture2D(img, tex, startX, startY, width, height) {
  60438. var renderer = this.viewer.renderer,
  60439. gl = renderer.getContext(),
  60440. webglState = renderer.state,
  60441. c = renderer.properties.get(tex);
  60442. webglState.bindTexture(gl.TEXTURE_2D, c.__webglTexture),
  60443. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, tex.flipY),
  60444. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, tex.premultiplyAlpha),
  60445. gl.pixelStorei(gl.UNPACK_ALIGNMENT, tex.unpackAlignment),
  60446. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, renderer.paramThreeToGL(tex.wrapS)),
  60447. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, renderer.paramThreeToGL(tex.wrapT)),
  60448. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, renderer.paramThreeToGL(tex.magFilter)),
  60449. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, renderer.paramThreeToGL(tex.minFilter)),
  60450. gl.texSubImage2D(gl.TEXTURE_2D, 0, startX, startY, gl.RGBA, gl.UNSIGNED_BYTE, img),
  60451. tex.generateMipmaps && gl.generateMipmap(gl.TEXTURE_2D),
  60452. webglState.bindTexture(gl.TEXTURE_2D, null);
  60453. }
  60454. getCubeOrientationForCubeFace(e, t) {
  60455. switch (e) {
  60456. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  60457. t.set(0, -Math.PI / 2, 0);
  60458. break;
  60459. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  60460. t.set(0, Math.PI / 2, 0);
  60461. break;
  60462. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
  60463. t.set(Math.PI / 2, Math.PI, 0);
  60464. break;
  60465. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  60466. t.set(-Math.PI / 2, Math.PI, 0);
  60467. break;
  60468. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  60469. t.set(0, -Math.PI, 0);
  60470. break;
  60471. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  60472. t.set(0, 0, 0);
  60473. }
  60474. }
  60475. }
  60476. PanoRenderer.prototype.setupZoomRenderTarget = function(){
  60477. var targets = {};
  60478. return function(){
  60479. if(this.qualityManager.maxRenderTargetSize == '2k' && this.qualityManager.getMaxNavPanoSize()=='2k')return; //不使用zoomTarget 直接用pano的tiledPanoRenderTarget,防崩溃
  60480. if (this.qualityManager.getMaxZoomPanoSize() >= this.qualityManager.getMaxNavPanoSize() /* && (config.tileClass != "2k" ||config.tileClass != "1k") */) {
  60481. //部分手机2k时copyCubeMap会重载 , 所以如果没有超出当前分辨率,就不使用zoomRenderTarget。但在微信依旧会重载,只是优化了些,safari几乎不会。
  60482. if (this.zoomRenderTarget && this.zoomRenderTarget.width === this.qualityManager.getMaxZoomPanoSize())
  60483. return;
  60484. var e = this.zoomRenderTarget;
  60485. var size = this.qualityManager.getMaxZoomPanoSize();
  60486. if(size > this.qualityManager.maxRenderTargetSize){
  60487. return
  60488. }
  60489. if(targets[size]){
  60490. this.zoomRenderTarget = targets[size];
  60491. }else {
  60492. this.zoomRenderTarget = this.initTiledPano(size, !1);
  60493. targets[size] = this.zoomRenderTarget;
  60494. }
  60495. if (e) {//将旧的zoomRenderTarget渲染到新zoomRenderTarget上
  60496. var t = e.width,
  60497. i = this.zoomRenderTarget.width;
  60498. this.copyCubeMap(e.texture, this.zoomRenderTarget, t, t, i, i),
  60499. e.texture.dispose(),
  60500. e.texture.loaded = !1,
  60501. e.texture.version = 0,
  60502. this.deallocateCubeTexture(e.texture),
  60503. e.texture = null;
  60504. }
  60505. this.zoomPanoRenderingDisabled = !1;
  60506. } else
  60507. this.zoomPanoRenderingDisabled = !0;
  60508. }
  60509. }();
  60510. PanoRenderer.prototype.updateActivePanos = function () {
  60511. var e = [];
  60512. return function (t, i) {
  60513. e.length = 0;
  60514. for (var n = 0; n < this.activePanos.length; n++) {
  60515. t && e.length === i && e.push(t);
  60516. var r = this.activePanos[n],
  60517. o = this.getActiveRenderTargetDescriptor(r.id);
  60518. t && r.id === t.id || !this.isRenderTargetDescriptorValid(o) || e.push(r);
  60519. }
  60520. t && i >= e.length && e.push(t),
  60521. this.activePanos.length = 0,
  60522. this.activePanos.push.apply(this.activePanos, e);
  60523. }
  60524. }();
  60525. PanoRenderer.prototype.renderPanoTiles = function () {
  60526. var e = [];
  60527. return function (panoId, i, n, r) {
  60528. this.zoomRenderTarget && this.zoomRenderTarget.width === this.qualityManager.getMaxZoomPanoSize() || this.zoomPanoRenderingDisabled || this.setupZoomRenderTarget(),//如果ZoomRenderTarget大小需要变动就重新创建
  60529. i = i || this.direction || Vectors.FORWARD; // [{1:Vectors.FORWARD}]?
  60530. var o = this.getActiveRenderTargetDescriptor(panoId);
  60531. if (!this.isRenderTargetDescriptorValid(o))
  60532. console.error("PanoRenderer.renderPanoTiles() -> Cannot render to a pano that is not activated.");
  60533. for (var a = 0; a < TileUtils.FACES_PER_PANO; a++) {
  60534. var s = this.getTileTree(panoId, a);
  60535. e.length = 0;
  60536. s.breadthFirst({//获取所有node? 85个
  60537. saveVisited: e
  60538. });
  60539. for (var l = 0; l < e.length; l++) {
  60540. var c = e[l];
  60541. this.queueTileUpload(c.tile, !1, r || 0 === l && n);//为什么第0个会直接uploadTile??
  60542. }
  60543. }
  60544. this.updateDirection(i);
  60545. }
  60546. }();
  60547. PanoRenderer.prototype.getNextFromUploadQueue = function () {
  60548. var e = function (e) {
  60549. var t = e.shift();
  60550. return t.uploadQueued = !1,
  60551. t
  60552. };
  60553. return function () {
  60554. if (this.forceQueue.length > 0)
  60555. return e(this.forceQueue);
  60556. var t = this.getTopUploadQueue();
  60557. return t && t.length > 0 ? e(t) : null
  60558. }
  60559. }();
  60560. PanoRenderer.prototype.refreshUploadInterval = function () {
  60561. var e = null;
  60562. return function (t) {
  60563. this.uploadIntervalCancelled || (e || (e = c$1.bind(this)),
  60564. null !== t && void 0 !== t || (t = w),
  60565. b || (t = _),
  60566. this.uploadInterval = window.setTimeout(e, t),
  60567. this.uploadIntervalDelay = t);
  60568. }
  60569. }();
  60570. PanoRenderer.prototype.update = function () {
  60571. var e = performance.now(),
  60572. t = 0;
  60573. return function () {
  60574. this.uploadIntervalCancelled = !0;
  60575. window.clearTimeout(this.uploadInterval);
  60576. this.uploadInterval = null;
  60577. var i = performance.now() - e;
  60578. //!(i > w || 0 === t) || !this.overlayTilesLoaded && this.usingTileOverlay || (this.updateUploadQueue(this.maxNonBaseUploadsPerFrame, this.maxBaseUploadsPerFrame),
  60579. //e = performance.now()),
  60580. if (!(i > w || 0 === t) || !this.overlayTilesLoaded && this.usingTileOverlay) {} else {
  60581. this.updateUploadQueue(this.maxNonBaseUploadsPerFrame, this.maxBaseUploadsPerFrame);
  60582. e = performance.now();
  60583. }
  60584. t++;
  60585. }
  60586. }();
  60587. PanoRenderer.prototype.uploadTile = function () {//重写
  60588. var collection = {},
  60589. overlayStyle = config$1.tiling.overlayStyle;
  60590. var failHistory = {};
  60591. return function (info, n) {
  60592. var id = info.panoId,
  60593. img = info.image,
  60594. tileSize = info.tileSize,
  60595. panoSize = info.panoSize,
  60596. tileIndex = info.tileIndex,
  60597. totalTiles = info.totalTiles,
  60598. tileX = info.tileX,
  60599. tileY = info.tileY,
  60600. p = !0,
  60601. g = !1,
  60602. ignore = false, //add
  60603. LodDescripor = (this.getPanoDescriptor(id), this.getPanoLODDescriptor(id, panoSize)),
  60604. activeDescripor = this.getActiveRenderTargetDescriptor(id),
  60605. renderTarget = activeDescripor.renderTarget,
  60606. size = activeDescripor.size;//当前要渲染的面的分辨率,也就是MaxNavPanoSize
  60607. if (this.isPanoZoomed(id) && this.zoomRenderTarget) {
  60608. renderTarget = this.zoomRenderTarget;
  60609. size = this.zoomRenderTarget.width; //this.qualityManager.getMaxZoomPanoSize(); //放大后可能2048或4096
  60610. }
  60611. let done = ()=>{
  60612. if(!LodDescripor.uploaded.includes(tileIndex)){//已经upload过(本来这时候直接返回,但发现缩放后这不会归零,导致清晰度不更新,所以还是redraw且emit吧)
  60613. //console.log('try to reupload and return',tileIndex)
  60614. LodDescripor.uploaded.push(tileIndex);
  60615. LodDescripor.uploadCount++;
  60616. }
  60617. this.dispatchEvent({type:PanoRendererEvents.TileRenderSuccess, id, panoSize, tileIndex, totalTiles});
  60618. LodDescripor.uploadCount === totalTiles && this.dispatchEvent({type:PanoRendererEvents.PanoRenderComplete, id, panoSize, totalTiles, updateFullComplete:true});
  60619. this.setUploaded(info, !0);
  60620. this.addCoverageForNode(info.node);
  60621. };
  60622. {//已经uploadTile过了不再uploadTile
  60623. if(!this.isRenderTargetDescriptorValid(activeDescripor)){
  60624. p = !1; g = !1;
  60625. }
  60626. if(!n){
  60627. this.anyUploaded(info.node) && (p = !1, g = !0,ignore = true ); //包括子集也uploadTile了
  60628. this.isTileUploaded(info) && (p = !1, g = !1,ignore = true ); //当前tile uploadTile了
  60629. }
  60630. }
  60631. if (p) {
  60632. /*if(failHistory[id+':'+ panoSize+ ':' +tileIndex]){
  60633. console.log('uploadTile retry',id, panoSize, tileIndex)
  60634. }
  60635. console.log('uploadTile 成功', id, panoSize, tileIndex) */
  60636. var C = tileX * tileSize,
  60637. I = tileY * tileSize,
  60638. E = tileSize / panoSize * size, // tile在renderTarget上渲染出的宽度
  60639. b = C / panoSize * size, // tile在renderTarget上渲染的startX
  60640. w = I / panoSize * size; // tile在renderTarget上渲染的startY
  60641. collection[tileSize] || (collection[tileSize] = this.initSizedTexture2D(tileSize, ClampToEdgeWrapping));
  60642. if(panoSize > this.qualityManager.maxRenderTargetSize ){ //4096 改
  60643. var tex = this.initSizedTexture2D(tileSize, ClampToEdgeWrapping);
  60644. var loaded = this.viewer.images360.isHighMapLoaded(info.cubeFace, tileX,tileY);
  60645. }else {
  60646. var tex = collection[tileSize];
  60647. }
  60648. this.uploadTexture2D(img, tex, 0, 0, tileSize, tileSize);//只替换tex对应的img,不新建
  60649. if(panoSize > this.qualityManager.maxRenderTargetSize){
  60650. loaded || this.viewer.images360.updateHighMap(tex, info.cubeFace, tileX,tileY);
  60651. }else {
  60652. if (1 === overlayStyle || 2 === overlayStyle) {
  60653. var T = 1 === overlayStyle ? this.overlayTilesBasic : this.overlayTilesEnhanced;
  60654. this.renderToCubeMap(tex, renderTarget, tileSize, tileSize, 0, 0, tileSize, tileSize, b, w, E, E, info.cubeFace);
  60655. this.renderToCubeMap(T[panoSize], renderTarget, tileSize, tileSize, 0, 0, tileSize, tileSize, b, w, E, E, info.cubeFace, NormalBlending, !0, .5);
  60656. } else {
  60657. this.renderToCubeMap(tex, renderTarget, tileSize, tileSize, 0, 0, tileSize, tileSize, b, w, E, E, info.cubeFace);
  60658. }
  60659. }
  60660. done();
  60661. }else if(ignore){
  60662. //console.log('finish because anyUploaded',id,panoSize,tileIndex)
  60663. done(); //改: 如果因为这部分更高清的贴图已加载所以才不绘制的话,直接完成
  60664. }else {
  60665. //console.log('uploadTile 失败', id, panoSize, tileIndex)
  60666. if(panoSize == 512){
  60667. //console.log("!!!!!!!!!!!!!")
  60668. }
  60669. failHistory[id+':'+ panoSize+ ':' +tileIndex] = true;
  60670. this.setUploaded(info, !1);
  60671. }
  60672. info.uploadAttempted || (LodDescripor.uploadAttempts++, this.dispatchEvent({type:PanoRendererEvents.TileUploadAttempted, id, panoSize, tileIndex, totalTiles})),
  60673. info.uploadAttempted = !0;
  60674. LodDescripor.uploadAttempts === totalTiles && this.dispatchEvent({type:PanoRendererEvents.UploadAttemptedForAllTiles, id, panoSize, totalTiles});
  60675. return g;
  60676. }
  60677. }();
  60678. /*
  60679. 注:tileY的方向同UV,从下到上
  60680. renderToCubeMap里的画布or镜头的xy范围是-0.5到0.5
  60681. */
  60682. PanoRenderer.prototype.renderToCubeMap = function() {
  60683. var inited = !1,
  60684. scene = null,
  60685. camera = null,
  60686. material = null,
  60687. geo = null,
  60688. plane = null,
  60689. l = 1;
  60690. return function(texture, renderTarget, tileWidth, tileHeight, startXinTile, startYinTile, widthinTile, heightinTile, startX, startY, width, height, cubeFace, E, b, w) {
  60691. var renderer = this.viewer.renderer;
  60692. inited || (camera = new OrthographicCamera(l / -2, l / 2, l / 2, l / -2, -200, 200),
  60693. camera.position.z = 150,
  60694. scene = new Scene,
  60695. scene.add(camera),
  60696. material = new ShaderMaterial({
  60697. uniforms: {
  60698. tDiffuse: {
  60699. type: "scene",
  60700. value: null
  60701. },
  60702. alpha: {
  60703. type: "startYinTile",
  60704. value: 1
  60705. }
  60706. },
  60707. vertexShader: Shaders['basicTextured.vs'],
  60708. fragmentShader: Shaders['basicTextured.fs'],
  60709. depthWrite: !1,
  60710. depthTest: !1,
  60711. side: DoubleSide
  60712. }),
  60713. geo = new PlaneBufferGeometry(l, l),
  60714. plane = new Mesh(geo, material),
  60715. plane.position.z = 0,
  60716. scene.add(plane),
  60717. inited = !0);
  60718. var uv = geo.getAttribute("uv");
  60719. uv.setDynamic(!0), //setUsage
  60720. uv.needsUpdate = !0;
  60721. var uvArr = uv.array,
  60722. S = startXinTile / tileWidth, //uv这几个值基本是固定的startXinTile:0,startYinTile:0,widthinTile:512,widthinTile:512,tileWidth:512,tileHeight:512 也就是说uv不会变、每张tile的有效范围是100%
  60723. M = startYinTile / tileHeight,
  60724. R = widthinTile / tileWidth,
  60725. P = heightinTile / tileHeight;
  60726. uvArr[0] = S,
  60727. uvArr[1] = M + P,
  60728. uvArr[2] = S + R,
  60729. uvArr[3] = M + P,
  60730. uvArr[4] = S,
  60731. uvArr[5] = M,
  60732. uvArr[6] = S + R,
  60733. uvArr[7] = M;
  60734. //修改posistion,使该plane只占据需要绘制的部分。类似拼图。
  60735. //startX startY width height 都是在画布上的大小,比如画布大小为2048*2048,此tile为16分之一,tileX是1,tileY是1,则startX=2048/4,startY=2048/4
  60736. var pos = geo.getAttribute("position");
  60737. pos.setDynamic(!0),
  60738. pos.needsUpdate = !0;
  60739. var posArr = pos.array,
  60740. D = startX / renderTarget.width - l / 2 // 起始x
  60741. ,
  60742. N = startY / renderTarget.height - l / 2 // 起始y
  60743. ,
  60744. B = width / renderTarget.width // 宽
  60745. ,
  60746. F = height / renderTarget.height; // 高
  60747. posArr[0] = D,
  60748. posArr[1] = N + F,
  60749. posArr[3] = D + B,
  60750. posArr[4] = N + F,
  60751. posArr[6] = D,
  60752. posArr[7] = N,
  60753. posArr[9] = D + B,
  60754. posArr[10] = N;
  60755. renderer.properties.get(scene);
  60756. material.uniforms.tDiffuse.value = texture;
  60757. material.blending = E || NoBlending,
  60758. material.transparent = !!b;
  60759. void 0 !== w && null !== w || (w = 1),
  60760. material.uniforms.alpha.value = w,
  60761. material.needUpdate = !0;
  60762. //renderTarget.activeCubeFace = cubeFace, //0-5 应该是指定渲染h中的面 失效
  60763. /* renderer.setScissorTest(!0)
  60764. //指定绘制区域,类似遮罩(相对于屏幕)
  60765. renderer.setScissor(startX,startY,width,height) //加上这个会不会快一些,尤其是spherical
  60766. //指定绘制视口位置和大小(相对于屏幕)
  60767. */
  60768. renderTarget.viewport.set(0, 0, renderTarget.width, renderTarget.height);
  60769. var V = renderer.autoClear;
  60770. var oldTarget = renderer.getRenderTarget();
  60771. renderer.autoClear = !1;
  60772. renderer.setRenderTarget(renderTarget, cubeFace);
  60773. renderer.render(scene, camera/* , renderTarget, !1 */);
  60774. renderer.setRenderTarget(oldTarget);
  60775. renderer.autoClear = V;
  60776. //renderer.setScissorTest(!1)
  60777. /* this.renderer.render(scene, camera, this.planeTargets[cubeFace], !1),//针对有的场景app第一个点图加载不成功的问题
  60778. console.log(`图index ${cubeFace} , ${startX}, ${startY}, ${width}, ${height}`)
  60779. this.targetList[cubeFace] || (this.targetList[cubeFace] = [])
  60780. this.targetList[cubeFace].push([startX,startY,width,height])*/
  60781. }
  60782. }();
  60783. /*
  60784. * 将texture渲染到zoomRenderTarget上(目的是复制贴图到zoomRenderTarget)
  60785. */
  60786. PanoRenderer.prototype.copyCubeMap = function() {//将texture渲染到zoomRenderTarget上
  60787. var inited = !1,
  60788. scene = null,
  60789. camera = null,
  60790. material = null,
  60791. geo = null,
  60792. mesh = null,
  60793. testCube = null, //add
  60794. c = new Euler;
  60795. return function(texture, renderTarget, tWidth, tHeight, rWidth, rHeight, m, v, A) {
  60796. if(rWidth > this.qualityManager.maxRenderTargetSize) return; //add
  60797. if (!inited) {
  60798. var w = 2;
  60799. camera = new OrthographicCamera(w / -2, w / 2, w / 2, w / -2, 0, 200),
  60800. camera.position.set(0, 0, 0),
  60801. scene = new Scene,
  60802. scene.add(camera);
  60803. material = new ShaderMaterial({
  60804. uniforms: {
  60805. tDiffuse: {
  60806. type: "t",
  60807. value: null
  60808. },
  60809. alpha: {
  60810. type: "f",
  60811. value: 1
  60812. }
  60813. },
  60814. vertexShader: Shaders['copyCubeMap.vs'],
  60815. fragmentShader:Shaders['copyCubeMap.fs'],
  60816. depthWrite: !1,
  60817. depthTest: !1,
  60818. side: DoubleSide
  60819. });
  60820. geo = new BoxGeometry(w, w, w),
  60821. mesh = new Mesh(geo, material),
  60822. scene.add(mesh);
  60823. inited = !0;
  60824. /* testCube = mesh.clone();
  60825. viewer.scene.scene.add(testCube);
  60826. viewer.setObjectLayers(testCube, 'sceneObjects')
  60827. */
  60828. }
  60829. let autoClear = this.viewer.renderer.autoClear;
  60830. let oldTarget = this.viewer.renderer.getRenderTarget();
  60831. this.viewer.renderer.autoClear = false;
  60832. material.uniforms.tDiffuse.value = texture;
  60833. material.blending = m || NoBlending;
  60834. material.transparent = !!v;
  60835. void 0 !== A && null !== A || (A = 1);
  60836. material.uniforms.alpha.value = A;
  60837. material.needUpdate = !0;
  60838. for (var C = 0; C < 6; C++){
  60839. this.getCubeOrientationForCubeFace(C, c);
  60840. mesh.rotation.copy(c);
  60841. mesh.matrixWorldNeedsUpdate = !0;
  60842. mesh.updateMatrixWorld();
  60843. renderTarget.viewport.set(0, 0, rWidth, rHeight);
  60844. this.viewer.renderer.setRenderTarget(renderTarget, C ); //renderTarget.activeCubeFace = C//失效
  60845. this.viewer.renderer.render(scene, camera);
  60846. }
  60847. //console.warn('copyCubeMap' + rWidth)
  60848. this.viewer.renderer.autoClear = autoClear;
  60849. this.viewer.renderer.setRenderTarget(oldTarget);
  60850. }
  60851. }();
  60852. class DepthImageSampler {
  60853. constructor(){
  60854. var canvas = document.createElement("canvas");
  60855. this.canvas = canvas;
  60856. this.context = canvas.getContext("2d");
  60857. /* document.getElementsByTagName('body')[0].appendChild(canvas);
  60858. canvas.style.position = 'fixed';
  60859. canvas.style.width = '1024px';
  60860. canvas.style.top = canvas.style.left = 0
  60861. canvas.style['z-index'] = 100
  60862. */
  60863. }
  60864. changeImg(img){
  60865. if(this.img == img)return
  60866. this.canvas.width = img.width;
  60867. this.canvas.height = img.height;
  60868. this.context.drawImage(img, 0, 0);
  60869. this.img = img;
  60870. }
  60871. getDepth(UVx, UVy) {//根据图片像素获取深度值
  60872. var x = Math.round(UVx * (this.canvas.width - 1))
  60873. , y = Math.round(UVy * (this.canvas.height - 1));
  60874. if (!(x < 0 || y < 0 || x >= this.width || y >= this.height)) {
  60875. var r = this.context.getImageData(x, y, 1, 1).data;
  60876. //console.log('color', r, x,y)
  60877. return r[1] + r[0] / 256
  60878. }
  60879. }
  60880. sample( intersect, currentPano, onlyPos ) {//通过和skybox的intersect得到真实的intersect的位置
  60881. if(!intersect)return
  60882. let location = new THREE.Vector3;
  60883. let normal;
  60884. currentPano = currentPano || viewer.images360.currentPano;
  60885. if(currentPano != this.currentPano){
  60886. if(!currentPano.depthTex/* || !currentPano.depthTex.image */) return //未加载
  60887. this.changeImg(currentPano.depthTex.image);
  60888. this.currentPano = currentPano;
  60889. }
  60890. let origin = currentPano.position;
  60891. let dir = intersect.dir || new THREE.Vector3().subVectors(intersect.point, origin).normalize();
  60892. //var uv = intersect.uv
  60893. //let dirInPano = math.getNormalDir(dir, currentPano)//转化为考虑漫游点旋转的方向
  60894. let dirInPano = dir.clone().applyMatrix4(currentPano.panoMatrix2Inverse).normalize(); //转化为考虑漫游点旋转的方向
  60895. let uv = math.getUVfromDir(dirInPano);//转化为uv
  60896. let distance = this.getDepth(uv.x, uv.y);
  60897. //console.log('depth', depth, uv.y)
  60898. if (!distance){
  60899. if(uv.y > 0.75){//漫游点底部识别不到的区域,给一个地板高度
  60900. //let height = origin.distanceTo(currentPano.floorPosition);
  60901. const margin = 0.1;
  60902. distance = (currentPano.floorPosition.z - origin.z - margin) / dir.z;
  60903. location.copy(dir).multiplyScalar(distance).add(origin);
  60904. let normal = new THREE.Vector3(0,0,1);
  60905. return {location, normal, distance}
  60906. }
  60907. else return !1; //应该是天空或模型外 , 因为很少有漫游点的地方还拍不到地板
  60908. }
  60909. //this.mainDepth = depth
  60910. location.copy(dir).multiplyScalar(distance).add(origin);
  60911. if(!onlyPos){
  60912. var pL = this.getNearbyPoint(origin, uv, -1, 0)
  60913. , pR = this.getNearbyPoint(origin, uv, 1, 0)
  60914. , pB = this.getNearbyPoint(origin, uv, 0, -1)
  60915. , pT = this.getNearbyPoint(origin, uv, 0, 1);
  60916. normal = this.planeFit(dir,location, pL,pR,pB,pT );
  60917. }
  60918. /* if(normal.x != normal.x ){
  60919. console.log('NAN', normal)
  60920. var pL = this.getNearbyPoint(origin, uv, -1, 0)
  60921. , pR = this.getNearbyPoint(origin, uv, 1, 0)
  60922. , pB = this.getNearbyPoint(origin, uv, 0, -1)
  60923. , pT = this.getNearbyPoint(origin, uv, 0, 1);
  60924. } */
  60925. //console.log('normal',normal)
  60926. return {location, normal, distance}
  60927. }
  60928. getNearbyPoint( origin, uv, x, y) { //获取附近的若干像素距离的点
  60929. let uv2 = uv.clone();
  60930. uv2.x += x/(this.canvas.width-1);
  60931. uv2.x = this.clampUV(uv2.x);
  60932. uv2.y += y/(this.canvas.height-1);
  60933. uv2.y = this.clampUV(uv2.y);
  60934. /* if(uv2.x < 0 || uv2.y < 0 || uv2.x > 1 || uv2.y > 1){
  60935. console.log('will nan')
  60936. } */
  60937. let dir = math.getDirFromUV(uv2);//从uv获取到方向
  60938. dir.applyMatrix4(viewer.images360.currentPano.panoMatrix2);
  60939. let depth = this.getDepth(uv2.x, uv2.y);
  60940. /* if(Math.abs(depth - this.mainDepth) > 0.3){
  60941. console.log('Math.abs(depth - this.mainDepth) > 0.3')
  60942. } */
  60943. //let dir = new THREE.Vector3().subVectors(intersect.point, origin).normalize()
  60944. let position = new THREE.Vector3().copy(dir).multiplyScalar(depth).add(origin);
  60945. //console.log('getNearbyPoint', uv2, depth, dir, position )
  60946. return position
  60947. }
  60948. clampUV(v){
  60949. return (v + 1) % 1; // 使输出在 0-1
  60950. }
  60951. planeFit(dir, position, pL,pR,pB,pT ) {//求平均法线
  60952. let normal = new THREE.Vector3;
  60953. let plane = new THREE.Plane;
  60954. function addNormal(p1, p2) {//根据临接的四个点,分别求法线,然后法线相加能得到平均法线
  60955. if(!p1 || !p2)return
  60956. plane.setFromCoplanarPoints(position, p1, p2);
  60957. //console.log('normalSub', plane.normal)
  60958. normal.addScaledVector(plane.normal, dir.dot(plane.normal) < 0 ? 1 : -1);//根据面的朝向判断加还是减
  60959. }
  60960. addNormal(pL, pB);
  60961. addNormal(pL, pT);
  60962. addNormal(pR, pB);
  60963. addNormal(pR, pT);
  60964. if(0 !== normal.x || 0 !== normal.y || 0 !== normal.z){
  60965. normal.normalize();
  60966. //console.log(normal)
  60967. return normal
  60968. }
  60969. /* 四个面拼成一个菱形 */
  60970. }
  60971. /* makeUvToPosMap(intersect, matrix1, vec1, vec2) {
  60972. var o = intersect.object.geometry
  60973. , a = o.attributes.position.array
  60974. , s = new THREE.Vector3(a[3 * intersect.face.a],a[3 * intersect.face.a + 1],a[3 * intersect.face.a + 2]).applyMatrix4(intersect.object.matrixWorld)
  60975. , c = new THREE.Vector3(a[3 * intersect.face.b],a[3 * intersect.face.b + 1],a[3 * intersect.face.b + 2]).applyMatrix4(intersect.object.matrixWorld)
  60976. , l = new THREE.Vector3(a[3 * intersect.face.c],a[3 * intersect.face.c + 1],a[3 * intersect.face.c + 2]).applyMatrix4(intersect.object.matrixWorld);
  60977. vec1.subVectors(s, c),
  60978. vec2.subVectors(l, c);
  60979. var u = o.attributes.uv.array
  60980. , d = new THREE.Vector2(u[2 * intersect.face.a],u[2 * intersect.face.a + 1])
  60981. , p = new THREE.Vector2(u[2 * intersect.face.b],u[2 * intersect.face.b + 1])
  60982. , h = new THREE.Vector2(u[2 * intersect.face.c],u[2 * intersect.face.c + 1])
  60983. , f = d.sub(p)
  60984. , g = h.sub(p);
  60985. matrix1.set(f.x, g.x, 0, f.y, g.y, 0, 0, 0, 1),
  60986. matrix1.getInverse(matrix1)
  60987. } */
  60988. /* getNearbyPoint( point, origin, uv, o, a, s, x, y) {
  60989. var add = new THREE.Vector3(x, y , 0 )
  60990. , depth = this.getDepth(uv.x + add.x, uv.y + add.y );
  60991. if (void 0 !== depth) {
  60992. var f = add.applyMatrix3(o);
  60993. return (new THREE.Vector3).addScaledVector(a, f.x).addScaledVector(s, f.y).add(point).sub(origin).normalize().multiplyScalar(depth).add(origin)
  60994. }
  60995. } */
  60996. }
  60997. /* var i = n(4)
  60998. , r = function() {
  60999. function t(t) {
  61000. }
  61001. return t.prototype.getDepth = function(t, e) {
  61002. var n = Math.round(t)
  61003. , i = Math.round(e);
  61004. if (!(n < 0 || i < 0 || n >= this.width || i >= this.height)) {
  61005. var r = this.context.getImageData(n, i, 1, 1).data;
  61006. return r[1] + r[0] / 256
  61007. }
  61008. }
  61009. ,
  61010. Object.defineProperty(t.prototype, "width", {
  61011. get: function() {
  61012. return this.context.canvas.width
  61013. },
  61014. enumerable: !0,
  61015. configurable: !0
  61016. }),
  61017. Object.defineProperty(t.prototype, "height", {
  61018. get: function() {
  61019. return this.context.canvas.height
  61020. },
  61021. enumerable: !0,
  61022. configurable: !0
  61023. }),
  61024. t
  61025. }();
  61026. e.CanvasDepthImage = r;
  61027. var o = function() {
  61028. function t() {}
  61029. return t.sample = function(e, n, r, o, a) {
  61030. var s = n.uv
  61031. , c = s.x * (e.width - 1)
  61032. , l = (1 - s.y) * (e.height - 1)
  61033. , u = e.getDepth(c, l);
  61034. if (!u)
  61035. return !1;
  61036. o.copy(n.point).sub(r).normalize().multiplyScalar(u).add(r);
  61037. var d = new i.Matrix3
  61038. , p = new i.Vector3
  61039. , h = new i.Vector3;
  61040. t.makeUvToPosMap(n, d, p, h);
  61041. var f = this.getNearbyPoint(e, n.point, r, s, d, p, h, -1, 0)
  61042. , g = this.getNearbyPoint(e, n.point, r, s, d, p, h, 1, 0)
  61043. , m = this.getNearbyPoint(e, n.point, r, s, d, p, h, 0, -1)
  61044. , v = this.getNearbyPoint(e, n.point, r, s, d, p, h, 0, 1);
  61045. return this.planeFit(o, r, f, g, m, v, a)
  61046. }
  61047. ,
  61048. t.makeUvToPosMap = function(t, e, n, r) {
  61049. var o = t.object.geometry
  61050. , a = o.attributes.position.array
  61051. , s = new i.Vector3(a[3 * t.face.a],a[3 * t.face.a + 1],a[3 * t.face.a + 2]).applyMatrix4(t.object.matrixWorld)
  61052. , c = new i.Vector3(a[3 * t.face.b],a[3 * t.face.b + 1],a[3 * t.face.b + 2]).applyMatrix4(t.object.matrixWorld)
  61053. , l = new i.Vector3(a[3 * t.face.c],a[3 * t.face.c + 1],a[3 * t.face.c + 2]).applyMatrix4(t.object.matrixWorld);
  61054. n.subVectors(s, c),
  61055. r.subVectors(l, c);
  61056. var u = o.attributes.uv.array
  61057. , d = new i.Vector2(u[2 * t.face.a],u[2 * t.face.a + 1])
  61058. , p = new i.Vector2(u[2 * t.face.b],u[2 * t.face.b + 1])
  61059. , h = new i.Vector2(u[2 * t.face.c],u[2 * t.face.c + 1])
  61060. , f = d.sub(p)
  61061. , g = h.sub(p);
  61062. e.set(f.x, g.x, 0, f.y, g.y, 0, 0, 0, 1),
  61063. e.getInverse(e)
  61064. }
  61065. ,
  61066. t.getNearbyPoint = function(t, e, n, r, o, a, s, c, l) {
  61067. var u = new i.Vector3(c / (t.width - 1),l / (t.height - 1))
  61068. , d = (r.x + u.x) * (t.width - 1)
  61069. , p = (1 - (r.y + u.y)) * (t.height - 1)
  61070. , h = t.getDepth(d, p);
  61071. if (void 0 !== h) {
  61072. var f = u.applyMatrix3(o);
  61073. return (new i.Vector3).addScaledVector(a, f.x).addScaledVector(s, f.y).add(e).sub(n).normalize().multiplyScalar(h).add(n)
  61074. }
  61075. }
  61076. ,
  61077. t.planeFit = function(t, e, n, r, o, a, s) {
  61078. s.set(0, 0, 0);
  61079. var c = t.clone().sub(e)
  61080. , l = new i.Plane;
  61081. function u(e, n) {
  61082. e && n && (l.setFromCoplanarPoints(t, e, n),
  61083. s.addScaledVector(l.normal, c.dot(l.normal) < 0 ? 1 : -1))
  61084. }
  61085. return u(n, o),
  61086. u(n, a),
  61087. u(r, o),
  61088. u(r, a),
  61089. (0 !== s.x || 0 !== s.y || 0 !== s.z) && (s.normalize(),
  61090. !0)
  61091. }
  61092. ,
  61093. t
  61094. }();
  61095. */
  61096. var rot90$1 = new Quaternion().setFromAxisAngle(new Vector3(0,0,1), Math.PI/2 ); //使用的是刚好适合全景图的,给cube贴图需要转90°
  61097. let raycaster = new Raycaster();
  61098. //let currentlyHovered = null;
  61099. let texLoader$3 = new TextureLoader();
  61100. let sm$1 = new MeshBasicMaterial({side: BackSide});
  61101. let tileArr = [];
  61102. let previousView = {
  61103. controls: null,
  61104. position: null,
  61105. target: null,
  61106. };
  61107. const HighMapCubeWidth = 1;
  61108. const directionFactor = 200; //原先10,几乎只往距离近的走了;设置太大楼梯上不去
  61109. class Images360 extends EventDispatcher{
  61110. constructor(viewer ){
  61111. super();
  61112. this.viewer = viewer;
  61113. this.selectingEnabled = true;
  61114. this.panos = [];
  61115. this.neighbourMap = {};
  61116. this.node = new Object3D();
  61117. this.node.name = 'ImagesNode';
  61118. //this.node2 = new THREE.Object3D();
  61119. this.cubePanos = [];
  61120. this.cube = new Mesh(new BoxBufferGeometry(1,1,1,1),new ModelTextureMaterial());
  61121. viewer.updateVisible(this.cube,'showSkybox', false );
  61122. this.cube.layers.set(Potree.config.renderLayers.skybox);
  61123. this.cube.name = 'skyboxCube';
  61124. viewer.scene.scene.add(this.cube);
  61125. this._visible = true;
  61126. this.currentPano = null;
  61127. this.mouseLastMoveTime = Date.now();
  61128. this.scrollZoomSpeed = 0.06;
  61129. this.zoomLevel = 1;
  61130. this.tileDownloader = new TileDownloader;
  61131. this.qualityManager = new QualityManager;
  61132. this.panoRenderer = new PanoRenderer(viewer, this.tileDownloader, this.qualityManager);
  61133. this.basePanoSize = this.qualityManager.getPanoSize(PanoSizeClass.BASE);
  61134. this.standardPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.STANDARD);
  61135. this.highPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.HIGH);
  61136. this.ultraHighPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.ULTRAHIGH);
  61137. this.tileDownloader.processPriorityQueue = !1;
  61138. this.tileDownloader.tilePrioritizer = new TilePrioritizer(this.qualityManager, this.basePanoSize, this.standardPanoSize, this.highPanoSize, this.ultraHighPanoSize);
  61139. this.flying_ = false;
  61140. {//高分辨率cube 放大
  61141. this.addHighMapCube();
  61142. viewer.addEventListener(PanoramaEvents.Enter,(e)=>{
  61143. this.setHighMap(e.newPano);
  61144. });
  61145. viewer.addEventListener('panoSetZoom',(e)=>{
  61146. if(Potree.settings.displayMode == 'showPanos'){
  61147. e.zoomed ? this.showHighMap() : this.hideHighMap(); //add
  61148. }
  61149. });
  61150. }
  61151. this.depthSampler = new DepthImageSampler();
  61152. this.addEventListener('loadedDepthImg',(e)=>{
  61153. this.updateDepthTex(e.pano);
  61154. });
  61155. let scroll = (e)=>{
  61156. if(e.hoverViewport != viewer.mainViewport)return
  61157. /* if(Potree.settings.displayMode == 'showPanos' && Potree.settings.zoom.enabled){
  61158. } */
  61159. };
  61160. viewer.fpControls.addEventListener('dollyStopCauseUnable',(e)=>{
  61161. if(/* e.hoverViewport != viewer.mainViewport || */!Potree.settings.zoom.enabled)return
  61162. if(e.scale != void 0){//触屏
  61163. this.zoomBy(e.scale, e.pointer);
  61164. }else {//滚轮
  61165. let zoom;
  61166. if(e.delta > 0){
  61167. zoom = 1 + this.scrollZoomSpeed;
  61168. }else {
  61169. zoom = 1 - this.scrollZoomSpeed;
  61170. }
  61171. e.delta != 0 && this.zoomBy(zoom);
  61172. }
  61173. });
  61174. let click = (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发
  61175. if(Potree.settings.unableNavigate || this.flying || !e.isTouch && e.button != MOUSE.LEFT || e.drag && e.drag.object //拖拽结束时不算
  61176. || Potree.settings.editType == 'pano' && viewer.modules.PanoEditor.activeViewName != 'mainView'
  61177. || Potree.settings.editType == 'merge' && !e.intersectPoint || viewer.inputHandler.hoveredElements[0] && viewer.inputHandler.hoveredElements[0].isModel && e.intersectPoint.distance > viewer.inputHandler.hoveredElements[0].distance
  61178. ) return
  61179. if(Potree.settings.editType != 'pano' && Potree.settings.editType != 'merge'){
  61180. if( e.hoverViewport == viewer.mapViewer.viewports[0]){
  61181. return viewer.mapViewer.dispatchEvent(e/* {type:'global_click',e } */)
  61182. }else if(e.hoverViewport != viewer.mainViewport){ //如数据集校准其他viewport
  61183. return
  61184. }
  61185. }
  61186. /* if(currentlyHovered && currentlyHovered.pano){
  61187. this.focusPano(currentlyHovered.pano);
  61188. }else{//add */
  61189. if(!Potree.settings.dblToFocusPoint/* && this.currentPano */){//双击不会focus点云 或者 已经focusPano了
  61190. this.flyToPanoClosestToMouse();
  61191. }
  61192. //}
  61193. };
  61194. viewer.addEventListener('global_click' , click);
  61195. viewer.addEventListener("global_mousemove", (e) => {
  61196. if(!Potree.settings.unableNavigate && Potree.settings.ifShowMarker && e.hoverViewport == viewer.mainViewport){//如果不显示marker,就在点击时再更新
  61197. this.updateClosestPano(e.intersectPoint);
  61198. }
  61199. });
  61200. this.addEventListener('markerHover',(e)=>{
  61201. this.updateClosestPano(e.pano, e.hovered);
  61202. });
  61203. if(!Potree.settings.isOfficial){
  61204. this.domRoot = viewer.renderer.domElement.parentElement;
  61205. let elUnfocus = $("<input type='button' value='unfocus'></input>");
  61206. elUnfocus.css({
  61207. position : "absolute",
  61208. right : '25%',
  61209. bottom: '20px',
  61210. zIndex: "10000",
  61211. fontSize:'1em', color:"black",
  61212. display:'none',
  61213. background:'rgba(255,255,255,0.8)',
  61214. });
  61215. elUnfocus.on("click", () => this.unfocus());
  61216. this.elUnfocus = elUnfocus;
  61217. this.domRoot.appendChild(elUnfocus[0]);
  61218. if(Potree.settings.editType != 'merge'){
  61219. let elHide = $("<input type='button' value='隐藏点云'></input>");
  61220. elHide.css({
  61221. position : "absolute",
  61222. right : '40%',
  61223. bottom: '20px',
  61224. zIndex: "10000",
  61225. fontSize:'1em' ,color:"black",
  61226. width : '100px',
  61227. background:'rgba(255,255,255,0.8)',
  61228. });
  61229. this.domRoot.appendChild(elHide[0]);
  61230. elHide.on("click", (e) => {
  61231. let visi = viewer.getObjVisiByReason(viewer.scene.pointclouds[0], 'force');
  61232. viewer.scene.pointclouds.forEach(e=>{
  61233. viewer.updateVisible(e, 'force', !visi);
  61234. });
  61235. elHide.val(!visi ? "隐藏点云" : "显示点云");
  61236. });
  61237. }
  61238. let elDisplayModel = $("<input type='button' value='>>全景'></input>");
  61239. elDisplayModel.css({
  61240. position : "absolute",
  61241. right : '65%',
  61242. bottom: '20px',
  61243. zIndex: "10000",
  61244. fontSize:'1em',color:"black",
  61245. width : '100px',
  61246. background:'rgba(255,255,255,0.8)',
  61247. });
  61248. this.domRoot.appendChild(elDisplayModel[0]);
  61249. elDisplayModel.on("click", (e) => {
  61250. if(Potree.settings.displayMode == 'showPointCloud' && this.panos.length == 0)return
  61251. Potree.settings.displayMode = Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud';
  61252. });
  61253. this.elDisplayModel = elDisplayModel;
  61254. }
  61255. {//切换模式
  61256. let displayMode = '';
  61257. let latestRequestMode = '';//因为可能延迟,所以记录下每次的请求模式,延迟后判断这个
  61258. Object.defineProperty(Potree.settings , "displayMode",{
  61259. get: function() {
  61260. return displayMode
  61261. },
  61262. set: (mode)=> {
  61263. latestRequestMode = mode;
  61264. console.warn('Request setMode: ' + mode);
  61265. if(mode != displayMode){
  61266. let config = Potree.config.displayMode[mode];
  61267. let config2;
  61268. let camera = viewer.scene.getActiveCamera();
  61269. if(mode == 'showPanos' && viewer.mainViewport.view.isFlying()){//飞完才能切换全景
  61270. let f = ()=>{
  61271. if(latestRequestMode == mode){//如果ui还是停在这个模式的话
  61272. Potree.settings.displayMode = mode;
  61273. }
  61274. viewer.mainViewport.view.removeEventListener('flyingDone', f);
  61275. };
  61276. viewer.mainViewport.view.addEventListener('flyingDone', f); //once
  61277. return
  61278. }
  61279. if(this.isAtPano() ){//this.currentPano
  61280. if(this.flying)config2 = config.transition;
  61281. else config2 = config.atPano;
  61282. }else {
  61283. config2 = config.atPano;
  61284. if(mode == 'showPanos'){//自动飞入一个pano
  61285. //要改成飞进最近的。。。
  61286. if(this.panos.length == 0)return
  61287. //this.modeChanging = true //主要是因为到全景图不会立刻成功
  61288. let wait = ()=>{
  61289. this.removeEventListener('flyToPanoDone',wait);
  61290. if(latestRequestMode == mode ){
  61291. Potree.settings.displayMode = mode;
  61292. }
  61293. };
  61294. this.flyToPano({
  61295. pano: this.findNearestPano(),
  61296. //dealDoneWhenCancel:true,
  61297. /* callback: ()=>{
  61298. setTimeout(()=>{ //防止循环,所以延迟
  61299. if(latestRequestMode == mode ){
  61300. Potree.settings.displayMode = mode
  61301. }
  61302. },1)
  61303. } */
  61304. });
  61305. this.addEventListener('flyToPanoDone',wait); //等待飞行完毕。flyToPano的callback可能不执行所以换这个。但也可能被cancel
  61306. return;
  61307. }else {
  61308. }
  61309. }
  61310. if(config2.showSkybox || config2.showPoint && config2.pointUsePanoTex){
  61311. this.tileDownloader.start();
  61312. }else {
  61313. this.tileDownloader.stop();
  61314. }
  61315. if(config2.showSkybox || config2.pointUsePanoTex){
  61316. let wait = ()=> {
  61317. setTimeout( ()=>{
  61318. if(latestRequestMode == mode ){
  61319. Potree.settings.displayMode = mode;
  61320. }
  61321. },1);
  61322. this.removeEventListener('loadedDepthImg', wait);
  61323. };
  61324. if(!this.currentPano.depthTex && this.currentPano.pointcloud.hasDepthTex){
  61325. this.addEventListener('loadedDepthImg', wait);
  61326. return this.currentPano.loadDepthImg()
  61327. }
  61328. //this.updateDepthTex()
  61329. if(this.checkAndWaitForPanoLoad(this.currentPano, this.basePanoSize, wait)){
  61330. return
  61331. }
  61332. }
  61333. viewer.scene.pointclouds.forEach(e=>{
  61334. viewer.updateVisible(e, 'displayMode', config2.showPoint, 2 );
  61335. });
  61336. if(config2.pointUsePanoTex){
  61337. viewer.scene.pointclouds.forEach(e=>{
  61338. e.material.setProjectedPanos(this.currentPano,this.currentPano, 1);
  61339. });
  61340. }else {
  61341. viewer.scene.pointclouds.forEach(e=>{
  61342. e.material.stopProjectedPanos();
  61343. });
  61344. }
  61345. viewer.updateVisible(this.cube,'showSkybox',config2.showSkybox );// this.cube.visible = config2.showSkybox
  61346. //this.cube.visible = config.atPano.showSkybox
  61347. if(this.cube.visible){
  61348. //this.cube.material.setProjectedPanos(this.currentPano, this.currentPano, 1)
  61349. this.setProjectedPanos({
  61350. progress:1,
  61351. ifSkybox: true,
  61352. ifPointcloud : false,
  61353. easeInOutRatio : 0,
  61354. pano0:this.currentPano,
  61355. pano1:this.currentPano
  61356. });
  61357. }else {
  61358. this.smoothZoomTo(1);
  61359. this.resetHighMap();
  61360. this.hideHighMap();
  61361. }
  61362. /* viewer.dispatchEvent({
  61363. type: "enableChangePos",
  61364. canLeavePano : config.canLeavePano ,
  61365. viewport:
  61366. }) */
  61367. //viewer.mainViewport.unableChangePos = !config.canLeavePano
  61368. displayMode = mode;
  61369. if(mode == 'showPanos'){
  61370. camera.far = viewer.farWhenShowPano; //修改far
  61371. Potree.settings.pointDensity = 'panorama';
  61372. if(Potree.config.displayMode.showPanos.transition.pointUsePanoTex){
  61373. viewer.scene.pointclouds.forEach(e=>{
  61374. e.material.pointSizeType = 'FIXED';
  61375. });
  61376. }
  61377. this.updateCube(this.currentPano);
  61378. }else {
  61379. if(camera.limitFar) camera.far = Potree.settings.cameraFar;//修改far
  61380. Potree.settings.pointDensity = Potree.settings.UserPointDensity;
  61381. //Potree.sdk && Potree.sdk.scene.changePointOpacity()
  61382. if(Potree.config.displayMode.showPanos.transition.pointUsePanoTex){
  61383. viewer.scene.pointclouds.forEach(e=>{
  61384. e.material.pointSizeType = Potree.config.material.pointSizeType;
  61385. });
  61386. }
  61387. }
  61388. camera.updateProjectionMatrix();
  61389. if(this.elDisplayModel){
  61390. this.elDisplayModel.val( mode == 'showPointCloud' ? ">>全景" : '>>点云');
  61391. }
  61392. /* this.panos.forEach(e=>{
  61393. viewer.updateVisible(e, 'modeIsShowPanos', mode == 'showPanos', 1, mode == 'showPanos' ? 'add':'cancel') //
  61394. }) */
  61395. this.dispatchEvent({type:'endChangeMode',mode});
  61396. console.log('setModeSuccess: ' + mode);
  61397. }else {
  61398. //this.dispatchEvent({type:'endChangeMode',mode})
  61399. }
  61400. }
  61401. });
  61402. Potree.settings.displayMode = 'showPointCloud';
  61403. }// 切换模式 end
  61404. {//
  61405. let currentPano = null;
  61406. Object.defineProperty(this , "currentPano",{
  61407. get: function() {
  61408. return currentPano
  61409. },
  61410. set: function(e) {
  61411. if(e != currentPano){
  61412. currentPano && currentPano.exit();
  61413. e && e.enter();
  61414. currentPano = e;
  61415. }
  61416. }
  61417. });
  61418. }
  61419. {//是否显示marker
  61420. let ifShowMarker = true;
  61421. Object.defineProperty(Potree.settings, "ifShowMarker",{
  61422. get: function() {
  61423. return ifShowMarker
  61424. },
  61425. set: (show)=>{
  61426. show = !!show;
  61427. if(show != ifShowMarker){
  61428. this.panos.forEach(pano=>{
  61429. viewer.updateVisible(pano, 'ifShowMarker', show, 1 );
  61430. });
  61431. //this.emit('markersDisplayChange', show)
  61432. ifShowMarker = show;
  61433. }
  61434. }
  61435. });
  61436. }
  61437. viewer.addEventListener("update", () => {
  61438. this.update(viewer);
  61439. });
  61440. //viewer.inputHandler.addInputListener(this);
  61441. var keys = {
  61442. FORWARD: ['W'.charCodeAt(0), 38],
  61443. BACKWARD: ['S'.charCodeAt(0), 40],
  61444. LEFT: ['A'.charCodeAt(0), 37],
  61445. RIGHT: ['D'.charCodeAt(0), 39],
  61446. };
  61447. viewer.inputHandler.addEventListener('keydown',(e)=>{
  61448. if(Potree.settings.displayMode == 'showPanos'){
  61449. for(let i in keys){
  61450. if(keys[i].some(a => a == e.keyCode)){
  61451. switch(i){
  61452. case 'FORWARD':
  61453. this.flyLocalDirection(Vectors.FORWARD.clone());
  61454. break;
  61455. case 'BACKWARD':
  61456. this.flyLocalDirection(Vectors.BACK.clone());
  61457. break;
  61458. case 'LEFT':
  61459. this.flyLocalDirection(Vectors.LEFT.clone());
  61460. break;
  61461. case 'RIGHT':
  61462. this.flyLocalDirection(Vectors.RIGHT.clone());
  61463. break;
  61464. }
  61465. break;
  61466. }
  61467. }
  61468. }
  61469. });
  61470. };
  61471. updateDepthTex(pano){
  61472. if(this.currentPano != pano || !pano.depthTex)return
  61473. //this.depthSampler.changeImg(pano.depthTex.image); //pick sampler要飞到了才能切换图,而skybox贴图是随着全景图切换而切换的
  61474. this.cube.material.updateDepthTex(pano); //确保一下
  61475. }
  61476. findNearestPano(pos){
  61477. pos = pos ? new Vector3().copy(pos) : this.position;
  61478. let result = Common.sortByScore(this.panos,[Images360.filters.isEnabled()],[e=>-e.position.distanceTo(pos)]);
  61479. let pano = result && result[0] && result[0].item;
  61480. return pano
  61481. }
  61482. /* set flying(v){//正在飞向pano
  61483. this.flying_ = !!v
  61484. //console.log('this.flying_ ', !!v )
  61485. //this.emit('flying', this.flying_)
  61486. let config = Potree.config.displayMode[Potree.settings.displayMode]
  61487. viewer.mainViewport.unableChangePos = !config.canLeavePano || !!v
  61488. }
  61489. get flying(){
  61490. return this.flying_
  61491. } */
  61492. flyLocalDirection(dir) {
  61493. var direction = this.getDirection(dir),
  61494. option1 = 1 === dir.y ? .4 : .75,
  61495. option2 = 1 === Math.abs(dir.x);
  61496. return this.flyDirection(direction, option1, option2)
  61497. }
  61498. getDirection(e) {
  61499. if(!e){
  61500. return viewer.scene.view.direction
  61501. }else {
  61502. return e = e ? e : (new Vector3).copy(Vectors.FORWARD),
  61503. e.applyQuaternion(viewer.scene.getActiveCamera().quaternion)
  61504. }
  61505. }
  61506. get position(){
  61507. return this.viewer.scene.view.position.clone()
  61508. }
  61509. get visible(){
  61510. return this._visible;
  61511. }
  61512. set visible(visible){
  61513. if(this._visible === visible){
  61514. return;
  61515. }
  61516. /* for(const image of this.panos){
  61517. image.mesh.visible = visible && (this.currentPano == null);
  61518. } */
  61519. //this.sphere.visible = visible && (this.currentPano != null);
  61520. this._visible = visible;
  61521. this.dispatchEvent({
  61522. type: "visibility_changed",
  61523. panos: this,
  61524. });
  61525. }
  61526. isAtPano(){//是否在某个漫游点上
  61527. return this.currentPano && viewer.scene.view.position.equals(this.currentPano.position)
  61528. }
  61529. updateProjectedPanos(){//更新材质贴图
  61530. //console.warn('updateProjectedPanos')
  61531. this.projectedPano0 && this.projectedPano1 && this.setProjectedPanos({pano0:this.projectedPano0, pano1:this.projectedPano1});
  61532. }
  61533. setProjectedPanos(o={}){//设置cube和点云的材质贴图
  61534. this.cube.material.setProjectedPanos(o.pano0, o.pano1, o.progress);
  61535. if(o.ifPointcloud){
  61536. viewer.scene.pointclouds.forEach(e=>{
  61537. e.material.setProjectedPanos(o.pano0, o.pano1, o.progress, o.easeInOutRatio);
  61538. });
  61539. }
  61540. //console.warn('setProjectedPanos ', o.pano0.id , o.pano1.id)
  61541. this.projectedPano0 = o.pano0;
  61542. this.projectedPano1 = o.pano1;
  61543. }
  61544. cancelFlyToPano(){//取消当前已有的飞行准备,前提是相机还未移动
  61545. if(viewer.mainViewport.view.isFlying())return
  61546. this.nextPano = null;
  61547. this.latestToPano = null;
  61548. //this.flying = false
  61549. }
  61550. flyToPano(toPano) { //飞向漫游点
  61551. if(!toPano)return
  61552. if(toPano instanceof Panorama){
  61553. toPano = {pano: toPano};
  61554. }
  61555. if(!toPano.pano.enabled)return
  61556. /* if(!this.currentPano){
  61557. return this.focusPano(toPano)
  61558. } */
  61559. let done = (makeIt, disturb)=>{
  61560. //console.log('flyToPano done ', toPano.pano.id, makeIt )
  61561. if(makeIt || disturb) { // disturb已经开始飞行但中途取消
  61562. toPano.callback && toPano.callback(makeIt);
  61563. //this.flying = false
  61564. this.cancelFlyToPano();
  61565. this.updateClosestPano(this.closestPano,false); //飞行结束后取消点击漫游点时得到的closestPano
  61566. }else {
  61567. console.log('makeit fail');
  61568. }
  61569. this.dispatchEvent({type:'flyToPanoDone', makeIt});
  61570. //this.dispatchEvent('cameraMoveDone')
  61571. toPano.deferred && toPano.deferred.resolve(makeIt); //测量线截图时发现,resolve需要写在flying=false 后才行。
  61572. };
  61573. if(this.currentPano == toPano.pano && this.isAtPano() && !toPano.target ){
  61574. this.dispatchEvent({type:'flyToPano', toPano});
  61575. return done(true);
  61576. }
  61577. if(this.latestToPano && this.latestToPano != toPano){
  61578. return done(false)
  61579. }
  61580. let target = toPano.target;
  61581. let easeName = toPano.easeName || 'easeInOutQuad'; // 'easeInOutSine'//'easeOutSine'
  61582. let config = Potree.config.displayMode[Potree.settings.displayMode];
  61583. var pointcloudVisi = config.atPano.showPoint; //viewer.scene.pointclouds[0].visible
  61584. var pano = toPano.pano;
  61585. let T = Potree.config.transitionsTime;
  61586. let maxTime = this.isAtPano() ? T.panoToPanoMax : T.flyIn;
  61587. var duration = toPano.duration == void 0 ? (T.flyMinTime+Math.min(T.flytimeDistanceMultiplier * this.position.distanceTo(pano.position), maxTime)) : toPano.duration;
  61588. toPano.duration = duration;
  61589. //console.warn("flyto "+pano.id + ' duration: ' + duration )
  61590. this.nextPano = pano;
  61591. this.latestToPano = toPano;
  61592. //this.flying = true //防止新的请求
  61593. {//不飞的话是否不要执行这段?
  61594. let wait = ()=> {
  61595. if(this.latestToPano != toPano)return //如果取消了
  61596. setTimeout(()=>{
  61597. if(this.latestToPano != toPano)return
  61598. this.flyToPano(toPano);
  61599. },1);
  61600. this.removeEventListener('loadedDepthImg', wait);
  61601. };
  61602. if(!pano.depthTex && pano.pointcloud.hasDepthTex){ //需要用到depthTex计算neighbour
  61603. this.addEventListener('loadedDepthImg', wait);
  61604. return pano.loadDepthImg()
  61605. }
  61606. if(config.atPano.showSkybox || config.atPano.pointUsePanoTex){
  61607. this.updateCube(this.currentPano, toPano.pano);
  61608. if(this.checkAndWaitForPanoLoad(pano, toPano.basePanoSize || this.basePanoSize, wait)){
  61609. return
  61610. }
  61611. }
  61612. }
  61613. viewer.updateVisible(this.cube,'showSkybox', config.atPano.showSkybox ); // this.cube.visible = config.atPano.showSkybox
  61614. /* this.cube.visible && this.cube.material.setProjectedPanos(this.currentPano, pano, 0)
  61615. if(config.transition.showPoint){
  61616. viewer.scene.pointclouds.forEach(e=>{
  61617. viewer.updateVisible(e, 'displayMode', true)
  61618. })
  61619. if(config.transition.pointUsePanoTex){
  61620. let easeInOutRatio = pointcloudVisi ? 0.3 : 0
  61621. viewer.scene.pointclouds.forEach(e=>{
  61622. e.material.setProjectedPanos(this.currentPano, pano, 0, easeInOutRatio)
  61623. })
  61624. }
  61625. } */
  61626. if(config.transition.showPoint){
  61627. viewer.scene.pointclouds.forEach(e=>{
  61628. viewer.updateVisible(e, 'displayMode', true);
  61629. });
  61630. }
  61631. if(config.transition.showSkybox || config.transition.pointUsePanoTex){
  61632. this.setProjectedPanos({
  61633. progress:0,
  61634. ifSkybox: this.cube.visible,
  61635. ifPointcloud : config.transition.pointUsePanoTex,
  61636. easeInOutRatio : pointcloudVisi ? 0.3 : 0,
  61637. pano0:this.currentPano,
  61638. pano1:pano
  61639. });
  61640. }
  61641. const endPosition = pano.position.clone();
  61642. {
  61643. toPano.duration = duration;
  61644. toPano.easeName = easeName;
  61645. this.beforeFlyToPano(toPano);
  61646. }
  61647. let fly = ()=>{
  61648. this.dispatchEvent({type:'flyToPano', toPano});
  61649. viewer.scene.view.setView({position:endPosition, target, quaternion:toPano.quaternion , duration,
  61650. callback:()=>{
  61651. if(!config.atPano.pointUsePanoTex){
  61652. viewer.scene.pointclouds.forEach(e=>{
  61653. e.material.stopProjectedPanos();
  61654. });
  61655. }
  61656. //this.currentPano.exit()
  61657. //pano.enter()
  61658. this.currentPano = pano;
  61659. this.nextPano = null;
  61660. if(Potree.settings.displayMode == 'showPanos'){
  61661. viewer.scene.pointclouds.forEach(e=>{
  61662. viewer.updateVisible(e, 'displayMode',pointcloudVisi);
  61663. });
  61664. }
  61665. done(true);
  61666. //this.updateCube(this.currentPano)
  61667. this.updateDepthTex(this.currentPano);
  61668. }, onUpdate:(progress)=>{
  61669. this.cube.material.uniforms.progress.value = progress;
  61670. viewer.scene.pointclouds.forEach(e=>{
  61671. e.material.uniforms.progress.value = progress;
  61672. });
  61673. },
  61674. cancelFun:()=>{ done(false, true); },
  61675. Easing:easeName
  61676. });
  61677. //duration > 0 && (this.flying = true) //再写一遍 防止cancel其他项目导致flying为false
  61678. };
  61679. if(Potree.settings.displayMode == 'showPanos'){
  61680. setTimeout(fly, 40); //更新geo后缓冲
  61681. }else {
  61682. fly();
  61683. }
  61684. //console.log('flyToPano:', toPano.pano.id)
  61685. }
  61686. beforeFlyToPano(toPano){
  61687. if(this.currentPano != toPano.pano) {
  61688. if(Potree.settings.displayMode == 'showPanos'){
  61689. this.resetHighMap();
  61690. }
  61691. this.smoothZoomTo(1, toPano.duration / 2);
  61692. }
  61693. }
  61694. /* focusPano(toPano ){
  61695. if(this.currentPano !== null){
  61696. return this.flyToPano(toPano);
  61697. }
  61698. if(toPano instanceof Panorama){
  61699. toPano = {pano: toPano}
  61700. }
  61701. let done = (makeIt)=>{
  61702. toPano.deferred && toPano.deferred.resolve(makeIt)
  61703. makeIt && toPano.callback && toPano.callback()
  61704. }
  61705. var pano = toPano.pano
  61706. let config = Potree.config.displayMode[Potree.settings.displayMode]
  61707. previousView = {
  61708. //controls: this.viewer.controls,
  61709. position: this.position,
  61710. target: viewer.scene.view.getPivot(),
  61711. };
  61712. //this.viewer.setControls(this.viewer.orbitControls);
  61713. this.viewer.orbitControls.doubleClockZoomEnabled = false;
  61714. for(let image of this.panos){
  61715. image.mesh.visible = false;
  61716. }
  61717. this.selectingEnabled = false;
  61718. //console.warn("flyto "+pano.file.split('/').pop() )
  61719. var dur = toPano.duration == void 0 ? 700 : toPano.duration
  61720. if(config.atPano.showSkybox){
  61721. if ( this.checkAndWaitForPanoLoad(pano, this.basePanoSize, ()=> {
  61722. setTimeout( ()=>{
  61723. this.focusPano(toPano)
  61724. },1)
  61725. })
  61726. ) {
  61727. return ;
  61728. }
  61729. }
  61730. this.cube.visible = config.atPano.showSkybox
  61731. //if(config.transition.showSkybox || config.transition.pointUsePanoTex){
  61732. this.setProjectedPanos({
  61733. progress:0,
  61734. ifSkybox: this.cube.visible,
  61735. ifPointcloud : config.atPano.pointUsePanoTex,
  61736. pano0:pano,
  61737. pano1:pano
  61738. })
  61739. //}
  61740. let newCamPos = pano.position.clone()
  61741. let target = newCamPos.clone().add(viewer.scene.view.direction)
  61742. viewer.scene.view.setView( {position:newCamPos, target, duration:dur ,
  61743. callback:()=>{//done
  61744. //pano.enter()
  61745. this.flying = false
  61746. this.currentPano = pano;
  61747. this.updateCube(this.currentPano)
  61748. done(true)
  61749. },onUpdate:(progress)=>{
  61750. },
  61751. cancelFun:()=>{this.flying = false}
  61752. })
  61753. this.flying = true
  61754. this.elUnfocus && (this.elUnfocus[0].style.display = "");
  61755. }
  61756. unfocus(o={}){
  61757. this.selectingEnabled = true;
  61758. Potree.settings.displayMode = 'showPointCloud'
  61759. if(!this.currentPano && !o.position){
  61760. return;
  61761. }
  61762. this.cube.visible = false
  61763. viewer.orbitControls.doubleClockZoomEnabled = true;
  61764. viewer.scene.view.setView($.extend({
  61765. position: previousView.position,
  61766. target:previousView.target,
  61767. duration:500
  61768. },o,{
  61769. callback:()=>{ //done
  61770. for(let pano of this.panos){
  61771. pano.mesh.visible = true;
  61772. //pano.marker.material.depthTest = true
  61773. }
  61774. o.callback && o.callback()
  61775. }
  61776. ,
  61777. cancelFun:()=>{this.flying = false},
  61778. }))
  61779. //this.currentPano.exit()
  61780. this.currentPano = null;
  61781. this.elUnfocus && (this.elUnfocus[0].style.display = "none");
  61782. } */
  61783. updateCube(pano0, pano1){
  61784. if(!viewer.scene.pointclouds.some(e=>!e.hasDepthTex)) return this.updateCube2(pano0, pano1) //都hasDepthTex的话
  61785. if(Potree.settings.displayMode != 'showPanos')return
  61786. let f = (bound, size)=>{
  61787. size = size || bound.getSize(new Vector3);
  61788. let center = bound.getCenter(new Vector3);
  61789. size.max(new Vector3(HighMapCubeWidth,HighMapCubeWidth,HighMapCubeWidth));
  61790. this.cube.scale.copy(size);
  61791. this.cube.position.copy(center);
  61792. };
  61793. let getDis = (bound1, bound2)=>{ //获取bound1边界到bound2边界距离
  61794. if(bound1.intersectsBox(bound2))return 0
  61795. let center1 = bound1.getCenter(new Vector3);
  61796. let center2 = bound2.getCenter(new Vector3);
  61797. let dis = center1.distanceTo(center2);
  61798. let dis1 = bound1.distanceToPoint(center2);
  61799. let dis2 = bound2.distanceToPoint(center1);
  61800. return dis1 + dis2 - dis
  61801. };
  61802. if(pano1){//过渡
  61803. if(pano0.pointcloud == pano1.pointcloud){//同一个数据集内的过渡
  61804. f(pano0.pointcloud.bound);
  61805. //console.log('updateCube1' )
  61806. }else {//非同一个数据集内的过渡
  61807. let bound = pano0.pointcloud.bound.clone().union(pano1.pointcloud.bound);
  61808. if(getDis(pano0.pointcloud.bound, pano1.pointcloud.bound) < 100){
  61809. f(bound);
  61810. }else {//如果两个数据集boundingbox距离大于这个距离,扩大一下,防止精度问题导致失真//对很远的数据集似乎没有什么用
  61811. let size = bound.getSize(new Vector3);
  61812. let max = Math.max(size.x, size.y, size.z);
  61813. size.set(max,max,max);
  61814. f(bound, size);
  61815. //console.log('updateCube2', size)
  61816. //far可能要修改下
  61817. }
  61818. }
  61819. }else {
  61820. f(pano0.pointcloud.bound); //假定一个数据集不会太大,否则会造成失真,且bump时移动距离看起来很小。或者可以考虑用固定大小
  61821. //console.log('updateCube3' )
  61822. }
  61823. }
  61824. /* updateCube(pano0, pano1){ //垂直上不分段、 每个pano只有5个方向的版本
  61825. if(Potree.settings.displayMode != 'showPanos')return
  61826. console.log('updateCube',pano0.id, pano1&&pano1.id)
  61827. let f = (bound, size)=>{
  61828. size = size || bound.getSize(new THREE.Vector3)
  61829. let center = bound.getCenter(new THREE.Vector3)
  61830. size.max(new THREE.Vector3(HighMapCubeWidth,HighMapCubeWidth,HighMapCubeWidth))
  61831. this.cube.scale.copy(size)
  61832. this.cube.position.copy(center)
  61833. }
  61834. this.cube.geometry.dispose();
  61835. if(pano1){//过渡
  61836. let add = (pano, dir, )=>{
  61837. let minZ, maxZ
  61838. minZ = pano.floorPosition.z
  61839. {//天花板高度值
  61840. //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
  61841. let rotMat = new THREE.Matrix4().makeRotationX(THREE.Math.degToRad(40))// 角度不能小于天花板中空的半径,大概就是0.2*Math.PI=36度
  61842. let dir1 = new THREE.Vector3(0,0,1).applyMatrix4(rotMat)
  61843. let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
  61844. let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
  61845. let dir2 = dir1.clone().applyMatrix4(rotMat1)
  61846. let dir3 = dir1.clone().applyMatrix4(rotMat2)
  61847. let zs = [dir1,dir2,dir3].map(dir_=>{
  61848. let intersect = this.depthSampler.sample( {dir: dir_}, pano, true )
  61849. let z = intersect ? intersect.location.z : pano.position.z
  61850. return z
  61851. })
  61852. zs.sort((a,b)=>{return b-a});//得最大值
  61853. maxZ = zs[0]
  61854. }
  61855. const angle = Math.PI/6 //每次转30度
  61856. let getDir = (angle_)=>{
  61857. let rotMat = new THREE.Matrix4().makeRotationZ(angle_)
  61858. return dir.clone().applyMatrix4(rotMat)
  61859. }
  61860. let dirs = [getDir(angle*2), getDir(angle),getDir(angle), dir.clone(), getDir(-angle), getDir(-angle*2)]; //总共五个方向,夹角总和180度
  61861. dirs.forEach(dir=>{//获取在这个方向上和墙体intersect的最远距离,使用中、上、下三个方向
  61862. //上下分别45度 刚好就是
  61863. let dir0 = dir.clone();// 水平方向
  61864. let dir1 = dir.clone().setZ(1).normalize() //上45度方向
  61865. let dir2 = dir.clone().setZ(-1).normalize() // 下45度方向
  61866. let disArr = [dir0,dir1,dir2].map(dir_ =>{
  61867. let intersect = this.depthSampler.sample( {dir: dir_}, pano, true )
  61868. let projectLen = intersect.distance ? dir_.dot(dir)*intersect.distance : 0 //得到project在dir的长度
  61869. return projectLen
  61870. })
  61871. disArr.sort((a,b)=>{return b-a});//得最大值
  61872. dir.multiplyScalar( disArr[0] );//得到水平方向上的最远向量
  61873. [minZ,maxZ].forEach(z=>{ //0-9
  61874. posArr.push(pano.position.clone().setZ(z).add(dir))
  61875. })
  61876. });
  61877. [minZ,maxZ].forEach(z=>{ // 10,11
  61878. posArr.push(pano.position.clone().setZ(z))
  61879. })
  61880. }
  61881. let posArr = [];
  61882. let faceArr = [[0,1,2],[1,2,3], [2,3,4],[3,4,5], [4,5,6],[5,6,7], [6,7,8],[7,8,9], //外侧四个面
  61883. [0,2,10],[2,4,10],[4,6,10],[6,8,10],//底部扇形
  61884. [1,3,11],[3,5,11],[5,7,11],[7,9,11],//顶部扇形
  61885. ]
  61886. //两点连线的水平向量
  61887. let vec = new THREE.Vector3().subVectors(pano0.position, pano1.position).setZ(0).normalize()
  61888. add(pano0, vec)
  61889. add(pano1, vec.negate())
  61890. let faceArr2 = faceArr.map(face=>face.map(i=>i+12))//加上pano2的部分
  61891. faceArr.push(...faceArr2)
  61892. //加上连接的部分,四个面
  61893. faceArr.push([0,1, 8+12],[1, 9+12, 8+12], [8,9,0+12],[9,1+12,0+12],
  61894. [0,8,0+12],[0,0+12,8+12], [1,9,1+12],[1,1+12,9+12],
  61895. )
  61896. let geo = MeshDraw.createGeometry(posArr, faceArr)
  61897. this.cube.geometry = geo
  61898. this.cube.scale.set(1,1,1);
  61899. this.cube.position.set(0,0,0)
  61900. }else{
  61901. if(this.hasUpdateOnePano)return
  61902. this.hasUpdateOnePano = true
  61903. this.cube.geometry = new THREE.BoxBufferGeometry(1,1,1,1)
  61904. f(pano0.pointcloud.bound)
  61905. }
  61906. } */
  61907. /* updateCube(pano0, pano1){//增加细分的版本,且垂直方向上也分多个
  61908. if(Potree.settings.displayMode != 'showPanos')return
  61909. console.log('updateCube',pano0.id, pano1&&pano1.id)
  61910. let f = (bound, size)=>{
  61911. size = size || bound.getSize(new THREE.Vector3)
  61912. let center = bound.getCenter(new THREE.Vector3)
  61913. size.max(new THREE.Vector3(HighMapCubeWidth,HighMapCubeWidth,HighMapCubeWidth))
  61914. this.cube.scale.copy(size)
  61915. this.cube.position.copy(center)
  61916. }
  61917. this.cube.geometry.dispose();
  61918. if(pano1){//过渡
  61919. let count1, count2;
  61920. let panoIndex = 0
  61921. let add = (pano, dir )=>{
  61922. let getPI = function(index, panoIndex_){
  61923. if(panoIndex_ == void 0) panoIndex_ = panoIndex
  61924. return (count1 * count2 + 2 ) * panoIndex_ + index + 2
  61925. }
  61926. let minZ, maxZ
  61927. minZ = pano.floorPosition.z
  61928. {//天花板高度值
  61929. //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
  61930. let rotMat = new THREE.Matrix4().makeRotationX(THREE.Math.degToRad(40))// 角度不能小于天花板中空的半径,大概就是0.2*Math.PI=36度
  61931. let dir1 = new THREE.Vector3(0,0,1).applyMatrix4(rotMat)
  61932. let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
  61933. let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
  61934. let dir2 = dir1.clone().applyMatrix4(rotMat1)
  61935. let dir3 = dir1.clone().applyMatrix4(rotMat2)
  61936. let zs = [dir1,dir2,dir3].map(dir_=>{
  61937. let intersect = this.depthSampler.sample( {dir: dir_}, pano, true )
  61938. let z = intersect ? intersect.location.z : pano.position.z
  61939. return z
  61940. })
  61941. zs.sort((a,b)=>{return b-a});//得最大值
  61942. maxZ = zs[0]
  61943. let min = pano.position.z + 1
  61944. if(maxZ < pano.position.z + 0.04){//户外
  61945. maxZ = pano.position.z + 50
  61946. }
  61947. maxZ = Math.max(min,maxZ)
  61948. console.log(pano.id, 'maxZ:',maxZ )
  61949. console.log(pano.id, 'minZ:',minZ )
  61950. }
  61951. [maxZ, minZ ].forEach(z=>{
  61952. posArr.push(pano.position.clone().setZ(z))
  61953. })
  61954. const angle = Math.PI/8
  61955. let getDir = (angle_)=>{
  61956. let rotMat = new THREE.Matrix4().makeRotationZ(angle_)
  61957. return dir.clone().applyMatrix4(rotMat)
  61958. }
  61959. let dirs = [ getDir(angle*4), getDir(angle*3), getDir(angle*2), getDir(angle), dir.clone(), getDir(-angle) , getDir(-angle*2), getDir(-angle*3), getDir(-angle*4) ]; // 夹角总和180度
  61960. count1 = dirs.length
  61961. dirs.forEach((dir, index)=>{//获取在这个方向上和墙体intersect的最远距离,使用中、上、下三个方向
  61962. let dirs_ = [
  61963. dir.clone().setZ(Math.tan(THREE.Math.degToRad(30))).normalize(),
  61964. dir.clone().setZ(Math.tan(THREE.Math.degToRad(15))).normalize(),
  61965. dir.clone(), // 水平方向
  61966. dir.clone().setZ(-Math.tan(THREE.Math.degToRad(15))).normalize(),
  61967. dir.clone().setZ(-Math.tan(THREE.Math.degToRad(30))).normalize(),
  61968. ];
  61969. count2 = dirs_.length
  61970. dirs_.forEach((dir_, i) =>{
  61971. let intersect = this.depthSampler.sample( {dir: dir_}, pano, true )
  61972. let location
  61973. if(!intersect){ //超级远
  61974. let distance = 100
  61975. location = dir_.clone().multiplyScalar(distance).add(pano.position)
  61976. intersect = {distance,location}
  61977. }
  61978. //intersect.distance
  61979. location = intersect.location.clone()
  61980. let shouldZ// = THREE.Math.clamp(intersect.location.z, minZ, maxZ);
  61981. let needShrink = false
  61982. if(i == 0){//最上方的点高度直接等于天花板
  61983. shouldZ = maxZ
  61984. if(location.z<maxZ)location.z = maxZ
  61985. else needShrink = true
  61986. }else if(i == count2-1){//最下方的点高度直接等于地板
  61987. shouldZ = minZ
  61988. if(location.z>minZ)location.z = minZ
  61989. else needShrink = true
  61990. }
  61991. if(needShrink ){//需要在保持dir_不变的情况下修改z
  61992. let len = (shouldZ - pano.position.z) / (intersect.location.z - pano.position.z) * intersect.distance
  61993. location = dir_.clone().multiplyScalar(len).add(pano.position)
  61994. }
  61995. posArr.push(location)
  61996. if(index!=0 && i!=0){//加入一块四方面
  61997. let curIndex = getPI(count2 * index + i);
  61998. faceArr.push([curIndex-1, curIndex-count2-1, curIndex-count2],
  61999. [curIndex-1, curIndex, curIndex-count2])
  62000. }
  62001. })
  62002. if(index!=0){
  62003. let top = -2;
  62004. let btm = -1
  62005. faceArr.push([getPI(count2*(index-1) ), getPI(count2*index ), getPI(top) ])//天花板扇形
  62006. faceArr.push([getPI(count2*index-1), getPI(count2*(index+1)-1), getPI(btm) ] )//地板扇形
  62007. }else{
  62008. //加入和另一个pano连接的其中一个侧边
  62009. let panoIndex2 = (panoIndex + 1) % 2;
  62010. for(let i=1;i<count2;i++){
  62011. faceArr.push([getPI(i-1), getPI(i), getPI((count1-1)*count2 +i, panoIndex2)],
  62012. [getPI(i-1), getPI((count1-1)*count2+i , panoIndex2) , getPI((count1-1)*count2+i-1 ,panoIndex2)])
  62013. }
  62014. faceArr.push([getPI(0), getPI((count1-1)*count2), getPI(0, panoIndex2)])//加入顶部的一半
  62015. faceArr.push([getPI(count2-1), getPI(count1*count2-1), getPI(count2-1, panoIndex2)])//加入底部的一半
  62016. }
  62017. });
  62018. panoIndex ++
  62019. }
  62020. let posArr = [];
  62021. let faceArr = []
  62022. //两点连线的水平向量
  62023. let vec = new THREE.Vector3().subVectors(pano0.position, pano1.position).setZ(0).normalize()
  62024. add(pano0, vec)
  62025. add(pano1, vec.negate())
  62026. let geo = MeshDraw.createGeometry(posArr, faceArr)
  62027. this.cube.geometry = geo
  62028. this.cube.scale.set(1,1,1);
  62029. this.cube.position.set(0,0,0)
  62030. }else{
  62031. this.cube.geometry = new THREE.BoxBufferGeometry(1,1,1,1)
  62032. f(pano0.pointcloud.bound)
  62033. }
  62034. } */
  62035. updateCube3(pano0, pano1){//增加细分的版本,且垂直方向上取中位数... 侧边只有一条
  62036. if(Potree.settings.displayMode != 'showPanos' || pano0 == pano1
  62037. || this.cubePanos.includes(pano0) && this.cubePanos.includes(pano1)
  62038. ) return
  62039. this.cubePanos = [pano0, pano1];
  62040. //console.log('updateCube',pano0.id, pano1&&pano1.id)
  62041. let f = (bound, size)=>{
  62042. size = size || bound.getSize(new Vector3);
  62043. let center = bound.getCenter(new Vector3);
  62044. size.max(new Vector3(HighMapCubeWidth,HighMapCubeWidth,HighMapCubeWidth));
  62045. this.cube.scale.copy(size);
  62046. this.cube.position.copy(center);
  62047. };
  62048. this.cube.geometry.dispose();
  62049. if(pano1){//过渡
  62050. const half = pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex ? ( browser.isMobile() ? 3 : 6 ) : (browser.isMobile() ? 2 : 3); //自行输入 (点云计算的慢,还不准)
  62051. let count1 = 2*half;//偶数个 dir 个数
  62052. //奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
  62053. let panoIndex = 0;
  62054. let getIntersect = (pano, dir, origin)=>{
  62055. if(pano && pano.pointcloud.hasDepthTex ){
  62056. return this.depthSampler.sample( {dir }, pano, true )
  62057. }else {
  62058. origin = origin || pano.position;
  62059. return viewer.inputHandler.getIntersect(viewer.inputHandler.hoverViewport, true, null, null, true, {
  62060. point: origin.clone().add(dir),
  62061. cameraPos: origin
  62062. })
  62063. }
  62064. };
  62065. let getDir = (angle_, vec)=>{ //旋转获得水平向量
  62066. let rotMat = new Matrix4().makeRotationZ(angle_);
  62067. return vec.clone().applyMatrix4(rotMat)
  62068. };
  62069. let getFar = (dir, pano, origin)=>{//获取在这个方向上和墙体intersect的最远距离
  62070. let dirs_ = [
  62071. //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。 户外时需要更多向上的方向,所以上方向多一个
  62072. dir.clone().setZ(Math.tan(MathUtils.degToRad(30))).normalize(),
  62073. dir.clone().setZ(Math.tan(MathUtils.degToRad(7))).normalize(),
  62074. dir.clone(), // 水平方向
  62075. dir.clone().setZ(-Math.tan(MathUtils.degToRad(5))).normalize(),
  62076. //dir.clone().setZ(-Math.tan(THREE.Math.degToRad(30))).normalize(),
  62077. ];
  62078. let max = 50;
  62079. let count2 = dirs_.length;
  62080. let disArr = dirs_.map((dir_, i) =>{
  62081. let intersect = getIntersect(pano, dir_, origin);
  62082. let projectLen = intersect && intersect.distance ? dir_.dot(dir)*intersect.distance : max; //得到project在dir的长度
  62083. return projectLen
  62084. });
  62085. disArr.sort((a,b)=>{return b-a}); //从大到小
  62086. //console.log(pano ? pano.id : 'side','disArr', disArr)
  62087. let dis = disArr[Math.floor(count2/2-0.5)]; //对半、取前(中位数)
  62088. return dis
  62089. };
  62090. let add = (pano, vec )=>{
  62091. let getPI = function(index, panoIndex_){
  62092. if(panoIndex_ == void 0) panoIndex_ = panoIndex;
  62093. return (count1*2 + 2 ) * panoIndex_ + index + 2
  62094. };
  62095. let minZ, maxZ;
  62096. minZ = pano.floorPosition.z;
  62097. if(pano.ceilZ != void 0){
  62098. maxZ = pano.ceilZ;
  62099. }else {//天花板高度值
  62100. //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
  62101. let rotMat = new Matrix4().makeRotationX(MathUtils.degToRad(40));// 角度不能小于天花板中空的半径,大概就是0.2*Math.PI=36度
  62102. let dir1 = new Vector3(0,0,1).applyMatrix4(rotMat);
  62103. let rotMat1 = new Matrix4().makeRotationZ(Math.PI*2 / 3);
  62104. let rotMat2 = new Matrix4().makeRotationZ(-Math.PI*2 / 3);
  62105. let dir2 = dir1.clone().applyMatrix4(rotMat1);
  62106. let dir3 = dir1.clone().applyMatrix4(rotMat2);
  62107. let zs = [dir1,dir2,dir3].map(dir_=>{
  62108. let intersect = getIntersect(pano, dir_);
  62109. let z = intersect ? intersect.location.z : pano.position.z+50;
  62110. return z
  62111. });
  62112. zs.sort((a,b)=>{return b-a});//得最大值
  62113. maxZ = zs[0];
  62114. let min = pano.position.z + 1;
  62115. maxZ = Math.max(min,maxZ);
  62116. pano.ceilZ = maxZ;
  62117. //console.log(pano.id, 'maxZ:',maxZ )
  62118. //console.log(pano.id, 'minZ:',minZ )
  62119. }
  62120. [maxZ, minZ ].forEach(z=>{
  62121. posArr.push(pano.position.clone().setZ(z));
  62122. });
  62123. const angle = Math.PI/(count1-1);
  62124. //在画面上线条从左往右数
  62125. let dirs = [];
  62126. for(let i=0;i<count1;i++){
  62127. dirs.push(getDir(Math.PI/2-i*angle, vec));//正的在左边
  62128. }
  62129. let sideDis = [];
  62130. dirs.forEach((dir, index)=>{
  62131. let dis = getFar(dir, pano);
  62132. if(index == 0 || index == count1-1){
  62133. sideDis.push(dis);
  62134. }
  62135. dir.multiplyScalar( dis );
  62136. [maxZ,minZ].forEach(z=>{
  62137. posArr.push(pano.position.clone().setZ(z).add(dir));
  62138. });
  62139. if(index!=0){//加入一块四方面
  62140. let m = index*2;
  62141. faceArr.push([getPI(m), getPI(m-1), getPI(m-2)],
  62142. [getPI(m), getPI(m+1), getPI(m-1)]);
  62143. let top = -2;
  62144. let btm = -1;
  62145. faceArr.push([getPI(m), getPI(m-2), getPI(top) ]);//天花板扇形
  62146. faceArr.push([getPI(btm), getPI(m-1), getPI(m+1) ] );//地板扇形
  62147. }
  62148. });
  62149. let panoIndex2 = (panoIndex + 1) % 2;
  62150. //let m = (count1-1)*2
  62151. /* faceArr.push([getPI(0), getPI(1), getPI(count1*2-1, panoIndex2)],
  62152. [getPI(0), getPI(count1*2-1,panoIndex2) , getPI(count1*2-2,panoIndex2)])
  62153. faceArr.push([getPI(0, panoIndex2), getPI(count1*2-2), getPI(0)])//加入顶部的一半
  62154. faceArr.push([getPI(1), getPI(count1*2-1), getPI(1, panoIndex2)])//加入底部的一半 */
  62155. //加入和另一个pano连接
  62156. let sideMid = count1*4+4; //侧边点start
  62157. //侧边的一半
  62158. faceArr.push([getPI(0), getPI(1), sideMid+panoIndex*2],
  62159. [sideMid+panoIndex*2, getPI(1) , sideMid+panoIndex*2+1 ],
  62160. [getPI(count1*2-2), sideMid+panoIndex2*2+1, getPI(count1*2-1)],
  62161. [getPI(count1*2-2), sideMid+panoIndex2*2, sideMid+panoIndex2*2+1 ]
  62162. );
  62163. faceArr.push([getPI(0), sideMid+panoIndex2*2, getPI(count1*2-2)],
  62164. [getPI(0),sideMid+panoIndex*2, sideMid+panoIndex2*2]
  62165. );//加入顶部的一半
  62166. faceArr.push([getPI(count1*2-1), sideMid+panoIndex2*2+1, getPI(1)],
  62167. [sideMid+panoIndex2*2+1, sideMid+panoIndex*2+1, getPI(1)]
  62168. );//加入底部的一半
  62169. panoIndex ++;
  62170. return sideDis;
  62171. };
  62172. let addSide = ()=>{//两个漫游点间两边各加一条侧线,为了适应四方形房间漫游点在对角方向的那种情况
  62173. //侧边为了取中点,没办法用全景图获取了,用点云
  62174. let sideMaxZ = (pano0.ceilZ + pano1.ceilZ)/2;
  62175. let sideMinZ = (pano0.floorPosition.z+pano1.floorPosition.z)/2;
  62176. let sideDis_ = [(sideDis0[0] + sideDis1[1])/2, (sideDis0[1] + sideDis1[0])/2];
  62177. let sideDis = [Math.min(sideDis0[0] , sideDis1[1]), Math.min(sideDis0[1] , sideDis1[0])];//
  62178. let mid = new Vector3().addVectors(pano0.position, pano1.position).multiplyScalar(0.5);
  62179. let sideDirs = [getDir(-Math.PI/2, vec), getDir(Math.PI/2, vec)];
  62180. if(pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex){
  62181. let panos = [pano0,pano1];
  62182. let vecs = [vec.negate(), vec];
  62183. let axis = [[-1,1],[1,-1]];
  62184. let dis2d = new Vector2$1().subVectors(pano0.position, pano1.position).length();//水平上的距离
  62185. let angles = [MathUtils.degToRad(45), MathUtils.degToRad(60)];
  62186. sideDirs.forEach((dir, index0)=>{
  62187. let disToSides = [];
  62188. panos.forEach((pano,index)=>{
  62189. let dirs = [getDir(axis[index0][index]*angles[0], vecs[index]), getDir(axis[index0][index]*angles[1], vecs[index])];//一侧的若干角度
  62190. dirs.forEach((dir_,i)=>{
  62191. let dis1 = getFar(dir_, pano);
  62192. //dir_.multiplyScalar( dis1 );
  62193. let disToPano2d = dis1 * Math.cos(angles[i]);
  62194. if(disToPano2d<dis2d){//超过的话都到另一半pano的半圆了,不计入
  62195. let disToSide = dis1 * Math.sin(angles[i]);
  62196. disToSides.push(disToSide);
  62197. }
  62198. });
  62199. });
  62200. let disToSide;
  62201. if(disToSides.length){
  62202. disToSides.sort((a,b)=>{return b-a});//从大到小
  62203. disToSide = disToSides[0];
  62204. console.log('disToSides', index0, disToSides);
  62205. }else {
  62206. disToSide = sideDis[index0];
  62207. }
  62208. dir.multiplyScalar( disToSide );
  62209. [sideMaxZ,sideMinZ].forEach(z=>{
  62210. posArr.push(mid.clone().setZ(z).add(dir)); //是直接使用最长dis的那个intersect点好还是mid
  62211. });
  62212. });
  62213. }else {
  62214. sideDirs.forEach((dir_ ,index)=>{
  62215. let dis = getFar(dir_, null, mid);
  62216. dir_.multiplyScalar( /* sideDis_[index] */ Math.max(dis, sideDis[index]) );
  62217. [sideMaxZ,sideMinZ].forEach(z=>{
  62218. posArr.push(mid.clone().setZ(z).add(dir_));
  62219. });
  62220. });
  62221. }
  62222. };
  62223. let posArr = [];
  62224. let faceArr = [];
  62225. //两点连线的水平向量
  62226. let vec = new Vector3().subVectors(pano0.position, pano1.position).setZ(0).normalize();
  62227. let sideDis0 = add(pano0, vec);
  62228. let sideDis1 = add(pano1, vec.negate());
  62229. addSide();
  62230. //MeshDraw.updateGeometry(this.cube.geometry, posArr, faceArr)
  62231. let geo = MeshDraw.createGeometry(posArr, faceArr);
  62232. this.cube.geometry = geo;
  62233. this.cube.scale.set(1,1,1);
  62234. this.cube.position.set(0,0,0);
  62235. //this.cube.scale.set(100,100,100);
  62236. //this.cube.position.copy(pano1.position).multiplyScalar(-100)
  62237. }else {
  62238. this.cube.geometry = new BoxBufferGeometry(1,1,1,1);
  62239. f(pano0.pointcloud.bound);
  62240. }
  62241. }
  62242. updateCube2(pano0, pano1){//增加细分的版本,且垂直方向上取中位数 侧边多条
  62243. if(Potree.settings.displayMode != 'showPanos' || pano0 == pano1
  62244. || this.cubePanos.includes(pano0) && this.cubePanos.includes(pano1)
  62245. ) return
  62246. this.cubePanos = [pano0, pano1];
  62247. //console.log('updateCube',pano0.id, pano1&&pano1.id)
  62248. let useBound = (bound, size)=>{
  62249. size = size || bound.getSize(new Vector3);
  62250. let center = bound.getCenter(new Vector3);
  62251. size.max(new Vector3(HighMapCubeWidth,HighMapCubeWidth,HighMapCubeWidth));
  62252. this.cube.geometry = new BoxBufferGeometry(1,1,1,1);
  62253. this.cube.scale.copy(size);
  62254. this.cube.position.copy(center);
  62255. };
  62256. this.cube.geometry.dispose();
  62257. if(pano1){//过渡
  62258. if(pano0.pointcloud != pano1.pointcloud){ //距离太远的数据集,过渡会畸变。所以扩大skybox
  62259. let dis = pano0.position.distanceTo(pano1.position);
  62260. if(dis > 100){
  62261. let bound = pano0.pointcloud.bound.clone().union(pano1.pointcloud.bound);
  62262. let size = bound.getSize(new Vector3);
  62263. let max = Math.max(size.x, size.y, size.z);
  62264. size.set(max,max,max);
  62265. return useBound(bound, size)
  62266. }
  62267. }
  62268. const half = pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex ? 6 : (browser.isMobile() ? 2 : 3); //自行输入 (点云计算的慢,还不准)
  62269. let count1 = 2*half;//偶数个 每个pano向 外dir 个数
  62270. //奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
  62271. //let panoIndex = 0
  62272. let getIntersect = (pano, dir, origin)=>{
  62273. if(pano && pano.pointcloud.hasDepthTex ){
  62274. return this.depthSampler.sample( {dir }, pano, true )
  62275. }else {
  62276. origin = origin || pano.position;
  62277. return viewer.inputHandler.getIntersect(viewer.inputHandler.hoverViewport, true, null, null, true, {
  62278. point: origin.clone().add(dir),
  62279. cameraPos: origin
  62280. })
  62281. }
  62282. };
  62283. let getDir = (angle_, vec)=>{ //旋转获得水平向量
  62284. let rotMat = new Matrix4().makeRotationZ(angle_);
  62285. return vec.clone().applyMatrix4(rotMat)
  62286. };
  62287. let getFar = (dir, pano, origin)=>{//获取在这个方向上和墙体intersect的距离
  62288. //在垂直方向上分出多个方向,取一个最可能的接近真实的距离
  62289. let dirs_ = [
  62290. //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。 户外时需要更多向上的方向,所以上方向多一个
  62291. dir.clone().setZ(Math.tan(MathUtils.degToRad(30))).normalize(),
  62292. dir.clone().setZ(Math.tan(MathUtils.degToRad(7))).normalize(),
  62293. dir.clone(), // 水平方向
  62294. dir.clone().setZ(-Math.tan(MathUtils.degToRad(5))).normalize(),
  62295. //dir.clone().setZ(-Math.tan(THREE.Math.degToRad(30))).normalize(),
  62296. ];
  62297. let max = 50;
  62298. let count2 = dirs_.length;
  62299. let disArr = dirs_.map((dir_, i) =>{
  62300. let intersect = getIntersect(pano, dir_, origin);
  62301. let projectLen = intersect && intersect.distance ? dir_.dot(dir)*intersect.distance : max; //得到project在dir的长度
  62302. return projectLen //得水平距离
  62303. });
  62304. disArr.sort((a,b)=>{return b-a}); //从大到小
  62305. //console.log(pano ? pano.id : 'side','disArr', disArr)
  62306. let dis = disArr[Math.floor(count2/2-0.5)]; //对半、取前(中位数)
  62307. return dis
  62308. };
  62309. let sideCount = [];
  62310. let addPos = (pano, vec )=>{//添加这个pano这一侧向外半圆的顶点
  62311. //添加pano位置对应的最高点最低点:
  62312. let minZ, maxZ;
  62313. minZ = pano.floorPosition.z;
  62314. if(pano.ceilZ != void 0){
  62315. maxZ = pano.ceilZ;
  62316. }else {//天花板高度值
  62317. //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
  62318. let rotMat = new Matrix4().makeRotationX(MathUtils.degToRad(40));// 角度不能小于天花板中空的半径,大概就是0.2*Math.PI=36度
  62319. let dir1 = new Vector3(0,0,1).applyMatrix4(rotMat);
  62320. let rotMat1 = new Matrix4().makeRotationZ(Math.PI*2 / 3);
  62321. let rotMat2 = new Matrix4().makeRotationZ(-Math.PI*2 / 3);
  62322. let dir2 = dir1.clone().applyMatrix4(rotMat1);
  62323. let dir3 = dir1.clone().applyMatrix4(rotMat2);
  62324. let skyHeight = 50;
  62325. let zs = [dir1,dir2,dir3].map(dir_=>{
  62326. let intersect = getIntersect(pano, dir_);
  62327. let z = intersect ? intersect.location.z : pano.position.z+skyHeight; //没有intersect代表可能是天空
  62328. return z
  62329. });
  62330. zs.sort((a,b)=>{return b-a});//得最大值 (不用中位数的原因:在屋檐处,如果仅有一个intersect是天空,因到了室外所以也用天空高度)
  62331. maxZ = zs[0];
  62332. let min = pano.position.z + 1; // 防止意外太低
  62333. maxZ = Math.max(min,maxZ);
  62334. pano.ceilZ = maxZ;
  62335. //console.log(pano.id, 'maxZ:',maxZ )
  62336. //console.log(pano.id, 'minZ:',minZ )
  62337. }
  62338. [maxZ, minZ ].forEach(z=>{
  62339. posArr.push(pano.position.clone().setZ(z));
  62340. });
  62341. //在画面上线条从左往右数
  62342. const angle = Math.PI/(count1-1);
  62343. const dirs = []; //平分这半边180度
  62344. for(let i=0;i<count1;i++){
  62345. dirs.push(getDir(Math.PI/2-i*angle, vec));//正的在左边
  62346. }
  62347. // let sideDis = []
  62348. dirs.forEach((dir, index)=>{
  62349. let dis = getFar(dir, pano);
  62350. // if(index == 0 || index == count1-1){
  62351. // sideDis.push(dis)
  62352. // }
  62353. dir.multiplyScalar( dis );
  62354. [maxZ,minZ].forEach(z=>{
  62355. posArr.push(pano.position.clone().setZ(z).add(dir)); //获取到外墙点
  62356. });
  62357. });
  62358. //panoIndex ++
  62359. //return sideDis;
  62360. };
  62361. let addSide = ()=>{//两个漫游点间两边各加一些侧线
  62362. //中点处的
  62363. let midMaxZ = (pano0.ceilZ + pano1.ceilZ)/2;
  62364. let midMinZ = (pano0.floorPosition.z+pano1.floorPosition.z)/2;
  62365. let mid = new Vector3().addVectors(pano0.position, pano1.position).multiplyScalar(0.5);
  62366. /* let sideDis_ = [(sideDis0[0] + sideDis1[1])/2, (sideDis0[1] + sideDis1[0])/2];
  62367. let sideDis = [Math.min(sideDis0[0] , sideDis1[1]), Math.min(sideDis0[1] , sideDis1[0])]//
  62368. */
  62369. if(pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex){
  62370. let panos = [pano0,pano1];
  62371. let vecs = [vec.clone().negate(), vec];
  62372. let axis = [[-1,1],[1,-1]];
  62373. let dis2d = new Vector2$1().subVectors(pano0.position, pano1.position).length();//水平上的距离
  62374. let angles = [MathUtils.degToRad(40), MathUtils.degToRad(70)]; //正的在左边 尽量能够平分中间这段墙体
  62375. axis.forEach((axis_, index0)=>{
  62376. let disToSides = [];
  62377. let accordingPano = index0 == 0 ? pano0 : pano1; //根据离该点在vec方向上的距离顺序来存顶点
  62378. panos.forEach((pano,index)=>{
  62379. let dirs = [getDir(axis_[index]*angles[0], vecs[index]), getDir(axis_[index]*angles[1], vecs[index])];//一侧的若干角度
  62380. dirs.forEach((dir_,i)=>{
  62381. let dis1 = getFar(dir_, pano);
  62382. let disToPano2d = dis1 * Math.cos(angles[i]);
  62383. if(disToPano2d<dis2d){//超过的话都到另一半pano的半圆了,不计入
  62384. let disToSide = dis1 * Math.sin(angles[i]);
  62385. if(pano != accordingPano){
  62386. disToPano2d = dis2d - disToPano2d; //反一下
  62387. }
  62388. dir_.multiplyScalar( dis1 );
  62389. disToSides.push({disToSide,disToPano2d, pano, dir_});
  62390. }
  62391. });
  62392. });
  62393. sideCount[index0] = disToSides.length; //记录侧边个数
  62394. if(disToSides.length){
  62395. //disToSides.sort((a,b)=>{return b-a});//从大到小
  62396. //由距离accordingPano的近到远:
  62397. disToSides.sort((a,b)=>{return a.disToPano2d-b.disToPano2d});
  62398. //console.log('disToSides', index0, disToSides)
  62399. disToSides.forEach(e=>{//求z
  62400. let ratio = e.disToPano2d / dis2d;
  62401. let r = accordingPano == pano0 ? (1-ratio) : ratio;
  62402. let sideMaxZ_ = pano0.ceilZ * r + pano1.ceilZ * (1-r);
  62403. let sideMinZ_ = pano0.floorPosition.z * r + pano1.floorPosition.z * (1-r);
  62404. [sideMaxZ_,sideMinZ_].forEach(z=>{
  62405. posArr.push(e.pano.position.clone().setZ(z).add(e.dir_)); //是直接使用最长dis的那个intersect点好还是mid
  62406. });
  62407. });
  62408. }
  62409. });
  62410. }else {
  62411. //这段针对点云时,仅测试才会执行到
  62412. sideCount = [1,1];
  62413. let sideDirs = [getDir(Math.PI/2, vec), getDir(-Math.PI/2, vec)];
  62414. sideDirs.forEach((dir_ ,index)=>{
  62415. let dis = getFar(dir_, null, mid); //直接从中点求两侧的距离
  62416. dir_.multiplyScalar( /* Math.max( */dis/* , sideDis[index]) */ );
  62417. [midMaxZ,midMinZ].forEach(z=>{
  62418. posArr.push(mid.clone().setZ(z).add(dir_));
  62419. });
  62420. });
  62421. }
  62422. //中心:
  62423. [midMaxZ,midMinZ].forEach(z=>{
  62424. posArr.push(mid.clone().setZ(z));
  62425. });
  62426. };
  62427. //positions存放顺序:pano的每边的 zMax和zMin 、count1个dir的点 ;侧边的点 ;连接处顶底的中点
  62428. let addFaces = ()=>{
  62429. let getPI = function(index, posType, panoIndex){//获取顶点序号
  62430. return 2 + (count1*2 + 2 ) * panoIndex + index*2 + (posType == 'top' ? 0 : 1)
  62431. };
  62432. let getSidePI = function(index, posType, panoIndex){//获取侧边顶点序号
  62433. if(panoIndex == 1) index += sideCount[0];
  62434. return getPI(index, posType, 2)-2
  62435. };
  62436. let getPanoPI = function(posType, panoIndex){//获取pano处对应的点序号
  62437. return getPI(-1, posType, panoIndex)
  62438. };
  62439. let topCenter = posArr.length-2; //最后添加的两个中心点
  62440. let btmCenter = posArr.length-1;
  62441. for(let i=0;i<2;i++){
  62442. for(let index=1; index<count1; index++){
  62443. //pano外侧半圆围墙
  62444. faceArr.push([getPI(index,'top',i), getPI(index-1,'btm',i), getPI(index-1,'top',i)],//加入一块四方面
  62445. [getPI(index,'top',i), getPI(index,'btm',i), getPI(index-1,'btm',i)]);
  62446. faceArr.push([getPI(index,'top',i), getPI(index-1,'top',i), getPanoPI('top',i)]);//天花板扇形
  62447. faceArr.push([getPI(index,'btm',i), getPI(index-1,'btm',i), getPanoPI('btm',i)]);//地板扇形
  62448. }
  62449. let j = (i + 1) % 2; //另一个pano
  62450. //侧边
  62451. for(let u=0; u<=sideCount[i]; u++){
  62452. //侧边每个四方的左上右上左下右下四个点
  62453. let pLT = u == 0 ? getPI(0,'top',i) : getSidePI(u-1, 'top',i);
  62454. let pRT = u == sideCount[i] ? getPI(count1-1,'top',j) : getSidePI(u, 'top',i);
  62455. let pLB = u == 0 ? getPI(0,'btm',i) : getSidePI(u-1, 'btm',i);
  62456. let pRB = u == sideCount[i] ? getPI(count1-1,'btm',j) : getSidePI(u, 'btm',i);
  62457. faceArr.push([pLT,pLB,pRB],[pLT,pRB,pRT]);//外侧四方面
  62458. faceArr.push([pLT,topCenter,pRT] ,[pLB,btmCenter,pRB] );//顶部和底部到整体中心的扇形(由于点的顺序是根据和两个pano的距离,因此到中心的夹角并没按顺序排列,所以可能会重叠)
  62459. if(i==0){//只需要算一次
  62460. //顶部和底部中心与两个pano边构成的三角形
  62461. if(u == 0){
  62462. faceArr.push([pLT,getPI(count1-1,'top',i),topCenter],
  62463. [pLB,getPI(count1-1,'btm',i),btmCenter],
  62464. );
  62465. }
  62466. //不能用else 因为当length==0时u==0也==sideCount[i],此时就是要两个面
  62467. if(u == sideCount[i]){
  62468. faceArr.push([pRT,getPI(0,'top',j),topCenter],
  62469. [pRB,getPI(0,'btm',j),btmCenter],
  62470. );
  62471. }
  62472. }
  62473. }
  62474. }
  62475. };
  62476. let posArr = [];
  62477. let faceArr = [];
  62478. //两点连线的水平向量
  62479. let vec = new Vector3().subVectors(pano0.position, pano1.position).setZ(0).normalize();
  62480. /* let sideDis0 = */addPos(pano0, vec);
  62481. /* let sideDis1 = */addPos(pano1, vec.clone().negate());
  62482. addSide();
  62483. addFaces();
  62484. //MeshDraw.updateGeometry(this.cube.geometry, posArr, faceArr)
  62485. let geo = MeshDraw.createGeometry(posArr, faceArr);
  62486. this.cube.geometry = geo;
  62487. this.cube.scale.set(1,1,1);
  62488. this.cube.position.set(0,0,0);
  62489. //this.cube.scale.set(100,100,100);
  62490. //this.cube.position.copy(pano1.position).multiplyScalar(-100)
  62491. }else {
  62492. useBound(pano0.pointcloud.bound);
  62493. }
  62494. }
  62495. /*
  62496. 注: 修改skybox,若不准的话,会遮住其他mesh,比如marker。尤其在没有深度贴图时。
  62497. */
  62498. /* updateCube(params){
  62499. let size = params.boundSize
  62500. this.cube.scale.set(Math.max(size.x, HighMapCubeWidth), Math.max(size.y, HighMapCubeWidth), Math.max(size.z, HighMapCubeWidth) )
  62501. this.cube.position.copy(params.center)
  62502. } */
  62503. bump(direction) {//撞墙弹回效果
  62504. if (!this.bumping && !this.latestToPano) {
  62505. console.log('bump');
  62506. let distance = Potree.settings.displayMode == 'showPanos' ? 0.3 : 0.2;//感觉点云模式比全景模式更明显,所以降低
  62507. let currentPos = this.position.clone();
  62508. let endPosition = new Vector3().addVectors(this.position, direction.clone().multiplyScalar(distance));
  62509. let duration = 150;
  62510. viewer.scene.view.setView({position:endPosition, duration,
  62511. callback:()=>{
  62512. viewer.scene.view.setView({position:currentPos, duration: duration*5,
  62513. callback: ()=>{
  62514. this.bumping = false;
  62515. //this.dispatchEvent('cameraMoveDone')
  62516. },
  62517. Easing:'easeInOutSine',
  62518. cancelFun:()=>{this.bumping = false;}
  62519. });
  62520. this.bumping = true;
  62521. },
  62522. cancelFun:()=>{this.bumping = false;},
  62523. Easing:'easeInOutSine'
  62524. });
  62525. this.bumping = true;
  62526. }
  62527. //备注:将4dkk中的‘前后方向变化fov、左右方向移动镜头’ 都改为移动镜头。 因为这里无法判断左右离壁距离。
  62528. }
  62529. /* load(pano, ){
  62530. return new Promise(resolve => {
  62531. let texture = texLoader.load(pano.file, resolve);
  62532. texture.wrapS = THREE.RepeatWrapping;
  62533. texture.repeat.x = -1;
  62534. texture.flipY = false//add
  62535. pano.texture = texture;
  62536. //add
  62537. texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
  62538. texture.minFilter = THREE.LinearFilter;
  62539. texture.magFilter = THREE.LinearFilter;
  62540. texture.generateMipmaps = true;
  62541. });
  62542. } */
  62543. flyToPanoClosestToMouse() {
  62544. /* if (Date.now() - this.mouseLastMoveTime > 50) {
  62545. //this.intersect = this.getMouseIntersect();
  62546. this.intersect && this.updateClosestPano(this.intersect);
  62547. } */
  62548. if(!Potree.settings.ifShowMarker){//不显示marker的时候mousemove没更新鼠标最近点所以更新
  62549. this.updateClosestPano(viewer.inputHandler.intersectPoint);
  62550. }
  62551. //console.log('flyToPanoClosestToMouse',this.closestPano)
  62552. if (this.closestPano) {
  62553. let pano = this.closestPano;
  62554. return this.flyToPano({
  62555. pano
  62556. });
  62557. }
  62558. var direction = this.viewer.inputHandler.getMouseDirection().direction;
  62559. this.flyDirection(direction);
  62560. }
  62561. flyDirection(direction, option1, option2) {
  62562. var deferred = $.Deferred();
  62563. //this.history.invalidate();
  62564. var panoSet = this.closestPanoInDirection(direction, option1, option2);
  62565. if (panoSet) {
  62566. this.flyToPano({
  62567. pano: panoSet,
  62568. callback: deferred.resolve.bind(deferred, !0)
  62569. } );
  62570. } else {
  62571. this.bump(direction);
  62572. deferred.resolve(!1);
  62573. }
  62574. return deferred.promise();
  62575. }
  62576. closestPanoInDirection(direction, option1, option2) {
  62577. return this.rankedPanoInDirection(0, direction, option1, option2)
  62578. }
  62579. rankedPanoInDirection(t, direction, option1, option2){
  62580. var panoSet = {
  62581. pano: null,
  62582. candidates: [] //缓存顺序--如果需要打印的话
  62583. };
  62584. t || (t = 0);
  62585. option1 = void 0 !== option1 ? option1 : .75;
  62586. var o = option2 ? "angle" : "direction";
  62587. var floor = viewer.modules.SiteModel.currentFloor;
  62588. var entity = viewer.modules.SiteModel.inEntity;
  62589. var getHeightDis = (pano)=>{
  62590. if(floor && !floor.panos.includes(pano) && pano.position.z < this.position.z){ //若是上方的漫游点,就正常走。因为一般不会点击天花板。
  62591. return this.position.z - pano.position.z
  62592. }else {
  62593. return 0
  62594. }
  62595. };
  62596. var request = [//必要条件
  62597. Images360.filters.inPanoDirection( this.position, direction, option1),
  62598. //Images360.filters.isNeighbourPanoTo(this.currentPano),
  62599. Images360.filters.not(this.currentPano),
  62600. Images360.filters.isEnabled(),
  62601. /* (pano)=>{ //防止不小心穿越地板到下一层, 尽量走楼梯,实在没有楼梯或楼梯漫游点稀疏的话就通过楼层按钮。
  62602. let dis = getHeightDis(pano)
  62603. //console.log('getHeightDis',pano.id,dis)
  62604. if(dis < 3){//不能超过最大高度差( 最大高度差暂定为接近一层楼的高度。)(最好的解决方案是设置漫游可行)
  62605. return true
  62606. }else{
  62607. return this.isNeighbour(this.currentPano, pano)
  62608. }
  62609. } */
  62610. ];
  62611. var list = [//决胜项目
  62612. Images360.scoreFunctions.distanceSquared(this.position,1, true),
  62613. Images360.scoreFunctions[o]( this.position, direction,true),
  62614. (pano)=>{
  62615. let neighbour = this.isNeighbour(this.currentPano, pano);
  62616. //console.log('neighbour', pano.id, neighbour ? directionFactor*0.4 : 0)
  62617. return neighbour ? directionFactor*1 : 0;
  62618. }
  62619. /* (pano)=>{//尽量不穿越地板到下一层
  62620. let dis = getHeightDis(pano)
  62621. return -dis * directionFactor * 0.1;
  62622. }, */
  62623. /* (pano)=>{ //尽量在一个建筑内行走,这样不易穿墙
  62624. if(entity && !entity.panos.includes(pano) ){
  62625. return - directionFactor * 0.05; //- directionFactor * 0.2;
  62626. }else{ //不能设置太高,否则会走不进大房间的小房间中,因为容易穿过小房间的一个门到另一个门外
  62627. return 0
  62628. }
  62629. } */
  62630. ];
  62631. if(viewer.inputHandler.intersectPoint && this.currentPano ){//方便上下楼, 考虑panos之间的角度差
  62632. let pos1 = this.currentPano.floorPosition;
  62633. let vec1 = new Vector3().subVectors(viewer.inputHandler.intersectPoint.location, pos1 ).normalize();//应该只有atPano时才会执行到这吧?
  62634. list.push( function(pano) {
  62635. var pos2 = pano.floorPosition;
  62636. var vec2 = pos2.clone().sub(pos1).normalize();
  62637. //console.log('direction2', pano.id, vec2.dot(vec1) * directionFactor * 1 );
  62638. return vec2.dot(vec1) * directionFactor * 1
  62639. });
  62640. }
  62641. this.findRankedByScore(t,request,list,panoSet);
  62642. return panoSet.pano;
  62643. }
  62644. findRankedByScore(e, t, i, n) {
  62645. n && (n.candidates = null, //candidates 缓存顺序--如果需要打印的话
  62646. n.pano = null),
  62647. e || (e = 0);
  62648. var r = Common.sortByScore(this.panos, t, i);
  62649. //console.log('findRankedByScore', r && r.map(u=>u.item.id + '|' + u.score))
  62650. return !r || 0 === r.length || e >= r.length ? null : (n && (n.candidates = r,
  62651. n.pano = r[e].item),
  62652. r[e].item)
  62653. }
  62654. isNeighbour(pano0, pano1){//是否之间没有遮挡(在加载visibles之前,自己算) 最好pano0是currentPano
  62655. let map0 = this.neighbourMap[pano0.id];
  62656. if(!map0){
  62657. map0 = {};
  62658. this.neighbourMap[pano0.id] = map0;
  62659. }
  62660. let map1 = this.neighbourMap[pano1.id];
  62661. if(!map1){
  62662. map1 = {};
  62663. this.neighbourMap[pano1.id] = map1;
  62664. }
  62665. let ifNeighbour = map0[pano1.id];//map0.get(pano1)
  62666. if(ifNeighbour == void 0){
  62667. ifNeighbour = true;
  62668. let margin = 0.1;
  62669. let usePointcloud = pano0.depthTex;
  62670. if(pano0.depthTex || pano1.depthTex){
  62671. let mainPano = pano0.depthTex ? pano0 : pano1;
  62672. let subPano = pano0.depthTex ? pano1 : pano0;
  62673. //暂时只判断到pano,不判断到marker的方向
  62674. let dir = new Vector3().subVectors(subPano.position, mainPano.position).normalize();
  62675. let intersectPoint = viewer.images360.depthSampler.sample({dir}, mainPano, true);
  62676. if(intersectPoint && intersectPoint.distance+margin <= pano0.position.distanceTo(pano1.position)){
  62677. ifNeighbour = false;
  62678. }
  62679. }else {
  62680. //使用点云判断(有深度贴图时不会执行到这)
  62681. ifNeighbour = !viewer.inputHandler.ifBlockedByIntersect(pano1.position, margin, true, pano0.position);
  62682. console.log('使用点云判断');
  62683. if(ifNeighbour){//点云模式下未加载的点云会判断为true
  62684. let dir = new Vector3().subVectors(pano1.position,pano0.position).normalize();
  62685. let dis = pano1.position.distanceTo(pano0.position);
  62686. let hfov = cameraLight.getHFOVForCamera(viewer.mainViewport.camera , true );
  62687. let max = Math.cos(MathUtils.degToRad(10));
  62688. let min = Math.cos(MathUtils.degToRad(80));
  62689. if(this.getDirection().dot(dir) < MathUtils.clamp(Math.cos(hfov/2/* THREE.Math.degToRad(40) */) * dis / 10, min, max )){//距离越远要求和视线角度越接近
  62690. ifNeighbour = undefined; //不确定
  62691. }
  62692. }
  62693. }
  62694. map0[pano1.id] = ifNeighbour;//map0.set(pano1, ifNeighbour)
  62695. map1[pano0.id] = ifNeighbour;//map1.set(pano0, ifNeighbour)
  62696. }
  62697. return ifNeighbour
  62698. }
  62699. updateClosestPano(intersect, state) {//hover到的pano 大多数时候是null
  62700. /* if(this.isAtPano() ){
  62701. filterFuncs.push(Images360.filters.not(this.currentPano));
  62702. //当静止在漫游点时closestPano只限制在每个漫游点附近,而在观看整个模型时,范围夸大,识别为离鼠标最近的漫游点。 (故而要排除flying时)
  62703. filterFuncs.push(Images360.filters.inFloorDirection(this.position, viewer.scene.view.direction, .25))//许钟文改
  62704. filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect, 0.35));
  62705. filterFuncs.push(Images360.filters.isEnabled())
  62706. }else{
  62707. } */
  62708. var pano;
  62709. if(this.isAtPano() ){
  62710. if(intersect instanceof Panorama){
  62711. pano = state ? intersect : null;
  62712. }else {
  62713. return
  62714. }
  62715. }else {
  62716. if(this.flying)return;
  62717. var filterFuncs = [];
  62718. intersect = intersect && intersect.location;
  62719. if(!intersect)return
  62720. let sortFuncs = Potree.settings.editType != 'pano'? [Images360.sortFunctions.floorDisSquaredToPoint(intersect)] : [Images360.sortFunctions.disSquaredToPoint(intersect)];
  62721. pano = Common.find(this.panos, filterFuncs, sortFuncs);
  62722. }
  62723. if (pano != this.closestPano) {
  62724. pano && (this.isPanoHover = !0);
  62725. this.closestPanoChanging(this.closestPano, pano); // 高亮marker
  62726. //console.log('closestPano '+ (pano ? pano.id : 'null' ))
  62727. this.closestPano = pano;
  62728. } else {
  62729. this.isPanoHover = !1;
  62730. }
  62731. }
  62732. closestPanoChanging(oldPano, newPano){
  62733. if(!Potree.settings.ifShowMarker)return
  62734. oldPano && oldPano.hoverOff({byImages360:true});
  62735. newPano && newPano.hoverOn({byImages360:true});
  62736. }
  62737. getTileDirection(){//根据不同dataset的来存储
  62738. var vectorForward = viewer.scene.view.direction.clone();
  62739. var vectorForwards = viewer.scene.pointclouds.map(e=>{
  62740. var inv = new Matrix4().copy(e.rotateMatrix).invert();//乘上dataset的旋转的反转
  62741. var direction = vectorForward.clone().applyMatrix4(inv);
  62742. return {
  62743. datasetId: e.dataset_id,
  62744. direction: math.convertVector.ZupToYup(direction)
  62745. }
  62746. });
  62747. //return vectorForwards[0].direction
  62748. return {
  62749. datasetsLocal: vectorForwards,
  62750. vectorForward
  62751. }
  62752. }
  62753. update(){
  62754. let {viewer} = this;
  62755. /* if(currentlyHovered){
  62756. currentlyHovered.material = sm;
  62757. currentlyHovered = null;
  62758. }
  62759. if(this.selectingEnabled){
  62760. this.handleHovering();
  62761. } */
  62762. if(this.tileDownloader.started){
  62763. var vectorForwards = this.getTileDirection();
  62764. //vectorForwards = vectorForwards[0].direction
  62765. this.updateTileDownloader(tileArr, vectorForwards);
  62766. this.updatePanoRenderer(vectorForwards);
  62767. }
  62768. this.updateZoomPano();
  62769. }
  62770. updateTileDownloader(t, vectorForward) {
  62771. var i = this.nextPano || this.currentPano;
  62772. if(i){
  62773. this.tileDownloader.tilePrioritizer.updateCriteria(i, viewer.scene.view.position.clone() , vectorForward, t.length > 0 ? t : null),
  62774. this.tileDownloader.processPriorityQueue = !0;
  62775. }
  62776. }
  62777. updatePanoRenderer(vectorForward) {
  62778. var i = this.nextPano || this.currentPano;
  62779. if(i){
  62780. if (this.panoRenderer.hasQueuedTiles() && i) {
  62781. this.panoRenderer.updateDirection(vectorForward);
  62782. }
  62783. }
  62784. }
  62785. //等待部分加载完
  62786. checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, l) {
  62787. if (!pano) {
  62788. console.error("Player.checkAndWaitForTiledPanoLoad() -> Cannot load texture for null pano.");
  62789. }
  62790. var vectorForward = this.getTileDirection();
  62791. if (!pano.isLoaded(basePanoSize)) {
  62792. iswait && viewer.waitForLoad(pano, function() {//发送loading
  62793. return pano.isLoaded(basePanoSize)
  62794. });
  62795. /* var fov = {//test for direction 预加载的边缘有一丢丢不准确,尤其在相机倾斜时(4dkk也是)。
  62796. hFov: cameraLight.getHFOVForCamera(viewer.scene.getActiveCamera() ),
  62797. vFov: viewer.scene.getActiveCamera().fov
  62798. }//原先是null,不要求方向 */
  62799. var fov = null; //若不为null的话,因为可能可见范围的tile下载过了从而无法触发下载,然后得不到下载成功的消息,怎么办
  62800. pano.loadTiledPano(/* 1024 */ basePanoSize , vectorForward, fov, isclear, l, null).done(function(e, t) {
  62801. callback1 && callback1(e, t);
  62802. }
  62803. .bind(this)).fail(function(msg) {
  62804. callback2 && callback2(msg);
  62805. }
  62806. .bind(this)).progress(function(e, t, i) {
  62807. progressCallback && progressCallback(e, t, i);
  62808. }
  62809. .bind(this));
  62810. return !0;
  62811. }
  62812. }
  62813. /* load(){//quickstart里的
  62814. var lowSize = this.qualityManager.getPanoSize(PanoSizeClass.BASE),
  62815. highSize = this.qualityManager.getPanoSize(PanoSizeClass.STANDARD),
  62816. d = cameraLight.getHFOVForCamera(this.quickStartcamera, $('#player').width(), $('#player').height()),
  62817. p = this.quickStartcamera.fov,
  62818. r = Vectors.FORWARD.clone().applyQuaternion(this.view.quaternion)
  62819. var promise1 = this.view.pano.loadTiledPano(highSize, r, {
  62820. hFov: d,
  62821. vFov: p
  62822. }, !1, !1 , !0 )
  62823. var promise2 = this.view.pano.loadTiledPano(lowSize, r.clone().negate(), null, !1, !1, !0)
  62824. this.loadPromise = this.pano.hasVideo ? promise2 : promise1;
  62825. //this.loadPromise = promise1;
  62826. }
  62827. */
  62828. fitPanoTowardPoint(o){ //寻找最适合的点位
  62829. var point = o.point, //相机最佳位置
  62830. target = o.target, //实际要看的位置
  62831. require = o.require || [],
  62832. rank = o.rank || [],
  62833. force = o.force,
  62834. getAll = o.getAll,
  62835. bestDistance = o.bestDistance || 0;
  62836. let camera = viewer.scene.getActiveCamera();
  62837. if(target){
  62838. var vec = new Vector3().subVectors(target,point).normalize();
  62839. }
  62840. //if(o.floor)require.push(Panorama.filters.atFloor(o.floor))
  62841. if(o.boundSphere){//只接受boundSphere
  62842. let aspect = 1;//size.x / size.y
  62843. let dis;
  62844. if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
  62845. dis = /* size.y */o.boundSphere.radius/* / 2 *// MathUtils.degToRad(camera.fov / 2);
  62846. }else {
  62847. let hfov = cameraLight.getHFOVForCamera(camera , true );
  62848. dis = /* size.x */ o.boundSphere.radius /* / 2 */ / (hfov / 2);
  62849. }
  62850. bestDistance = dis;//*0.8
  62851. }
  62852. let bestDisSquared = bestDistance * bestDistance;
  62853. rank.push((pano)=>{
  62854. let dis1 = Math.abs(pano.position.distanceToSquared(point) - bestDisSquared); //距离最佳位置
  62855. if(!target){
  62856. return -dis1
  62857. }else {
  62858. let dis2 = pano.position.distanceToSquared(target); //距离目标点
  62859. let vec2 = new Vector3().subVectors(target,pano.position).normalize();
  62860. let cos = vec.dot(vec2);
  62861. let result = (- dis1 - Math.pow(dis2 , 1.5)) / (cos + 2); // cos+2是为了调整到1-3, 尽量贴近最佳位置的角度;
  62862. //console.log(pano.id, dis1,dis2, cos, result)
  62863. return result
  62864. }
  62865. },(pano)=>{
  62866. if(pano.depthTex && o.checkIntersect){ //没加载好的话,不管了
  62867. let intersect = viewer.inputHandler.ifBlockedByIntersect(target, 0.1 , null, null, null, pano);
  62868. if(intersect){
  62869. //console.log('intersected', pano.id )
  62870. return -10000
  62871. }else return 0
  62872. }else return 0
  62873. });
  62874. /* var temp = {position:point}
  62875. rank.push(Panorama.scoreFunctions.distanceSquared(temp, -2)); */
  62876. var g = Common.sortByScore(this.panos, require, rank);
  62877. if(getAll)return g;
  62878. return g && g.length > 0 && g[0].item
  62879. }
  62880. //---------------scroll zoom ------------------------------------------
  62881. /* zoomIn = function() { //放大
  62882. this.zoomBy(1 + this.zoomSpeed);
  62883. }
  62884. zoomOut = function() {//缩小
  62885. this.zoomBy(1 - this.zoomSpeed);
  62886. } */
  62887. zoomBy(e, pointer) {//以倍数
  62888. this.zoomTo(this.zoomLevel * e, pointer);
  62889. }
  62890. zoomTo(zoomLevel, pointer) {//缩放到某绝对zoomLevel
  62891. let zoom = Potree.settings.zoom;
  62892. if (zoom.enabled) {
  62893. zoomLevel = MathUtils.clamp(zoomLevel, zoom.min, zoom.max);
  62894. //console.log(zoomLevel)
  62895. if(zoomLevel == this.zoomLevel) return;
  62896. /* if (zoomLevel > this.zoomLevel) {
  62897. this.emit(ZoomEvents.ZoomIn);
  62898. zoomLevel === settings.zoom.max && this.emit(ZoomEvents.ZoomMax);
  62899. } else if (zoomLevel < this.zoomLevel) {
  62900. this.emit(ZoomEvents.ZoomOut);
  62901. zoomLevel === settings.zoom.min && this.emit(ZoomEvents.ZoomMin);
  62902. } */
  62903. this.zoomLevel = zoomLevel;
  62904. //定点缩放:使当前鼠标所在的位置缩放后不变
  62905. let view = viewer.scene.view;
  62906. let originDir = viewer.scene.view.direction;
  62907. let oldPointerDir = viewer.inputHandler.getMouseDirection(pointer).direction;
  62908. viewer.setFOV(Potree.config.view.fov * (1 / this.zoomLevel));
  62909. let newPointerDir = viewer.inputHandler.getMouseDirection(pointer).direction;
  62910. view.direction = oldPointerDir; //获取一下鼠标所在位置的yaw 和 pitch
  62911. let oldPitch = view.pitch, oldYaw = view.yaw;
  62912. view.direction = newPointerDir;
  62913. let newPitch = view.pitch, newYaw = view.yaw;
  62914. view.direction = originDir; //还原
  62915. viewer.scene.view.pitch -= newPitch - oldPitch;
  62916. viewer.scene.view.yaw -= newYaw - oldYaw;
  62917. }
  62918. }
  62919. zoomFovTo( fov ) { //通过fov来算zoomLevel
  62920. let zoomLevel = this.baseFov / fov;
  62921. this.zoomTo( zoomLevel );
  62922. }
  62923. smoothZoomTo(aimLevel, dur=0) {
  62924. var currentLevel = this.zoomLevel;
  62925. if(currentLevel == aimLevel)return;
  62926. var fun = (progress)=>{
  62927. //progress > 1 && (progress = 1)
  62928. let level = currentLevel * (1 - progress) + aimLevel * progress;
  62929. this.zoomTo(level, !0);
  62930. };
  62931. transitions.start(fun, dur, null, null, 0 , easing['easeInOutQuad'] );
  62932. }
  62933. /* zoomDefault{
  62934. this.zoomTo(1, !0)
  62935. }
  62936. smoothZoomToDefault(e, t) {
  62937. var i, n = this.zoomLevel,
  62938. r = function(e) {
  62939. e > 1 && (e = 1),
  62940. i = n * (1 - e) + e,
  62941. this.zoomTo(i, !0)
  62942. }
  62943. .bind(this),
  62944. o = function() {
  62945. this.zoomDefault(),
  62946. t && window.setTimeout(t, 50)
  62947. }
  62948. .bind(this);
  62949. transitions.start(r, e, o, null, 0, easing[settings.transition.blendEasing])
  62950. } */
  62951. updateZoomPano() {
  62952. if (!this.panoRenderer.zoomPanoRenderingDisabled && Potree.settings.displayMode == 'showPanos') {
  62953. var currentPano = this.currentPano;
  62954. if (currentPano) {
  62955. var activationThreshold = Potree.settings.navTileClass == '2k' && Potree.settings.tileClass == '4k' ? 1.7 : Potree.settings.zoom.activationThreshold;//1.1
  62956. var t = this.zoomLevel > activationThreshold,
  62957. n = !(this.flying && this.nextPano && this.nextPano !== this.currentPano),
  62958. r = t && n;
  62959. this.tileDownloader.tilePrioritizer.setZoomingActive(r);
  62960. this.panoRenderer.setZoomingActive(r, currentPano, !0);
  62961. var o = (pano, zoomedFlag)=>{
  62962. this.panoRenderer.resetRenderStatus(pano.id, !1, !0, this.qualityManager.getMaxNavPanoSize());
  62963. this.panoRenderer.clearAllQueuedUploadsForPano(pano.id);
  62964. this.panoRenderer.renderPanoTiles(pano.id, null, !1, !1);
  62965. pano.setZoomed(zoomedFlag);
  62966. };
  62967. if (r && (!currentPano.zoomed || this.qualityManager.zoomLevelResolution && this.qualityManager.zoomLevelResolution != '4k')) {
  62968. currentPano.zoomed || o(currentPano, !0);
  62969. if(Potree.settings.navTileClass == '1k' && Potree.settings.tileClass != '1k' && this.zoomLevel < 2){
  62970. this.panoRenderer.enableHighQuality( function() {//开启2k
  62971. if(Potree.settings.tileClass != '4k') o(currentPano, !0);
  62972. }.bind(this));
  62973. }else {
  62974. this.panoRenderer.enableUltraHighQualityMode(function() {//开启4k getMaxZoomPanoSize
  62975. this.qualityManager.useUltraHighResolutionPanos && (Potree.settings.zoom.max = Potree.config.ultraHighQualityMaxZoom);
  62976. o(currentPano, !0);
  62977. }.bind(this));
  62978. }
  62979. } else {
  62980. !t && currentPano.zoomed && o(currentPano, !1);
  62981. }
  62982. if(r && Potree.settings.navTileClass == '1k' && Potree.settings.tileClass == '4k' ){ //目前只有手机端navTileClass == '1k'
  62983. var change = (zoomedFlag)=>{
  62984. this.qualityManager.updateMaximums();//更新maxZoomPanoSize
  62985. this.panoRenderer.setupZoomRenderTarget(); //更新renderTarget
  62986. //currentPano.setZoomed(t);//更新uniforms贴图
  62987. };
  62988. this.qualityManager.zoomLevelResolution = this.zoomLevel >= 2 ? '4k' : this.zoomLevel > 1.1 ? '2k' : '1k';
  62989. if(this.oldZoomLevel < 2 && this.zoomLevel >= 2){//1k/2k-4k
  62990. change();
  62991. o(currentPano, t);
  62992. }else if(this.oldZoomLevel <= Potree.settings.zoom.activationThreshold && this.zoomLevel > Potree.settings.zoom.activationThreshold){//1k-2k
  62993. change();
  62994. }else if(this.oldZoomLevel > 2 && this.zoomLevel <= 2){//4k-2k/1k
  62995. change();
  62996. o(currentPano, t);
  62997. }else if(this.oldZoomLevel > Potree.settings.zoom.activationThreshold && this.zoomLevel <= Potree.settings.zoom.activationThreshold){//2k-1k
  62998. change();
  62999. }
  63000. this.oldZoomLevel = this.zoomLevel;
  63001. }
  63002. }
  63003. }
  63004. }
  63005. //--------------------
  63006. addHighMapCube(){//创建8*8的tile cube 主要因手机版崩溃 要在电脑端测试得设置maxRenderTargetSize
  63007. if( Potree.settings.tileClass == '4k' && this.qualityManager.maxRenderTargetSize == 2048){
  63008. var geo = new PlaneGeometry(1, 1, 1, 1);
  63009. var cube = new Object3D;
  63010. for(var cubeIndex=0; cubeIndex<6; cubeIndex++){
  63011. var face = new Object3D;
  63012. for(var i=0;i<8;i++){
  63013. for(var j=0;j<8;j++){
  63014. var tile = new Mesh(geo, new MeshBasicMaterial({
  63015. //side:THREE.DoubleSide
  63016. }));
  63017. tile.position.set(i-3.5, j-3.5, -4);
  63018. tile.material.opacity = 0.4;
  63019. tile.material.transparent = true;
  63020. if(Potree.settings.isTest){
  63021. var colorHue = Math.random();
  63022. tile.material.color = (new Color()).setHSL(colorHue, 0.5, 0.9);
  63023. }
  63024. tile.visible = false;
  63025. face.add(tile);
  63026. }
  63027. }
  63028. switch(cubeIndex){
  63029. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  63030. face.rotation.set(0,Math.PI/2,0);
  63031. break;
  63032. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  63033. face.rotation.set(0,-Math.PI/2,0);
  63034. break;
  63035. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
  63036. var rot1 = new Quaternion().setFromAxisAngle(new Vector3(0,1,0),Math.PI);
  63037. var rot2 = new Quaternion().setFromAxisAngle(new Vector3(1,0,0),Math.PI/2);
  63038. face.quaternion.copy(rot1).multiply(rot2);
  63039. //face.rotation.set(Math.PI/2,0,0);
  63040. break;
  63041. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  63042. //face.rotation.set(-Math.PI/2,0,0);
  63043. var rot1 = new Quaternion().setFromAxisAngle(new Vector3(0,1,0),Math.PI);
  63044. var rot2 = new Quaternion().setFromAxisAngle(new Vector3(1,0,0),-Math.PI/2);
  63045. face.quaternion.copy(rot1).multiply(rot2);
  63046. break;
  63047. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  63048. face.rotation.set(0,Math.PI,0);
  63049. break;
  63050. case GLCubeFaces$1.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  63051. face.rotation.set(0,0,0);
  63052. }
  63053. face.scale.set(1,-1,1);
  63054. cube.add(face);
  63055. }
  63056. cube.name = 'highMapCube';
  63057. this.highMapCube = cube;
  63058. viewer.scene.scene.add(cube);
  63059. //cube.scale.set(0.01,0.01,0.01)
  63060. this.highMapCube.visible = false;
  63061. viewer.setObjectLayers(this.highMapCube, 'sceneObjects'/* 'skybox' */); //如果是skybox层,点云可见时会被遮住,depthTest为false呢? 但不会遮住场景物体
  63062. //console.warn('addHighMapCube')
  63063. }
  63064. }
  63065. isHighMapLoaded( cubeFace, tileX, tileY){
  63066. var tile = this.highMapCube.children[cubeFace].children[tileX*8+tileY];
  63067. return !!tile.material.map
  63068. }
  63069. updateHighMap(tex, cubeFace, tileX, tileY){
  63070. //console.warn('updateHighMap')
  63071. var tile = this.highMapCube.children[cubeFace].children[tileX*8+tileY];
  63072. tile.material.map = tex;
  63073. tile.material.opacity = 1;
  63074. tile.material.transparent = false;
  63075. tile.visible = true;
  63076. tile.material.needsUpdate = true; //发现每次开始放大但还未放大到4k时也会把之前加载过的4k加载
  63077. }
  63078. resetHighMap(){
  63079. if(!this.highMapCube) return
  63080. //console.warn('resetHighMap')
  63081. this.highMapCube.children.forEach(e=>e.children.forEach(tile=>{
  63082. if(tile.material.map){
  63083. tile.material.map.dispose();
  63084. tile.material.map.loaded = !1;
  63085. tile.material.map.version = 0;
  63086. var h = viewer.renderer.properties.get(tile.material.map);
  63087. viewer.renderer.getContext().deleteTexture(h.__webglTexture);
  63088. //类似app.sceneRenderer.deallocateCubeTexture(tile.material.map)
  63089. tile.material.map = null;
  63090. /* tile.material.opacity = 0.4;
  63091. tile.material.transparent = true */
  63092. tile.material.needsUpdate = true;
  63093. tile.visible = false;
  63094. }
  63095. }));
  63096. this.highMapCube.visible = false;
  63097. }
  63098. setHighMap(pano){
  63099. if(!this.highMapCube) return
  63100. this.highMapCube.position.copy(pano.position);
  63101. //可以利用第0个pano查看,其 rotation4dkk是(_x: 0, _y: -1.5707963267948966, _z: 0 )而手动旋转至(_x:1.5707963, _y: -1.57079, _z: 0)时才正确,说明要在4dkk的旋转基础上,绕x轴转90度,(也就是转成navvis坐标系), 然后得到YupToZup的函数写法的
  63102. this.highMapCube.quaternion.copy( math.convertQuaternion.YupToZup( pano.quaternion4dkk ) );
  63103. //乘上数据集整体的旋转:
  63104. let modelRotQua = new Quaternion().setFromRotationMatrix(pano.pointcloud.rotateMatrix);
  63105. this.highMapCube.quaternion.premultiply(modelRotQua);
  63106. }
  63107. showHighMap(){
  63108. if(!this.highMapCube) return
  63109. //console.warn('showHighMap')
  63110. this.highMapCube.visible = true;
  63111. }
  63112. hideHighMap(){
  63113. if(!this.highMapCube) return
  63114. //console.warn('hideHighMap')
  63115. this.highMapCube.visible = false;
  63116. }
  63117. //缩小后继续显示cube呢还是不显示? 不显示的话,就要把cube上的复制到renderTarget上……会不会又崩溃,or没加载的显示???
  63118. addPanoData(data, datasetId ){
  63119. //data[0].file_id = '00019'
  63120. if(data.data) data = data.data;
  63121. if(data.length == 0)console.error(datasetId + ' 没有漫游点');
  63122. //data = data.sort(function(a,b){return a.id-b.id})
  63123. data.forEach((info)=>{
  63124. //if(Potree.fileServer){
  63125. info.id = this.panos.length; //把info的id的一长串数字改简单点
  63126. //}
  63127. let pano = new Panorama( info, this );
  63128. /* pano.mesh.layers.set(Potree.config.renderLayers.marker)
  63129. pano.marker.layers.set(Potree.config.renderLayers.marker) */
  63130. pano.addEventListener('dispose',(e)=>{
  63131. if(this.closestPano == pano) this.closestPano = null;
  63132. });
  63133. this.panos.push(pano);
  63134. if(Potree.settings.editType == 'pano'){
  63135. Potree.settings.datasetsPanos[datasetId].panos.push(pano);
  63136. }
  63137. });
  63138. }
  63139. loadDone(){
  63140. viewer.setObjectLayers(this.node, 'sceneObjects');
  63141. //this.updateCube(/* viewer.bound */)
  63142. this.panos.forEach(e=>{
  63143. e.label && viewer.setObjectLayers(e.label, 'bothMapAndScene');
  63144. });
  63145. this.tileDownloader.setPanoData(this.panos, [] /* , Potree.settings.number */);
  63146. {
  63147. /* var panosBound = new THREE.Box3
  63148. this.panos.forEach(pano=>{
  63149. panosBound.expandByPoint(pano.position)
  63150. })
  63151. let center = panosBound.getCenter(new THREE.Vector3)
  63152. let minBound = (new THREE.Box3()).setFromCenterAndSize(center, new THREE.Vector3(1,1,1))
  63153. panosBound.union(minBound)
  63154. this.bound = {
  63155. bounding:panosBound,
  63156. size: panosBound.getSize(new THREE.Vector3),
  63157. center,
  63158. } */
  63159. let minSize = new Vector3(1,1,1);
  63160. this.bound = math.getBoundByPoints(this.panos.map(e=>e.position), minSize);
  63161. viewer.scene.pointclouds.forEach(pointcloud=>pointcloud.getPanosBound());
  63162. }
  63163. if(viewer.scene.pointclouds.some(e=>e.panos.length == 0)){
  63164. //console.warn('存在数据集没有pano');
  63165. viewer.hasNoPanoDataset = true;
  63166. }
  63167. }
  63168. getPano(value, typeName='id'){ //默认找的是id,也可以是sid、uuid
  63169. return this.panos.find(p=>p[typeName] == value)
  63170. }
  63171. };
  63172. //判断当前点是否加载了全景图
  63173. Images360.prototype.checkAndWaitForPanoLoad = function() {
  63174. var isLoadedPanos = {},
  63175. LoadedTimePanos = {},
  63176. loadedCallback = {}, //add
  63177. maxTime = 5e3;
  63178. var withinTime = function() {
  63179. for (var panoId in isLoadedPanos)
  63180. if (isLoadedPanos.hasOwnProperty(panoId) && isLoadedPanos[panoId]) {
  63181. var differTime = performance.now() - LoadedTimePanos[panoId];
  63182. if (differTime < maxTime)
  63183. return !0
  63184. }
  63185. return !1
  63186. };
  63187. return function(pano, basePanoSize, doneFun1, doneFun2, progressCallback, iswait, isclear, p ) {
  63188. loadedCallback[pano.id] = doneFun1;//add 因为有可能之前请求的没加doneFun1, 如果加载好就执行最新的doneFun1
  63189. if (withinTime()){//距离上次请求时间很近
  63190. return !0; //这里感觉应该是!1
  63191. }
  63192. var callback1 = (param1, param2)=>{
  63193. setTimeout(()=>{
  63194. isLoadedPanos[pano.id] = !1;
  63195. loadedCallback[pano.id] && loadedCallback[pano.id](param1, param2);
  63196. },1);
  63197. };
  63198. var callback2 = (param)=>{//没有看到有传doneFun2的
  63199. setTimeout(()=>{
  63200. isLoadedPanos[pano.id] = !1;
  63201. doneFun2 && doneFun2(param);
  63202. },1);
  63203. };
  63204. try {
  63205. null !== iswait && void 0 !== iswait || (iswait = !0);
  63206. isLoadedPanos[pano.id] = this.checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, p );
  63207. //true代表没加载好
  63208. isLoadedPanos[pano.id] && (LoadedTimePanos[pano.id] = performance.now());
  63209. return isLoadedPanos[pano.id];
  63210. } catch (msg) {
  63211. isLoadedPanos[pano.id] = !1;
  63212. LoadedTimePanos[pano.id] = performance.now() - maxTime;
  63213. throw msg;
  63214. }
  63215. }
  63216. }();
  63217. Images360.filters = {
  63218. inPanoDirection : function(pos, dir, i) {
  63219. return function(pano) {
  63220. var r = pano.floorPosition.clone().sub(pos).normalize();
  63221. var o = pano.position.clone().sub(pos).normalize();
  63222. return r.dot(dir) > i || o.dot(dir) > i
  63223. }
  63224. },
  63225. inFloorDirection: function(pos, e, o) {//许钟文 改 for鱼眼
  63226. return function(n) {
  63227. var i = n.floorPosition.clone().sub(pos).setZ(0).normalize();//改成在xz方向上,否则点击墙面不会移动
  63228. return i.dot(e) > o
  63229. }
  63230. },
  63231. isNotBehindNormal: function(e, t) {
  63232. var i = new Vector3;
  63233. return t = t.clone(),
  63234. function(n) {
  63235. var r = i.copy(n.position).sub(e).normalize();
  63236. return r.dot(t) > 0
  63237. }
  63238. },
  63239. isCloseEnoughTo: function(e, t) {
  63240. return function(i) {//因为marker可能比地面高,所以识别范围要比marker看起来更近一些。(因为投影到地板的位置比marker更近)
  63241. return e.distanceTo(i.floorPosition) < t //许钟文
  63242. }
  63243. },
  63244. not: function(e) {
  63245. return function(t) {
  63246. return t !== e
  63247. }
  63248. } ,
  63249. isEnabled:function() {
  63250. return function(t) {
  63251. return t.enabled
  63252. }
  63253. },
  63254. isVisible:function() {
  63255. return function(t) {
  63256. return t.visible
  63257. }
  63258. }
  63259. };
  63260. Images360.scoreFunctions = {
  63261. direction: function(curPos, dir, ifLog) {
  63262. return function(pano) {
  63263. var pos1 = /* pano.floorPosition */ pano.position; //旧:改为权重放在marker上,这样对有斜坡的更准确,如上楼, 但这样近距离的pano角度就会向下了,以致于走不到
  63264. var n = pos1.clone().sub(curPos).normalize();
  63265. //ifLog && console.log('direction', pano.id, n.dot(dir) * directionFactor )
  63266. return n.dot(dir) * directionFactor
  63267. }
  63268. },
  63269. distanceSquared: function(pos1, r, ifLog) {
  63270. if(pos1.position)pos1 = pos1.position;
  63271. return function(pano) {//许钟文 改
  63272. var pos2 = pano.position.clone();
  63273. //ifLog && console.log('distanceSquared', pano.id, pos1.distanceToSquared(pos2) * -1 )
  63274. return pos1.distanceToSquared(pos2) * -1 * r;
  63275. }
  63276. },
  63277. angle: function(e, t) {
  63278. return function(i) {
  63279. var n = i.position.clone().sub(e).normalize();
  63280. return n.angleTo(t) * Potree.config.navigation.angleFactor
  63281. }
  63282. },
  63283. };
  63284. Images360.sortFunctions = {//排序函数,涉及到两个item相减
  63285. floorDisSquaredToPoint: function(e) {
  63286. return function(t, i) {
  63287. return t.floorPosition.distanceToSquared(e) - i.floorPosition.distanceToSquared(e)
  63288. }
  63289. },
  63290. disSquaredToPoint: function(e) {
  63291. return function(t, i) {
  63292. return t.position.distanceToSquared(e) - i.position.distanceToSquared(e)
  63293. }
  63294. },
  63295. };
  63296. /* var centerCross = new THREE.Mesh(new THREE.SphereGeometry(1, 4, 4),new THREE.MeshBasicMaterial({
  63297. transparent:true, color:"#ff0000", opacity:0.5
  63298. })); */
  63299. /* const mapHeight = -1000;//要比点云低。最低
  63300. const cameraHeight = 1000; //最高 */
  63301. const panosHeight = config$1.map.mapHeight + 100; //要比点云低 (marker)
  63302. const cursorHeight = 0;//比地图高就行
  63303. const routeLayerHeight = config$1.map.mapHeight + 105;
  63304. const texLoader$4 = new TextureLoader();
  63305. const planeGeo$2 = new PlaneBufferGeometry(1,1);
  63306. const markerSize = 1;
  63307. var initCameraFeildWidth = 50;
  63308. var panoMarkerMats;
  63309. class MapViewer extends ViewerBase{
  63310. constructor(dom){
  63311. super(dom, {
  63312. clearColor: Potree.config.mapBG,
  63313. name: 'mapViewer'
  63314. });
  63315. this.visible = true;
  63316. this.initScene();
  63317. this.mapLayer = new MapLayer(this, this.viewports[0]);
  63318. this.scene.add(this.mapLayer.sceneGroup);
  63319. this.mapLayer.sceneGroup.position.setZ(Potree.config.map.mapHeight);
  63320. this.mapRatio = 0.5;
  63321. this.splitDir = 'leftRight';
  63322. //this.scene.add(centerCross)
  63323. viewer.addEventListener("camera_changed", (e)=>{
  63324. if(e.viewport == viewer.mainViewport) this.updateCursor();
  63325. else this.updateWhenAtViewer();
  63326. });
  63327. //viewer.addEventListener("global_mousemove", this.updateWhenAtViewer.bind(this)) //鼠标移动时reticule也动,所以直接就needRender
  63328. viewer.reticule.addEventListener('update',(e)=>{
  63329. if(this.attachedToViewer)this.needRender = true;
  63330. });
  63331. viewer.scene.addEventListener("360_images_added", this.addPanos.bind(this));
  63332. viewer.addEventListener("loadPointCloudDone", this.initProjection.bind(this));
  63333. this.addEventListener('global_click',(e)=>{
  63334. if(!e.isTouch && e.button != MOUSE.LEFT)return
  63335. this.updateClosestPano(e.intersectPoint);
  63336. });
  63337. this.addEventListener('add',(e)=>{//添加其他mesh
  63338. this.scene.add(e.object);
  63339. if(e.name == 'route'){
  63340. e.object.position.z = routeLayerHeight;
  63341. }
  63342. viewer.setObjectLayers(e.object, 'mapObjects' );
  63343. });
  63344. if(!Potree.settings.isOfficial){
  63345. let domRoot = viewer.renderer.domElement.parentElement;
  63346. let elAttach = $("<input type='button' value='map绑定'></input>");
  63347. elAttach.css({
  63348. position : "absolute",
  63349. right : '80%',
  63350. bottom: '20px',
  63351. zIndex: "10000",
  63352. fontSize:'1em', color:"black",
  63353. background:'rgba(255,255,255,0.8)',
  63354. });
  63355. let state = false;
  63356. elAttach.on("click", () => {
  63357. state = !state;
  63358. this.attachToMainViewer(state, 'measure');
  63359. elAttach.val(state ? 'map分离':'map绑定');
  63360. });
  63361. domRoot.appendChild(elAttach[0]);
  63362. }
  63363. }
  63364. waitLoadDone(callback){//确保加载完后执行
  63365. if(this.mapLayer.loadingInProgress == 0){
  63366. callback();
  63367. }else {
  63368. var f = ()=>{
  63369. callback();
  63370. this.mapLayer.removeEventListener('loadDone', f);
  63371. };
  63372. this.mapLayer.addEventListener('loadDone', f);
  63373. }
  63374. }
  63375. addListener(images360){
  63376. images360.addEventListener('flyToPano',e=>{
  63377. let toPano = e.toPano;
  63378. if(toPano.dontMoveMap) return
  63379. /* transitions.start(lerp.vector(this.view.position, toPano.pano.position.clone().setZ(cameraHeight),
  63380. (pos, progress)=>{
  63381. }), toPano.duration, null, 0, easing[toPano.easeName] ); */
  63382. let boundSize;// = new THREE.Vector2(10,10)
  63383. this.moveTo(toPano.pano.position.clone().setZ(Potree.config.map.cameraHeight), boundSize, toPano.duration, toPano.easeName);
  63384. });
  63385. }
  63386. initProjection(){
  63387. this.started = true;
  63388. this.mapLayer.initProjection();
  63389. }
  63390. initScene(){
  63391. let w = initCameraFeildWidth;
  63392. let width = this.renderArea.clientWidth;
  63393. let height = this.renderArea.clientHeight;
  63394. //let aspect = width / height
  63395. this.camera = new OrthographicCamera(-width/2,width/2,height/2,-height/2/* -w/2, w/2, w/2/aspect, -w/2/aspect */, 0.01, 10000);
  63396. this.camera.zoom = width / w; //zoom越大视野越小
  63397. //this.camera.position.set(0,0,10);
  63398. this.camera.up.set(0,0,1);
  63399. //this.camera.lookAt(new THREE.Vector3())
  63400. //this.camera.updateMatrixWorld()
  63401. this.view = new View();
  63402. this.view.position.set(0,0,Potree.config.map.cameraHeight);
  63403. this.view.lookAt(0,0,0);
  63404. this.setViewLimit('standard');
  63405. let viewport = new Viewport( this.view, this.camera, {
  63406. left:0, bottom:0, width:1, height: 1, name:'mapViewport'
  63407. });
  63408. viewport.axis = ["x","y"];
  63409. viewport.axisSign = [1,1];
  63410. viewport.noPointcloud = true; //不要渲染点云
  63411. viewport.render = this.render.bind(this);//标志给mainView渲染
  63412. //viewport.unableDepth = true //depthBasicMaterial等在此viewport中不开启depth
  63413. this.viewports = [viewport];
  63414. this.controls = new FirstPersonControls(this, this.viewports[0]);
  63415. this.controls.setEnable(true);
  63416. this.scene = new Scene();
  63417. this.inputHandler = new InputHandler(this, this.scene);
  63418. this.inputHandler.name = 'mapInputHandler';
  63419. //this.inputHandler.addInputListener(this.controls);
  63420. this.inputHandler.registerInteractiveScene(this.scene);//interactiveScenes
  63421. this.viewports[0].interactiveScenes = this.inputHandler.interactiveScenes;//供viewer的inputHandler使用
  63422. var cursor = new Mesh(planeGeo$2, new MeshBasicMaterial({
  63423. transparent:true,
  63424. opacity:0.9,
  63425. depthTest : false, //防止透明冲突
  63426. map: texLoader$4.load(Potree.resourcePath+'/textures/pic_location128.png' )
  63427. }));
  63428. cursor.position.set(0,0,cursorHeight);
  63429. this.cursor = cursor;
  63430. this.scene.add(cursor);
  63431. viewer.setObjectLayers(this.scene, 'mapObjects' );
  63432. }
  63433. setViewLimit(state){//设置边界,当编辑空间模型等时要解禁
  63434. let setting = Potree.config.OrthoCameraLimit[state];
  63435. if(setting){
  63436. this.view.limitBound = new Box3().copy(setting.posBound);
  63437. this.camera.zoomLimit = $.extend({},setting.zoom);
  63438. }else {
  63439. this.view.limitBound = null;
  63440. this.camera.zoomLimit = null;
  63441. }
  63442. }
  63443. updateCursor(){
  63444. var scale = math.getScaleForConstantSize( {//规定下最小最大像素
  63445. minSize : 80, maxSize : 200, nearBound : initCameraFeildWidth*0.1 , farBound : initCameraFeildWidth*2,
  63446. camera:this.camera , position: this.cursor.getWorldPosition(new Vector3()),
  63447. resolution: this.viewports[0].resolution//2
  63448. });
  63449. this.cursor.scale.set(scale, scale, scale);//当地图缩放时
  63450. this.cursor.position.copy(viewer.mainViewport.camera.position).setZ(cursorHeight);//当场景镜头旋转移动时
  63451. this.cursor.rotation.z = viewer.mainViewport.view.yaw;
  63452. this.needRender = true;
  63453. }
  63454. addPanos(e){
  63455. var panosGroup = new Object3D;
  63456. panoMarkerMats = {
  63457. default: new MeshBasicMaterial({
  63458. transparent:true,
  63459. opacity: 0.5,
  63460. map: texLoader$4.load(Potree.resourcePath+'/textures/map_marker.png' ),
  63461. }),
  63462. selected: new MeshBasicMaterial({
  63463. transparent:true,
  63464. opacity: 1,
  63465. map: texLoader$4.load(Potree.resourcePath+'/textures/map_marker.png' ),
  63466. })
  63467. };
  63468. e.images.panos.forEach(pano=>{
  63469. pano.mapMarker = new Mesh(planeGeo$2, panoMarkerMats.default);
  63470. pano.mapMarker.position.copy(pano.position).setZ(0);
  63471. pano.mapMarker.scale.set(markerSize,markerSize,markerSize);
  63472. pano.mapMarker.name = 'mapMarker';
  63473. panosGroup.add(pano.mapMarker);
  63474. let mouseover = (e)=>{
  63475. if(!e.byMap){
  63476. pano.mapMarker.material = panoMarkerMats.selected;
  63477. if(!e.byMainView) pano.dispatchEvent({type: "hoverOn", byMap:true});
  63478. this.needRender = true;
  63479. }
  63480. };
  63481. let mouseleave = (e)=>{
  63482. if(!e.byMap){
  63483. pano.mapMarker.material = panoMarkerMats.default;
  63484. if(!e.byMainView) pano.dispatchEvent({type: "hoverOff", byMap:true});
  63485. this.needRender = true;
  63486. }
  63487. };
  63488. pano.mapMarker.addEventListener('mouseover', mouseover);
  63489. pano.mapMarker.addEventListener('mouseleave', mouseleave);
  63490. pano.addEventListener('hoverOn', mouseover);
  63491. pano.addEventListener('hoverOff', mouseleave);
  63492. let onclick = (e)=>{
  63493. viewer.images360.flyToPano(pano);
  63494. };
  63495. pano.mapMarker.addEventListener('click', onclick);
  63496. pano.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
  63497. //console.log('panoMarker isVisible', pano.id, e.visible)
  63498. viewer.updateVisible(pano.mapMarker, 'panoVisible', e.visible );
  63499. this.needRender = true;
  63500. });
  63501. pano.addEventListener('rePos',(e)=>{
  63502. pano.mapMarker.position.copy(pano.position).setZ(0);
  63503. });
  63504. });
  63505. this.scene.add(panosGroup);
  63506. panosGroup.position.z = panosHeight;
  63507. this.panosGroup = panosGroup;
  63508. viewer.setObjectLayers(panosGroup, 'mapObjects' );
  63509. /* e.images.on('markersDisplayChange', (show)=>{
  63510. panosGroup.visible = show
  63511. this.needRender = true
  63512. }) */
  63513. //-------
  63514. //this.fitPanosToViewport()
  63515. this.initFitView();
  63516. }
  63517. updateClosestPano(intersect){
  63518. if(viewer.images360.flying)return;
  63519. intersect = intersect && intersect.orthoIntersect;
  63520. if(!intersect)return
  63521. intersect = intersect.clone().setZ(0);
  63522. const minDis = 20; //距离鼠标不能太远
  63523. var filterFuncs = [
  63524. (pano)=>{
  63525. return pano.position.clone().setZ(0).distanceTo(intersect) < minDis
  63526. },
  63527. Images360.filters.isEnabled(),
  63528. Images360.filters.isVisible(),//只走显示的点,否则会走到别的层
  63529. ];
  63530. var pano = Common.find(viewer.images360.panos, filterFuncs, [Images360.sortFunctions.floorDisSquaredToPoint(intersect)]);
  63531. if (pano && pano != viewer.images360.currentPano ) {
  63532. viewer.images360.flyToPano(pano);
  63533. }
  63534. }
  63535. fitPanosToViewport(){//使所有漫游点占满viewport
  63536. //var w = viewer.bound.boundSize.x;
  63537. var boundSize = viewer.images360.bound.size.clone().multiplyScalar(1.1);
  63538. boundSize.max(new Vector3(4,4,4));
  63539. let endPosition = viewer.images360.bound.center.clone();
  63540. this.moveTo(endPosition, boundSize, 0);
  63541. }
  63542. fitToPointcloud(pointcloud, duration=400){
  63543. var boundSize = pointcloud.bound.getSize(new Vector3);/* .multiplyScalar(1.1); */
  63544. boundSize.max(new Vector3(4,4,4));
  63545. let endPosition = pointcloud.bound.getCenter(new Vector3);
  63546. this.moveTo(endPosition, boundSize, duration); //给点duration去变化 否则地图放大后所占的还是很小
  63547. }
  63548. initFitView(){
  63549. let dis = 5 , px = 70; //地图上px像素长度代表的距离为dis //px是手动缩放到5m后发现是这个长度
  63550. let zoom = px / dis;
  63551. this.camera.zoom = zoom;
  63552. this.moveTo(viewer.images360.position/* viewer.images360.bound.center */);
  63553. this.camera.updateProjectionMatrix();
  63554. }
  63555. fitToDatasets(datasets){
  63556. let bound = new Box3;
  63557. datasets.forEach(e=>bound.union(e.bound));
  63558. let center = bound.getCenter(new Vector3);
  63559. let size = bound.getSize(new Vector3);
  63560. this.moveTo(center, size, 200 ); //给duration是为了顺应视口大小改变,缓冲
  63561. }
  63562. moveTo(endPosition, boundSize, duration=0, easeName){//前两个参数有xy即可
  63563. endPosition = new Vector3(endPosition.x,endPosition.y,Potree.config.map.cameraHeight);
  63564. this.view.moveOrthoCamera(this.viewports[0], {endPosition, boundSize }, duration, easeName);
  63565. /* let endZoom, startZoom = this.camera.zoom
  63566. //修改相机为bound中心,这样能看到全部(宽度范围内)
  63567. this.view.setView({ position:endPosition, duration,
  63568. callback:()=>{//done
  63569. },
  63570. onUpdate:(progress)=>{
  63571. if(boundSize){
  63572. let aspect = boundSize.x / boundSize.y
  63573. let w, h;
  63574. if(this.camera.aspect > aspect){//视野更宽则用bound的纵向来决定
  63575. h = boundSize.y
  63576. //w = h * this.camera.aspect
  63577. endZoom = this.viewports[0].resolution.y / h
  63578. }else{
  63579. w = boundSize.x;
  63580. //h = w / this.camera.aspect
  63581. endZoom = this.viewports[0].resolution.x / w
  63582. }
  63583. //onUpdate时更新endzoom是因为画布大小可能更改
  63584. this.camera.zoom = endZoom * progress + startZoom * (1 - progress)
  63585. this.camera.updateProjectionMatrix()
  63586. }
  63587. },
  63588. Easing:easeName
  63589. }) */
  63590. }
  63591. updateWhenAtViewer(e){
  63592. if(this.attachedToViewer){
  63593. if(this.started) this.mapLayer.update();
  63594. this.updateCursor();
  63595. this.needRender = true;
  63596. }
  63597. }
  63598. update(delta, areaSize ){
  63599. if(!this.visible && !this.attachedToViewer )return
  63600. if(this.attachedToViewer){
  63601. if(this.mapLayer.needUpdate){//必须更新。(较少触发)
  63602. this.updateWhenAtViewer();
  63603. }
  63604. return
  63605. }
  63606. this.updateScreenSize();
  63607. this.controls.update(delta);
  63608. this.view.applyToCamera(this.camera);
  63609. let changed = this.cameraChanged();
  63610. if(this.started && (changed || this.mapLayer.needUpdate))this.mapLayer.update();
  63611. if(changed /*|| || this.needRender */){
  63612. this.dispatchEvent({
  63613. type: "camera_changed",
  63614. camera: this.camera,
  63615. viewport : this.viewports[0]
  63616. });
  63617. this.needRender = true;
  63618. this.updateCursor();//更改大小
  63619. }
  63620. this.render();
  63621. }
  63622. attachToMainViewer(state, desc, mapRatio=0.5, options={}){//转移到viewer中。测量时展示or截图需要
  63623. if(!Potree.settings.isOfficial)this.renderArea.style.display = state ? 'none':'block';
  63624. if(state){
  63625. this.enabledOld = this.enabled;
  63626. this.enabled = true;
  63627. if(mapRatio != 'dontSet'){
  63628. this.changeSplitScreenDir(options.dir, mapRatio);
  63629. if(this.attachedToViewer){
  63630. //this.fitPanosToViewport()
  63631. viewer.updateScreenSize({forceUpdateSize:true});
  63632. return
  63633. }
  63634. viewer.viewports = [viewer.mainViewport, viewer.mapViewer.viewports[0] ];//因为mainViewer的相机变化会触发map的变化,所以先渲染mainViewer
  63635. }
  63636. if(desc == 'measure') this.inputHandler.registerInteractiveScene(viewer.measuringTool.scene);//虽然用的是viewer的inputHandler,但借用了this.inputHandler的interactiveScenes
  63637. else if(desc == 'split4Screens') {
  63638. this.inputHandler.registerInteractiveScene(viewer.scene.scene);
  63639. }
  63640. }else {
  63641. if(!this.attachedToViewer)return
  63642. viewer.mainViewport.left = 0;
  63643. viewer.mainViewport.bottom = 0;
  63644. viewer.mainViewport.width = 1;
  63645. viewer.mainViewport.height = 1;
  63646. this.viewports[0].width = 1;
  63647. this.viewports[0].bottom = 0;
  63648. this.viewports[0].height = 1;
  63649. this.viewports[0].left = 0;
  63650. this.inputHandler.unregisterInteractiveScene(viewer.measuringTool.scene);
  63651. this.inputHandler.unregisterInteractiveScene(viewer.scene.scene);
  63652. viewer.viewports = [viewer.mainViewport];
  63653. this.updateScreenSize({forceUpdateSize:true}); //更新相机projectionMatrix
  63654. }
  63655. //if(desc == 'measure')this.renderMeasure = state
  63656. this.attachedToViewer = state;
  63657. viewer.updateScreenSize({forceUpdateSize:true});
  63658. //mapRatio != 'dontSet' && !options.dontFit && this.moveTo(...)//要写在updateScreenSize后面,因为要根据视图大小来fit
  63659. if(options.moveToCurrentPos){
  63660. let boundSize = new Vector2$1(10,10);
  63661. let duration = 1000;
  63662. this.moveTo(viewer.images360.position.clone(), boundSize, duration);
  63663. }
  63664. this.needRender = true;
  63665. }
  63666. changeSplitScreenDir(dir, mapRatio){//左右 | 上下
  63667. //if(!dir || dir == this.dir)return
  63668. if(dir )this.splitDir = dir;
  63669. this.updateSplitSize(mapRatio);
  63670. /* if(this.attachedToViewer){ //如果已经分屏了,中途修改方向的话……
  63671. this.updateSplitSize()
  63672. } */
  63673. }
  63674. updateSplitSize(mapRatio){
  63675. if(mapRatio != void 0) this.mapRatio = mapRatio;
  63676. //console.log(this.mapRatio)
  63677. if(this.splitDir == 'leftRight'){//地图在左方
  63678. viewer.mainViewport.left = this.mapRatio;
  63679. viewer.mainViewport.width = 1-this.mapRatio;
  63680. this.viewports[0].width = this.mapRatio;
  63681. viewer.mainViewport.bottom = this.viewports[0].bottom = 0;
  63682. viewer.mainViewport.height = this.viewports[0].height = 1;
  63683. }else if(this.splitDir == 'upDown'){ //地图在下方
  63684. viewer.mainViewport.bottom = this.mapRatio;
  63685. viewer.mainViewport.height = 1-this.mapRatio;
  63686. this.viewports[0].height = this.mapRatio;
  63687. viewer.mainViewport.left = this.viewports[0].left = 0;
  63688. viewer.mainViewport.width = this.viewports[0].width = 1;
  63689. }
  63690. if(this.attachedToViewer){
  63691. viewer.updateScreenSize({forceUpdateSize:true});
  63692. }
  63693. }
  63694. render(params={}){
  63695. if(!this.visible && !this.attachedToViewer || !this.needRender && !params.force)return
  63696. let renderer = params.renderer || this.renderer;
  63697. if(params.target){
  63698. renderer.setRenderTarget(params.target);
  63699. }
  63700. /* if(params.resize){
  63701. this.emitResizeMsg(new THREE.Vector2(params.width,params.height, viewport:params.viewport))
  63702. } */
  63703. params.clear ? params.clear() : renderer.clear();
  63704. if(!this.attachedToViewer){
  63705. viewer.dispatchEvent({type: "render.begin", viewer: this, viewport:this.viewports[0], params });
  63706. }
  63707. viewer.setCameraLayers(this.camera, ['map','mapObjects' , 'bothMapAndScene' ]);
  63708. if(this.mapGradientBG){//渲染背景
  63709. viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg);
  63710. renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
  63711. }
  63712. renderer.render(this.scene, this.camera);
  63713. renderer.render(viewer.scene.scene, this.camera);
  63714. //测量线等
  63715. //params.renderOverlay && params.renderOverlay({camera:this.camera, isMap:true, viewport: this.viewports[0] })//其余如reticule 等场景层
  63716. params.renderOverlay && params.renderOverlay( $.extend({}, params, { isMap:true }));
  63717. renderer.setRenderTarget(null);
  63718. this.needRender = false;
  63719. }
  63720. /* render(){
  63721. let camera = viewer.scene.getActiveCamera();
  63722. viewer.scene.view.position.x += 0.01
  63723. viewer.setCameraLayers(camera, ['sceneObjects','marker','reticule','skybox' ])
  63724. this.renderer.render(viewer.scene.scene, camera);
  63725. } */
  63726. }
  63727. //本地调试地图白屏是因为代码自动更新了 但没刷新
  63728. class CSVExporter {
  63729. static toString (points) {
  63730. let string = '';
  63731. let attributes = Object.keys(points.data)
  63732. .filter(a => a !== 'normal')
  63733. .sort((a, b) => {
  63734. if (a === 'position') return -1;
  63735. if (b === 'position') return 1;
  63736. if (a === 'rgba') return -1;
  63737. if (b === 'rgba') return 1;
  63738. });
  63739. let headerValues = [];
  63740. for (let attribute of attributes) {
  63741. let itemSize = points.data[attribute].length / points.numPoints;
  63742. if (attribute === 'position') {
  63743. headerValues = headerValues.concat(['x', 'y', 'z']);
  63744. } else if (attribute === 'rgba') {
  63745. headerValues = headerValues.concat(['r', 'g', 'b', 'a']);
  63746. } else if (itemSize > 1) {
  63747. for (let i = 0; i < itemSize; i++) {
  63748. headerValues.push(`${attribute}_${i}`);
  63749. }
  63750. } else {
  63751. headerValues.push(attribute);
  63752. }
  63753. }
  63754. string = headerValues.join(', ') + '\n';
  63755. for (let i = 0; i < points.numPoints; i++) {
  63756. let values = [];
  63757. for (let attribute of attributes) {
  63758. let itemSize = points.data[attribute].length / points.numPoints;
  63759. let value = points.data[attribute]
  63760. .subarray(itemSize * i, itemSize * i + itemSize)
  63761. .join(', ');
  63762. values.push(value);
  63763. }
  63764. string += values.join(', ') + '\n';
  63765. }
  63766. return string;
  63767. }
  63768. };
  63769. class LASExporter {
  63770. static toLAS (points) {
  63771. // TODO Unused: let string = '';
  63772. let boundingBox = points.boundingBox;
  63773. let offset = boundingBox.min.clone();
  63774. let diagonal = boundingBox.min.distanceTo(boundingBox.max);
  63775. let scale = new Vector3(0.001, 0.001, 0.001);
  63776. if (diagonal > 1000 * 1000) {
  63777. scale = new Vector3(0.01, 0.01, 0.01);
  63778. } else {
  63779. scale = new Vector3(0.001, 0.001, 0.001);
  63780. }
  63781. let setString = function (string, offset, buffer) {
  63782. let view = new Uint8Array(buffer);
  63783. for (let i = 0; i < string.length; i++) {
  63784. let charCode = string.charCodeAt(i);
  63785. view[offset + i] = charCode;
  63786. }
  63787. };
  63788. let buffer = new ArrayBuffer(227 + 28 * points.numPoints);
  63789. let view = new DataView(buffer);
  63790. let u8View = new Uint8Array(buffer);
  63791. // let u16View = new Uint16Array(buffer);
  63792. setString('LASF', 0, buffer);
  63793. u8View[24] = 1;
  63794. u8View[25] = 2;
  63795. // system identifier o:26 l:32
  63796. // generating software o:58 l:32
  63797. setString('Potree 1.7', 58, buffer);
  63798. // file creation day of year o:90 l:2
  63799. // file creation year o:92 l:2
  63800. // header size o:94 l:2
  63801. view.setUint16(94, 227, true);
  63802. // offset to point data o:96 l:4
  63803. view.setUint32(96, 227, true);
  63804. // number of letiable length records o:100 l:4
  63805. // point data record format 104 1
  63806. u8View[104] = 2;
  63807. // point data record length 105 2
  63808. view.setUint16(105, 28, true);
  63809. // number of point records 107 4
  63810. view.setUint32(107, points.numPoints, true);
  63811. // number of points by return 111 20
  63812. // x scale factor 131 8
  63813. view.setFloat64(131, scale.x, true);
  63814. // y scale factor 139 8
  63815. view.setFloat64(139, scale.y, true);
  63816. // z scale factor 147 8
  63817. view.setFloat64(147, scale.z, true);
  63818. // x offset 155 8
  63819. view.setFloat64(155, offset.x, true);
  63820. // y offset 163 8
  63821. view.setFloat64(163, offset.y, true);
  63822. // z offset 171 8
  63823. view.setFloat64(171, offset.z, true);
  63824. // max x 179 8
  63825. view.setFloat64(179, boundingBox.max.x, true);
  63826. // min x 187 8
  63827. view.setFloat64(187, boundingBox.min.x, true);
  63828. // max y 195 8
  63829. view.setFloat64(195, boundingBox.max.y, true);
  63830. // min y 203 8
  63831. view.setFloat64(203, boundingBox.min.y, true);
  63832. // max z 211 8
  63833. view.setFloat64(211, boundingBox.max.z, true);
  63834. // min z 219 8
  63835. view.setFloat64(219, boundingBox.min.z, true);
  63836. let boffset = 227;
  63837. for (let i = 0; i < points.numPoints; i++) {
  63838. let px = points.data.position[3 * i + 0];
  63839. let py = points.data.position[3 * i + 1];
  63840. let pz = points.data.position[3 * i + 2];
  63841. let ux = parseInt((px - offset.x) / scale.x);
  63842. let uy = parseInt((py - offset.y) / scale.y);
  63843. let uz = parseInt((pz - offset.z) / scale.z);
  63844. view.setUint32(boffset + 0, ux, true);
  63845. view.setUint32(boffset + 4, uy, true);
  63846. view.setUint32(boffset + 8, uz, true);
  63847. if (points.data.intensity) {
  63848. view.setUint16(boffset + 12, (points.data.intensity[i]), true);
  63849. }
  63850. let rt = 0;
  63851. if (points.data.returnNumber) {
  63852. rt += points.data.returnNumber[i];
  63853. }
  63854. if (points.data.numberOfReturns) {
  63855. rt += (points.data.numberOfReturns[i] << 3);
  63856. }
  63857. view.setUint8(boffset + 14, rt);
  63858. if (points.data.classification) {
  63859. view.setUint8(boffset + 15, points.data.classification[i]);
  63860. }
  63861. // scan angle rank
  63862. // user data
  63863. // point source id
  63864. if (points.data.pointSourceID) {
  63865. view.setUint16(boffset + 18, points.data.pointSourceID[i]);
  63866. }
  63867. if (points.data.rgba) {
  63868. let rgba = points.data.rgba;
  63869. view.setUint16(boffset + 20, (rgba[4 * i + 0] * 255), true);
  63870. view.setUint16(boffset + 22, (rgba[4 * i + 1] * 255), true);
  63871. view.setUint16(boffset + 24, (rgba[4 * i + 2] * 255), true);
  63872. }
  63873. boffset += 28;
  63874. }
  63875. return buffer;
  63876. }
  63877. }
  63878. function copyMaterial(source, target){
  63879. for(let name of Object.keys(target.uniforms)){
  63880. target.uniforms[name].value = source.uniforms[name].value;
  63881. }
  63882. target.gradientTexture = source.gradientTexture;
  63883. target.visibleNodesTexture = source.visibleNodesTexture;
  63884. target.classificationTexture = source.classificationTexture;
  63885. target.matcapTexture = source.matcapTexture;
  63886. target.activeAttributeName = source.activeAttributeName;
  63887. target.ranges = source.ranges;
  63888. //target.updateShaderSource();
  63889. }
  63890. class Batch{
  63891. constructor(geometry, material){
  63892. this.geometry = geometry;
  63893. this.material = material;
  63894. this.sceneNode = new Points(geometry, material);
  63895. this.geometryNode = {
  63896. estimatedSpacing: 1.0,
  63897. geometry: geometry,
  63898. };
  63899. }
  63900. getLevel(){
  63901. return 0;
  63902. }
  63903. }
  63904. class ProfileFakeOctree extends PointCloudTree{
  63905. constructor(octree){
  63906. super();
  63907. this.trueOctree = octree;
  63908. this.pcoGeometry = octree.pcoGeometry;
  63909. this.points = [];
  63910. this.visibleNodes = [];
  63911. //this.material = this.trueOctree.material;
  63912. this.material = new PointCloudMaterial$1();
  63913. //this.material.copy(this.trueOctree.material);
  63914. copyMaterial(this.trueOctree.material, this.material);
  63915. this.material.pointSizeType = PointSizeType.FIXED;
  63916. this.batchSize = 100 * 1000;
  63917. this.currentBatch = null;
  63918. }
  63919. getAttribute(name){
  63920. return this.trueOctree.getAttribute(name);
  63921. }
  63922. dispose(){
  63923. for(let node of this.visibleNodes){
  63924. node.geometry.dispose();
  63925. }
  63926. this.visibleNodes = [];
  63927. this.currentBatch = null;
  63928. this.points = [];
  63929. }
  63930. addPoints(data){
  63931. // since each call to addPoints can deliver very very few points,
  63932. // we're going to batch them into larger buffers for efficiency.
  63933. if(this.currentBatch === null){
  63934. this.currentBatch = this.createNewBatch(data);
  63935. }
  63936. this.points.push(data);
  63937. let updateRange = {
  63938. start: this.currentBatch.geometry.drawRange.count,
  63939. count: 0
  63940. };
  63941. let projectedBox = new Box3();
  63942. let truePos = new Vector3();
  63943. for(let i = 0; i < data.numPoints; i++){
  63944. if(updateRange.start + updateRange.count >= this.batchSize){
  63945. // current batch full, start new batch
  63946. for(let key of Object.keys(this.currentBatch.geometry.attributes)){
  63947. let attribute = this.currentBatch.geometry.attributes[key];
  63948. attribute.updateRange.offset = updateRange.start;
  63949. attribute.updateRange.count = updateRange.count;
  63950. attribute.needsUpdate = true;
  63951. }
  63952. this.currentBatch.geometry.computeBoundingBox();
  63953. this.currentBatch.geometry.computeBoundingSphere();
  63954. this.currentBatch = this.createNewBatch(data);
  63955. updateRange = {
  63956. start: 0,
  63957. count: 0
  63958. };
  63959. }
  63960. truePos.set(
  63961. data.data.position[3 * i + 0] + this.trueOctree.position.x,
  63962. data.data.position[3 * i + 1] + this.trueOctree.position.y,
  63963. data.data.position[3 * i + 2] + this.trueOctree.position.z,
  63964. );
  63965. let x = data.data.mileage[i];
  63966. let y = 0;
  63967. let z = truePos.z;
  63968. projectedBox.expandByPoint(new Vector3(x, y, z));
  63969. let index = updateRange.start + updateRange.count;
  63970. let geometry = this.currentBatch.geometry;
  63971. for(let attributeName of Object.keys(data.data)){
  63972. let source = data.data[attributeName];
  63973. let target = geometry.attributes[attributeName];
  63974. let numElements = target.itemSize;
  63975. for(let item = 0; item < numElements; item++){
  63976. target.array[numElements * index + item] = source[numElements * i + item];
  63977. }
  63978. }
  63979. {
  63980. let position = geometry.attributes.position;
  63981. position.array[3 * index + 0] = x;
  63982. position.array[3 * index + 1] = y;
  63983. position.array[3 * index + 2] = z;
  63984. }
  63985. updateRange.count++;
  63986. this.currentBatch.geometry.drawRange.count++;
  63987. }
  63988. for(let key of Object.keys(this.currentBatch.geometry.attributes)){
  63989. let attribute = this.currentBatch.geometry.attributes[key];
  63990. attribute.updateRange.offset = updateRange.start;
  63991. attribute.updateRange.count = updateRange.count;
  63992. attribute.needsUpdate = true;
  63993. }
  63994. data.projectedBox = projectedBox;
  63995. this.projectedBox = this.points.reduce( (a, i) => a.union(i.projectedBox), new Box3());
  63996. }
  63997. createNewBatch(data){
  63998. let geometry = new BufferGeometry();
  63999. // create new batches with batch_size elements of the same type as the attribute
  64000. for(let attributeName of Object.keys(data.data)){
  64001. let buffer = data.data[attributeName];
  64002. let numElements = buffer.length / data.numPoints; // 3 for pos, 4 for col, 1 for scalars
  64003. let constructor = buffer.constructor;
  64004. let normalized = false;
  64005. if(this.trueOctree.root.sceneNode){
  64006. if(this.trueOctree.root.sceneNode.geometry.attributes[attributeName]){
  64007. normalized = this.trueOctree.root.sceneNode.geometry.attributes[attributeName].normalized;
  64008. }
  64009. }
  64010. let batchBuffer = new constructor(numElements * this.batchSize);
  64011. let bufferAttribute = new BufferAttribute(batchBuffer, numElements, normalized);
  64012. bufferAttribute.potree = {
  64013. range: [0, 1],
  64014. };
  64015. geometry.setAttribute(attributeName, bufferAttribute);
  64016. }
  64017. geometry.drawRange.start = 0;
  64018. geometry.drawRange.count = 0;
  64019. let batch = new Batch(geometry, this.material);
  64020. this.visibleNodes.push(batch);
  64021. return batch;
  64022. }
  64023. computeVisibilityTextureData(){
  64024. let data = new Uint8Array(this.visibleNodes.length * 4);
  64025. let offsets = new Map();
  64026. for(let i = 0; i < this.visibleNodes.length; i++){
  64027. let node = this.visibleNodes[i];
  64028. offsets[node] = i;
  64029. }
  64030. return {
  64031. data: data,
  64032. offsets: offsets,
  64033. };
  64034. }
  64035. }
  64036. class ProfileWindow extends EventDispatcher {
  64037. constructor (viewer) {
  64038. super();
  64039. this.viewer = viewer;
  64040. this.elRoot = $('#profile_window');
  64041. this.renderArea = this.elRoot.find('#profileCanvasContainer');
  64042. this.svg = d3.select('svg#profileSVG');
  64043. this.mouseIsDown = false;
  64044. this.projectedBox = new Box3();
  64045. this.pointclouds = new Map();
  64046. this.numPoints = 0;
  64047. this.lastAddPointsTimestamp = undefined;
  64048. this.mouse = new Vector2$1(0, 0);
  64049. this.scale = new Vector3(1, 1, 1);
  64050. this.autoFitEnabled = true; // completely disable/enable
  64051. this.autoFit = false; // internal
  64052. let cwIcon = `${exports.resourcePath}/icons/arrow_cw.svg`;
  64053. $('#potree_profile_rotate_cw').attr('src', cwIcon);
  64054. let ccwIcon = `${exports.resourcePath}/icons/arrow_ccw.svg`;
  64055. $('#potree_profile_rotate_ccw').attr('src', ccwIcon);
  64056. let forwardIcon = `${exports.resourcePath}/icons/arrow_up.svg`;
  64057. $('#potree_profile_move_forward').attr('src', forwardIcon);
  64058. let backwardIcon = `${exports.resourcePath}/icons/arrow_down.svg`;
  64059. $('#potree_profile_move_backward').attr('src', backwardIcon);
  64060. let csvIcon = `${exports.resourcePath}/icons/file_csv_2d.svg`;
  64061. $('#potree_download_csv_icon').attr('src', csvIcon);
  64062. let lasIcon = `${exports.resourcePath}/icons/file_las_3d.svg`;
  64063. $('#potree_download_las_icon').attr('src', lasIcon);
  64064. let closeIcon = `${exports.resourcePath}/icons/close.svg`;
  64065. $('#closeProfileContainer').attr("src", closeIcon);
  64066. this.initTHREE();
  64067. this.initSVG();
  64068. this.initListeners();
  64069. this.pRenderer = new Renderer(this.renderer);
  64070. this.elRoot.i18n();
  64071. }
  64072. initListeners () {
  64073. $(window).resize(() => {
  64074. if (this.enabled) {
  64075. this.render();
  64076. }
  64077. });
  64078. this.renderArea.mousedown(e => {
  64079. this.mouseIsDown = true;
  64080. });
  64081. this.renderArea.mouseup(e => {
  64082. this.mouseIsDown = false;
  64083. });
  64084. let viewerPickSphereSizeHandler = () => {
  64085. let camera = this.viewer.scene.getActiveCamera();
  64086. let domElement = this.viewer.renderer.domElement;
  64087. let distance = this.viewerPickSphere.position.distanceTo(camera.position);
  64088. let pr = Utils.projectedRadius(1, camera, distance, domElement.clientWidth, domElement.clientHeight);
  64089. let scale = (10 / pr);
  64090. this.viewerPickSphere.scale.set(scale, scale, scale);
  64091. };
  64092. this.renderArea.mousemove(e => {
  64093. if (this.pointclouds.size === 0) {
  64094. return;
  64095. }
  64096. let rect = this.renderArea[0].getBoundingClientRect();
  64097. let x = e.clientX - rect.left;
  64098. let y = e.clientY - rect.top;
  64099. let newMouse = new Vector2$1(x, y);
  64100. if (this.mouseIsDown) {
  64101. // DRAG
  64102. this.autoFit = false;
  64103. this.lastDrag = new Date().getTime();
  64104. let cPos = [this.scaleX.invert(this.mouse.x), this.scaleY.invert(this.mouse.y)];
  64105. let ncPos = [this.scaleX.invert(newMouse.x), this.scaleY.invert(newMouse.y)];
  64106. this.camera.position.x -= ncPos[0] - cPos[0];
  64107. this.camera.position.z -= ncPos[1] - cPos[1];
  64108. this.render();
  64109. } else if (this.pointclouds.size > 0) {
  64110. // FIND HOVERED POINT
  64111. let radius = Math.abs(this.scaleX.invert(0) - this.scaleX.invert(40));
  64112. let mileage = this.scaleX.invert(newMouse.x);
  64113. let elevation = this.scaleY.invert(newMouse.y);
  64114. let closest = this.selectPoint(mileage, elevation, radius);
  64115. if (closest) {
  64116. let point = closest.point;
  64117. let position = new Float64Array([
  64118. point.position[0] + closest.pointcloud.position.x,
  64119. point.position[1] + closest.pointcloud.position.y,
  64120. point.position[2] + closest.pointcloud.position.z
  64121. ]);
  64122. this.elRoot.find('#profileSelectionProperties').fadeIn(200);
  64123. this.pickSphere.visible = true;
  64124. this.pickSphere.scale.set(0.5 * radius, 0.5 * radius, 0.5 * radius);
  64125. this.pickSphere.position.set(point.mileage, 0, position[2]);
  64126. this.viewerPickSphere.position.set(...position);
  64127. if(!this.viewer.scene.scene.children.includes(this.viewerPickSphere)){
  64128. this.viewer.scene.scene.add(this.viewerPickSphere);
  64129. if(!this.viewer.hasEventListener("update", viewerPickSphereSizeHandler)){
  64130. this.viewer.addEventListener("update", viewerPickSphereSizeHandler);
  64131. }
  64132. }
  64133. let info = this.elRoot.find('#profileSelectionProperties');
  64134. let html = '<table>';
  64135. for (let attributeName of Object.keys(point)) {
  64136. let value = point[attributeName];
  64137. let attribute = closest.pointcloud.getAttribute(attributeName);
  64138. let transform = value => value;
  64139. if(attribute && attribute.type.size > 4){
  64140. let range = attribute.initialRange;
  64141. let scale = 1 / (range[1] - range[0]);
  64142. let offset = range[0];
  64143. transform = value => value / scale + offset;
  64144. }
  64145. if (attributeName === 'position') {
  64146. let values = [...position].map(v => Utils.addCommas(v.toFixed(3)));
  64147. html += `
  64148. <tr>
  64149. <td>x</td>
  64150. <td>${values[0]}</td>
  64151. </tr>
  64152. <tr>
  64153. <td>y</td>
  64154. <td>${values[1]}</td>
  64155. </tr>
  64156. <tr>
  64157. <td>z</td>
  64158. <td>${values[2]}</td>
  64159. </tr>`;
  64160. } else if (attributeName === 'rgba') {
  64161. html += `
  64162. <tr>
  64163. <td>${attributeName}</td>
  64164. <td>${value.join(', ')}</td>
  64165. </tr>`;
  64166. } else if (attributeName === 'normal') {
  64167. continue;
  64168. } else if (attributeName === 'mileage') {
  64169. html += `
  64170. <tr>
  64171. <td>${attributeName}</td>
  64172. <td>${value.toFixed(3)}</td>
  64173. </tr>`;
  64174. } else {
  64175. html += `
  64176. <tr>
  64177. <td>${attributeName}</td>
  64178. <td>${transform(value)}</td>
  64179. </tr>`;
  64180. }
  64181. }
  64182. html += '</table>';
  64183. info.html(html);
  64184. this.selectedPoint = point;
  64185. } else {
  64186. // this.pickSphere.visible = false;
  64187. // this.selectedPoint = null;
  64188. this.viewer.scene.scene.add(this.viewerPickSphere);
  64189. let index = this.viewer.scene.scene.children.indexOf(this.viewerPickSphere);
  64190. if(index >= 0){
  64191. this.viewer.scene.scene.children.splice(index, 1);
  64192. }
  64193. this.viewer.removeEventListener("update", viewerPickSphereSizeHandler);
  64194. }
  64195. this.render();
  64196. }
  64197. this.mouse.copy(newMouse);
  64198. });
  64199. let onWheel = e => {
  64200. this.autoFit = false;
  64201. let delta = 0;
  64202. if (e.wheelDelta !== undefined) { // WebKit / Opera / Explorer 9
  64203. delta = e.wheelDelta;
  64204. } else if (e.detail !== undefined) { // Firefox
  64205. delta = -e.detail;
  64206. }
  64207. let ndelta = Math.sign(delta);
  64208. let cPos = [this.scaleX.invert(this.mouse.x), this.scaleY.invert(this.mouse.y)];
  64209. if (ndelta > 0) {
  64210. // + 10%
  64211. this.scale.multiplyScalar(1.1);
  64212. } else {
  64213. // - 10%
  64214. this.scale.multiplyScalar(100 / 110);
  64215. }
  64216. this.updateScales();
  64217. let ncPos = [this.scaleX.invert(this.mouse.x), this.scaleY.invert(this.mouse.y)];
  64218. this.camera.position.x -= ncPos[0] - cPos[0];
  64219. this.camera.position.z -= ncPos[1] - cPos[1];
  64220. this.render();
  64221. this.updateScales();
  64222. };
  64223. $(this.renderArea)[0].addEventListener('mousewheel', onWheel, false);
  64224. $(this.renderArea)[0].addEventListener('DOMMouseScroll', onWheel, false); // Firefox
  64225. $('#closeProfileContainer').click(() => {
  64226. this.hide();
  64227. });
  64228. let getProfilePoints = () => {
  64229. let points = new Points$1();
  64230. for(let [pointcloud, entry] of this.pointclouds){
  64231. for(let pointSet of entry.points){
  64232. let originPos = pointSet.data.position;
  64233. let trueElevationPosition = new Float32Array(originPos);
  64234. for(let i = 0; i < pointSet.numPoints; i++){
  64235. trueElevationPosition[3 * i + 2] += pointcloud.position.z;
  64236. }
  64237. pointSet.data.position = trueElevationPosition;
  64238. points.add(pointSet);
  64239. pointSet.data.position = originPos;
  64240. }
  64241. }
  64242. return points;
  64243. };
  64244. $('#potree_download_csv_icon').click(() => {
  64245. let points = getProfilePoints();
  64246. let string = CSVExporter.toString(points);
  64247. let blob = new Blob([string], {type: "text/string"});
  64248. $('#potree_download_profile_ortho_link').attr('href', URL.createObjectURL(blob));
  64249. });
  64250. $('#potree_download_las_icon').click(() => {
  64251. let points = getProfilePoints();
  64252. let buffer = LASExporter.toLAS(points);
  64253. let blob = new Blob([buffer], {type: "application/octet-binary"});
  64254. $('#potree_download_profile_link').attr('href', URL.createObjectURL(blob));
  64255. });
  64256. }
  64257. selectPoint (mileage, elevation, radius) {
  64258. let closest = {
  64259. distance: Infinity,
  64260. pointcloud: null,
  64261. points: null,
  64262. index: null
  64263. };
  64264. let pointBox = new Box2(
  64265. new Vector2$1(mileage - radius, elevation - radius),
  64266. new Vector2$1(mileage + radius, elevation + radius));
  64267. let numTested = 0;
  64268. let numSkipped = 0;
  64269. let numTestedPoints = 0;
  64270. let numSkippedPoints = 0;
  64271. for (let [pointcloud, entry] of this.pointclouds) {
  64272. for(let points of entry.points){
  64273. let collisionBox = new Box2(
  64274. new Vector2$1(points.projectedBox.min.x, points.projectedBox.min.z),
  64275. new Vector2$1(points.projectedBox.max.x, points.projectedBox.max.z)
  64276. );
  64277. let intersects = collisionBox.intersectsBox(pointBox);
  64278. if(!intersects){
  64279. numSkipped++;
  64280. numSkippedPoints += points.numPoints;
  64281. continue;
  64282. }
  64283. numTested++;
  64284. numTestedPoints += points.numPoints;
  64285. for (let i = 0; i < points.numPoints; i++) {
  64286. let m = points.data.mileage[i] - mileage;
  64287. let e = points.data.position[3 * i + 2] - elevation + pointcloud.position.z;
  64288. let r = Math.sqrt(m * m + e * e);
  64289. const withinDistance = r < radius && r < closest.distance;
  64290. let unfilteredClass = true;
  64291. if(points.data.classification){
  64292. const classification = pointcloud.material.classification;
  64293. const pointClassID = points.data.classification[i];
  64294. const pointClassValue = classification[pointClassID];
  64295. if(pointClassValue && (!pointClassValue.visible || pointClassValue.color.w === 0)){
  64296. unfilteredClass = false;
  64297. }
  64298. }
  64299. if (withinDistance && unfilteredClass) {
  64300. closest = {
  64301. distance: r,
  64302. pointcloud: pointcloud,
  64303. points: points,
  64304. index: i
  64305. };
  64306. }
  64307. }
  64308. }
  64309. }
  64310. //console.log(`nodes: ${numTested}, ${numSkipped} || points: ${numTestedPoints}, ${numSkippedPoints}`);
  64311. if (closest.distance < Infinity) {
  64312. let points = closest.points;
  64313. let point = {};
  64314. let attributes = Object.keys(points.data);
  64315. for (let attribute of attributes) {
  64316. let attributeData = points.data[attribute];
  64317. let itemSize = attributeData.length / points.numPoints;
  64318. let value = attributeData.subarray(itemSize * closest.index, itemSize * closest.index + itemSize);
  64319. if (value.length === 1) {
  64320. point[attribute] = value[0];
  64321. } else {
  64322. point[attribute] = value;
  64323. }
  64324. }
  64325. closest.point = point;
  64326. return closest;
  64327. } else {
  64328. return null;
  64329. }
  64330. }
  64331. initTHREE () {
  64332. this.renderer = new WebGLRenderer({alpha: true, premultipliedAlpha: false});
  64333. this.renderer.setClearColor(0x000000, 0);
  64334. this.renderer.setSize(10, 10);
  64335. this.renderer.autoClear = false;
  64336. this.renderArea.append($(this.renderer.domElement));
  64337. this.renderer.domElement.tabIndex = '2222';
  64338. $(this.renderer.domElement).css('width', '100%');
  64339. $(this.renderer.domElement).css('height', '100%');
  64340. {
  64341. let gl = this.renderer.getContext();
  64342. if(gl.createVertexArray == null){
  64343. let extVAO = gl.getExtension('OES_vertex_array_object');
  64344. if(!extVAO){
  64345. throw new Error("OES_vertex_array_object extension not supported");
  64346. }
  64347. gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
  64348. gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
  64349. }
  64350. }
  64351. this.camera = new OrthographicCamera(-1000, 1000, 1000, -1000, -1000, 1000);
  64352. /* */
  64353. if(window.axisYup){
  64354. }else {
  64355. this.camera.up.set(0, 0, 1);
  64356. this.camera.rotation.order = "ZXY";
  64357. this.camera.rotation.x = Math.PI / 2.0;
  64358. }
  64359. this.scene = new Scene();
  64360. this.profileScene = new Scene();
  64361. let sg = new SphereGeometry(1, 16, 16);
  64362. let sm = new MeshNormalMaterial();
  64363. this.pickSphere = new Mesh(sg, sm);
  64364. this.scene.add(this.pickSphere);
  64365. this.viewerPickSphere = new Mesh(sg, sm);
  64366. }
  64367. initSVG () {
  64368. let width = this.renderArea[0].clientWidth;
  64369. let height = this.renderArea[0].clientHeight;
  64370. let marginLeft = this.renderArea[0].offsetLeft;
  64371. this.svg.selectAll('*').remove();
  64372. this.scaleX = d3.scale.linear()
  64373. .domain([this.camera.left + this.camera.position.x, this.camera.right + this.camera.position.x])
  64374. .range([0, width]);
  64375. this.scaleY = d3.scale.linear()
  64376. .domain([this.camera.bottom + this.camera.position.z, this.camera.top + this.camera.position.z])
  64377. .range([height, 0]);
  64378. this.xAxis = d3.svg.axis()
  64379. .scale(this.scaleX)
  64380. .orient('bottom')
  64381. .innerTickSize(-height)
  64382. .outerTickSize(1)
  64383. .tickPadding(10)
  64384. .ticks(width / 50);
  64385. this.yAxis = d3.svg.axis()
  64386. .scale(this.scaleY)
  64387. .orient('left')
  64388. .innerTickSize(-width)
  64389. .outerTickSize(1)
  64390. .tickPadding(10)
  64391. .ticks(height / 20);
  64392. this.elXAxis = this.svg.append('g')
  64393. .attr('class', 'x axis')
  64394. .attr('transform', `translate(${marginLeft}, ${height})`)
  64395. .call(this.xAxis);
  64396. this.elYAxis = this.svg.append('g')
  64397. .attr('class', 'y axis')
  64398. .attr('transform', `translate(${marginLeft}, 0)`)
  64399. .call(this.yAxis);
  64400. }
  64401. addPoints (pointcloud, points) {
  64402. if(points.numPoints === 0){
  64403. return;
  64404. }
  64405. let entry = this.pointclouds.get(pointcloud);
  64406. if(!entry){
  64407. entry = new ProfileFakeOctree(pointcloud);
  64408. this.pointclouds.set(pointcloud, entry);
  64409. this.profileScene.add(entry);
  64410. let materialChanged = () => {
  64411. this.render();
  64412. };
  64413. materialChanged();
  64414. pointcloud.material.addEventListener('material_property_changed', materialChanged);
  64415. this.addEventListener("on_reset_once", () => {
  64416. pointcloud.material.removeEventListener('material_property_changed', materialChanged);
  64417. });
  64418. }
  64419. entry.addPoints(points);
  64420. this.projectedBox.union(entry.projectedBox);
  64421. if (this.autoFit && this.autoFitEnabled) {
  64422. let width = this.renderArea[0].clientWidth;
  64423. let height = this.renderArea[0].clientHeight;
  64424. let size = this.projectedBox.getSize(new Vector3());
  64425. let sx = width / size.x;
  64426. let sy = height / size.z;
  64427. let scale = Math.min(sx, sy);
  64428. let center = this.projectedBox.getCenter(new Vector3());
  64429. this.scale.set(scale, scale, 1);
  64430. this.camera.position.copy(center);
  64431. //console.log("camera: ", this.camera.position.toArray().join(", "));
  64432. }
  64433. //console.log(entry);
  64434. this.render();
  64435. let numPoints = 0;
  64436. for (let [key, value] of this.pointclouds.entries()) {
  64437. numPoints += value.points.reduce( (a, i) => a + i.numPoints, 0);
  64438. }
  64439. $(`#profile_num_points`).html(Utils.addCommas(numPoints));
  64440. }
  64441. reset () {
  64442. this.lastReset = new Date().getTime();
  64443. this.dispatchEvent({type: "on_reset_once"});
  64444. this.removeEventListeners("on_reset_once");
  64445. this.autoFit = true;
  64446. this.projectedBox = new Box3();
  64447. for(let [key, entry] of this.pointclouds){
  64448. entry.dispose();
  64449. }
  64450. this.pointclouds.clear();
  64451. this.mouseIsDown = false;
  64452. this.mouse.set(0, 0);
  64453. if(this.autoFitEnabled){
  64454. this.scale.set(1, 1, 1);
  64455. }
  64456. this.pickSphere.visible = false;
  64457. this.elRoot.find('#profileSelectionProperties').hide();
  64458. this.render();
  64459. }
  64460. show () {
  64461. this.elRoot.fadeIn();
  64462. this.enabled = true;
  64463. }
  64464. hide () {
  64465. this.elRoot.fadeOut();
  64466. this.enabled = false;
  64467. }
  64468. updateScales () {
  64469. let width = this.renderArea[0].clientWidth;
  64470. let height = this.renderArea[0].clientHeight;
  64471. let left = (-width / 2) / this.scale.x;
  64472. let right = (+width / 2) / this.scale.x;
  64473. let top = (+height / 2) / this.scale.y;
  64474. let bottom = (-height / 2) / this.scale.y;
  64475. this.camera.left = left;
  64476. this.camera.right = right;
  64477. this.camera.top = top;
  64478. this.camera.bottom = bottom;
  64479. this.camera.updateProjectionMatrix();
  64480. this.scaleX.domain([this.camera.left + this.camera.position.x, this.camera.right + this.camera.position.x])
  64481. .range([0, width]);
  64482. this.scaleY.domain([this.camera.bottom + this.camera.position.z, this.camera.top + this.camera.position.z])
  64483. .range([height, 0]);
  64484. let marginLeft = this.renderArea[0].offsetLeft;
  64485. this.xAxis.scale(this.scaleX)
  64486. .orient('bottom')
  64487. .innerTickSize(-height)
  64488. .outerTickSize(1)
  64489. .tickPadding(10)
  64490. .ticks(width / 50);
  64491. this.yAxis.scale(this.scaleY)
  64492. .orient('left')
  64493. .innerTickSize(-width)
  64494. .outerTickSize(1)
  64495. .tickPadding(10)
  64496. .ticks(height / 20);
  64497. this.elXAxis
  64498. .attr('transform', `translate(${marginLeft}, ${height})`)
  64499. .call(this.xAxis);
  64500. this.elYAxis
  64501. .attr('transform', `translate(${marginLeft}, 0)`)
  64502. .call(this.yAxis);
  64503. }
  64504. requestScaleUpdate(){
  64505. let threshold = 100;
  64506. let allowUpdate = ((this.lastReset === undefined) || (this.lastScaleUpdate === undefined))
  64507. || ((new Date().getTime() - this.lastReset) > threshold && (new Date().getTime() - this.lastScaleUpdate) > threshold);
  64508. if(allowUpdate){
  64509. this.updateScales();
  64510. this.lastScaleUpdate = new Date().getTime();
  64511. this.scaleUpdatePending = false;
  64512. }else if(!this.scaleUpdatePending) {
  64513. setTimeout(this.requestScaleUpdate.bind(this), 100);
  64514. this.scaleUpdatePending = true;
  64515. }
  64516. }
  64517. render () {
  64518. let width = this.renderArea[0].clientWidth;
  64519. let height = this.renderArea[0].clientHeight;
  64520. let {renderer, pRenderer, camera, profileScene, scene} = this;
  64521. let {scaleX, pickSphere} = this;
  64522. renderer.setSize(width, height);
  64523. renderer.setClearColor(0x000000, 0);
  64524. renderer.clear(true, true, false);
  64525. for(let pointcloud of this.pointclouds.keys()){
  64526. let source = pointcloud.material;
  64527. let target = this.pointclouds.get(pointcloud).material;
  64528. copyMaterial(source, target);
  64529. target.size = 2;
  64530. }
  64531. pRenderer.render(profileScene, camera, null);
  64532. let radius = Math.abs(scaleX.invert(0) - scaleX.invert(5));
  64533. if (radius === 0) {
  64534. pickSphere.visible = false;
  64535. } else {
  64536. pickSphere.scale.set(radius, radius, radius);
  64537. pickSphere.visible = true;
  64538. }
  64539. renderer.render(scene, camera);
  64540. this.requestScaleUpdate();
  64541. }
  64542. };
  64543. class ProfileWindowController {
  64544. constructor (viewer) {
  64545. this.viewer = viewer;
  64546. this.profileWindow = viewer.profileWindow;
  64547. this.profile = null;
  64548. this.numPoints = 0;
  64549. this.threshold = 60 * 1000;
  64550. this.rotateAmount = 10;
  64551. this.scheduledRecomputeTime = null;
  64552. this.enabled = true;
  64553. this.requests = [];
  64554. this._recompute = () => { this.recompute(); };
  64555. this.viewer.addEventListener("scene_changed", e => {
  64556. e.oldScene.removeEventListener("pointcloud_added", this._recompute);
  64557. e.scene.addEventListener("pointcloud_added", this._recompute);
  64558. });
  64559. this.viewer.scene.addEventListener("pointcloud_added", this._recompute);
  64560. $("#potree_profile_rotate_amount").val(parseInt(this.rotateAmount));
  64561. $("#potree_profile_rotate_amount").on("input", (e) => {
  64562. const str = $("#potree_profile_rotate_amount").val();
  64563. if(!isNaN(str)){
  64564. const value = parseFloat(str);
  64565. this.rotateAmount = value;
  64566. $("#potree_profile_rotate_amount").css("background-color", "");
  64567. }else {
  64568. $("#potree_profile_rotate_amount").css("background-color", "#ff9999");
  64569. }
  64570. });
  64571. const rotate = (radians) => {
  64572. const profile = this.profile;
  64573. const points = profile.points;
  64574. const start = points[0];
  64575. const end = points[points.length - 1];
  64576. const center = start.clone().add(end).multiplyScalar(0.5);
  64577. const mMoveOrigin = new Matrix4().makeTranslation(-center.x, -center.y, -center.z);
  64578. const mRotate = new Matrix4().makeRotationZ(radians);
  64579. const mMoveBack = new Matrix4().makeTranslation(center.x, center.y, center.z);
  64580. //const transform = mMoveOrigin.multiply(mRotate).multiply(mMoveBack);
  64581. const transform = mMoveBack.multiply(mRotate).multiply(mMoveOrigin);
  64582. const rotatedPoints = points.map( point => point.clone().applyMatrix4(transform) );
  64583. this.profileWindow.autoFitEnabled = false;
  64584. for(let i = 0; i < points.length; i++){
  64585. profile.setPosition(i, rotatedPoints[i]);
  64586. }
  64587. };
  64588. $("#potree_profile_rotate_cw").click( () => {
  64589. const radians = MathUtils.degToRad(this.rotateAmount);
  64590. rotate(-radians);
  64591. });
  64592. $("#potree_profile_rotate_ccw").click( () => {
  64593. const radians = MathUtils.degToRad(this.rotateAmount);
  64594. rotate(radians);
  64595. });
  64596. $("#potree_profile_move_forward").click( () => {
  64597. const profile = this.profile;
  64598. const points = profile.points;
  64599. const start = points[0];
  64600. const end = points[points.length - 1];
  64601. const dir = end.clone().sub(start).normalize();
  64602. const up = new Vector3(0, 0, 1);
  64603. const forward = up.cross(dir);
  64604. const move = forward.clone().multiplyScalar(profile.width / 2);
  64605. this.profileWindow.autoFitEnabled = false;
  64606. for(let i = 0; i < points.length; i++){
  64607. profile.setPosition(i, points[i].clone().add(move));
  64608. }
  64609. });
  64610. $("#potree_profile_move_backward").click( () => {
  64611. const profile = this.profile;
  64612. const points = profile.points;
  64613. const start = points[0];
  64614. const end = points[points.length - 1];
  64615. const dir = end.clone().sub(start).normalize();
  64616. const up = new Vector3(0, 0, 1);
  64617. const forward = up.cross(dir);
  64618. const move = forward.clone().multiplyScalar(-profile.width / 2);
  64619. this.profileWindow.autoFitEnabled = false;
  64620. for(let i = 0; i < points.length; i++){
  64621. profile.setPosition(i, points[i].clone().add(move));
  64622. }
  64623. });
  64624. }
  64625. setProfile (profile) {
  64626. if (this.profile !== null && this.profile !== profile) {
  64627. this.profile.removeEventListener('marker_moved', this._recompute);
  64628. this.profile.removeEventListener('marker_added', this._recompute);
  64629. this.profile.removeEventListener('marker_removed', this._recompute);
  64630. this.profile.removeEventListener('width_changed', this._recompute);
  64631. }
  64632. this.profile = profile;
  64633. {
  64634. this.profile.addEventListener('marker_moved', this._recompute);
  64635. this.profile.addEventListener('marker_added', this._recompute);
  64636. this.profile.addEventListener('marker_removed', this._recompute);
  64637. this.profile.addEventListener('width_changed', this._recompute);
  64638. }
  64639. this.recompute();
  64640. }
  64641. reset () {
  64642. this.profileWindow.reset();
  64643. this.numPoints = 0;
  64644. if (this.profile) {
  64645. for (let request of this.requests) {
  64646. request.cancel();
  64647. }
  64648. }
  64649. }
  64650. progressHandler (pointcloud, progress) {
  64651. for (let segment of progress.segments) {
  64652. this.profileWindow.addPoints(pointcloud, segment.points);
  64653. this.numPoints += segment.points.numPoints;
  64654. }
  64655. }
  64656. cancel () {
  64657. for (let request of this.requests) {
  64658. request.cancel();
  64659. // request.finishLevelThenCancel();
  64660. }
  64661. this.requests = [];
  64662. };
  64663. finishLevelThenCancel(){
  64664. for (let request of this.requests) {
  64665. request.finishLevelThenCancel();
  64666. }
  64667. this.requests = [];
  64668. }
  64669. recompute () {
  64670. if (!this.profile) {
  64671. return;
  64672. }
  64673. if (this.scheduledRecomputeTime !== null && this.scheduledRecomputeTime > new Date().getTime()) {
  64674. return;
  64675. } else {
  64676. this.scheduledRecomputeTime = new Date().getTime() + 100;
  64677. }
  64678. this.scheduledRecomputeTime = null;
  64679. this.reset();
  64680. for (let pointcloud of this.viewer.scene.pointclouds.filter(p => p.visible)) {
  64681. let request = pointcloud.getPointsInProfile(this.profile, null, {
  64682. 'onProgress': (event) => {
  64683. if (!this.enabled) {
  64684. return;
  64685. }
  64686. this.progressHandler(pointcloud, event.points);
  64687. if (this.numPoints > this.threshold) {
  64688. this.finishLevelThenCancel();
  64689. }
  64690. },
  64691. 'onFinish': (event) => {
  64692. if (!this.enabled) {
  64693. }
  64694. },
  64695. 'onCancel': () => {
  64696. if (!this.enabled) {
  64697. }
  64698. }
  64699. });
  64700. this.requests.push(request);
  64701. }
  64702. }
  64703. };
  64704. /**
  64705. *
  64706. * @author sigeom sa / http://sigeom.ch
  64707. * @author Ioda-Net Sàrl / https://www.ioda-net.ch/
  64708. * @author Markus Schütz / http://potree.org
  64709. *
  64710. */
  64711. class GeoJSONExporter{
  64712. static measurementToFeatures (measurement) {
  64713. let coords = measurement.points.map(e => e.position.toArray());
  64714. let features = [];
  64715. if (coords.length === 1) {
  64716. let feature = {
  64717. type: 'Feature',
  64718. geometry: {
  64719. type: 'Point',
  64720. coordinates: coords[0]
  64721. },
  64722. properties: {
  64723. name: measurement.name
  64724. }
  64725. };
  64726. features.push(feature);
  64727. } else if (coords.length > 1 && !measurement.closed) {
  64728. let object = {
  64729. 'type': 'Feature',
  64730. 'geometry': {
  64731. 'type': 'LineString',
  64732. 'coordinates': coords
  64733. },
  64734. 'properties': {
  64735. name: measurement.name
  64736. }
  64737. };
  64738. features.push(object);
  64739. } else if (coords.length > 1 && measurement.closed) {
  64740. let object = {
  64741. 'type': 'Feature',
  64742. 'geometry': {
  64743. 'type': 'Polygon',
  64744. 'coordinates': [[...coords, coords[0]]]
  64745. },
  64746. 'properties': {
  64747. name: measurement.name
  64748. }
  64749. };
  64750. features.push(object);
  64751. }
  64752. if (measurement.showDistances) {
  64753. measurement.edgeLabels.forEach((label) => {
  64754. let labelPoint = {
  64755. type: 'Feature',
  64756. geometry: {
  64757. type: 'Point',
  64758. coordinates: label.position.toArray()
  64759. },
  64760. properties: {
  64761. distance: label.text
  64762. }
  64763. };
  64764. features.push(labelPoint);
  64765. });
  64766. }
  64767. if (measurement.showArea) {
  64768. let point = measurement.areaLabel.position;
  64769. let labelArea = {
  64770. type: 'Feature',
  64771. geometry: {
  64772. type: 'Point',
  64773. coordinates: point.toArray()
  64774. },
  64775. properties: {
  64776. area: measurement.areaLabel.text
  64777. }
  64778. };
  64779. features.push(labelArea);
  64780. }
  64781. return features;
  64782. }
  64783. static toString (measurements) {
  64784. if (!(measurements instanceof Array)) {
  64785. measurements = [measurements];
  64786. }
  64787. measurements = measurements.filter(m => m instanceof Measure);
  64788. let features = [];
  64789. for (let measure of measurements) {
  64790. let f = GeoJSONExporter.measurementToFeatures(measure);
  64791. features = features.concat(f);
  64792. }
  64793. let geojson = {
  64794. 'type': 'FeatureCollection',
  64795. 'features': features
  64796. };
  64797. return JSON.stringify(geojson, null, '\t');
  64798. }
  64799. }
  64800. /**
  64801. *
  64802. * @author sigeom sa / http://sigeom.ch
  64803. * @author Ioda-Net Sàrl / https://www.ioda-net.ch/
  64804. * @author Markus Schuetz / http://potree.org
  64805. *
  64806. */
  64807. class DXFExporter {
  64808. static measurementPointSection (measurement) {
  64809. let position = measurement.points[0].position;
  64810. if (!position) {
  64811. return '';
  64812. }
  64813. let dxfSection = `0
  64814. CIRCLE
  64815. 8
  64816. layer_point
  64817. 10
  64818. ${position.x}
  64819. 20
  64820. ${position.y}
  64821. 30
  64822. ${position.z}
  64823. 40
  64824. 1.0
  64825. `;
  64826. return dxfSection;
  64827. }
  64828. static measurementPolylineSection (measurement) {
  64829. // bit code for polygons/polylines:
  64830. // https://www.autodesk.com/techpubs/autocad/acad2000/dxf/polyline_dxf_06.htm
  64831. let geomCode = 8;
  64832. if (measurement.closed) {
  64833. geomCode += 1;
  64834. }
  64835. let dxfSection = `0
  64836. POLYLINE
  64837. 8
  64838. layer_polyline
  64839. 62
  64840. 1
  64841. 66
  64842. 1
  64843. 10
  64844. 0.0
  64845. 20
  64846. 0.0
  64847. 30
  64848. 0.0
  64849. 70
  64850. ${geomCode}
  64851. `;
  64852. let xMax = 0.0;
  64853. let yMax = 0.0;
  64854. let zMax = 0.0;
  64855. for (let point of measurement.points) {
  64856. point = point.position;
  64857. xMax = Math.max(xMax, point.x);
  64858. yMax = Math.max(yMax, point.y);
  64859. zMax = Math.max(zMax, point.z);
  64860. dxfSection += `0
  64861. VERTEX
  64862. 8
  64863. 0
  64864. 10
  64865. ${point.x}
  64866. 20
  64867. ${point.y}
  64868. 30
  64869. ${point.z}
  64870. 70
  64871. 32
  64872. `;
  64873. }
  64874. dxfSection += `0
  64875. SEQEND
  64876. `;
  64877. return dxfSection;
  64878. }
  64879. static measurementSection (measurement) {
  64880. // if(measurement.points.length <= 1){
  64881. // return "";
  64882. // }
  64883. if (measurement.points.length === 0) {
  64884. return '';
  64885. } else if (measurement.points.length === 1) {
  64886. return DXFExporter.measurementPointSection(measurement);
  64887. } else if (measurement.points.length >= 2) {
  64888. return DXFExporter.measurementPolylineSection(measurement);
  64889. }
  64890. }
  64891. static toString(measurements){
  64892. if (!(measurements instanceof Array)) {
  64893. measurements = [measurements];
  64894. }
  64895. measurements = measurements.filter(m => m instanceof Measure);
  64896. let points = measurements.filter(m => (m instanceof Measure))
  64897. .map(m => m.points)
  64898. .reduce((a, v) => a.concat(v))
  64899. .map(p => p.position);
  64900. let min = new Vector3(Infinity, Infinity, Infinity);
  64901. let max = new Vector3(-Infinity, -Infinity, -Infinity);
  64902. for (let point of points) {
  64903. min.min(point);
  64904. max.max(point);
  64905. }
  64906. let dxfHeader = `999
  64907. DXF created from potree
  64908. 0
  64909. SECTION
  64910. 2
  64911. HEADER
  64912. 9
  64913. $ACADVER
  64914. 1
  64915. AC1006
  64916. 9
  64917. $INSBASE
  64918. 10
  64919. 0.0
  64920. 20
  64921. 0.0
  64922. 30
  64923. 0.0
  64924. 9
  64925. $EXTMIN
  64926. 10
  64927. ${min.x}
  64928. 20
  64929. ${min.y}
  64930. 30
  64931. ${min.z}
  64932. 9
  64933. $EXTMAX
  64934. 10
  64935. ${max.x}
  64936. 20
  64937. ${max.y}
  64938. 30
  64939. ${max.z}
  64940. 0
  64941. ENDSEC
  64942. `;
  64943. let dxfBody = `0
  64944. SECTION
  64945. 2
  64946. ENTITIES
  64947. `;
  64948. for (let measurement of measurements) {
  64949. dxfBody += DXFExporter.measurementSection(measurement);
  64950. }
  64951. dxfBody += `0
  64952. ENDSEC
  64953. `;
  64954. let dxf = dxfHeader + dxfBody + '0\nEOF';
  64955. return dxf;
  64956. }
  64957. }
  64958. class MeasurePanel{
  64959. constructor(viewer, measurement, propertiesPanel){
  64960. this.viewer = viewer;
  64961. this.measurement = measurement;
  64962. this.propertiesPanel = propertiesPanel;
  64963. this._update = () => { this.update(); };
  64964. }
  64965. createCoordinatesTable(points){
  64966. let table = $(`
  64967. <table class="measurement_value_table">
  64968. <tr>
  64969. <th>x</th>
  64970. <th>y</th>
  64971. <th>z</th>
  64972. <th></th>
  64973. </tr>
  64974. </table>
  64975. `);
  64976. let copyIconPath = Potree.resourcePath + '/icons/copy.svg';
  64977. for (let point of points) {
  64978. let x = Utils.addCommas(point.x.toFixed(3));
  64979. let y = Utils.addCommas(point.y.toFixed(3));
  64980. let z = Utils.addCommas(point.z.toFixed(3));
  64981. let row = $(`
  64982. <tr>
  64983. <td><span>${x}</span></td>
  64984. <td><span>${y}</span></td>
  64985. <td><span>${z}</span></td>
  64986. <td align="right" style="width: 25%">
  64987. <img name="copy" title="copy" class="button-icon" src="${copyIconPath}" style="width: 16px; height: 16px"/>
  64988. </td>
  64989. </tr>
  64990. `);
  64991. this.elCopy = row.find("img[name=copy]");
  64992. this.elCopy.click( () => {
  64993. let msg = point.toArray().map(c => c.toFixed(3)).join(", ");
  64994. Utils.clipboardCopy(msg);
  64995. this.viewer.postMessage(
  64996. `Copied value to clipboard: <br>'${msg}'`,
  64997. {duration: 3000});
  64998. });
  64999. table.append(row);
  65000. }
  65001. return table;
  65002. };
  65003. createAttributesTable(){
  65004. let elTable = $('<table class="measurement_value_table"></table>');
  65005. let point = this.measurement.points[0];
  65006. /* for(let attributeName of Object.keys(point)){
  65007. if(attributeName === "position"){
  65008. }else if(attributeName === "rgba"){
  65009. let color = point.rgba;
  65010. let text = color.join(', ');
  65011. elTable.append($(`
  65012. <tr>
  65013. <td>rgb</td>
  65014. <td>${text}</td>
  65015. </tr>
  65016. `));
  65017. }else{
  65018. let value = point[attributeName];
  65019. let text = value.join(', ');
  65020. elTable.append($(`
  65021. <tr>
  65022. <td>${attributeName}</td>
  65023. <td>${text}</td>
  65024. </tr>
  65025. `));
  65026. }
  65027. } */
  65028. return elTable;
  65029. }
  65030. update(){
  65031. }
  65032. };
  65033. class DistancePanel extends MeasurePanel{
  65034. constructor(viewer, measurement, propertiesPanel){
  65035. super(viewer, measurement, propertiesPanel);
  65036. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65037. this.elContent = $(`
  65038. <div class="measurement_content selectable">
  65039. <span class="coordinates_table_container"></span>
  65040. <br>
  65041. <table id="distances_table" class="measurement_value_table"></table>
  65042. <!-- ACTIONS -->
  65043. <div style="display: flex; margin-top: 12px">
  65044. <span>
  65045. <input type="button" name="make_profile" value="profile from measure" />
  65046. </span>
  65047. <span style="flex-grow: 1"></span>
  65048. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65049. </div>
  65050. </div>
  65051. `);
  65052. this.elRemove = this.elContent.find("img[name=remove]");
  65053. this.elRemove.click( () => {
  65054. this.viewer.scene.removeMeasurement(measurement);
  65055. });
  65056. this.elMakeProfile = this.elContent.find("input[name=make_profile]");
  65057. this.elMakeProfile.click( () => {
  65058. //measurement.points;
  65059. const profile = new Profile();
  65060. profile.name = measurement.name;
  65061. profile.width = measurement.getTotalDistance() / 50;
  65062. for(const point of measurement.points){
  65063. profile.addMarker(point.position.clone());
  65064. }
  65065. this.viewer.scene.addProfile(profile);
  65066. });
  65067. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65068. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65069. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65070. this.update();
  65071. }
  65072. update(){
  65073. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65074. elCoordiantesContainer.empty();
  65075. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points));
  65076. let positions = this.measurement.points;
  65077. let distances = [];
  65078. for (let i = 0; i < positions.length - 1; i++) {
  65079. let d = positions[i].distanceTo(positions[i + 1]);
  65080. distances.push(d.toFixed(3));
  65081. }
  65082. let totalDistance = this.measurement.getTotalDistance().toFixed(3);
  65083. let elDistanceTable = this.elContent.find(`#distances_table`);
  65084. elDistanceTable.empty();
  65085. for (let i = 0; i < distances.length; i++) {
  65086. let label = (i === 0) ? 'Distances: ' : '';
  65087. let distance = distances[i];
  65088. let elDistance = $(`
  65089. <tr>
  65090. <th>${label}</th>
  65091. <td style="width: 100%; padding-left: 10px">${distance}</td>
  65092. </tr>`);
  65093. elDistanceTable.append(elDistance);
  65094. }
  65095. let elTotal = $(`
  65096. <tr>
  65097. <th>Total: </td><td style="width: 100%; padding-left: 10px">${totalDistance}</th>
  65098. </tr>`);
  65099. elDistanceTable.append(elTotal);
  65100. }
  65101. };
  65102. class PointPanel extends MeasurePanel{
  65103. constructor(viewer, measurement, propertiesPanel){
  65104. super(viewer, measurement, propertiesPanel);
  65105. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65106. this.elContent = $(`
  65107. <div class="measurement_content selectable">
  65108. <span class="coordinates_table_container"></span>
  65109. <br>
  65110. <span class="attributes_table_container"></span>
  65111. <!-- ACTIONS -->
  65112. <div style="display: flex; margin-top: 12px">
  65113. <span></span>
  65114. <span style="flex-grow: 1"></span>
  65115. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65116. </div>
  65117. </div>
  65118. `);
  65119. this.elRemove = this.elContent.find("img[name=remove]");
  65120. this.elRemove.click( () => {
  65121. this.viewer.scene.removeMeasurement(measurement);
  65122. });
  65123. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65124. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65125. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65126. this.update();
  65127. }
  65128. update(){
  65129. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65130. elCoordiantesContainer.empty();
  65131. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points));
  65132. let elAttributesContainer = this.elContent.find('.attributes_table_container');
  65133. elAttributesContainer.empty();
  65134. elAttributesContainer.append(this.createAttributesTable());
  65135. }
  65136. };
  65137. class AreaPanel extends MeasurePanel{
  65138. constructor(viewer, measurement, propertiesPanel){
  65139. super(viewer, measurement, propertiesPanel);
  65140. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65141. this.elContent = $(`
  65142. <div class="measurement_content selectable">
  65143. <span class="coordinates_table_container"></span>
  65144. <br>
  65145. <span style="font-weight: bold">Area: </span>
  65146. <span id="measurement_area"></span>
  65147. <!-- ACTIONS -->
  65148. <div style="display: flex; margin-top: 12px">
  65149. <span></span>
  65150. <span style="flex-grow: 1"></span>
  65151. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65152. </div>
  65153. </div>
  65154. `);
  65155. this.elRemove = this.elContent.find("img[name=remove]");
  65156. this.elRemove.click( () => {
  65157. this.viewer.scene.removeMeasurement(measurement);
  65158. });
  65159. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65160. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65161. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65162. this.update();
  65163. }
  65164. update(){
  65165. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65166. elCoordiantesContainer.empty();
  65167. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points));
  65168. let elArea = this.elContent.find(`#measurement_area`);
  65169. elArea.html(this.measurement.area.value.toFixed(3));
  65170. }
  65171. };
  65172. class AnglePanel extends MeasurePanel{
  65173. constructor(viewer, measurement, propertiesPanel){
  65174. super(viewer, measurement, propertiesPanel);
  65175. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65176. this.elContent = $(`
  65177. <div class="measurement_content selectable">
  65178. <span class="coordinates_table_container"></span>
  65179. <br>
  65180. <table class="measurement_value_table">
  65181. <tr>
  65182. <th>\u03b1</th>
  65183. <th>\u03b2</th>
  65184. <th>\u03b3</th>
  65185. </tr>
  65186. <tr>
  65187. <td align="center" id="angle_cell_alpha" style="width: 33%"></td>
  65188. <td align="center" id="angle_cell_betta" style="width: 33%"></td>
  65189. <td align="center" id="angle_cell_gamma" style="width: 33%"></td>
  65190. </tr>
  65191. </table>
  65192. <!-- ACTIONS -->
  65193. <div style="display: flex; margin-top: 12px">
  65194. <span></span>
  65195. <span style="flex-grow: 1"></span>
  65196. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65197. </div>
  65198. </div>
  65199. `);
  65200. this.elRemove = this.elContent.find("img[name=remove]");
  65201. this.elRemove.click( () => {
  65202. this.viewer.scene.removeMeasurement(measurement);
  65203. });
  65204. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65205. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65206. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65207. this.update();
  65208. }
  65209. update(){
  65210. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65211. elCoordiantesContainer.empty();
  65212. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points.map(p => p.position)));
  65213. let angles = [];
  65214. for(let i = 0; i < this.measurement.points.length; i++){
  65215. angles.push(this.measurement.getAngle(i) * (180.0 / Math.PI));
  65216. }
  65217. angles = angles.map(a => a.toFixed(1) + '\u00B0');
  65218. let elAlpha = this.elContent.find(`#angle_cell_alpha`);
  65219. let elBetta = this.elContent.find(`#angle_cell_betta`);
  65220. let elGamma = this.elContent.find(`#angle_cell_gamma`);
  65221. elAlpha.html(angles[0]);
  65222. elBetta.html(angles[1]);
  65223. elGamma.html(angles[2]);
  65224. }
  65225. };
  65226. class CirclePanel extends MeasurePanel{
  65227. constructor(viewer, measurement, propertiesPanel){
  65228. super(viewer, measurement, propertiesPanel);
  65229. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65230. this.elContent = $(`
  65231. <div class="measurement_content selectable">
  65232. <span class="coordinates_table_container"></span>
  65233. <br>
  65234. <table id="infos_table" class="measurement_value_table"></table>
  65235. <!-- ACTIONS -->
  65236. <div style="display: flex; margin-top: 12px">
  65237. <span></span>
  65238. <span style="flex-grow: 1"></span>
  65239. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65240. </div>
  65241. </div>
  65242. `);
  65243. this.elRemove = this.elContent.find("img[name=remove]");
  65244. this.elRemove.click( () => {
  65245. this.viewer.scene.removeMeasurement(measurement);
  65246. });
  65247. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65248. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65249. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65250. this.update();
  65251. }
  65252. update(){
  65253. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65254. elCoordiantesContainer.empty();
  65255. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points.map(p => p.position)));
  65256. const elInfos = this.elContent.find(`#infos_table`);
  65257. if(this.measurement.points.length !== 3){
  65258. elInfos.empty();
  65259. return;
  65260. }
  65261. const A = this.measurement.points[0].position;
  65262. const B = this.measurement.points[1].position;
  65263. const C = this.measurement.points[2].position;
  65264. const center = Potree.Utils.computeCircleCenter(A, B, C);
  65265. const radius = center.distanceTo(A);
  65266. const circumference = 2 * Math.PI * radius;
  65267. const format = (number) => {
  65268. return Potree.Utils.addCommas(number.toFixed(3));
  65269. };
  65270. const txtCenter = `${format(center.x)} ${format(center.y)} ${format(center.z)}`;
  65271. const txtRadius = format(radius);
  65272. const txtCircumference = format(circumference);
  65273. const thStyle = `style="text-align: left"`;
  65274. const tdStyle = `style="width: 100%; padding: 5px;"`;
  65275. elInfos.html(`
  65276. <tr>
  65277. <th ${thStyle}>Center: </th>
  65278. <td ${tdStyle}></td>
  65279. </tr>
  65280. <tr>
  65281. <td ${tdStyle} colspan="2">
  65282. ${txtCenter}
  65283. </td>
  65284. </tr>
  65285. <tr>
  65286. <th ${thStyle}>Radius: </th>
  65287. <td ${tdStyle}>${txtRadius}</td>
  65288. </tr>
  65289. <tr>
  65290. <th ${thStyle}>Circumference: </th>
  65291. <td ${tdStyle}>${txtCircumference}</td>
  65292. </tr>
  65293. `);
  65294. }
  65295. };
  65296. class HeightPanel extends MeasurePanel{
  65297. constructor(viewer, measurement, propertiesPanel){
  65298. super(viewer, measurement, propertiesPanel);
  65299. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65300. this.elContent = $(`
  65301. <div class="measurement_content selectable">
  65302. <span class="coordinates_table_container"></span>
  65303. <br>
  65304. <span id="height_label">Height: </span><br>
  65305. <!-- ACTIONS -->
  65306. <div style="display: flex; margin-top: 12px">
  65307. <span></span>
  65308. <span style="flex-grow: 1"></span>
  65309. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65310. </div>
  65311. </div>
  65312. `);
  65313. this.elRemove = this.elContent.find("img[name=remove]");
  65314. this.elRemove.click( () => {
  65315. this.viewer.scene.removeMeasurement(measurement);
  65316. });
  65317. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65318. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65319. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65320. this.update();
  65321. }
  65322. update(){
  65323. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65324. elCoordiantesContainer.empty();
  65325. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points.map(p => p.position)));
  65326. {
  65327. let points = this.measurement.points;
  65328. let sorted = points.slice().sort((a, b) => a.position.z - b.position.z);
  65329. let lowPoint = sorted[0].position.clone();
  65330. let highPoint = sorted[sorted.length - 1].position.clone();
  65331. let min = lowPoint.z;
  65332. let max = highPoint.z;
  65333. let height = max - min;
  65334. height = height.toFixed(3);
  65335. this.elHeightLabel = this.elContent.find(`#height_label`);
  65336. this.elHeightLabel.html(`<b>Height:</b> ${height}`);
  65337. }
  65338. }
  65339. };
  65340. class VolumePanel extends MeasurePanel{
  65341. constructor(viewer, measurement, propertiesPanel){
  65342. super(viewer, measurement, propertiesPanel);
  65343. let copyIconPath = Potree.resourcePath + '/icons/copy.svg';
  65344. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65345. let lblLengthText = new Map([
  65346. [BoxVolume, "length"],
  65347. [SphereVolume, "rx"],
  65348. ]).get(measurement.constructor);
  65349. let lblWidthText = new Map([
  65350. [BoxVolume, "width"],
  65351. [SphereVolume, "ry"],
  65352. ]).get(measurement.constructor);
  65353. let lblHeightText = new Map([
  65354. [BoxVolume, "height"],
  65355. [SphereVolume, "rz"],
  65356. ]).get(measurement.constructor);
  65357. this.elContent = $(`
  65358. <div class="measurement_content selectable">
  65359. <span class="coordinates_table_container"></span>
  65360. <table class="measurement_value_table">
  65361. <tr>
  65362. <th>\u03b1</th>
  65363. <th>\u03b2</th>
  65364. <th>\u03b3</th>
  65365. <th></th>
  65366. </tr>
  65367. <tr>
  65368. <td align="center" id="angle_cell_alpha" style="width: 33%"></td>
  65369. <td align="center" id="angle_cell_betta" style="width: 33%"></td>
  65370. <td align="center" id="angle_cell_gamma" style="width: 33%"></td>
  65371. <td align="right" style="width: 25%">
  65372. <img name="copyRotation" title="copy" class="button-icon" src="${copyIconPath}" style="width: 16px; height: 16px"/>
  65373. </td>
  65374. </tr>
  65375. </table>
  65376. <table class="measurement_value_table">
  65377. <tr>
  65378. <th>${lblLengthText}</th>
  65379. <th>${lblWidthText}</th>
  65380. <th>${lblHeightText}</th>
  65381. <th></th>
  65382. </tr>
  65383. <tr>
  65384. <td align="center" id="cell_length" style="width: 33%"></td>
  65385. <td align="center" id="cell_width" style="width: 33%"></td>
  65386. <td align="center" id="cell_height" style="width: 33%"></td>
  65387. <td align="right" style="width: 25%">
  65388. <img name="copyScale" title="copy" class="button-icon" src="${copyIconPath}" style="width: 16px; height: 16px"/>
  65389. </td>
  65390. </tr>
  65391. </table>
  65392. <br>
  65393. <span style="font-weight: bold">Volume: </span>
  65394. <span id="measurement_volume"></span>
  65395. <!--
  65396. <li>
  65397. <label style="whitespace: nowrap">
  65398. <input id="volume_show" type="checkbox"/>
  65399. <span>show volume</span>
  65400. </label>
  65401. </li>-->
  65402. <li>
  65403. <label style="whitespace: nowrap">
  65404. <input id="volume_clip" type="checkbox"/>
  65405. <span>make clip volume</span>
  65406. </label>
  65407. </li>
  65408. <li style="margin-top: 10px">
  65409. <input name="download_volume" type="button" value="prepare download" style="width: 100%" />
  65410. <div name="download_message"></div>
  65411. </li>
  65412. <!-- ACTIONS -->
  65413. <li style="display: grid; grid-template-columns: auto auto; grid-column-gap: 5px; margin-top: 10px">
  65414. <input id="volume_reset_orientation" type="button" value="reset orientation"/>
  65415. <input id="volume_make_uniform" type="button" value="make uniform"/>
  65416. </li>
  65417. <div style="display: flex; margin-top: 12px">
  65418. <span></span>
  65419. <span style="flex-grow: 1"></span>
  65420. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65421. </div>
  65422. </div>
  65423. `);
  65424. { // download
  65425. this.elDownloadButton = this.elContent.find("input[name=download_volume]");
  65426. if(this.propertiesPanel.viewer.server){
  65427. this.elDownloadButton.click(() => this.download());
  65428. } else {
  65429. this.elDownloadButton.hide();
  65430. }
  65431. }
  65432. this.elCopyRotation = this.elContent.find("img[name=copyRotation]");
  65433. this.elCopyRotation.click( () => {
  65434. let rotation = this.measurement.rotation.toArray().slice(0, 3);
  65435. let msg = rotation.map(c => c.toFixed(3)).join(", ");
  65436. Utils.clipboardCopy(msg);
  65437. this.viewer.postMessage(
  65438. `Copied value to clipboard: <br>'${msg}'`,
  65439. {duration: 3000});
  65440. });
  65441. this.elCopyScale = this.elContent.find("img[name=copyScale]");
  65442. this.elCopyScale.click( () => {
  65443. let scale = this.measurement.scale.toArray();
  65444. let msg = scale.map(c => c.toFixed(3)).join(", ");
  65445. Utils.clipboardCopy(msg);
  65446. this.viewer.postMessage(
  65447. `Copied value to clipboard: <br>'${msg}'`,
  65448. {duration: 3000});
  65449. });
  65450. this.elRemove = this.elContent.find("img[name=remove]");
  65451. this.elRemove.click( () => {
  65452. this.viewer.scene.removeVolume(measurement);
  65453. });
  65454. this.elContent.find("#volume_reset_orientation").click(() => {
  65455. measurement.rotation.set(0, 0, 0);
  65456. });
  65457. this.elContent.find("#volume_make_uniform").click(() => {
  65458. let mean = (measurement.scale.x + measurement.scale.y + measurement.scale.z) / 3;
  65459. measurement.scale.set(mean, mean, mean);
  65460. });
  65461. this.elCheckClip = this.elContent.find('#volume_clip');
  65462. this.elCheckClip.click(event => {
  65463. this.measurement.clip = event.target.checked;
  65464. });
  65465. this.elCheckShow = this.elContent.find('#volume_show');
  65466. this.elCheckShow.click(event => {
  65467. this.measurement.visible = event.target.checked;
  65468. });
  65469. this.propertiesPanel.addVolatileListener(measurement, "position_changed", this._update);
  65470. this.propertiesPanel.addVolatileListener(measurement, "orientation_changed", this._update);
  65471. this.propertiesPanel.addVolatileListener(measurement, "scale_changed", this._update);
  65472. this.propertiesPanel.addVolatileListener(measurement, "clip_changed", this._update);
  65473. this.update();
  65474. }
  65475. async download(){
  65476. let clipBox = this.measurement;
  65477. let regions = [];
  65478. //for(let clipBox of boxes){
  65479. {
  65480. let toClip = clipBox.matrixWorld;
  65481. let px = new Vector3(+0.5, 0, 0).applyMatrix4(toClip);
  65482. let nx = new Vector3(-0.5, 0, 0).applyMatrix4(toClip);
  65483. let py = new Vector3(0, +0.5, 0).applyMatrix4(toClip);
  65484. let ny = new Vector3(0, -0.5, 0).applyMatrix4(toClip);
  65485. let pz = new Vector3(0, 0, +0.5).applyMatrix4(toClip);
  65486. let nz = new Vector3(0, 0, -0.5).applyMatrix4(toClip);
  65487. let pxN = new Vector3().subVectors(nx, px).normalize();
  65488. let nxN = pxN.clone().multiplyScalar(-1);
  65489. let pyN = new Vector3().subVectors(ny, py).normalize();
  65490. let nyN = pyN.clone().multiplyScalar(-1);
  65491. let pzN = new Vector3().subVectors(nz, pz).normalize();
  65492. let nzN = pzN.clone().multiplyScalar(-1);
  65493. let planes = [
  65494. new Plane().setFromNormalAndCoplanarPoint(pxN, px),
  65495. new Plane().setFromNormalAndCoplanarPoint(nxN, nx),
  65496. new Plane().setFromNormalAndCoplanarPoint(pyN, py),
  65497. new Plane().setFromNormalAndCoplanarPoint(nyN, ny),
  65498. new Plane().setFromNormalAndCoplanarPoint(pzN, pz),
  65499. new Plane().setFromNormalAndCoplanarPoint(nzN, nz),
  65500. ];
  65501. let planeQueryParts = [];
  65502. for(let plane of planes){
  65503. let part = [plane.normal.toArray(), plane.constant].join(",");
  65504. part = `[${part}]`;
  65505. planeQueryParts.push(part);
  65506. }
  65507. let region = "[" + planeQueryParts.join(",") + "]";
  65508. regions.push(region);
  65509. }
  65510. let regionsArg = regions.join(",");
  65511. let pointcloudArgs = [];
  65512. for(let pointcloud of this.viewer.scene.pointclouds){
  65513. if(!pointcloud.visible){
  65514. continue;
  65515. }
  65516. let offset = pointcloud.pcoGeometry.offset.clone();
  65517. let negateOffset = new Matrix4().makeTranslation(...offset.multiplyScalar(-1).toArray());
  65518. let matrixWorld = pointcloud.matrixWorld;
  65519. let transform = new Matrix4().multiplyMatrices(matrixWorld, negateOffset);
  65520. let path = `${window.location.pathname}/../${pointcloud.pcoGeometry.url}`;
  65521. let arg = {
  65522. path: path,
  65523. transform: transform.elements,
  65524. };
  65525. let argString = JSON.stringify(arg);
  65526. pointcloudArgs.push(argString);
  65527. }
  65528. let pointcloudsArg = pointcloudArgs.join(",");
  65529. let elMessage = this.elContent.find("div[name=download_message]");
  65530. let error = (message) => {
  65531. elMessage.html(`<div style="color: #ff0000">ERROR: ${message}</div>`);
  65532. };
  65533. let info = (message) => {
  65534. elMessage.html(`${message}`);
  65535. };
  65536. let handle = null;
  65537. { // START FILTER
  65538. let url = `${viewer.server}/create_regions_filter?pointclouds=[${pointcloudsArg}]&regions=[${regionsArg}]`;
  65539. //console.log(url);
  65540. info("estimating results ...");
  65541. let response = await fetch(url);
  65542. let jsResponse = await response.json();
  65543. //console.log(jsResponse);
  65544. if(!jsResponse.handle){
  65545. error(jsResponse.message);
  65546. return;
  65547. }else {
  65548. handle = jsResponse.handle;
  65549. }
  65550. }
  65551. { // WAIT, CHECK PROGRESS, HANDLE FINISH
  65552. let url = `${viewer.server}/check_regions_filter?handle=${handle}`;
  65553. let sleep = (function(duration){
  65554. return new Promise( (res, rej) => {
  65555. setTimeout(() => {
  65556. res();
  65557. }, duration);
  65558. });
  65559. });
  65560. let handleFiltering = (jsResponse) => {
  65561. let {progress, estimate} = jsResponse;
  65562. let progressFract = progress["processed points"] / estimate.points;
  65563. let progressPercents = parseInt(progressFract * 100);
  65564. info(`progress: ${progressPercents}%`);
  65565. };
  65566. let handleFinish = (jsResponse) => {
  65567. let message = "downloads ready: <br>";
  65568. message += "<ul>";
  65569. for(let i = 0; i < jsResponse.pointclouds.length; i++){
  65570. let url = `${viewer.server}/download_regions_filter_result?handle=${handle}&index=${i}`;
  65571. message += `<li><a href="${url}">result_${i}.las</a> </li>\n`;
  65572. }
  65573. let reportURL = `${viewer.server}/download_regions_filter_report?handle=${handle}`;
  65574. message += `<li> <a href="${reportURL}">report.json</a> </li>\n`;
  65575. message += "</ul>";
  65576. info(message);
  65577. };
  65578. let handleUnexpected = (jsResponse) => {
  65579. let message = `Unexpected Response. <br>status: ${jsResponse.status} <br>message: ${jsResponse.message}`;
  65580. info(message);
  65581. };
  65582. let handleError = (jsResponse) => {
  65583. let message = `ERROR: ${jsResponse.message}`;
  65584. error(message);
  65585. throw new Error(message);
  65586. };
  65587. let start = Date.now();
  65588. while(true){
  65589. let response = await fetch(url);
  65590. let jsResponse = await response.json();
  65591. if(jsResponse.status === "ERROR"){
  65592. handleError(jsResponse);
  65593. }else if(jsResponse.status === "FILTERING"){
  65594. handleFiltering(jsResponse);
  65595. }else if(jsResponse.status === "FINISHED"){
  65596. handleFinish(jsResponse);
  65597. break;
  65598. }else {
  65599. handleUnexpected(jsResponse);
  65600. }
  65601. let durationS = (Date.now() - start) / 1000;
  65602. let sleepAmountMS = durationS < 10 ? 100 : 1000;
  65603. await sleep(sleepAmountMS);
  65604. }
  65605. }
  65606. }
  65607. update(){
  65608. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65609. elCoordiantesContainer.empty();
  65610. elCoordiantesContainer.append(this.createCoordinatesTable([this.measurement.position]));
  65611. {
  65612. let angles = this.measurement.rotation.toVector3();
  65613. angles = angles.toArray();
  65614. //angles = [angles.z, angles.x, angles.y];
  65615. angles = angles.map(v => 180 * v / Math.PI);
  65616. angles = angles.map(a => a.toFixed(1) + '\u00B0');
  65617. let elAlpha = this.elContent.find(`#angle_cell_alpha`);
  65618. let elBetta = this.elContent.find(`#angle_cell_betta`);
  65619. let elGamma = this.elContent.find(`#angle_cell_gamma`);
  65620. elAlpha.html(angles[0]);
  65621. elBetta.html(angles[1]);
  65622. elGamma.html(angles[2]);
  65623. }
  65624. {
  65625. let dimensions = this.measurement.scale.toArray();
  65626. dimensions = dimensions.map(v => Utils.addCommas(v.toFixed(2)));
  65627. let elLength = this.elContent.find(`#cell_length`);
  65628. let elWidth = this.elContent.find(`#cell_width`);
  65629. let elHeight = this.elContent.find(`#cell_height`);
  65630. elLength.html(dimensions[0]);
  65631. elWidth.html(dimensions[1]);
  65632. elHeight.html(dimensions[2]);
  65633. }
  65634. {
  65635. let elVolume = this.elContent.find(`#measurement_volume`);
  65636. let volume = this.measurement.getVolume();
  65637. elVolume.html(Utils.addCommas(volume.toFixed(2)));
  65638. }
  65639. this.elCheckClip.prop("checked", this.measurement.clip);
  65640. this.elCheckShow.prop("checked", this.measurement.visible);
  65641. }
  65642. };
  65643. class ProfilePanel extends MeasurePanel{
  65644. constructor(viewer, measurement, propertiesPanel){
  65645. super(viewer, measurement, propertiesPanel);
  65646. let removeIconPath = Potree.resourcePath + '/icons/remove.svg';
  65647. this.elContent = $(`
  65648. <div class="measurement_content selectable">
  65649. <span class="coordinates_table_container"></span>
  65650. <br>
  65651. <span style="display:flex">
  65652. <span style="display:flex; align-items: center; padding-right: 10px">Width: </span>
  65653. <input id="sldProfileWidth" name="sldProfileWidth" value="5.06" style="flex-grow: 1; width:100%">
  65654. </span>
  65655. <br>
  65656. <li style="margin-top: 10px">
  65657. <input name="download_profile" type="button" value="prepare download" style="width: 100%" />
  65658. <div name="download_message"></div>
  65659. </li>
  65660. <br>
  65661. <input type="button" id="show_2d_profile" value="show 2d profile" style="width: 100%"/>
  65662. <!-- ACTIONS -->
  65663. <div style="display: flex; margin-top: 12px">
  65664. <span></span>
  65665. <span style="flex-grow: 1"></span>
  65666. <img name="remove" class="button-icon" src="${removeIconPath}" style="width: 16px; height: 16px"/>
  65667. </div>
  65668. </div>
  65669. `);
  65670. this.elRemove = this.elContent.find("img[name=remove]");
  65671. this.elRemove.click( () => {
  65672. this.viewer.scene.removeProfile(measurement);
  65673. });
  65674. { // download
  65675. this.elDownloadButton = this.elContent.find(`input[name=download_profile]`);
  65676. if(this.propertiesPanel.viewer.server){
  65677. this.elDownloadButton.click(() => this.download());
  65678. } else {
  65679. this.elDownloadButton.hide();
  65680. }
  65681. }
  65682. { // width spinner
  65683. let elWidthSlider = this.elContent.find(`#sldProfileWidth`);
  65684. elWidthSlider.spinner({
  65685. min: 0, max: 10 * 1000 * 1000, step: 0.01,
  65686. numberFormat: 'n',
  65687. start: () => {},
  65688. spin: (event, ui) => {
  65689. let value = elWidthSlider.spinner('value');
  65690. measurement.setWidth(value);
  65691. },
  65692. change: (event, ui) => {
  65693. let value = elWidthSlider.spinner('value');
  65694. measurement.setWidth(value);
  65695. },
  65696. stop: (event, ui) => {
  65697. let value = elWidthSlider.spinner('value');
  65698. measurement.setWidth(value);
  65699. },
  65700. incremental: (count) => {
  65701. let value = elWidthSlider.spinner('value');
  65702. let step = elWidthSlider.spinner('option', 'step');
  65703. let delta = value * 0.05;
  65704. let increments = Math.max(1, parseInt(delta / step));
  65705. return increments;
  65706. }
  65707. });
  65708. elWidthSlider.spinner('value', measurement.getWidth());
  65709. elWidthSlider.spinner('widget').css('width', '100%');
  65710. let widthListener = (event) => {
  65711. let value = elWidthSlider.spinner('value');
  65712. if (value !== measurement.getWidth()) {
  65713. elWidthSlider.spinner('value', measurement.getWidth());
  65714. }
  65715. };
  65716. this.propertiesPanel.addVolatileListener(measurement, "width_changed", widthListener);
  65717. }
  65718. let elShow2DProfile = this.elContent.find(`#show_2d_profile`);
  65719. elShow2DProfile.click(() => {
  65720. this.propertiesPanel.viewer.profileWindow.show();
  65721. this.propertiesPanel.viewer.profileWindowController.setProfile(measurement);
  65722. });
  65723. this.propertiesPanel.addVolatileListener(measurement, "marker_added", this._update);
  65724. this.propertiesPanel.addVolatileListener(measurement, "marker_removed", this._update);
  65725. this.propertiesPanel.addVolatileListener(measurement, "marker_moved", this._update);
  65726. this.update();
  65727. }
  65728. update(){
  65729. let elCoordiantesContainer = this.elContent.find('.coordinates_table_container');
  65730. elCoordiantesContainer.empty();
  65731. elCoordiantesContainer.append(this.createCoordinatesTable(this.measurement.points));
  65732. }
  65733. async download(){
  65734. let profile = this.measurement;
  65735. let regions = [];
  65736. {
  65737. let segments = profile.getSegments();
  65738. let width = profile.width;
  65739. for(let segment of segments){
  65740. let start = segment.start.clone().multiply(new Vector3(1, 1, 0));
  65741. let end = segment.end.clone().multiply(new Vector3(1, 1, 0));
  65742. let center = new Vector3().addVectors(start, end).multiplyScalar(0.5);
  65743. let startEndDir = new Vector3().subVectors(end, start).normalize();
  65744. let endStartDir = new Vector3().subVectors(start, end).normalize();
  65745. let upDir = new Vector3(0, 0, 1);
  65746. let rightDir = new Vector3().crossVectors(startEndDir, upDir);
  65747. let leftDir = new Vector3().crossVectors(endStartDir, upDir);
  65748. console.log(leftDir);
  65749. let right = rightDir.clone().multiplyScalar(width * 0.5).add(center);
  65750. let left = leftDir.clone().multiplyScalar(width * 0.5).add(center);
  65751. let planes = [
  65752. new Plane().setFromNormalAndCoplanarPoint(startEndDir, start),
  65753. new Plane().setFromNormalAndCoplanarPoint(endStartDir, end),
  65754. new Plane().setFromNormalAndCoplanarPoint(leftDir, right),
  65755. new Plane().setFromNormalAndCoplanarPoint(rightDir, left),
  65756. ];
  65757. let planeQueryParts = [];
  65758. for(let plane of planes){
  65759. let part = [plane.normal.toArray(), plane.constant].join(",");
  65760. part = `[${part}]`;
  65761. planeQueryParts.push(part);
  65762. }
  65763. let region = "[" + planeQueryParts.join(",") + "]";
  65764. regions.push(region);
  65765. }
  65766. }
  65767. let regionsArg = regions.join(",");
  65768. let pointcloudArgs = [];
  65769. for(let pointcloud of this.viewer.scene.pointclouds){
  65770. if(!pointcloud.visible){
  65771. continue;
  65772. }
  65773. let offset = pointcloud.pcoGeometry.offset.clone();
  65774. let negateOffset = new Matrix4().makeTranslation(...offset.multiplyScalar(-1).toArray());
  65775. let matrixWorld = pointcloud.matrixWorld;
  65776. let transform = new Matrix4().multiplyMatrices(matrixWorld, negateOffset);
  65777. let path = `${window.location.pathname}/../${pointcloud.pcoGeometry.url}`;
  65778. let arg = {
  65779. path: path,
  65780. transform: transform.elements,
  65781. };
  65782. let argString = JSON.stringify(arg);
  65783. pointcloudArgs.push(argString);
  65784. }
  65785. let pointcloudsArg = pointcloudArgs.join(",");
  65786. let elMessage = this.elContent.find("div[name=download_message]");
  65787. let error = (message) => {
  65788. elMessage.html(`<div style="color: #ff0000">ERROR: ${message}</div>`);
  65789. };
  65790. let info = (message) => {
  65791. elMessage.html(`${message}`);
  65792. };
  65793. let handle = null;
  65794. { // START FILTER
  65795. let url = `${viewer.server}/create_regions_filter?pointclouds=[${pointcloudsArg}]&regions=[${regionsArg}]`;
  65796. //console.log(url);
  65797. info("estimating results ...");
  65798. let response = await fetch(url);
  65799. let jsResponse = await response.json();
  65800. //console.log(jsResponse);
  65801. if(!jsResponse.handle){
  65802. error(jsResponse.message);
  65803. return;
  65804. }else {
  65805. handle = jsResponse.handle;
  65806. }
  65807. }
  65808. { // WAIT, CHECK PROGRESS, HANDLE FINISH
  65809. let url = `${viewer.server}/check_regions_filter?handle=${handle}`;
  65810. let sleep = (function(duration){
  65811. return new Promise( (res, rej) => {
  65812. setTimeout(() => {
  65813. res();
  65814. }, duration);
  65815. });
  65816. });
  65817. let handleFiltering = (jsResponse) => {
  65818. let {progress, estimate} = jsResponse;
  65819. let progressFract = progress["processed points"] / estimate.points;
  65820. let progressPercents = parseInt(progressFract * 100);
  65821. info(`progress: ${progressPercents}%`);
  65822. };
  65823. let handleFinish = (jsResponse) => {
  65824. let message = "downloads ready: <br>";
  65825. message += "<ul>";
  65826. for(let i = 0; i < jsResponse.pointclouds.length; i++){
  65827. let url = `${viewer.server}/download_regions_filter_result?handle=${handle}&index=${i}`;
  65828. message += `<li><a href="${url}">result_${i}.las</a> </li>\n`;
  65829. }
  65830. let reportURL = `${viewer.server}/download_regions_filter_report?handle=${handle}`;
  65831. message += `<li> <a href="${reportURL}">report.json</a> </li>\n`;
  65832. message += "</ul>";
  65833. info(message);
  65834. };
  65835. let handleUnexpected = (jsResponse) => {
  65836. let message = `Unexpected Response. <br>status: ${jsResponse.status} <br>message: ${jsResponse.message}`;
  65837. info(message);
  65838. };
  65839. let handleError = (jsResponse) => {
  65840. let message = `ERROR: ${jsResponse.message}`;
  65841. error(message);
  65842. throw new Error(message);
  65843. };
  65844. let start = Date.now();
  65845. while(true){
  65846. let response = await fetch(url);
  65847. let jsResponse = await response.json();
  65848. if(jsResponse.status === "ERROR"){
  65849. handleError(jsResponse);
  65850. }else if(jsResponse.status === "FILTERING"){
  65851. handleFiltering(jsResponse);
  65852. }else if(jsResponse.status === "FINISHED"){
  65853. handleFinish(jsResponse);
  65854. break;
  65855. }else {
  65856. handleUnexpected(jsResponse);
  65857. }
  65858. let durationS = (Date.now() - start) / 1000;
  65859. let sleepAmountMS = durationS < 10 ? 100 : 1000;
  65860. await sleep(sleepAmountMS);
  65861. }
  65862. }
  65863. }
  65864. };
  65865. class CameraPanel{
  65866. constructor(viewer, propertiesPanel){
  65867. this.viewer = viewer;
  65868. this.propertiesPanel = propertiesPanel;
  65869. this._update = () => { this.update(); };
  65870. let copyIconPath = Potree.resourcePath + '/icons/copy.svg';
  65871. this.elContent = $(`
  65872. <div class="propertypanel_content">
  65873. <table>
  65874. <tr>
  65875. <th colspan="3">position</th>
  65876. <th></th>
  65877. </tr>
  65878. <tr>
  65879. <td align="center" id="camera_position_x" style="width: 25%"></td>
  65880. <td align="center" id="camera_position_y" style="width: 25%"></td>
  65881. <td align="center" id="camera_position_z" style="width: 25%"></td>
  65882. <td align="right" id="copy_camera_position" style="width: 25%">
  65883. <img name="copyPosition" title="copy" class="button-icon" src="${copyIconPath}" style="width: 16px; height: 16px"/>
  65884. </td>
  65885. </tr>
  65886. <tr>
  65887. <th colspan="3">target</th>
  65888. <th></th>
  65889. </tr>
  65890. <tr>
  65891. <td align="center" id="camera_target_x" style="width: 25%"></td>
  65892. <td align="center" id="camera_target_y" style="width: 25%"></td>
  65893. <td align="center" id="camera_target_z" style="width: 25%"></td>
  65894. <td align="right" id="copy_camera_target" style="width: 25%">
  65895. <img name="copyTarget" title="copy" class="button-icon" src="${copyIconPath}" style="width: 16px; height: 16px"/>
  65896. </td>
  65897. </tr>
  65898. </table>
  65899. </div>
  65900. `);
  65901. this.elCopyPosition = this.elContent.find("img[name=copyPosition]");
  65902. this.elCopyPosition.click( () => {
  65903. let pos = this.viewer.scene.getActiveCamera().position.toArray();
  65904. let msg = pos.map(c => c.toFixed(3)).join(", ");
  65905. Utils.clipboardCopy(msg);
  65906. this.viewer.postMessage(
  65907. `Copied value to clipboard: <br>'${msg}'`,
  65908. {duration: 3000});
  65909. });
  65910. this.elCopyTarget = this.elContent.find("img[name=copyTarget]");
  65911. this.elCopyTarget.click( () => {
  65912. let pos = this.viewer.scene.view.getPivot().toArray();
  65913. let msg = pos.map(c => c.toFixed(3)).join(", ");
  65914. Utils.clipboardCopy(msg);
  65915. this.viewer.postMessage(
  65916. `Copied value to clipboard: <br>'${msg}'`,
  65917. {duration: 3000});
  65918. });
  65919. this.propertiesPanel.addVolatileListener(viewer, "camera_changed", this._update);
  65920. this.update();
  65921. }
  65922. update(){
  65923. //console.log("updating camera panel");
  65924. let camera = this.viewer.scene.getActiveCamera();
  65925. let view = this.viewer.scene.view;
  65926. let pos = camera.position.toArray().map(c => Utils.addCommas(c.toFixed(3)));
  65927. this.elContent.find("#camera_position_x").html(pos[0]);
  65928. this.elContent.find("#camera_position_y").html(pos[1]);
  65929. this.elContent.find("#camera_position_z").html(pos[2]);
  65930. let target = view.getPivot().toArray().map(c => Utils.addCommas(c.toFixed(3)));
  65931. this.elContent.find("#camera_target_x").html(target[0]);
  65932. this.elContent.find("#camera_target_y").html(target[1]);
  65933. this.elContent.find("#camera_target_z").html(target[2]);
  65934. }
  65935. };
  65936. class AnnotationPanel{
  65937. constructor(viewer, propertiesPanel, annotation){
  65938. this.viewer = viewer;
  65939. this.propertiesPanel = propertiesPanel;
  65940. this.annotation = annotation;
  65941. this._update = () => { this.update(); };
  65942. let copyIconPath = `${Potree.resourcePath}/icons/copy.svg`;
  65943. this.elContent = $(`
  65944. <div class="propertypanel_content">
  65945. <table>
  65946. <tr>
  65947. <th colspan="3">position</th>
  65948. <th></th>
  65949. </tr>
  65950. <tr>
  65951. <td align="center" id="annotation_position_x" style="width: 25%"></td>
  65952. <td align="center" id="annotation_position_y" style="width: 25%"></td>
  65953. <td align="center" id="annotation_position_z" style="width: 25%"></td>
  65954. <td align="right" id="copy_annotation_position" style="width: 25%">
  65955. <img name="copyPosition" title="copy" class="button-icon" src="${copyIconPath}" style="width: 16px; height: 16px"/>
  65956. </td>
  65957. </tr>
  65958. </table>
  65959. <div>
  65960. <div class="heading">Title</div>
  65961. <div id="annotation_title" contenteditable="true">
  65962. Annotation Title
  65963. </div>
  65964. <div class="heading">Description</div>
  65965. <div id="annotation_description" contenteditable="true">
  65966. A longer description of this annotation.
  65967. Can be multiple lines long. TODO: the user should be able
  65968. to modify title and description.
  65969. </div>
  65970. </div>
  65971. </div>
  65972. `);
  65973. this.elCopyPosition = this.elContent.find("img[name=copyPosition]");
  65974. this.elCopyPosition.click( () => {
  65975. let pos = this.annotation.position.toArray();
  65976. let msg = pos.map(c => c.toFixed(3)).join(", ");
  65977. Utils.clipboardCopy(msg);
  65978. this.viewer.postMessage(
  65979. `Copied value to clipboard: <br>'${msg}'`,
  65980. {duration: 3000});
  65981. });
  65982. this.elTitle = this.elContent.find("#annotation_title").html(annotation.title);
  65983. this.elDescription = this.elContent.find("#annotation_description").html(annotation.description);
  65984. this.elTitle[0].addEventListener("input", () => {
  65985. const title = this.elTitle.html();
  65986. annotation.title = title;
  65987. }, false);
  65988. this.elDescription[0].addEventListener("input", () => {
  65989. const description = this.elDescription.html();
  65990. annotation.description = description;
  65991. }, false);
  65992. this.update();
  65993. }
  65994. update(){
  65995. const {annotation, elContent, elTitle, elDescription} = this;
  65996. let pos = annotation.position.toArray().map(c => Utils.addCommas(c.toFixed(3)));
  65997. elContent.find("#annotation_position_x").html(pos[0]);
  65998. elContent.find("#annotation_position_y").html(pos[1]);
  65999. elContent.find("#annotation_position_z").html(pos[2]);
  66000. elTitle.html(annotation.title);
  66001. elDescription.html(annotation.description);
  66002. }
  66003. };
  66004. class CameraAnimationPanel{
  66005. constructor(viewer, propertiesPanel, animation){
  66006. this.viewer = viewer;
  66007. this.propertiesPanel = propertiesPanel;
  66008. this.animation = animation;
  66009. this.elContent = $(`
  66010. <div class="propertypanel_content">
  66011. <span id="animation_keyframes"></span>
  66012. <span>
  66013. <span style="display:flex">
  66014. <span style="display:flex; align-items: center; padding-right: 10px">Duration: </span>
  66015. <input name="spnDuration" value="5.0" style="flex-grow: 1; width:100%">
  66016. </span>
  66017. <span>Time: </span><span id="lblTime"></span> <div id="sldTime"></div>
  66018. <input name="play" type="button" value="play"/>
  66019. </span>
  66020. </div>
  66021. `);
  66022. const elPlay = this.elContent.find("input[name=play]");
  66023. elPlay.click( () => {
  66024. animation.play();
  66025. });
  66026. const elSlider = this.elContent.find('#sldTime');
  66027. elSlider.slider({
  66028. value: 0,
  66029. min: 0,
  66030. max: 1,
  66031. step: 0.001,
  66032. slide: (event, ui) => {
  66033. animation.set(ui.value);
  66034. animation.updateFrustum();
  66035. }
  66036. });
  66037. let elDuration = this.elContent.find(`input[name=spnDuration]`);
  66038. elDuration.spinner({
  66039. min: 0, max: 300, step: 0.01,
  66040. numberFormat: 'n',
  66041. start: () => {},
  66042. spin: (event, ui) => {
  66043. let value = elDuration.spinner('value');
  66044. animation.setDuration(value);
  66045. },
  66046. change: (event, ui) => {
  66047. let value = elDuration.spinner('value');
  66048. animation.setDuration(value);
  66049. },
  66050. stop: (event, ui) => {
  66051. let value = elDuration.spinner('value');
  66052. animation.setDuration(value);
  66053. },
  66054. incremental: (count) => {
  66055. let value = elDuration.spinner('value');
  66056. let step = elDuration.spinner('option', 'step');
  66057. let delta = value * 0.05;
  66058. let increments = Math.max(1, parseInt(delta / step));
  66059. return increments;
  66060. }
  66061. });
  66062. elDuration.spinner('value', animation.getDuration());
  66063. elDuration.spinner('widget').css('width', '100%');
  66064. const elKeyframes = this.elContent.find("#animation_keyframes");
  66065. const updateKeyframes = () => {
  66066. elKeyframes.empty();
  66067. //let index = 0;
  66068. // <span style="flex-grow: 0;">
  66069. // <img name="add" src="${Potree.resourcePath}/icons/add.svg" style="width: 1.5em; height: 1.5em"/>
  66070. // </span>
  66071. const addNewKeyframeItem = (index) => {
  66072. let elNewKeyframe = $(`
  66073. <div style="display: flex; margin: 0.2em 0em">
  66074. <span style="flex-grow: 1"></span>
  66075. <input type="button" name="add" value="insert control point" />
  66076. <span style="flex-grow: 1"></span>
  66077. </div>
  66078. `);
  66079. const elAdd = elNewKeyframe.find("input[name=add]");
  66080. elAdd.click( () => {
  66081. animation.createControlPoint(index);
  66082. animation.changeCallback();
  66083. });
  66084. elKeyframes.append(elNewKeyframe);
  66085. };
  66086. const addKeyframeItem = (index) => {
  66087. let elKeyframe = $(`
  66088. <div style="display: flex; margin: 0.2em 0em">
  66089. <span style="flex-grow: 0;">
  66090. <img name="assign" src="${Potree.resourcePath}/icons/assign.svg" style="width: 1.5em; height: 1.5em"/>
  66091. </span>
  66092. <span style="flex-grow: 0;">
  66093. <img name="move" src="${Potree.resourcePath}/icons/circled_dot.svg" style="width: 1.5em; height: 1.5em"/>
  66094. </span>
  66095. <span style="flex-grow: 0; width: 1.5em; height: 1.5em"></span>
  66096. <span style="flex-grow: 0; font-size: 1.5em">keyframe</span>
  66097. <span style="flex-grow: 1"></span>
  66098. <span style="flex-grow: 0;">
  66099. <img name="delete" src="${Potree.resourcePath}/icons/remove.svg" style="width: 1.5em; height: 1.5em"/>
  66100. </span>
  66101. </div>
  66102. `);
  66103. const elAssign = elKeyframe.find("img[name=assign]");
  66104. const elMove = elKeyframe.find("img[name=move]");
  66105. const elDelete = elKeyframe.find("img[name=delete]");
  66106. elAssign.click( () => {
  66107. animation.posCurve.points[index].copy(viewer.scene.view.position);
  66108. animation.targetCurve.points[index].copy(viewer.scene.view.getPivot());
  66109. animation.changeCallback();
  66110. });
  66111. elMove.click( () => {
  66112. viewer.scene.view.position.copy(animation.posCurve.points[index]);
  66113. viewer.scene.view.lookAt(animation.targetCurve.points[index]);
  66114. });
  66115. elDelete.click( () => {
  66116. animation.removeControlPoint(index);
  66117. animation.changeCallback();
  66118. });
  66119. elKeyframes.append(elKeyframe);
  66120. };
  66121. let index = 0;
  66122. addNewKeyframeItem(index);
  66123. animation.posCurve.points.forEach(e=>{
  66124. addKeyframeItem(index);
  66125. index++;
  66126. addNewKeyframeItem(index);
  66127. });
  66128. };
  66129. updateKeyframes();
  66130. animation.addEventListener("controlpoint_added", updateKeyframes);
  66131. animation.addEventListener("controlpoint_removed", updateKeyframes);
  66132. // this._update = () => { this.update(); };
  66133. // this.update();
  66134. }
  66135. update(){
  66136. }
  66137. };
  66138. class PropertiesPanel{
  66139. constructor(container, viewer){
  66140. this.container = container;
  66141. this.viewer = viewer;
  66142. this.object = null;
  66143. this.cleanupTasks = [];
  66144. this.scene = null;
  66145. }
  66146. setScene(scene){
  66147. this.scene = scene;
  66148. }
  66149. set(object){
  66150. if(this.object === object){
  66151. return;
  66152. }
  66153. this.object = object;
  66154. for(let task of this.cleanupTasks){
  66155. task();
  66156. }
  66157. this.cleanupTasks = [];
  66158. this.container.empty();
  66159. if(object instanceof PointCloudTree){
  66160. this.setPointCloud(object);
  66161. }else if(object instanceof Measure || object instanceof Profile || object instanceof Volume){
  66162. this.setMeasurement(object);
  66163. }else if(object instanceof Camera){
  66164. this.setCamera(object);
  66165. }else if(object instanceof Annotation){
  66166. this.setAnnotation(object);
  66167. }else if(object instanceof CameraAnimation){
  66168. this.setCameraAnimation(object);
  66169. }
  66170. }
  66171. //
  66172. // Used for events that should be removed when the property object changes.
  66173. // This is for listening to materials, scene, point clouds, etc.
  66174. // not required for DOM listeners, since they are automatically cleared by removing the DOM subtree.
  66175. //
  66176. addVolatileListener(target, type, callback){
  66177. target.addEventListener(type, callback);
  66178. this.cleanupTasks.push(() => {
  66179. target.removeEventListener(type, callback);
  66180. });
  66181. }
  66182. setPointCloud(pointcloud){
  66183. let material = pointcloud.material;
  66184. let panel = $(`
  66185. <div class="scene_content selectable">
  66186. <ul class="pv-menu-list">
  66187. <li>
  66188. <span data-i18n="appearance.point_size"></span>:&nbsp;<span id="lblPointSize"></span> <div id="sldPointSize"></div>
  66189. </li>
  66190. <li>
  66191. <span data-i18n="appearance.min_point_size"></span>:&nbsp;<span id="lblMinPointSize"></span> <div id="sldMinPointSize"></div>
  66192. </li>
  66193. <!-- SIZE TYPE -->
  66194. <li>
  66195. <label for="optPointSizing" class="pv-select-label" data-i18n="appearance.point_size_type">Point Sizing </label>
  66196. <select id="optPointSizing" name="optPointSizing">
  66197. <option>FIXED</option>
  66198. <option>ATTENUATED</option>
  66199. <option>ADAPTIVE</option>
  66200. </select>
  66201. </li>
  66202. <!-- SHAPE -->
  66203. <li>
  66204. <label for="optShape" class="pv-select-label" data-i18n="appearance.point_shape"></label><br>
  66205. <select id="optShape" name="optShape">
  66206. <option>SQUARE</option>
  66207. <option>CIRCLE</option>
  66208. <option>PARABOLOID</option>
  66209. </select>
  66210. </li>
  66211. <li id="materials_backface_container">
  66212. <label><input id="set_backface_culling" type="checkbox" /><span data-i18n="appearance.backface_culling"></span></label>
  66213. </li>
  66214. <!-- OPACITY -->
  66215. <li><span data-i18n="appearance.point_opacity"></span>:<span id="lblOpacity"></span><div id="sldOpacity"></div></li>
  66216. <div class="divider">
  66217. <span>Attribute</span>
  66218. </div>
  66219. <li>
  66220. <select id="optMaterial" name="optMaterial"></select>
  66221. </li>
  66222. <div id="materials.composite_weight_container">
  66223. <div class="divider">
  66224. <span>Attribute Weights</span>
  66225. </div>
  66226. <li>RGB: <span id="lblWeightRGB"></span> <div id="sldWeightRGB"></div> </li>
  66227. <li>Intensity: <span id="lblWeightIntensity"></span> <div id="sldWeightIntensity"></div> </li>
  66228. <li>Elevation: <span id="lblWeightElevation"></span> <div id="sldWeightElevation"></div> </li>
  66229. <li>Classification: <span id="lblWeightClassification"></span> <div id="sldWeightClassification"></div> </li>
  66230. <li>Return Number: <span id="lblWeightReturnNumber"></span> <div id="sldWeightReturnNumber"></div> </li>
  66231. <li>Source ID: <span id="lblWeightSourceID"></span> <div id="sldWeightSourceID"></div> </li>
  66232. </div>
  66233. <div id="materials.rgb_container">
  66234. <div class="divider">
  66235. <span>RGB</span>
  66236. </div>
  66237. <li>Gamma: <span id="lblRGBGamma"></span> <div id="sldRGBGamma"></div> </li>
  66238. <li>Brightness: <span id="lblRGBBrightness"></span> <div id="sldRGBBrightness"></div> </li>
  66239. <li>Contrast: <span id="lblRGBContrast"></span> <div id="sldRGBContrast"></div> </li>
  66240. </div>
  66241. <div id="materials.extra_container">
  66242. <div class="divider">
  66243. <span>Extra Attribute</span>
  66244. </div>
  66245. <li><span data-i18n="appearance.extra_range"></span>: <span id="lblExtraRange"></span> <div id="sldExtraRange"></div></li>
  66246. <li>Gamma: <span id="lblExtraGamma"></span> <div id="sldExtraGamma"></div></li>
  66247. <li>Brightness: <span id="lblExtraBrightness"></span> <div id="sldExtraBrightness"></div></li>
  66248. <li>Contrast: <span id="lblExtraContrast"></span> <div id="sldExtraContrast"></div></li>
  66249. </div>
  66250. <div id="materials.matcap_container">
  66251. <div class="divider">
  66252. <span>MATCAP</span>
  66253. </div>
  66254. <li>
  66255. <div id="matcap_scheme_selection" style="display: flex; flex-wrap: wrap;"> </div>
  66256. </li>
  66257. </div>
  66258. <div id="materials.color_container">
  66259. <div class="divider">
  66260. <span>Color</span>
  66261. </div>
  66262. <input id="materials.color.picker" />
  66263. </div>
  66264. <div id="materials.elevation_container">
  66265. <div class="divider">
  66266. <span>Elevation</span>
  66267. </div>
  66268. <li><span data-i18n="appearance.elevation_range"></span>: <span id="lblHeightRange"></span> <div id="sldHeightRange"></div> </li>
  66269. <li>
  66270. <selectgroup id="gradient_repeat_option">
  66271. <option id="gradient_repeat_clamp" value="CLAMP">Clamp</option>
  66272. <option id="gradient_repeat_repeat" value="REPEAT">Repeat</option>
  66273. <option id="gradient_repeat_mirrored_repeat" value="MIRRORED_REPEAT">Mirrored Repeat</option>
  66274. </selectgroup>
  66275. </li>
  66276. <li>
  66277. <span>Gradient Scheme:</span>
  66278. <div id="elevation_gradient_scheme_selection" style="display: flex; padding: 1em 0em">
  66279. </div>
  66280. </li>
  66281. </div>
  66282. <div id="materials.transition_container">
  66283. <div class="divider">
  66284. <span>Transition</span>
  66285. </div>
  66286. <li>transition: <span id="lblTransition"></span> <div id="sldTransition"></div> </li>
  66287. </div>
  66288. <div id="materials.intensity_container">
  66289. <div class="divider">
  66290. <span>Intensity</span>
  66291. </div>
  66292. <li>Range: <span id="lblIntensityRange"></span> <div id="sldIntensityRange"></div> </li>
  66293. <li>Gamma: <span id="lblIntensityGamma"></span> <div id="sldIntensityGamma"></div> </li>
  66294. <li>Brightness: <span id="lblIntensityBrightness"></span> <div id="sldIntensityBrightness"></div> </li>
  66295. <li>Contrast: <span id="lblIntensityContrast"></span> <div id="sldIntensityContrast"></div> </li>
  66296. </div>
  66297. <div id="materials.gpstime_container">
  66298. <div class="divider">
  66299. <span>GPS Time</span>
  66300. </div>
  66301. </div>
  66302. <div id="materials.index_container">
  66303. <div class="divider">
  66304. <span>Indices</span>
  66305. </div>
  66306. </div>
  66307. </ul>
  66308. </div>
  66309. `);
  66310. panel.i18n();
  66311. this.container.append(panel);
  66312. { // POINT SIZE
  66313. let sldPointSize = panel.find(`#sldPointSize`);
  66314. let lblPointSize = panel.find(`#lblPointSize`);
  66315. sldPointSize.slider({
  66316. value: material.size,
  66317. min: 0,
  66318. max: 3,
  66319. step: 0.01,
  66320. slide: function (event, ui) { material.size = ui.value; }
  66321. });
  66322. let update = (e) => {
  66323. lblPointSize.html(material.size.toFixed(2));
  66324. sldPointSize.slider({value: material.size});
  66325. };
  66326. this.addVolatileListener(material, "point_size_changed", update);
  66327. update();
  66328. }
  66329. { // MINIMUM POINT SIZE
  66330. let sldMinPointSize = panel.find(`#sldMinPointSize`);
  66331. let lblMinPointSize = panel.find(`#lblMinPointSize`);
  66332. sldMinPointSize.slider({
  66333. value: material.size,
  66334. min: 0,
  66335. max: 3,
  66336. step: 0.01,
  66337. slide: function (event, ui) { material.minSize = ui.value; }
  66338. });
  66339. let update = (e) => {
  66340. lblMinPointSize.html(material.minSize.toFixed(2));
  66341. sldMinPointSize.slider({value: material.minSize});
  66342. };
  66343. this.addVolatileListener(material, "point_size_changed", update);
  66344. update();
  66345. }
  66346. { // POINT SIZING
  66347. let strSizeType = Object.keys(PointSizeType)[material.pointSizeType];
  66348. let opt = panel.find(`#optPointSizing`);
  66349. opt.selectmenu();
  66350. opt.val(strSizeType).selectmenu('refresh');
  66351. opt.selectmenu({
  66352. change: (event, ui) => {
  66353. material.pointSizeType = PointSizeType[ui.item.value];
  66354. }
  66355. });
  66356. }
  66357. { // SHAPE
  66358. let opt = panel.find(`#optShape`);
  66359. opt.selectmenu({
  66360. change: (event, ui) => {
  66361. let value = ui.item.value;
  66362. material.shape = PointShape[value];
  66363. }
  66364. });
  66365. let update = () => {
  66366. let typename = Object.keys(PointShape)[material.shape];
  66367. opt.selectmenu().val(typename).selectmenu('refresh');
  66368. };
  66369. this.addVolatileListener(material, "point_shape_changed", update);
  66370. update();
  66371. }
  66372. { // BACKFACE CULLING
  66373. let opt = panel.find(`#set_backface_culling`);
  66374. opt.click(() => {
  66375. material.backfaceCulling = opt.prop("checked");
  66376. });
  66377. let update = () => {
  66378. let value = material.backfaceCulling;
  66379. opt.prop("checked", value);
  66380. };
  66381. this.addVolatileListener(material, "backface_changed", update);
  66382. update();
  66383. let blockBackface = $('#materials_backface_container');
  66384. blockBackface.css('display', 'none');
  66385. const pointAttributes = pointcloud.pcoGeometry.pointAttributes;
  66386. const hasNormals = pointAttributes.hasNormals ? pointAttributes.hasNormals() : false;
  66387. if(hasNormals) {
  66388. blockBackface.css('display', 'block');
  66389. }
  66390. /*
  66391. opt.checkboxradio({
  66392. clicked: (event, ui) => {
  66393. // let value = ui.item.value;
  66394. let value = ui.item.checked;
  66395. console.log(value);
  66396. material.backfaceCulling = value; // $('#set_freeze').prop("checked");
  66397. }
  66398. });
  66399. */
  66400. }
  66401. { // OPACITY
  66402. let sldOpacity = panel.find(`#sldOpacity`);
  66403. let lblOpacity = panel.find(`#lblOpacity`);
  66404. sldOpacity.slider({
  66405. value: material.opacity,
  66406. min: 0,
  66407. max: 1,
  66408. step: 0.001,
  66409. slide: function (event, ui) {
  66410. material.opacity = ui.value;
  66411. }
  66412. });
  66413. let update = (e) => {
  66414. lblOpacity.html(material.opacity.toFixed(2));
  66415. sldOpacity.slider({value: material.opacity});
  66416. };
  66417. this.addVolatileListener(material, "opacity_changed", update);
  66418. update();
  66419. }
  66420. {
  66421. const attributes = pointcloud.pcoGeometry.pointAttributes.attributes;
  66422. let options = [];
  66423. options.push(...attributes.map(a => a.name));
  66424. const intensityIndex = options.indexOf("intensity");
  66425. if(intensityIndex >= 0){
  66426. options.splice(intensityIndex + 1, 0, "intensity gradient");
  66427. }
  66428. options.push(
  66429. "elevation",
  66430. "color",
  66431. 'matcap',
  66432. 'indices',
  66433. 'level of detail',
  66434. 'composite'
  66435. );
  66436. const blacklist = [
  66437. "POSITION_CARTESIAN",
  66438. "position",
  66439. ];
  66440. options = options.filter(o => !blacklist.includes(o));
  66441. let attributeSelection = panel.find('#optMaterial');
  66442. for(let option of options){
  66443. let elOption = $(`<option>${option}</option>`);
  66444. attributeSelection.append(elOption);
  66445. }
  66446. let updateMaterialPanel = (event, ui) => {
  66447. let selectedValue = attributeSelection.selectmenu().val();
  66448. material.activeAttributeName = selectedValue;
  66449. let attribute = pointcloud.getAttribute(selectedValue);
  66450. if(selectedValue === "intensity gradient"){
  66451. attribute = pointcloud.getAttribute("intensity");
  66452. }
  66453. const isIntensity = attribute ? ["intensity", "intensity gradient"].includes(attribute.name) : false;
  66454. if(isIntensity){
  66455. if(pointcloud.material.intensityRange[0] === Infinity){
  66456. pointcloud.material.intensityRange = attribute.range;
  66457. }
  66458. const [min, max] = attribute.range;
  66459. panel.find('#sldIntensityRange').slider({
  66460. range: true,
  66461. min: min, max: max, step: 0.01,
  66462. values: [min, max],
  66463. slide: (event, ui) => {
  66464. let min = ui.values[0];
  66465. let max = ui.values[1];
  66466. material.intensityRange = [min, max];
  66467. }
  66468. });
  66469. } else if(attribute){
  66470. let [min, max] = attribute.range;
  66471. let selectedRange = material.getRange(attribute.name);
  66472. if(!selectedRange){
  66473. selectedRange = [...attribute.range];
  66474. }
  66475. let minMaxAreNumbers = typeof min === "number" && typeof max === "number";
  66476. /* min = 0 ;max = 50
  66477. selectedRange[0] =min; selectedRange[1] = max; */
  66478. if(minMaxAreNumbers){
  66479. panel.find('#sldExtraRange').slider({
  66480. range: true,
  66481. min: min,
  66482. max: max,
  66483. step: 0.01,
  66484. values: selectedRange,
  66485. slide: (event, ui) => {
  66486. let [a, b] = ui.values;
  66487. material.setRange(attribute.name, [a, b]);
  66488. }
  66489. });
  66490. }
  66491. }
  66492. let blockWeights = $('#materials\\.composite_weight_container');
  66493. let blockElevation = $('#materials\\.elevation_container');
  66494. let blockRGB = $('#materials\\.rgb_container');
  66495. let blockExtra = $('#materials\\.extra_container');
  66496. let blockColor = $('#materials\\.color_container');
  66497. let blockIntensity = $('#materials\\.intensity_container');
  66498. let blockIndex = $('#materials\\.index_container');
  66499. let blockTransition = $('#materials\\.transition_container');
  66500. let blockGps = $('#materials\\.gpstime_container');
  66501. let blockMatcap = $('#materials\\.matcap_container');
  66502. blockIndex.css('display', 'none');
  66503. blockIntensity.css('display', 'none');
  66504. blockElevation.css('display', 'none');
  66505. blockRGB.css('display', 'none');
  66506. blockExtra.css('display', 'none');
  66507. blockColor.css('display', 'none');
  66508. blockWeights.css('display', 'none');
  66509. blockTransition.css('display', 'none');
  66510. blockMatcap.css('display', 'none');
  66511. blockGps.css('display', 'none');
  66512. if (selectedValue === 'composite') {
  66513. blockWeights.css('display', 'block');
  66514. blockElevation.css('display', 'block');
  66515. blockRGB.css('display', 'block');
  66516. blockIntensity.css('display', 'block');
  66517. } else if (selectedValue === 'elevation') {
  66518. blockElevation.css('display', 'block');
  66519. } else if (selectedValue === 'RGB and Elevation') {
  66520. blockRGB.css('display', 'block');
  66521. blockElevation.css('display', 'block');
  66522. } else if (selectedValue === 'rgba') {
  66523. blockRGB.css('display', 'block');
  66524. } else if (selectedValue === 'color') {
  66525. blockColor.css('display', 'block');
  66526. } else if (selectedValue === 'intensity') {
  66527. blockIntensity.css('display', 'block');
  66528. } else if (selectedValue === 'intensity gradient') {
  66529. blockIntensity.css('display', 'block');
  66530. } else if (selectedValue === "indices" ){
  66531. blockIndex.css('display', 'block');
  66532. } else if (selectedValue === "matcap" ){
  66533. blockMatcap.css('display', 'block');
  66534. } else if (selectedValue === "classification" ){
  66535. // add classification color selctor?
  66536. } else if (selectedValue === "gps-time" ){
  66537. blockGps.css('display', 'block');
  66538. } else if(selectedValue === "number of returns"){
  66539. } else if(selectedValue === "return number"){
  66540. } else if(["source id", "point source id"].includes(selectedValue)){
  66541. } else {
  66542. blockExtra.css('display', 'block');
  66543. }
  66544. };
  66545. attributeSelection.selectmenu({change: updateMaterialPanel});
  66546. let update = () => {
  66547. attributeSelection.val(material.activeAttributeName).selectmenu('refresh');
  66548. };
  66549. this.addVolatileListener(material, "point_color_type_changed", update);
  66550. this.addVolatileListener(material, "active_attribute_changed", update);
  66551. update();
  66552. updateMaterialPanel();
  66553. }
  66554. {
  66555. const schemes = Object.keys(Potree.Gradients).map(name => ({name: name, values: Gradients[name]}));
  66556. let elSchemeContainer = panel.find("#elevation_gradient_scheme_selection");
  66557. for(let scheme of schemes){
  66558. let elScheme = $(`
  66559. <span style="flex-grow: 1;">
  66560. </span>
  66561. `);
  66562. const svg = Potree.Utils.createSvgGradient(scheme.values);
  66563. svg.setAttributeNS(null, "class", `button-icon`);
  66564. elScheme.append($(svg));
  66565. elScheme.click( () => {
  66566. material.gradient = Gradients[scheme.name];
  66567. });
  66568. elSchemeContainer.append(elScheme);
  66569. }
  66570. }
  66571. {
  66572. let matcaps = [
  66573. {name: "Normals", icon: `${Potree.resourcePath}/icons/matcap/check_normal+y.jpg`},
  66574. {name: "Basic 1", icon: `${Potree.resourcePath}/icons/matcap/basic_1.jpg`},
  66575. {name: "Basic 2", icon: `${Potree.resourcePath}/icons/matcap/basic_2.jpg`},
  66576. {name: "Basic Dark", icon: `${Potree.resourcePath}/icons/matcap/basic_dark.jpg`},
  66577. {name: "Basic Side", icon: `${Potree.resourcePath}/icons/matcap/basic_side.jpg`},
  66578. {name: "Ceramic Dark", icon: `${Potree.resourcePath}/icons/matcap/ceramic_dark.jpg`},
  66579. {name: "Ceramic Lightbulb", icon: `${Potree.resourcePath}/icons/matcap/ceramic_lightbulb.jpg`},
  66580. {name: "Clay Brown", icon: `${Potree.resourcePath}/icons/matcap/clay_brown.jpg`},
  66581. {name: "Clay Muddy", icon: `${Potree.resourcePath}/icons/matcap/clay_muddy.jpg`},
  66582. {name: "Clay Studio", icon: `${Potree.resourcePath}/icons/matcap/clay_studio.jpg`},
  66583. {name: "Resin", icon: `${Potree.resourcePath}/icons/matcap/resin.jpg`},
  66584. {name: "Skin", icon: `${Potree.resourcePath}/icons/matcap/skin.jpg`},
  66585. {name: "Jade", icon: `${Potree.resourcePath}/icons/matcap/jade.jpg`},
  66586. {name: "Metal_ Anisotropic", icon: `${Potree.resourcePath}/icons/matcap/metal_anisotropic.jpg`},
  66587. {name: "Metal Carpaint", icon: `${Potree.resourcePath}/icons/matcap/metal_carpaint.jpg`},
  66588. {name: "Metal Lead", icon: `${Potree.resourcePath}/icons/matcap/metal_lead.jpg`},
  66589. {name: "Metal Shiny", icon: `${Potree.resourcePath}/icons/matcap/metal_shiny.jpg`},
  66590. {name: "Pearl", icon: `${Potree.resourcePath}/icons/matcap/pearl.jpg`},
  66591. {name: "Toon", icon: `${Potree.resourcePath}/icons/matcap/toon.jpg`},
  66592. {name: "Check Rim Light", icon: `${Potree.resourcePath}/icons/matcap/check_rim_light.jpg`},
  66593. {name: "Check Rim Dark", icon: `${Potree.resourcePath}/icons/matcap/check_rim_dark.jpg`},
  66594. {name: "Contours 1", icon: `${Potree.resourcePath}/icons/matcap/contours_1.jpg`},
  66595. {name: "Contours 2", icon: `${Potree.resourcePath}/icons/matcap/contours_2.jpg`},
  66596. {name: "Contours 3", icon: `${Potree.resourcePath}/icons/matcap/contours_3.jpg`},
  66597. {name: "Reflection Check Horizontal", icon: `${Potree.resourcePath}/icons/matcap/reflection_check_horizontal.jpg`},
  66598. {name: "Reflection Check Vertical", icon: `${Potree.resourcePath}/icons/matcap/reflection_check_vertical.jpg`},
  66599. ];
  66600. let elMatcapContainer = panel.find("#matcap_scheme_selection");
  66601. for(let matcap of matcaps){
  66602. let elMatcap = $(`
  66603. <img src="${matcap.icon}" class="button-icon" style="width: 25%;" />
  66604. `);
  66605. elMatcap.click( () => {
  66606. material.matcap = matcap.icon.substring(matcap.icon.lastIndexOf('/'));
  66607. });
  66608. elMatcapContainer.append(elMatcap);
  66609. }
  66610. }
  66611. {
  66612. panel.find('#sldRGBGamma').slider({
  66613. value: material.rgbGamma,
  66614. min: 0, max: 4, step: 0.01,
  66615. slide: (event, ui) => {material.rgbGamma = ui.value;}
  66616. });
  66617. panel.find('#sldRGBContrast').slider({
  66618. value: material.rgbContrast,
  66619. min: -1, max: 1, step: 0.01,
  66620. slide: (event, ui) => {material.rgbContrast = ui.value;}
  66621. });
  66622. panel.find('#sldRGBBrightness').slider({
  66623. value: material.rgbBrightness,
  66624. min: -1, max: 1, step: 0.01,
  66625. slide: (event, ui) => {material.rgbBrightness = ui.value;}
  66626. });
  66627. panel.find('#sldExtraGamma').slider({
  66628. value: material.extraGamma,
  66629. min: 0, max: 4, step: 0.01,
  66630. slide: (event, ui) => {material.extraGamma = ui.value;}
  66631. });
  66632. panel.find('#sldExtraBrightness').slider({
  66633. value: material.extraBrightness,
  66634. min: -1, max: 1, step: 0.01,
  66635. slide: (event, ui) => {material.extraBrightness = ui.value;}
  66636. });
  66637. panel.find('#sldExtraContrast').slider({
  66638. value: material.extraContrast,
  66639. min: -1, max: 1, step: 0.01,
  66640. slide: (event, ui) => {material.extraContrast = ui.value;}
  66641. });
  66642. panel.find('#sldHeightRange').slider({
  66643. range: true,
  66644. min: 0, max: 1000, step: 0.01,
  66645. values: [0, 1000],
  66646. slide: (event, ui) => {
  66647. material.heightMin = ui.values[0];
  66648. material.heightMax = ui.values[1];
  66649. }
  66650. });
  66651. panel.find('#sldIntensityGamma').slider({
  66652. value: material.intensityGamma,
  66653. min: 0, max: 4, step: 0.01,
  66654. slide: (event, ui) => {material.intensityGamma = ui.value;}
  66655. });
  66656. panel.find('#sldIntensityContrast').slider({
  66657. value: material.intensityContrast,
  66658. min: -1, max: 1, step: 0.01,
  66659. slide: (event, ui) => {material.intensityContrast = ui.value;}
  66660. });
  66661. panel.find('#sldIntensityBrightness').slider({
  66662. value: material.intensityBrightness,
  66663. min: -1, max: 1, step: 0.01,
  66664. slide: (event, ui) => {material.intensityBrightness = ui.value;}
  66665. });
  66666. panel.find('#sldWeightRGB').slider({
  66667. value: material.weightRGB,
  66668. min: 0, max: 1, step: 0.01,
  66669. slide: (event, ui) => {material.weightRGB = ui.value;}
  66670. });
  66671. panel.find('#sldWeightIntensity').slider({
  66672. value: material.weightIntensity,
  66673. min: 0, max: 1, step: 0.01,
  66674. slide: (event, ui) => {material.weightIntensity = ui.value;}
  66675. });
  66676. panel.find('#sldWeightElevation').slider({
  66677. value: material.weightElevation,
  66678. min: 0, max: 1, step: 0.01,
  66679. slide: (event, ui) => {material.weightElevation = ui.value;}
  66680. });
  66681. panel.find('#sldWeightClassification').slider({
  66682. value: material.weightClassification,
  66683. min: 0, max: 1, step: 0.01,
  66684. slide: (event, ui) => {material.weightClassification = ui.value;}
  66685. });
  66686. panel.find('#sldWeightReturnNumber').slider({
  66687. value: material.weightReturnNumber,
  66688. min: 0, max: 1, step: 0.01,
  66689. slide: (event, ui) => {material.weightReturnNumber = ui.value;}
  66690. });
  66691. panel.find('#sldWeightSourceID').slider({
  66692. value: material.weightSourceID,
  66693. min: 0, max: 1, step: 0.01,
  66694. slide: (event, ui) => {material.weightSourceID = ui.value;}
  66695. });
  66696. panel.find(`#materials\\.color\\.picker`).spectrum({
  66697. flat: true,
  66698. showInput: true,
  66699. preferredFormat: 'rgb',
  66700. cancelText: '',
  66701. chooseText: 'Apply',
  66702. color: `#${material.color.getHexString()}`,
  66703. move: color => {
  66704. let cRGB = color.toRgb();
  66705. let tc = new Color().setRGB(cRGB.r / 255, cRGB.g / 255, cRGB.b / 255);
  66706. material.color = tc;
  66707. },
  66708. change: color => {
  66709. let cRGB = color.toRgb();
  66710. let tc = new Color().setRGB(cRGB.r / 255, cRGB.g / 255, cRGB.b / 255);
  66711. material.color = tc;
  66712. }
  66713. });
  66714. this.addVolatileListener(material, "color_changed", () => {
  66715. panel.find(`#materials\\.color\\.picker`)
  66716. .spectrum('set', `#${material.color.getHexString()}`);
  66717. });
  66718. let updateHeightRange = function () {
  66719. let aPosition = pointcloud.getAttribute("position");
  66720. let bMin, bMax;
  66721. if(aPosition){
  66722. // for new format 2.0 and loader that contain precomputed min/max of attributes
  66723. let min = aPosition.range[0][2];
  66724. let max = aPosition.range[1][2];
  66725. let width = max - min;
  66726. bMin = min - 0.2 * width;
  66727. bMax = max + 0.2 * width;
  66728. }else {
  66729. // for format up until exlusive 2.0
  66730. let box = [pointcloud.pcoGeometry.tightBoundingBox, pointcloud.getBoundingBoxWorld()]
  66731. .find(v => v !== undefined);
  66732. pointcloud.updateMatrixWorld(true);
  66733. box = Utils.computeTransformedBoundingBox(box, pointcloud.matrixWorld);
  66734. let bWidth = box.max.z - box.min.z;
  66735. bMin = box.min.z - 0.2 * bWidth;
  66736. bMax = box.max.z + 0.2 * bWidth;
  66737. }
  66738. let range = material.elevationRange;
  66739. panel.find('#lblHeightRange').html(`${range[0].toFixed(2)} to ${range[1].toFixed(2)}`);
  66740. panel.find('#sldHeightRange').slider({min: bMin, max: bMax, values: range});
  66741. };
  66742. let updateExtraRange = function () {
  66743. let attributeName = material.activeAttributeName;
  66744. let attribute = pointcloud.getAttribute(attributeName);
  66745. if(attribute == null){
  66746. return;
  66747. }
  66748. let range = material.getRange(attributeName);
  66749. if(range == null){
  66750. range = attribute.range;
  66751. }
  66752. // currently only supporting scalar ranges.
  66753. // rgba, normals, positions, etc have vector ranges, however
  66754. let isValidRange = (typeof range[0] === "number") && (typeof range[1] === "number");
  66755. if(!isValidRange){
  66756. return;
  66757. }
  66758. if(range){
  66759. let msg = `${range[0].toFixed(2)} to ${range[1].toFixed(2)}`;
  66760. panel.find('#lblExtraRange').html(msg);
  66761. }else {
  66762. panel.find("could not deduce range");
  66763. }
  66764. };
  66765. let updateIntensityRange = function () {
  66766. let range = material.intensityRange;
  66767. panel.find('#lblIntensityRange').html(`${parseInt(range[0])} to ${parseInt(range[1])}`);
  66768. };
  66769. {
  66770. updateHeightRange();
  66771. panel.find(`#sldHeightRange`).slider('option', 'min');
  66772. panel.find(`#sldHeightRange`).slider('option', 'max');
  66773. }
  66774. {
  66775. let elGradientRepeat = panel.find("#gradient_repeat_option");
  66776. elGradientRepeat.selectgroup({title: "Gradient"});
  66777. elGradientRepeat.find("input").click( (e) => {
  66778. this.viewer.setElevationGradientRepeat(ElevationGradientRepeat[e.target.value]);
  66779. });
  66780. let current = Object.keys(ElevationGradientRepeat)
  66781. .filter(key => ElevationGradientRepeat[key] === this.viewer.elevationGradientRepeat);
  66782. elGradientRepeat.find(`input[value=${current}]`).trigger("click");
  66783. }
  66784. let onIntensityChange = () => {
  66785. let gamma = material.intensityGamma;
  66786. let contrast = material.intensityContrast;
  66787. let brightness = material.intensityBrightness;
  66788. updateIntensityRange();
  66789. panel.find('#lblIntensityGamma').html(gamma.toFixed(2));
  66790. panel.find('#lblIntensityContrast').html(contrast.toFixed(2));
  66791. panel.find('#lblIntensityBrightness').html(brightness.toFixed(2));
  66792. panel.find('#sldIntensityGamma').slider({value: gamma});
  66793. panel.find('#sldIntensityContrast').slider({value: contrast});
  66794. panel.find('#sldIntensityBrightness').slider({value: brightness});
  66795. };
  66796. let onRGBChange = () => {
  66797. let gamma = material.rgbGamma;
  66798. let contrast = material.rgbContrast;
  66799. let brightness = material.rgbBrightness;
  66800. panel.find('#lblRGBGamma').html(gamma.toFixed(2));
  66801. panel.find('#lblRGBContrast').html(contrast.toFixed(2));
  66802. panel.find('#lblRGBBrightness').html(brightness.toFixed(2));
  66803. panel.find('#sldRGBGamma').slider({value: gamma});
  66804. panel.find('#sldRGBContrast').slider({value: contrast});
  66805. panel.find('#sldRGBBrightness').slider({value: brightness});
  66806. };
  66807. this.addVolatileListener(material, "material_property_changed", updateExtraRange);
  66808. this.addVolatileListener(material, "material_property_changed", updateHeightRange);
  66809. this.addVolatileListener(material, "material_property_changed", onIntensityChange);
  66810. this.addVolatileListener(material, "material_property_changed", onRGBChange);
  66811. updateExtraRange();
  66812. updateHeightRange();
  66813. onIntensityChange();
  66814. onRGBChange();
  66815. }
  66816. }
  66817. setMeasurement(object){
  66818. let TYPE = {
  66819. DISTANCE: {panel: DistancePanel},
  66820. AREA: {panel: AreaPanel},
  66821. POINT: {panel: PointPanel},
  66822. ANGLE: {panel: AnglePanel},
  66823. HEIGHT: {panel: HeightPanel},
  66824. PROFILE: {panel: ProfilePanel},
  66825. VOLUME: {panel: VolumePanel},
  66826. CIRCLE: {panel: CirclePanel},
  66827. OTHER: {panel: PointPanel},
  66828. };
  66829. let getType = (measurement) => {
  66830. if (measurement instanceof Measure) {
  66831. if (measurement.showDistances && !measurement.showArea && !measurement.showAngles) {
  66832. return TYPE.DISTANCE;
  66833. } else if (measurement.showDistances && measurement.showArea && !measurement.showAngles) {
  66834. return TYPE.AREA;
  66835. } else if (measurement.maxMarkers === 1) {
  66836. return TYPE.POINT;
  66837. } else if (!measurement.showDistances && !measurement.showArea && measurement.showAngles) {
  66838. return TYPE.ANGLE;
  66839. } else if (measurement.showHeight) {
  66840. return TYPE.HEIGHT;
  66841. } else if (measurement.showCircle) {
  66842. return TYPE.CIRCLE;
  66843. } else {
  66844. return TYPE.OTHER;
  66845. }
  66846. } else if (measurement instanceof Profile) {
  66847. return TYPE.PROFILE;
  66848. } else if (measurement instanceof Volume) {
  66849. return TYPE.VOLUME;
  66850. }
  66851. };
  66852. //this.container.html("measurement");
  66853. let type = getType(object);
  66854. let Panel = type.panel;
  66855. let panel = new Panel(this.viewer, object, this);
  66856. this.container.append(panel.elContent);
  66857. }
  66858. setCamera(camera){
  66859. let panel = new CameraPanel(this.viewer, this);
  66860. this.container.append(panel.elContent);
  66861. }
  66862. setAnnotation(annotation){
  66863. let panel = new AnnotationPanel(this.viewer, this, annotation);
  66864. this.container.append(panel.elContent);
  66865. }
  66866. setCameraAnimation(animation){
  66867. let panel = new CameraAnimationPanel(this.viewer, this, animation);
  66868. this.container.append(panel.elContent);
  66869. }
  66870. }
  66871. function addCommas(nStr){
  66872. nStr += '';
  66873. let x = nStr.split('.');
  66874. let x1 = x[0];
  66875. let x2 = x.length > 1 ? '.' + x[1] : '';
  66876. let rgx = /(\d+)(\d{3})/;
  66877. while (rgx.test(x1)) {
  66878. x1 = x1.replace(rgx, '$1' + ',' + '$2');
  66879. }
  66880. return x1 + x2;
  66881. };
  66882. function format(value){
  66883. return addCommas(value.toFixed(3));
  66884. };
  66885. class HierarchicalSlider{
  66886. constructor(params = {}){
  66887. this.element = document.createElement("div");
  66888. this.labels = [];
  66889. this.sliders = [];
  66890. this.range = params.range != null ? params.range : [0, 1];
  66891. this.slide = params.slide != null ? params.slide : null;
  66892. this.step = params.step != null ? params.step : 0.0001;
  66893. let levels = params.levels != null ? params.levels : 1;
  66894. for(let level = 0; level < levels; level++){
  66895. this.addLevel();
  66896. }
  66897. }
  66898. setRange(range){
  66899. this.range = [...range];
  66900. { // root slider
  66901. let slider = this.sliders[0];
  66902. $(slider).slider({
  66903. min: range[0],
  66904. max: range[1],
  66905. });
  66906. }
  66907. for(let i = 1; i < this.sliders.length; i++){
  66908. let parentSlider = this.sliders[i - 1];
  66909. let slider = this.sliders[i];
  66910. let parentValues = $(parentSlider).slider("option", "values");
  66911. let childRange = [...parentValues];
  66912. $(slider).slider({
  66913. min: childRange[0],
  66914. max: childRange[1],
  66915. });
  66916. }
  66917. this.updateLabels();
  66918. }
  66919. setValues(values){
  66920. for(let slider of this.sliders){
  66921. $(slider).slider({
  66922. values: [...values],
  66923. });
  66924. }
  66925. this.updateLabels();
  66926. }
  66927. addLevel(){
  66928. const elLevel = document.createElement("li");
  66929. const elRange = document.createTextNode("Range: ");
  66930. const label = document.createElement("span");
  66931. const slider = document.createElement("div");
  66932. let level = this.sliders.length;
  66933. let [min, max] = [0, 0];
  66934. if(this.sliders.length === 0){
  66935. [min, max] = this.range;
  66936. }else {
  66937. let parentSlider = this.sliders[this.sliders.length - 1];
  66938. [min, max] = $(parentSlider).slider("option", "values");
  66939. }
  66940. $(slider).slider({
  66941. range: true,
  66942. min: min,
  66943. max: max,
  66944. step: this.step,
  66945. values: [min, max],
  66946. slide: (event, ui) => {
  66947. // set all descendants to same range
  66948. let levels = this.sliders.length;
  66949. for(let i = level + 1; i < levels; i++){
  66950. let descendant = this.sliders[i];
  66951. $(descendant).slider({
  66952. range: true,
  66953. min: ui.values[0],
  66954. max: ui.values[1],
  66955. values: [...ui.values],
  66956. });
  66957. }
  66958. if(this.slide){
  66959. let values = [...ui.values];
  66960. this.slide({
  66961. target: this,
  66962. range: this.range,
  66963. values: values,
  66964. });
  66965. }
  66966. this.updateLabels();
  66967. },
  66968. });
  66969. elLevel.append(elRange, label, slider);
  66970. this.sliders.push(slider);
  66971. this.labels.push(label);
  66972. this.element.append(elLevel);
  66973. this.updateLabels();
  66974. }
  66975. removeLevel(){
  66976. }
  66977. updateSliders(){
  66978. }
  66979. updateLabels(){
  66980. let levels = this.sliders.length;
  66981. for(let i = 0; i < levels; i++){
  66982. let slider = this.sliders[i];
  66983. let label = this.labels[i];
  66984. let [min, max] = $(slider).slider("option", "values");
  66985. let strMin = format(min);
  66986. let strMax = format(max);
  66987. let strLabel = `${strMin} to ${strMax}`;
  66988. label.innerHTML = strLabel;
  66989. }
  66990. }
  66991. }
  66992. class OrientedImageControls extends EventDispatcher{
  66993. constructor(viewer){
  66994. super();
  66995. this.viewer = viewer;
  66996. this.renderer = viewer.renderer;
  66997. this.originalCam = viewer.scene.getActiveCamera();
  66998. this.shearCam = viewer.scene.getActiveCamera().clone();
  66999. this.shearCam.rotation.set(this.originalCam.rotation.toArray());
  67000. this.shearCam.updateProjectionMatrix();
  67001. this.shearCam.updateProjectionMatrix = () => {
  67002. return this.shearCam.projectionMatrix;
  67003. };
  67004. this.image = null;
  67005. this.fadeFactor = 20;
  67006. this.fovDelta = 0;
  67007. this.fovMin = 0.1;
  67008. this.fovMax = 120;
  67009. this.shear = [0, 0];
  67010. // const style = ``;
  67011. this.elUp = $(`<input type="button" value="🡅" style="position: absolute; top: 10px; left: calc(50%); z-index: 1000" />`);
  67012. this.elRight = $(`<input type="button" value="🡆" style="position: absolute; top: calc(50%); right: 10px; z-index: 1000" />`);
  67013. this.elDown = $(`<input type="button" value="🡇" style="position: absolute; bottom: 10px; left: calc(50%); z-index: 1000" />`);
  67014. this.elLeft = $(`<input type="button" value="🡄" style="position: absolute; top: calc(50%); left: 10px; z-index: 1000" />`);
  67015. this.elExit = $(`<input type="button" value="Back to 3D view" style="position: absolute; bottom: 10px; right: 10px; z-index: 1000" />`);
  67016. this.elExit.click( () => {
  67017. this.release();
  67018. });
  67019. this.elUp.click(() => {
  67020. const fovY = viewer.getFOV();
  67021. const top = Math.tan(MathUtils.degToRad(fovY / 2));
  67022. this.shear[1] += 0.1 * top;
  67023. });
  67024. this.elRight.click(() => {
  67025. const fovY = viewer.getFOV();
  67026. const top = Math.tan(MathUtils.degToRad(fovY / 2));
  67027. this.shear[0] += 0.1 * top;
  67028. });
  67029. this.elDown.click(() => {
  67030. const fovY = viewer.getFOV();
  67031. const top = Math.tan(MathUtils.degToRad(fovY / 2));
  67032. this.shear[1] -= 0.1 * top;
  67033. });
  67034. this.elLeft.click(() => {
  67035. const fovY = viewer.getFOV();
  67036. const top = Math.tan(MathUtils.degToRad(fovY / 2));
  67037. this.shear[0] -= 0.1 * top;
  67038. });
  67039. this.scene = null;
  67040. this.sceneControls = new Scene();
  67041. let scroll = (e) => {
  67042. this.fovDelta += -e.delta * 1.0;
  67043. };
  67044. this.addEventListener('mousewheel', scroll);
  67045. //this.addEventListener("mousemove", onMove);
  67046. }
  67047. hasSomethingCaptured(){
  67048. return this.image !== null;
  67049. }
  67050. capture(image){
  67051. if(this.hasSomethingCaptured()){
  67052. return;
  67053. }
  67054. this.image = image;
  67055. this.originalFOV = this.viewer.getFOV();
  67056. this.originalControls = this.viewer.getControls();
  67057. this.viewer.setControls(this);
  67058. this.viewer.scene.overrideCamera = this.shearCam;
  67059. const elCanvas = this.viewer.renderer.domElement;
  67060. const elRoot = $(elCanvas.parentElement);
  67061. this.shear = [0, 0];
  67062. elRoot.append(this.elUp);
  67063. elRoot.append(this.elRight);
  67064. elRoot.append(this.elDown);
  67065. elRoot.append(this.elLeft);
  67066. elRoot.append(this.elExit);
  67067. }
  67068. release(){
  67069. this.image = null;
  67070. this.viewer.scene.overrideCamera = null;
  67071. this.elUp.detach();
  67072. this.elRight.detach();
  67073. this.elDown.detach();
  67074. this.elLeft.detach();
  67075. this.elExit.detach();
  67076. this.viewer.setFOV(this.originalFOV);
  67077. this.viewer.setControls(this.originalControls);
  67078. }
  67079. setScene (scene) {
  67080. this.scene = scene;
  67081. }
  67082. update (delta) {
  67083. // const view = this.scene.view;
  67084. // let prevTotal = this.shearCam.projectionMatrix.elements.reduce( (a, i) => a + i, 0);
  67085. //const progression = Math.min(1, this.fadeFactor * delta);
  67086. //const attenuation = Math.max(0, 1 - this.fadeFactor * delta);
  67087. const progression = 1;
  67088. const attenuation = 0;
  67089. const oldFov = this.viewer.getFOV();
  67090. let fovProgression = progression * this.fovDelta;
  67091. let newFov = oldFov * ((1 + fovProgression / 10));
  67092. newFov = Math.max(this.fovMin, newFov);
  67093. newFov = Math.min(this.fovMax, newFov);
  67094. let diff = newFov / oldFov;
  67095. const mouse = this.viewer.inputHandler.mouse;
  67096. const canvasSize = this.viewer.renderer.getSize(new Vector2$1());
  67097. const uv = [
  67098. (mouse.x / canvasSize.x),
  67099. ((canvasSize.y - mouse.y) / canvasSize.y)
  67100. ];
  67101. const fovY = newFov;
  67102. const aspect = canvasSize.x / canvasSize.y;
  67103. const top = Math.tan(MathUtils.degToRad(fovY / 2));
  67104. const height = 2 * top;
  67105. const width = aspect * height;
  67106. const shearRangeX = [
  67107. this.shear[0] - 0.5 * width,
  67108. this.shear[0] + 0.5 * width,
  67109. ];
  67110. const shearRangeY = [
  67111. this.shear[1] - 0.5 * height,
  67112. this.shear[1] + 0.5 * height,
  67113. ];
  67114. const shx = (1 - uv[0]) * shearRangeX[0] + uv[0] * shearRangeX[1];
  67115. const shy = (1 - uv[1]) * shearRangeY[0] + uv[1] * shearRangeY[1];
  67116. const shu = (1 - diff);
  67117. const newShear = [
  67118. (1 - shu) * this.shear[0] + shu * shx,
  67119. (1 - shu) * this.shear[1] + shu * shy,
  67120. ];
  67121. this.shear = newShear;
  67122. this.viewer.setFOV(newFov);
  67123. const {originalCam, shearCam} = this;
  67124. originalCam.fov = newFov;
  67125. originalCam.updateMatrixWorld();
  67126. originalCam.updateProjectionMatrix();
  67127. shearCam.copy(originalCam);
  67128. shearCam.rotation.set(...originalCam.rotation.toArray());
  67129. shearCam.updateMatrixWorld();
  67130. shearCam.projectionMatrix.copy(originalCam.projectionMatrix);
  67131. const [sx, sy] = this.shear;
  67132. const mShear = new Matrix4().set(
  67133. 1, 0, sx, 0,
  67134. 0, 1, sy, 0,
  67135. 0, 0, 1, 0,
  67136. 0, 0, 0, 1,
  67137. );
  67138. const proj = shearCam.projectionMatrix;
  67139. proj.multiply(mShear);
  67140. shearCam.projectionMatrixInverse.copy(proj).invert();
  67141. let total = shearCam.projectionMatrix.elements.reduce( (a, i) => a + i, 0);
  67142. this.fovDelta *= attenuation;
  67143. }
  67144. };
  67145. // https://support.pix4d.com/hc/en-us/articles/205675256-How-are-yaw-pitch-roll-defined
  67146. // https://support.pix4d.com/hc/en-us/articles/202558969-How-are-omega-phi-kappa-defined
  67147. function createMaterial(){
  67148. let vertexShader = `
  67149. uniform float uNear;
  67150. varying vec2 vUV;
  67151. varying vec4 vDebug;
  67152. void main(){
  67153. vDebug = vec4(0.0, 1.0, 0.0, 1.0);
  67154. vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
  67155. // make sure that this mesh is at least in front of the near plane
  67156. modelViewPosition.xyz += normalize(modelViewPosition.xyz) * uNear;
  67157. gl_Position = projectionMatrix * modelViewPosition;
  67158. vUV = uv;
  67159. }
  67160. `;
  67161. let fragmentShader = `
  67162. uniform sampler2D tColor;
  67163. uniform float uOpacity;
  67164. varying vec2 vUV;
  67165. varying vec4 vDebug;
  67166. void main(){
  67167. vec4 color = texture2D(tColor, vUV);
  67168. gl_FragColor = color;
  67169. gl_FragColor.a = uOpacity;
  67170. }
  67171. `;
  67172. const material = new ShaderMaterial( {
  67173. uniforms: {
  67174. // time: { value: 1.0 },
  67175. // resolution: { value: new THREE.Vector2() }
  67176. tColor: {value: new Texture() },
  67177. uNear: {value: 0.0},
  67178. uOpacity: {value: 1.0},
  67179. },
  67180. vertexShader: vertexShader,
  67181. fragmentShader: fragmentShader,
  67182. side: DoubleSide,
  67183. } );
  67184. material.side = DoubleSide;
  67185. return material;
  67186. }
  67187. const planeGeometry = new PlaneGeometry(1, 1);
  67188. const lineGeometry = new Geometry();
  67189. lineGeometry.vertices.push(
  67190. new Vector3(-0.5, -0.5, 0),
  67191. new Vector3( 0.5, -0.5, 0),
  67192. new Vector3( 0.5, 0.5, 0),
  67193. new Vector3(-0.5, 0.5, 0),
  67194. new Vector3(-0.5, -0.5, 0),
  67195. );
  67196. class OrientedImage{
  67197. constructor(id){
  67198. this.id = id;
  67199. this.fov = 1.0;
  67200. this.position = new Vector3();
  67201. this.rotation = new Vector3();
  67202. this.width = 0;
  67203. this.height = 0;
  67204. this.fov = 1.0;
  67205. const material = createMaterial();
  67206. const lineMaterial = new LineBasicMaterial( { color: 0x00ff00 } );
  67207. this.mesh = new Mesh(planeGeometry, material);
  67208. this.line = new Line(lineGeometry, lineMaterial);
  67209. this.texture = null;
  67210. this.mesh.orientedImage = this;
  67211. }
  67212. set(position, rotation, dimension, fov){
  67213. let radians = rotation.map(MathUtils.degToRad);
  67214. this.position.set(...position);
  67215. this.mesh.position.set(...position);
  67216. this.rotation.set(...radians);
  67217. this.mesh.rotation.set(...radians);
  67218. [this.width, this.height] = dimension;
  67219. this.mesh.scale.set(this.width / this.height, 1, 1);
  67220. this.fov = fov;
  67221. this.updateTransform();
  67222. }
  67223. updateTransform(){
  67224. let {mesh, line, fov} = this;
  67225. mesh.updateMatrixWorld();
  67226. const dir = mesh.getWorldDirection();
  67227. const alpha = MathUtils.degToRad(fov / 2);
  67228. const d = -0.5 / Math.tan(alpha);
  67229. const move = dir.clone().multiplyScalar(d);
  67230. mesh.position.add(move);
  67231. line.position.copy(mesh.position);
  67232. line.scale.copy(mesh.scale);
  67233. line.rotation.copy(mesh.rotation);
  67234. }
  67235. };
  67236. class OrientedImages extends EventDispatcher{
  67237. constructor(){
  67238. super();
  67239. this.node = null;
  67240. this.cameraParams = null;
  67241. this.imageParams = null;
  67242. this.images = null;
  67243. this._visible = true;
  67244. }
  67245. set visible(visible){
  67246. if(this._visible === visible){
  67247. return;
  67248. }
  67249. for(const image of this.images){
  67250. image.mesh.visible = visible;
  67251. image.line.visible = visible;
  67252. }
  67253. this._visible = visible;
  67254. this.dispatchEvent({
  67255. type: "visibility_changed",
  67256. images: this,
  67257. });
  67258. }
  67259. get visible(){
  67260. return this._visible;
  67261. }
  67262. };
  67263. class OrientedImageLoader{
  67264. static async loadCameraParams(path){
  67265. const res = await fetch(path);
  67266. const text = await res.text();
  67267. const parser = new DOMParser();
  67268. const doc = parser.parseFromString(text, "application/xml");
  67269. const width = parseInt(doc.getElementsByTagName("width")[0].textContent);
  67270. const height = parseInt(doc.getElementsByTagName("height")[0].textContent);
  67271. const f = parseFloat(doc.getElementsByTagName("f")[0].textContent);
  67272. let a = (height / 2) / f;
  67273. let fov = 2 * MathUtils.radToDeg(Math.atan(a));
  67274. const params = {
  67275. path: path,
  67276. width: width,
  67277. height: height,
  67278. f: f,
  67279. fov: fov,
  67280. };
  67281. return params;
  67282. }
  67283. static async loadImageParams(path){
  67284. const response = await fetch(path);
  67285. if(!response.ok){
  67286. console.error(`failed to load ${path}`);
  67287. return;
  67288. }
  67289. const content = await response.text();
  67290. const lines = content.split(/\r?\n/);
  67291. const imageParams = [];
  67292. for(let i = 1; i < lines.length; i++){
  67293. const line = lines[i];
  67294. if(line.startsWith("#")){
  67295. continue;
  67296. }
  67297. const tokens = line.split(/\s+/);
  67298. if(tokens.length < 6){
  67299. continue;
  67300. }
  67301. const params = {
  67302. id: tokens[0],
  67303. x: Number.parseFloat(tokens[1]),
  67304. y: Number.parseFloat(tokens[2]),
  67305. z: Number.parseFloat(tokens[3]),
  67306. omega: Number.parseFloat(tokens[4]),
  67307. phi: Number.parseFloat(tokens[5]),
  67308. kappa: Number.parseFloat(tokens[6]),
  67309. };
  67310. // const whitelist = ["47518.jpg"];
  67311. // if(whitelist.includes(params.id)){
  67312. // imageParams.push(params);
  67313. // }
  67314. imageParams.push(params);
  67315. }
  67316. // debug
  67317. //return [imageParams[50]];
  67318. return imageParams;
  67319. }
  67320. static async load(cameraParamsPath, imageParamsPath, viewer){
  67321. const tStart = performance.now();
  67322. const [cameraParams, imageParams] = await Promise.all([
  67323. OrientedImageLoader.loadCameraParams(cameraParamsPath),
  67324. OrientedImageLoader.loadImageParams(imageParamsPath),
  67325. ]);
  67326. const orientedImageControls = new OrientedImageControls(viewer);
  67327. const raycaster = new Raycaster();
  67328. const tEnd = performance.now();
  67329. console.log(tEnd - tStart);
  67330. // const sp = new THREE.PlaneGeometry(1, 1);
  67331. // const lg = new THREE.Geometry();
  67332. // lg.vertices.push(
  67333. // new THREE.Vector3(-0.5, -0.5, 0),
  67334. // new THREE.Vector3( 0.5, -0.5, 0),
  67335. // new THREE.Vector3( 0.5, 0.5, 0),
  67336. // new THREE.Vector3(-0.5, 0.5, 0),
  67337. // new THREE.Vector3(-0.5, -0.5, 0),
  67338. // );
  67339. const {width, height} = cameraParams;
  67340. const orientedImages = [];
  67341. const sceneNode = new Object3D();
  67342. sceneNode.name = "oriented_images";
  67343. for(const params of imageParams){
  67344. // const material = createMaterial();
  67345. // const lm = new THREE.LineBasicMaterial( { color: 0x00ff00 } );
  67346. // const mesh = new THREE.Mesh(sp, material);
  67347. const {x, y, z, omega, phi, kappa} = params;
  67348. // const [rx, ry, rz] = [omega, phi, kappa]
  67349. // .map(THREE.Math.degToRad);
  67350. // mesh.position.set(x, y, z);
  67351. // mesh.scale.set(width / height, 1, 1);
  67352. // mesh.rotation.set(rx, ry, rz);
  67353. // {
  67354. // mesh.updateMatrixWorld();
  67355. // const dir = mesh.getWorldDirection();
  67356. // const alpha = THREE.Math.degToRad(cameraParams.fov / 2);
  67357. // const d = -0.5 / Math.tan(alpha);
  67358. // const move = dir.clone().multiplyScalar(d);
  67359. // mesh.position.add(move);
  67360. // }
  67361. // sceneNode.add(mesh);
  67362. // const line = new THREE.Line(lg, lm);
  67363. // line.position.copy(mesh.position);
  67364. // line.scale.copy(mesh.scale);
  67365. // line.rotation.copy(mesh.rotation);
  67366. // sceneNode.add(line);
  67367. let orientedImage = new OrientedImage(params.id);
  67368. // orientedImage.setPosition(x, y, z);
  67369. // orientedImage.setRotation(omega, phi, kappa);
  67370. // orientedImage.setDimension(width, height);
  67371. let position = [x, y, z];
  67372. let rotation = [omega, phi, kappa];
  67373. let dimension = [width, height];
  67374. orientedImage.set(position, rotation, dimension, cameraParams.fov);
  67375. sceneNode.add(orientedImage.mesh);
  67376. sceneNode.add(orientedImage.line);
  67377. orientedImages.push(orientedImage);
  67378. }
  67379. let hoveredElement = null;
  67380. let clipVolume = null;
  67381. const onMouseMove = (evt) => {
  67382. const tStart = performance.now();
  67383. if(hoveredElement){
  67384. hoveredElement.line.material.color.setRGB(0, 1, 0);
  67385. }
  67386. evt.preventDefault();
  67387. //var array = getMousePosition( container, evt.clientX, evt.clientY );
  67388. const rect = viewer.renderer.domElement.getBoundingClientRect();
  67389. const [x, y] = [evt.clientX, evt.clientY];
  67390. const array = [
  67391. ( x - rect.left ) / rect.width,
  67392. ( y - rect.top ) / rect.height
  67393. ];
  67394. const onClickPosition = new Vector2$1(...array);
  67395. //const intersects = getIntersects(onClickPosition, scene.children);
  67396. const camera = viewer.scene.getActiveCamera();
  67397. const mouse = new Vector3(
  67398. + ( onClickPosition.x * 2 ) - 1,
  67399. - ( onClickPosition.y * 2 ) + 1 );
  67400. const objects = orientedImages.map(i => i.mesh);
  67401. raycaster.setFromCamera( mouse, camera );
  67402. const intersects = raycaster.intersectObjects( objects );
  67403. let selectionChanged = false;
  67404. if ( intersects.length > 0){
  67405. //console.log(intersects);
  67406. const intersection = intersects[0];
  67407. const orientedImage = intersection.object.orientedImage;
  67408. orientedImage.line.material.color.setRGB(1, 0, 0);
  67409. selectionChanged = hoveredElement !== orientedImage;
  67410. hoveredElement = orientedImage;
  67411. }else {
  67412. hoveredElement = null;
  67413. }
  67414. let shouldRemoveClipVolume = clipVolume !== null && hoveredElement === null;
  67415. let shouldAddClipVolume = clipVolume === null && hoveredElement !== null;
  67416. if(clipVolume !== null && (hoveredElement === null || selectionChanged)){
  67417. // remove existing
  67418. viewer.scene.removePolygonClipVolume(clipVolume);
  67419. clipVolume = null;
  67420. }
  67421. if(shouldAddClipVolume || selectionChanged){
  67422. const img = hoveredElement;
  67423. const fov = cameraParams.fov;
  67424. const aspect = cameraParams.width / cameraParams.height;
  67425. const near = 1.0;
  67426. const far = 1000 * 1000;
  67427. const camera = new PerspectiveCamera(fov, aspect, near, far);
  67428. camera.rotation.order = viewer.scene.getActiveCamera().rotation.order;
  67429. camera.rotation.copy(img.mesh.rotation);
  67430. {
  67431. const mesh = img.mesh;
  67432. const dir = mesh.getWorldDirection();
  67433. const pos = mesh.position;
  67434. const alpha = MathUtils.degToRad(fov / 2);
  67435. const d = 0.5 / Math.tan(alpha);
  67436. const newCamPos = pos.clone().add(dir.clone().multiplyScalar(d));
  67437. const newCamDir = pos.clone().sub(newCamPos);
  67438. const newCamTarget = new Vector3().addVectors(
  67439. newCamPos,
  67440. newCamDir.clone().multiplyScalar(viewer.getMoveSpeed()));
  67441. camera.position.copy(newCamPos);
  67442. }
  67443. let volume = new Potree.PolygonClipVolume(camera);
  67444. let m0 = new Mesh();
  67445. let m1 = new Mesh();
  67446. let m2 = new Mesh();
  67447. let m3 = new Mesh();
  67448. m0.position.set(-1, -1, 0);
  67449. m1.position.set( 1, -1, 0);
  67450. m2.position.set( 1, 1, 0);
  67451. m3.position.set(-1, 1, 0);
  67452. volume.markers.push(m0, m1, m2, m3);
  67453. volume.initialized = true;
  67454. viewer.scene.addPolygonClipVolume(volume);
  67455. clipVolume = volume;
  67456. }
  67457. const tEnd = performance.now();
  67458. //console.log(tEnd - tStart);
  67459. };
  67460. const moveToImage = (image) => {
  67461. console.log("move to image " + image.id);
  67462. const mesh = image.mesh;
  67463. const newCamPos = image.position.clone();
  67464. const newCamTarget = mesh.position.clone();
  67465. viewer.scene.view.setView(newCamPos, newCamTarget, 500, () => {
  67466. orientedImageControls.capture(image);
  67467. });
  67468. if(image.texture === null){
  67469. const target = image;
  67470. const tmpImagePath = `${Potree.resourcePath}/images/loading.jpg`;
  67471. new TextureLoader().load(tmpImagePath,
  67472. (texture) => {
  67473. if(target.texture === null){
  67474. target.texture = texture;
  67475. target.mesh.material.uniforms.tColor.value = texture;
  67476. mesh.material.needsUpdate = true;
  67477. }
  67478. }
  67479. );
  67480. const imagePath = `${imageParamsPath}/../${target.id}`;
  67481. new TextureLoader().load(imagePath,
  67482. (texture) => {
  67483. target.texture = texture;
  67484. target.mesh.material.uniforms.tColor.value = texture;
  67485. mesh.material.needsUpdate = true;
  67486. }
  67487. );
  67488. }
  67489. };
  67490. const onMouseClick = (evt) => {
  67491. if(orientedImageControls.hasSomethingCaptured()){
  67492. return;
  67493. }
  67494. if(hoveredElement){
  67495. moveToImage(hoveredElement);
  67496. }
  67497. };
  67498. viewer.renderer.domElement.addEventListener( 'mousemove', onMouseMove, false );
  67499. viewer.renderer.domElement.addEventListener( 'mousedown', onMouseClick, false );
  67500. viewer.addEventListener("update", () => {
  67501. for(const image of orientedImages){
  67502. const world = image.mesh.matrixWorld;
  67503. const {width, height} = image;
  67504. const aspect = width / height;
  67505. const camera = viewer.scene.getActiveCamera();
  67506. const imgPos = image.mesh.getWorldPosition(new Vector3());
  67507. const camPos = camera.position;
  67508. const d = camPos.distanceTo(imgPos);
  67509. const minSize = 1; // in degrees of fov
  67510. const a = MathUtils.degToRad(minSize);
  67511. let r = d * Math.tan(a);
  67512. r = Math.max(r, 1);
  67513. image.mesh.scale.set(r * aspect, r, 1);
  67514. image.line.scale.set(r * aspect, r, 1);
  67515. image.mesh.material.uniforms.uNear.value = camera.near;
  67516. }
  67517. });
  67518. const images = new OrientedImages();
  67519. images.node = sceneNode;
  67520. images.cameraParamsPath = cameraParamsPath;
  67521. images.imageParamsPath = imageParamsPath;
  67522. images.cameraParams = cameraParams;
  67523. images.imageParams = imageParams;
  67524. images.images = orientedImages;
  67525. Potree.debug.moveToImage = moveToImage;
  67526. return images;
  67527. }
  67528. }
  67529. // This is a generated file. Do not edit.
  67530. var Space_Separator = /[\u1680\u2000-\u200A\u202F\u205F\u3000]/;
  67531. var ID_Start = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/;
  67532. var ID_Continue = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/;
  67533. var unicode = {
  67534. Space_Separator: Space_Separator,
  67535. ID_Start: ID_Start,
  67536. ID_Continue: ID_Continue
  67537. };
  67538. var util = {
  67539. isSpaceSeparator (c) {
  67540. return typeof c === 'string' && unicode.Space_Separator.test(c)
  67541. },
  67542. isIdStartChar (c) {
  67543. return typeof c === 'string' && (
  67544. (c >= 'a' && c <= 'z') ||
  67545. (c >= 'A' && c <= 'Z') ||
  67546. (c === '$') || (c === '_') ||
  67547. unicode.ID_Start.test(c)
  67548. )
  67549. },
  67550. isIdContinueChar (c) {
  67551. return typeof c === 'string' && (
  67552. (c >= 'a' && c <= 'z') ||
  67553. (c >= 'A' && c <= 'Z') ||
  67554. (c >= '0' && c <= '9') ||
  67555. (c === '$') || (c === '_') ||
  67556. (c === '\u200C') || (c === '\u200D') ||
  67557. unicode.ID_Continue.test(c)
  67558. )
  67559. },
  67560. isDigit (c) {
  67561. return typeof c === 'string' && /[0-9]/.test(c)
  67562. },
  67563. isHexDigit (c) {
  67564. return typeof c === 'string' && /[0-9A-Fa-f]/.test(c)
  67565. },
  67566. };
  67567. let source;
  67568. let parseState;
  67569. let stack;
  67570. let pos;
  67571. let line;
  67572. let column;
  67573. let token;
  67574. let key;
  67575. let root;
  67576. var parse = function parse (text, reviver) {
  67577. source = String(text);
  67578. parseState = 'start';
  67579. stack = [];
  67580. pos = 0;
  67581. line = 1;
  67582. column = 0;
  67583. token = undefined;
  67584. key = undefined;
  67585. root = undefined;
  67586. do {
  67587. token = lex();
  67588. // This code is unreachable.
  67589. // if (!parseStates[parseState]) {
  67590. // throw invalidParseState()
  67591. // }
  67592. parseStates[parseState]();
  67593. } while (token.type !== 'eof')
  67594. if (typeof reviver === 'function') {
  67595. return internalize({'': root}, '', reviver)
  67596. }
  67597. return root
  67598. };
  67599. function internalize (holder, name, reviver) {
  67600. const value = holder[name];
  67601. if (value != null && typeof value === 'object') {
  67602. for (const key in value) {
  67603. const replacement = internalize(value, key, reviver);
  67604. if (replacement === undefined) {
  67605. delete value[key];
  67606. } else {
  67607. value[key] = replacement;
  67608. }
  67609. }
  67610. }
  67611. return reviver.call(holder, name, value)
  67612. }
  67613. let lexState;
  67614. let buffer;
  67615. let doubleQuote;
  67616. let sign$1;
  67617. let c$2;
  67618. function lex () {
  67619. lexState = 'default';
  67620. buffer = '';
  67621. doubleQuote = false;
  67622. sign$1 = 1;
  67623. for (;;) {
  67624. c$2 = peek();
  67625. // This code is unreachable.
  67626. // if (!lexStates[lexState]) {
  67627. // throw invalidLexState(lexState)
  67628. // }
  67629. const token = lexStates[lexState]();
  67630. if (token) {
  67631. return token
  67632. }
  67633. }
  67634. }
  67635. function peek () {
  67636. if (source[pos]) {
  67637. return String.fromCodePoint(source.codePointAt(pos))
  67638. }
  67639. }
  67640. function read () {
  67641. const c = peek();
  67642. if (c === '\n') {
  67643. line++;
  67644. column = 0;
  67645. } else if (c) {
  67646. column += c.length;
  67647. } else {
  67648. column++;
  67649. }
  67650. if (c) {
  67651. pos += c.length;
  67652. }
  67653. return c
  67654. }
  67655. const lexStates = {
  67656. default () {
  67657. switch (c$2) {
  67658. case '\t':
  67659. case '\v':
  67660. case '\f':
  67661. case ' ':
  67662. case '\u00A0':
  67663. case '\uFEFF':
  67664. case '\n':
  67665. case '\r':
  67666. case '\u2028':
  67667. case '\u2029':
  67668. read();
  67669. return
  67670. case '/':
  67671. read();
  67672. lexState = 'comment';
  67673. return
  67674. case undefined:
  67675. read();
  67676. return newToken('eof')
  67677. }
  67678. if (util.isSpaceSeparator(c$2)) {
  67679. read();
  67680. return
  67681. }
  67682. // This code is unreachable.
  67683. // if (!lexStates[parseState]) {
  67684. // throw invalidLexState(parseState)
  67685. // }
  67686. return lexStates[parseState]()
  67687. },
  67688. comment () {
  67689. switch (c$2) {
  67690. case '*':
  67691. read();
  67692. lexState = 'multiLineComment';
  67693. return
  67694. case '/':
  67695. read();
  67696. lexState = 'singleLineComment';
  67697. return
  67698. }
  67699. throw invalidChar(read())
  67700. },
  67701. multiLineComment () {
  67702. switch (c$2) {
  67703. case '*':
  67704. read();
  67705. lexState = 'multiLineCommentAsterisk';
  67706. return
  67707. case undefined:
  67708. throw invalidChar(read())
  67709. }
  67710. read();
  67711. },
  67712. multiLineCommentAsterisk () {
  67713. switch (c$2) {
  67714. case '*':
  67715. read();
  67716. return
  67717. case '/':
  67718. read();
  67719. lexState = 'default';
  67720. return
  67721. case undefined:
  67722. throw invalidChar(read())
  67723. }
  67724. read();
  67725. lexState = 'multiLineComment';
  67726. },
  67727. singleLineComment () {
  67728. switch (c$2) {
  67729. case '\n':
  67730. case '\r':
  67731. case '\u2028':
  67732. case '\u2029':
  67733. read();
  67734. lexState = 'default';
  67735. return
  67736. case undefined:
  67737. read();
  67738. return newToken('eof')
  67739. }
  67740. read();
  67741. },
  67742. value () {
  67743. switch (c$2) {
  67744. case '{':
  67745. case '[':
  67746. return newToken('punctuator', read())
  67747. case 'n':
  67748. read();
  67749. literal('ull');
  67750. return newToken('null', null)
  67751. case 't':
  67752. read();
  67753. literal('rue');
  67754. return newToken('boolean', true)
  67755. case 'f':
  67756. read();
  67757. literal('alse');
  67758. return newToken('boolean', false)
  67759. case '-':
  67760. case '+':
  67761. if (read() === '-') {
  67762. sign$1 = -1;
  67763. }
  67764. lexState = 'sign';
  67765. return
  67766. case '.':
  67767. buffer = read();
  67768. lexState = 'decimalPointLeading';
  67769. return
  67770. case '0':
  67771. buffer = read();
  67772. lexState = 'zero';
  67773. return
  67774. case '1':
  67775. case '2':
  67776. case '3':
  67777. case '4':
  67778. case '5':
  67779. case '6':
  67780. case '7':
  67781. case '8':
  67782. case '9':
  67783. buffer = read();
  67784. lexState = 'decimalInteger';
  67785. return
  67786. case 'I':
  67787. read();
  67788. literal('nfinity');
  67789. return newToken('numeric', Infinity)
  67790. case 'N':
  67791. read();
  67792. literal('aN');
  67793. return newToken('numeric', NaN)
  67794. case '"':
  67795. case "'":
  67796. doubleQuote = (read() === '"');
  67797. buffer = '';
  67798. lexState = 'string';
  67799. return
  67800. }
  67801. throw invalidChar(read())
  67802. },
  67803. identifierNameStartEscape () {
  67804. if (c$2 !== 'u') {
  67805. throw invalidChar(read())
  67806. }
  67807. read();
  67808. const u = unicodeEscape();
  67809. switch (u) {
  67810. case '$':
  67811. case '_':
  67812. break
  67813. default:
  67814. if (!util.isIdStartChar(u)) {
  67815. throw invalidIdentifier()
  67816. }
  67817. break
  67818. }
  67819. buffer += u;
  67820. lexState = 'identifierName';
  67821. },
  67822. identifierName () {
  67823. switch (c$2) {
  67824. case '$':
  67825. case '_':
  67826. case '\u200C':
  67827. case '\u200D':
  67828. buffer += read();
  67829. return
  67830. case '\\':
  67831. read();
  67832. lexState = 'identifierNameEscape';
  67833. return
  67834. }
  67835. if (util.isIdContinueChar(c$2)) {
  67836. buffer += read();
  67837. return
  67838. }
  67839. return newToken('identifier', buffer)
  67840. },
  67841. identifierNameEscape () {
  67842. if (c$2 !== 'u') {
  67843. throw invalidChar(read())
  67844. }
  67845. read();
  67846. const u = unicodeEscape();
  67847. switch (u) {
  67848. case '$':
  67849. case '_':
  67850. case '\u200C':
  67851. case '\u200D':
  67852. break
  67853. default:
  67854. if (!util.isIdContinueChar(u)) {
  67855. throw invalidIdentifier()
  67856. }
  67857. break
  67858. }
  67859. buffer += u;
  67860. lexState = 'identifierName';
  67861. },
  67862. sign () {
  67863. switch (c$2) {
  67864. case '.':
  67865. buffer = read();
  67866. lexState = 'decimalPointLeading';
  67867. return
  67868. case '0':
  67869. buffer = read();
  67870. lexState = 'zero';
  67871. return
  67872. case '1':
  67873. case '2':
  67874. case '3':
  67875. case '4':
  67876. case '5':
  67877. case '6':
  67878. case '7':
  67879. case '8':
  67880. case '9':
  67881. buffer = read();
  67882. lexState = 'decimalInteger';
  67883. return
  67884. case 'I':
  67885. read();
  67886. literal('nfinity');
  67887. return newToken('numeric', sign$1 * Infinity)
  67888. case 'N':
  67889. read();
  67890. literal('aN');
  67891. return newToken('numeric', NaN)
  67892. }
  67893. throw invalidChar(read())
  67894. },
  67895. zero () {
  67896. switch (c$2) {
  67897. case '.':
  67898. buffer += read();
  67899. lexState = 'decimalPoint';
  67900. return
  67901. case 'e':
  67902. case 'E':
  67903. buffer += read();
  67904. lexState = 'decimalExponent';
  67905. return
  67906. case 'x':
  67907. case 'X':
  67908. buffer += read();
  67909. lexState = 'hexadecimal';
  67910. return
  67911. }
  67912. return newToken('numeric', sign$1 * 0)
  67913. },
  67914. decimalInteger () {
  67915. switch (c$2) {
  67916. case '.':
  67917. buffer += read();
  67918. lexState = 'decimalPoint';
  67919. return
  67920. case 'e':
  67921. case 'E':
  67922. buffer += read();
  67923. lexState = 'decimalExponent';
  67924. return
  67925. }
  67926. if (util.isDigit(c$2)) {
  67927. buffer += read();
  67928. return
  67929. }
  67930. return newToken('numeric', sign$1 * Number(buffer))
  67931. },
  67932. decimalPointLeading () {
  67933. if (util.isDigit(c$2)) {
  67934. buffer += read();
  67935. lexState = 'decimalFraction';
  67936. return
  67937. }
  67938. throw invalidChar(read())
  67939. },
  67940. decimalPoint () {
  67941. switch (c$2) {
  67942. case 'e':
  67943. case 'E':
  67944. buffer += read();
  67945. lexState = 'decimalExponent';
  67946. return
  67947. }
  67948. if (util.isDigit(c$2)) {
  67949. buffer += read();
  67950. lexState = 'decimalFraction';
  67951. return
  67952. }
  67953. return newToken('numeric', sign$1 * Number(buffer))
  67954. },
  67955. decimalFraction () {
  67956. switch (c$2) {
  67957. case 'e':
  67958. case 'E':
  67959. buffer += read();
  67960. lexState = 'decimalExponent';
  67961. return
  67962. }
  67963. if (util.isDigit(c$2)) {
  67964. buffer += read();
  67965. return
  67966. }
  67967. return newToken('numeric', sign$1 * Number(buffer))
  67968. },
  67969. decimalExponent () {
  67970. switch (c$2) {
  67971. case '+':
  67972. case '-':
  67973. buffer += read();
  67974. lexState = 'decimalExponentSign';
  67975. return
  67976. }
  67977. if (util.isDigit(c$2)) {
  67978. buffer += read();
  67979. lexState = 'decimalExponentInteger';
  67980. return
  67981. }
  67982. throw invalidChar(read())
  67983. },
  67984. decimalExponentSign () {
  67985. if (util.isDigit(c$2)) {
  67986. buffer += read();
  67987. lexState = 'decimalExponentInteger';
  67988. return
  67989. }
  67990. throw invalidChar(read())
  67991. },
  67992. decimalExponentInteger () {
  67993. if (util.isDigit(c$2)) {
  67994. buffer += read();
  67995. return
  67996. }
  67997. return newToken('numeric', sign$1 * Number(buffer))
  67998. },
  67999. hexadecimal () {
  68000. if (util.isHexDigit(c$2)) {
  68001. buffer += read();
  68002. lexState = 'hexadecimalInteger';
  68003. return
  68004. }
  68005. throw invalidChar(read())
  68006. },
  68007. hexadecimalInteger () {
  68008. if (util.isHexDigit(c$2)) {
  68009. buffer += read();
  68010. return
  68011. }
  68012. return newToken('numeric', sign$1 * Number(buffer))
  68013. },
  68014. string () {
  68015. switch (c$2) {
  68016. case '\\':
  68017. read();
  68018. buffer += escape$1();
  68019. return
  68020. case '"':
  68021. if (doubleQuote) {
  68022. read();
  68023. return newToken('string', buffer)
  68024. }
  68025. buffer += read();
  68026. return
  68027. case "'":
  68028. if (!doubleQuote) {
  68029. read();
  68030. return newToken('string', buffer)
  68031. }
  68032. buffer += read();
  68033. return
  68034. case '\n':
  68035. case '\r':
  68036. throw invalidChar(read())
  68037. case '\u2028':
  68038. case '\u2029':
  68039. separatorChar(c$2);
  68040. break
  68041. case undefined:
  68042. throw invalidChar(read())
  68043. }
  68044. buffer += read();
  68045. },
  68046. start () {
  68047. switch (c$2) {
  68048. case '{':
  68049. case '[':
  68050. return newToken('punctuator', read())
  68051. // This code is unreachable since the default lexState handles eof.
  68052. // case undefined:
  68053. // return newToken('eof')
  68054. }
  68055. lexState = 'value';
  68056. },
  68057. beforePropertyName () {
  68058. switch (c$2) {
  68059. case '$':
  68060. case '_':
  68061. buffer = read();
  68062. lexState = 'identifierName';
  68063. return
  68064. case '\\':
  68065. read();
  68066. lexState = 'identifierNameStartEscape';
  68067. return
  68068. case '}':
  68069. return newToken('punctuator', read())
  68070. case '"':
  68071. case "'":
  68072. doubleQuote = (read() === '"');
  68073. lexState = 'string';
  68074. return
  68075. }
  68076. if (util.isIdStartChar(c$2)) {
  68077. buffer += read();
  68078. lexState = 'identifierName';
  68079. return
  68080. }
  68081. throw invalidChar(read())
  68082. },
  68083. afterPropertyName () {
  68084. if (c$2 === ':') {
  68085. return newToken('punctuator', read())
  68086. }
  68087. throw invalidChar(read())
  68088. },
  68089. beforePropertyValue () {
  68090. lexState = 'value';
  68091. },
  68092. afterPropertyValue () {
  68093. switch (c$2) {
  68094. case ',':
  68095. case '}':
  68096. return newToken('punctuator', read())
  68097. }
  68098. throw invalidChar(read())
  68099. },
  68100. beforeArrayValue () {
  68101. if (c$2 === ']') {
  68102. return newToken('punctuator', read())
  68103. }
  68104. lexState = 'value';
  68105. },
  68106. afterArrayValue () {
  68107. switch (c$2) {
  68108. case ',':
  68109. case ']':
  68110. return newToken('punctuator', read())
  68111. }
  68112. throw invalidChar(read())
  68113. },
  68114. end () {
  68115. // This code is unreachable since it's handled by the default lexState.
  68116. // if (c === undefined) {
  68117. // read()
  68118. // return newToken('eof')
  68119. // }
  68120. throw invalidChar(read())
  68121. },
  68122. };
  68123. function newToken (type, value) {
  68124. return {
  68125. type,
  68126. value,
  68127. line,
  68128. column,
  68129. }
  68130. }
  68131. function literal (s) {
  68132. for (const c of s) {
  68133. const p = peek();
  68134. if (p !== c) {
  68135. throw invalidChar(read())
  68136. }
  68137. read();
  68138. }
  68139. }
  68140. function escape$1 () {
  68141. const c = peek();
  68142. switch (c) {
  68143. case 'b':
  68144. read();
  68145. return '\b'
  68146. case 'f':
  68147. read();
  68148. return '\f'
  68149. case 'n':
  68150. read();
  68151. return '\n'
  68152. case 'r':
  68153. read();
  68154. return '\r'
  68155. case 't':
  68156. read();
  68157. return '\t'
  68158. case 'v':
  68159. read();
  68160. return '\v'
  68161. case '0':
  68162. read();
  68163. if (util.isDigit(peek())) {
  68164. throw invalidChar(read())
  68165. }
  68166. return '\0'
  68167. case 'x':
  68168. read();
  68169. return hexEscape()
  68170. case 'u':
  68171. read();
  68172. return unicodeEscape()
  68173. case '\n':
  68174. case '\u2028':
  68175. case '\u2029':
  68176. read();
  68177. return ''
  68178. case '\r':
  68179. read();
  68180. if (peek() === '\n') {
  68181. read();
  68182. }
  68183. return ''
  68184. case '1':
  68185. case '2':
  68186. case '3':
  68187. case '4':
  68188. case '5':
  68189. case '6':
  68190. case '7':
  68191. case '8':
  68192. case '9':
  68193. throw invalidChar(read())
  68194. case undefined:
  68195. throw invalidChar(read())
  68196. }
  68197. return read()
  68198. }
  68199. function hexEscape () {
  68200. let buffer = '';
  68201. let c = peek();
  68202. if (!util.isHexDigit(c)) {
  68203. throw invalidChar(read())
  68204. }
  68205. buffer += read();
  68206. c = peek();
  68207. if (!util.isHexDigit(c)) {
  68208. throw invalidChar(read())
  68209. }
  68210. buffer += read();
  68211. return String.fromCodePoint(parseInt(buffer, 16))
  68212. }
  68213. function unicodeEscape () {
  68214. let buffer = '';
  68215. let count = 4;
  68216. while (count-- > 0) {
  68217. const c = peek();
  68218. if (!util.isHexDigit(c)) {
  68219. throw invalidChar(read())
  68220. }
  68221. buffer += read();
  68222. }
  68223. return String.fromCodePoint(parseInt(buffer, 16))
  68224. }
  68225. const parseStates = {
  68226. start () {
  68227. if (token.type === 'eof') {
  68228. throw invalidEOF()
  68229. }
  68230. push();
  68231. },
  68232. beforePropertyName () {
  68233. switch (token.type) {
  68234. case 'identifier':
  68235. case 'string':
  68236. key = token.value;
  68237. parseState = 'afterPropertyName';
  68238. return
  68239. case 'punctuator':
  68240. // This code is unreachable since it's handled by the lexState.
  68241. // if (token.value !== '}') {
  68242. // throw invalidToken()
  68243. // }
  68244. pop();
  68245. return
  68246. case 'eof':
  68247. throw invalidEOF()
  68248. }
  68249. // This code is unreachable since it's handled by the lexState.
  68250. // throw invalidToken()
  68251. },
  68252. afterPropertyName () {
  68253. // This code is unreachable since it's handled by the lexState.
  68254. // if (token.type !== 'punctuator' || token.value !== ':') {
  68255. // throw invalidToken()
  68256. // }
  68257. if (token.type === 'eof') {
  68258. throw invalidEOF()
  68259. }
  68260. parseState = 'beforePropertyValue';
  68261. },
  68262. beforePropertyValue () {
  68263. if (token.type === 'eof') {
  68264. throw invalidEOF()
  68265. }
  68266. push();
  68267. },
  68268. beforeArrayValue () {
  68269. if (token.type === 'eof') {
  68270. throw invalidEOF()
  68271. }
  68272. if (token.type === 'punctuator' && token.value === ']') {
  68273. pop();
  68274. return
  68275. }
  68276. push();
  68277. },
  68278. afterPropertyValue () {
  68279. // This code is unreachable since it's handled by the lexState.
  68280. // if (token.type !== 'punctuator') {
  68281. // throw invalidToken()
  68282. // }
  68283. if (token.type === 'eof') {
  68284. throw invalidEOF()
  68285. }
  68286. switch (token.value) {
  68287. case ',':
  68288. parseState = 'beforePropertyName';
  68289. return
  68290. case '}':
  68291. pop();
  68292. }
  68293. // This code is unreachable since it's handled by the lexState.
  68294. // throw invalidToken()
  68295. },
  68296. afterArrayValue () {
  68297. // This code is unreachable since it's handled by the lexState.
  68298. // if (token.type !== 'punctuator') {
  68299. // throw invalidToken()
  68300. // }
  68301. if (token.type === 'eof') {
  68302. throw invalidEOF()
  68303. }
  68304. switch (token.value) {
  68305. case ',':
  68306. parseState = 'beforeArrayValue';
  68307. return
  68308. case ']':
  68309. pop();
  68310. }
  68311. // This code is unreachable since it's handled by the lexState.
  68312. // throw invalidToken()
  68313. },
  68314. end () {
  68315. // This code is unreachable since it's handled by the lexState.
  68316. // if (token.type !== 'eof') {
  68317. // throw invalidToken()
  68318. // }
  68319. },
  68320. };
  68321. function push () {
  68322. let value;
  68323. switch (token.type) {
  68324. case 'punctuator':
  68325. switch (token.value) {
  68326. case '{':
  68327. value = {};
  68328. break
  68329. case '[':
  68330. value = [];
  68331. break
  68332. }
  68333. break
  68334. case 'null':
  68335. case 'boolean':
  68336. case 'numeric':
  68337. case 'string':
  68338. value = token.value;
  68339. break
  68340. // This code is unreachable.
  68341. // default:
  68342. // throw invalidToken()
  68343. }
  68344. if (root === undefined) {
  68345. root = value;
  68346. } else {
  68347. const parent = stack[stack.length - 1];
  68348. if (Array.isArray(parent)) {
  68349. parent.push(value);
  68350. } else {
  68351. parent[key] = value;
  68352. }
  68353. }
  68354. if (value !== null && typeof value === 'object') {
  68355. stack.push(value);
  68356. if (Array.isArray(value)) {
  68357. parseState = 'beforeArrayValue';
  68358. } else {
  68359. parseState = 'beforePropertyName';
  68360. }
  68361. } else {
  68362. const current = stack[stack.length - 1];
  68363. if (current == null) {
  68364. parseState = 'end';
  68365. } else if (Array.isArray(current)) {
  68366. parseState = 'afterArrayValue';
  68367. } else {
  68368. parseState = 'afterPropertyValue';
  68369. }
  68370. }
  68371. }
  68372. function pop () {
  68373. stack.pop();
  68374. const current = stack[stack.length - 1];
  68375. if (current == null) {
  68376. parseState = 'end';
  68377. } else if (Array.isArray(current)) {
  68378. parseState = 'afterArrayValue';
  68379. } else {
  68380. parseState = 'afterPropertyValue';
  68381. }
  68382. }
  68383. // This code is unreachable.
  68384. // function invalidParseState () {
  68385. // return new Error(`JSON5: invalid parse state '${parseState}'`)
  68386. // }
  68387. // This code is unreachable.
  68388. // function invalidLexState (state) {
  68389. // return new Error(`JSON5: invalid lex state '${state}'`)
  68390. // }
  68391. function invalidChar (c) {
  68392. if (c === undefined) {
  68393. return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
  68394. }
  68395. return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
  68396. }
  68397. function invalidEOF () {
  68398. return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
  68399. }
  68400. // This code is unreachable.
  68401. // function invalidToken () {
  68402. // if (token.type === 'eof') {
  68403. // return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
  68404. // }
  68405. // const c = String.fromCodePoint(token.value.codePointAt(0))
  68406. // return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
  68407. // }
  68408. function invalidIdentifier () {
  68409. column -= 5;
  68410. return syntaxError(`JSON5: invalid identifier character at ${line}:${column}`)
  68411. }
  68412. function separatorChar (c) {
  68413. console.warn(`JSON5: '${formatChar(c)}' in strings is not valid ECMAScript; consider escaping`);
  68414. }
  68415. function formatChar (c) {
  68416. const replacements = {
  68417. "'": "\\'",
  68418. '"': '\\"',
  68419. '\\': '\\\\',
  68420. '\b': '\\b',
  68421. '\f': '\\f',
  68422. '\n': '\\n',
  68423. '\r': '\\r',
  68424. '\t': '\\t',
  68425. '\v': '\\v',
  68426. '\0': '\\0',
  68427. '\u2028': '\\u2028',
  68428. '\u2029': '\\u2029',
  68429. };
  68430. if (replacements[c]) {
  68431. return replacements[c]
  68432. }
  68433. if (c < ' ') {
  68434. const hexString = c.charCodeAt(0).toString(16);
  68435. return '\\x' + ('00' + hexString).substring(hexString.length)
  68436. }
  68437. return c
  68438. }
  68439. function syntaxError (message) {
  68440. const err = new SyntaxError(message);
  68441. err.lineNumber = line;
  68442. err.columnNumber = column;
  68443. return err
  68444. }
  68445. var stringify = function stringify (value, replacer, space) {
  68446. const stack = [];
  68447. let indent = '';
  68448. let propertyList;
  68449. let replacerFunc;
  68450. let gap = '';
  68451. let quote;
  68452. if (
  68453. replacer != null &&
  68454. typeof replacer === 'object' &&
  68455. !Array.isArray(replacer)
  68456. ) {
  68457. space = replacer.space;
  68458. quote = replacer.quote;
  68459. replacer = replacer.replacer;
  68460. }
  68461. if (typeof replacer === 'function') {
  68462. replacerFunc = replacer;
  68463. } else if (Array.isArray(replacer)) {
  68464. propertyList = [];
  68465. for (const v of replacer) {
  68466. let item;
  68467. if (typeof v === 'string') {
  68468. item = v;
  68469. } else if (
  68470. typeof v === 'number' ||
  68471. v instanceof String ||
  68472. v instanceof Number
  68473. ) {
  68474. item = String(v);
  68475. }
  68476. if (item !== undefined && propertyList.indexOf(item) < 0) {
  68477. propertyList.push(item);
  68478. }
  68479. }
  68480. }
  68481. if (space instanceof Number) {
  68482. space = Number(space);
  68483. } else if (space instanceof String) {
  68484. space = String(space);
  68485. }
  68486. if (typeof space === 'number') {
  68487. if (space > 0) {
  68488. space = Math.min(10, Math.floor(space));
  68489. gap = ' '.substr(0, space);
  68490. }
  68491. } else if (typeof space === 'string') {
  68492. gap = space.substr(0, 10);
  68493. }
  68494. return serializeProperty('', {'': value})
  68495. function serializeProperty (key, holder) {
  68496. let value = holder[key];
  68497. if (value != null) {
  68498. if (typeof value.toJSON5 === 'function') {
  68499. value = value.toJSON5(key);
  68500. } else if (typeof value.toJSON === 'function') {
  68501. value = value.toJSON(key);
  68502. }
  68503. }
  68504. if (replacerFunc) {
  68505. value = replacerFunc.call(holder, key, value);
  68506. }
  68507. if (value instanceof Number) {
  68508. value = Number(value);
  68509. } else if (value instanceof String) {
  68510. value = String(value);
  68511. } else if (value instanceof Boolean) {
  68512. value = value.valueOf();
  68513. }
  68514. switch (value) {
  68515. case null: return 'null'
  68516. case true: return 'true'
  68517. case false: return 'false'
  68518. }
  68519. if (typeof value === 'string') {
  68520. return quoteString(value, false)
  68521. }
  68522. if (typeof value === 'number') {
  68523. return String(value)
  68524. }
  68525. if (typeof value === 'object') {
  68526. return Array.isArray(value) ? serializeArray(value) : serializeObject(value)
  68527. }
  68528. return undefined
  68529. }
  68530. function quoteString (value) {
  68531. const quotes = {
  68532. "'": 0.1,
  68533. '"': 0.2,
  68534. };
  68535. const replacements = {
  68536. "'": "\\'",
  68537. '"': '\\"',
  68538. '\\': '\\\\',
  68539. '\b': '\\b',
  68540. '\f': '\\f',
  68541. '\n': '\\n',
  68542. '\r': '\\r',
  68543. '\t': '\\t',
  68544. '\v': '\\v',
  68545. '\0': '\\0',
  68546. '\u2028': '\\u2028',
  68547. '\u2029': '\\u2029',
  68548. };
  68549. let product = '';
  68550. for (let i = 0; i < value.length; i++) {
  68551. const c = value[i];
  68552. switch (c) {
  68553. case "'":
  68554. case '"':
  68555. quotes[c]++;
  68556. product += c;
  68557. continue
  68558. case '\0':
  68559. if (util.isDigit(value[i + 1])) {
  68560. product += '\\x00';
  68561. continue
  68562. }
  68563. }
  68564. if (replacements[c]) {
  68565. product += replacements[c];
  68566. continue
  68567. }
  68568. if (c < ' ') {
  68569. let hexString = c.charCodeAt(0).toString(16);
  68570. product += '\\x' + ('00' + hexString).substring(hexString.length);
  68571. continue
  68572. }
  68573. product += c;
  68574. }
  68575. const quoteChar = quote || Object.keys(quotes).reduce((a, b) => (quotes[a] < quotes[b]) ? a : b);
  68576. product = product.replace(new RegExp(quoteChar, 'g'), replacements[quoteChar]);
  68577. return quoteChar + product + quoteChar
  68578. }
  68579. function serializeObject (value) {
  68580. if (stack.indexOf(value) >= 0) {
  68581. throw TypeError('Converting circular structure to JSON5')
  68582. }
  68583. stack.push(value);
  68584. let stepback = indent;
  68585. indent = indent + gap;
  68586. let keys = propertyList || Object.keys(value);
  68587. let partial = [];
  68588. for (const key of keys) {
  68589. const propertyString = serializeProperty(key, value);
  68590. if (propertyString !== undefined) {
  68591. let member = serializeKey(key) + ':';
  68592. if (gap !== '') {
  68593. member += ' ';
  68594. }
  68595. member += propertyString;
  68596. partial.push(member);
  68597. }
  68598. }
  68599. let final;
  68600. if (partial.length === 0) {
  68601. final = '{}';
  68602. } else {
  68603. let properties;
  68604. if (gap === '') {
  68605. properties = partial.join(',');
  68606. final = '{' + properties + '}';
  68607. } else {
  68608. let separator = ',\n' + indent;
  68609. properties = partial.join(separator);
  68610. final = '{\n' + indent + properties + ',\n' + stepback + '}';
  68611. }
  68612. }
  68613. stack.pop();
  68614. indent = stepback;
  68615. return final
  68616. }
  68617. function serializeKey (key) {
  68618. if (key.length === 0) {
  68619. return quoteString(key, true)
  68620. }
  68621. const firstChar = String.fromCodePoint(key.codePointAt(0));
  68622. if (!util.isIdStartChar(firstChar)) {
  68623. return quoteString(key, true)
  68624. }
  68625. for (let i = firstChar.length; i < key.length; i++) {
  68626. if (!util.isIdContinueChar(String.fromCodePoint(key.codePointAt(i)))) {
  68627. return quoteString(key, true)
  68628. }
  68629. }
  68630. return key
  68631. }
  68632. function serializeArray (value) {
  68633. if (stack.indexOf(value) >= 0) {
  68634. throw TypeError('Converting circular structure to JSON5')
  68635. }
  68636. stack.push(value);
  68637. let stepback = indent;
  68638. indent = indent + gap;
  68639. let partial = [];
  68640. for (let i = 0; i < value.length; i++) {
  68641. const propertyString = serializeProperty(String(i), value);
  68642. partial.push((propertyString !== undefined) ? propertyString : 'null');
  68643. }
  68644. let final;
  68645. if (partial.length === 0) {
  68646. final = '[]';
  68647. } else {
  68648. if (gap === '') {
  68649. let properties = partial.join(',');
  68650. final = '[' + properties + ']';
  68651. } else {
  68652. let separator = ',\n' + indent;
  68653. let properties = partial.join(separator);
  68654. final = '[\n' + indent + properties + ',\n' + stepback + ']';
  68655. }
  68656. }
  68657. stack.pop();
  68658. indent = stepback;
  68659. return final
  68660. }
  68661. };
  68662. const JSON5 = {
  68663. parse,
  68664. stringify,
  68665. };
  68666. var lib = JSON5;
  68667. class Sidebar{
  68668. constructor(viewer){
  68669. this.viewer = viewer;
  68670. this.measuringTool = viewer.measuringTool;
  68671. this.profileTool = viewer.profileTool;
  68672. this.volumeTool = viewer.volumeTool;
  68673. this.dom = $("#sidebar_root");
  68674. }
  68675. createToolIcon(icon, title, callback){
  68676. let element = $(`
  68677. <img src="${icon}"
  68678. style="width: 32px; height: 32px"
  68679. class="button-icon"
  68680. data-i18n="${title}" />
  68681. `);
  68682. element.click(callback);
  68683. return element;
  68684. }
  68685. init(){
  68686. if(Potree.settings.editType == 'merge'){
  68687. this.initMergeBar();
  68688. this.initToolbar();
  68689. this.initScene();
  68690. this.initNavigation();
  68691. }else {
  68692. this.initAccordion();
  68693. this.initAppearance();
  68694. this.initToolbar();
  68695. this.initScene();
  68696. this.initNavigation();
  68697. this.initFilters();
  68698. this.initClippingTool();
  68699. this.initSettings();
  68700. if(Potree.settings.editType != 'pano'){
  68701. this.initAlignment();
  68702. this.initClipModel();
  68703. this.initSiteModel();
  68704. this.initParitcle();
  68705. }else {
  68706. this.initPanosEdit();
  68707. }
  68708. }
  68709. $('#potree_version_number').html(Potree.version.major + "." + Potree.version.minor + Potree.version.suffix);
  68710. }
  68711. initAlignment(){
  68712. let Alignment = viewer.modules.Alignment;
  68713. var pannel = $('#alignment');
  68714. var buttons = pannel.find('[name="transform"] button');
  68715. var applyToPointcloud = (fun, value)=>{
  68716. return function(){
  68717. var selected = $('#alignment li[name="selectPointCloud"] input:checked' );
  68718. Array.from(selected).forEach(e=>{
  68719. var pointcloud = viewer.scene.pointclouds.find(p=>p.name == e.name);
  68720. fun(pointcloud, value);
  68721. });
  68722. }
  68723. };
  68724. //逆时针是正数
  68725. buttons.eq(0).on('click', applyToPointcloud(Alignment.rotate, 10));
  68726. //viewer.scene.pointclouds[0].rotation.z += THREE.Math.degToRad(10)
  68727. buttons.eq(1).on('click' ,applyToPointcloud(Alignment.rotate, 1));
  68728. buttons.eq(2).on('click', applyToPointcloud(Alignment.rotate, 0.1));
  68729. buttons.eq(3).on('click', applyToPointcloud(Alignment.rotate, -10));
  68730. buttons.eq(4).on('click',applyToPointcloud(Alignment.rotate, -1));
  68731. buttons.eq(5).on('click',applyToPointcloud(Alignment.rotate, -0.1));
  68732. buttons.eq(6).on('click', applyToPointcloud(Alignment.translate, new Vector3(-1,0,0)));
  68733. buttons.eq(7).on('click', applyToPointcloud(Alignment.translate, new Vector3(1,0,0)));
  68734. buttons.eq(8).on('click', applyToPointcloud(Alignment.translate, new Vector3(0,-1,0)));
  68735. buttons.eq(9).on('click', applyToPointcloud(Alignment.translate, new Vector3(0,1,0)));
  68736. buttons.eq(10).on('click', applyToPointcloud(Alignment.translate, new Vector3(0,0,-1)));
  68737. buttons.eq(11).on('click', applyToPointcloud(Alignment.translate, new Vector3(0,0,1)));
  68738. pannel.find('#startAlignment').on('click', ()=>{
  68739. Alignment.enter();
  68740. });
  68741. pannel.find('#exitAlignment').on('click', ()=>{
  68742. Alignment.save();
  68743. Alignment.leave();
  68744. });
  68745. pannel.find('#rotTool').on('click', ()=>{
  68746. Alignment.switchHandle('rotate');
  68747. });
  68748. pannel.find('#moveTool').on('click', ()=>{
  68749. Alignment.switchHandle('translate');
  68750. });
  68751. }
  68752. initMergeBar(){//多元融合模块
  68753. var pannel = $('#mergeModel');
  68754. var buttons = pannel.find('button');
  68755. let MergeEditor = viewer.modules.MergeEditor;
  68756. let loading = false;
  68757. pannel.find('ul[name="model"] li button').on('click',(e)=>{
  68758. if(loading)return console.log('还在加载', loading)
  68759. let $elem = $(e.target);
  68760. let parent = $elem.parent();
  68761. let name = parent.attr('name');
  68762. if($elem.attr('name') == 'select'){
  68763. return Potree.selectModel(name)
  68764. }
  68765. if($elem.text() == '添加'){
  68766. let startTime = Date.now();
  68767. Potree.addModel(name,()=>{
  68768. loading = false;
  68769. $elem.text('删除');
  68770. let now = Date.now();
  68771. console.log('加载完毕', name, '用时', (now-startTime)/1000, 's');
  68772. });
  68773. loading = name;
  68774. }else {
  68775. Potree.removeModel(name);
  68776. $elem.text('添加');
  68777. }
  68778. });
  68779. pannel.find('li button[name="splitScreen"]').on('click',(e)=>{
  68780. let $elem = $(e.target);
  68781. if($elem.text() == '分屏'){
  68782. $elem.text('恢复');
  68783. MergeEditor.enterSplit();
  68784. }else {
  68785. $elem.text('分屏');
  68786. MergeEditor.leaveSplit();
  68787. }
  68788. });
  68789. }
  68790. addAlignmentButton(pointcloud){
  68791. var pannel = $('#alignment li[name="selectPointCloud"]>div');
  68792. var option = $(` <input name="${pointcloud.name}" class="editCheckbox" type="checkbox" >
  68793. <label for="showingLabels">${pointcloud.name}</label>`);
  68794. pannel.append(option);
  68795. /* option.find("input").on('change',function(){
  68796. })
  68797. */
  68798. }
  68799. initClipModel(){
  68800. let Clip = viewer.modules.Clip;
  68801. var pannel = $('#clipModel');
  68802. var buttons = pannel.find('button');
  68803. buttons.eq(0).on('click', Clip.enter.bind(Clip));
  68804. buttons.eq(1).on('click', Clip.download.bind(Clip));
  68805. buttons.eq(2).on('click', Clip.leave.bind(Clip));
  68806. }
  68807. initSiteModel(){
  68808. let SiteModel = viewer.modules.SiteModel;
  68809. var pannel = $('#siteModel');
  68810. pannel.find('button[name="start"] ').on('click', SiteModel.enter.bind(SiteModel));
  68811. pannel.find('button[name="exit"] ').on('click', SiteModel.leave.bind(SiteModel));
  68812. pannel.find('button[name="building"] ').on('click', SiteModel.startInsertion.bind(SiteModel,'building'));
  68813. pannel.find('button[name="floor"] ').on('click', ()=>{
  68814. SiteModel.addFloor(SiteModel.buildings[0], 'top');
  68815. } );
  68816. pannel.find('button[name="room"] ').on('click', ()=>{
  68817. SiteModel.startInsertion('room', SiteModel.buildings[0].buildChildren[0]);
  68818. });
  68819. pannel.find('button[name="digHole"] ').on('click', ()=>{
  68820. SiteModel.selected && SiteModel.startInsertion('hole', SiteModel.selected);
  68821. });
  68822. pannel.find('button[name="selectBuilding"] ').on('click', ()=>{
  68823. SiteModel.selectEntity(SiteModel.buildings[0] );
  68824. } );
  68825. pannel.find('button[name="selectFloor"] ').on('click', ()=>{
  68826. SiteModel.selectEntity(SiteModel.buildings[0].buildChildren[0]);
  68827. } );
  68828. pannel.find('button[name="selectRoom"] ').on('click', ()=>{
  68829. SiteModel.selectEntity(SiteModel.buildings[0].buildChildren[0].buildChildren[0]);
  68830. });
  68831. pannel.find('button[name="removeFirstBuilding"] ').on('click', ()=>{
  68832. SiteModel.removeEntity(SiteModel.buildings[0]);
  68833. });
  68834. pannel.find('button[name="removeFirstFloor"] ').on('click', ()=>{
  68835. SiteModel.removeEntity(SiteModel.buildings[0].buildChildren[0]);
  68836. });
  68837. pannel.find('button[name="removeFirstRoom"] ').on('click', ()=>{
  68838. SiteModel.removeEntity(SiteModel.buildings[0].buildChildren[0].buildChildren[0]);
  68839. });
  68840. pannel.find('button[name="removeFirstHole"] ').on('click', ()=>{
  68841. SiteModel.selected.removeHole(SiteModel.selected.holes[0]);
  68842. });
  68843. pannel.find('button[name="removeFirstMarker"] ').on('click', ()=>{
  68844. //SiteModel.removeMarker(SiteModel.selected.markers[0])
  68845. SiteModel.selected.removeMarker(0);
  68846. });
  68847. }
  68848. initParitcle(){
  68849. let ParticleEditor = viewer.modules.ParticleEditor;
  68850. var pannel = $('#particle');
  68851. pannel.find('button[name="addFire"] ').on('click', ()=>{
  68852. ParticleEditor.startInsertion('fire+smoke');
  68853. });
  68854. pannel.find('button[name="addExplode"] ').on('click', ()=>{
  68855. ParticleEditor.startInsertion('explode');
  68856. });
  68857. }
  68858. initPanosEdit(){
  68859. let PanoEditor = viewer.modules.PanoEditor;
  68860. let Alignment = viewer.modules.Alignment;
  68861. var pannel = $('#panos');
  68862. pannel.find('button[name="save"] ').on('click', ()=>{
  68863. console.log('saveData',PanoEditor.exportSavingData());
  68864. });
  68865. pannel.find('button[name="translate"] ').on('click', ()=>{
  68866. Alignment.switchHandle('translate');
  68867. });
  68868. pannel.find('button[name="rotate"] ').on('click', ()=>{
  68869. Alignment.switchHandle('rotate');
  68870. });
  68871. pannel.find('button[name="topView"] ').on('click', ()=>{
  68872. PanoEditor.switchView('top');
  68873. });
  68874. pannel.find('button[name="sideView"] ').on('click', ()=>{
  68875. PanoEditor.switchView('right');
  68876. });
  68877. pannel.find('button[name="3DView"] ').on('click', ()=>{
  68878. PanoEditor.switchView('mainView');
  68879. });
  68880. pannel.find('button[name="addLink"] ').on('click', ()=>{
  68881. PanoEditor.setLinkOperateState('addLink', true);
  68882. });
  68883. pannel.find('button[name="removeLink"] ').on('click', ()=>{
  68884. PanoEditor.setLinkOperateState('removeLink', true);
  68885. });
  68886. pannel.find('button[name="getCloser"] ').on('click', ()=>{
  68887. PanoEditor.setZoomInState(true);
  68888. });
  68889. }
  68890. initToolbar(){
  68891. // ANGLE
  68892. let elToolbar = $('#tools');
  68893. elToolbar.append(this.createToolIcon(
  68894. Potree.resourcePath + '/icons/angle.png',
  68895. '[title]tt.angle_measurement',
  68896. () => {
  68897. $('#menu_measurements').next().slideDown();
  68898. let measurement = this.measuringTool.startInsertion({
  68899. showDistances: false,
  68900. showAngles: true,
  68901. showArea: false,
  68902. closed: true,
  68903. maxMarkers: 3,
  68904. minMarkers:3,
  68905. measureType: 'Angle'});
  68906. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  68907. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  68908. $.jstree.reference(jsonNode.id).deselect_all();
  68909. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  68910. }
  68911. ));
  68912. // POINT
  68913. elToolbar.append(this.createToolIcon(
  68914. Potree.resourcePath + '/icons/point.svg',
  68915. '[title]tt.point_measurement',
  68916. () => {
  68917. $('#menu_measurements').next().slideDown();
  68918. let measurement = this.measuringTool.startInsertion({
  68919. showDistances: false,
  68920. showAngles: false,
  68921. showCoordinates: true,
  68922. showEdges:false,
  68923. showArea: false,
  68924. closed: true,
  68925. maxMarkers: 1,
  68926. minMarkers:1,
  68927. measureType: 'Point'});
  68928. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  68929. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  68930. $.jstree.reference(jsonNode.id).deselect_all();
  68931. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  68932. }
  68933. ));
  68934. // DISTANCE
  68935. elToolbar.append(this.createToolIcon(
  68936. Potree.resourcePath + '/icons/distance.svg',
  68937. '[title]tt.distance_measurement',
  68938. () => {
  68939. $('#menu_measurements').next().slideDown();
  68940. let measurement = this.measuringTool.startInsertion({
  68941. showDistances: true,
  68942. showArea: false,
  68943. closed: false,
  68944. minMarkers:2,
  68945. maxMarkers: 2,
  68946. measureType: 'Distance'
  68947. });
  68948. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  68949. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  68950. $.jstree.reference(jsonNode.id).deselect_all();
  68951. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  68952. }
  68953. ));
  68954. // HEIGHT
  68955. elToolbar.append(this.createToolIcon(
  68956. Potree.resourcePath + '/icons/height.svg',
  68957. '[title]tt.height_measurement',
  68958. () => {
  68959. $('#menu_measurements').next().slideDown();
  68960. let measurement = this.measuringTool.startInsertion({
  68961. showDistances: true,//false,
  68962. showHeight: true,
  68963. showArea: false,
  68964. closed: false,
  68965. maxMarkers: 2,
  68966. minMarkers:2,
  68967. //showGuideLine: true: true
  68968. measureType: 'Ver Distance',
  68969. });
  68970. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  68971. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  68972. $.jstree.reference(jsonNode.id).deselect_all();
  68973. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  68974. }
  68975. ));
  68976. // CIRCLE
  68977. elToolbar.append(this.createToolIcon(
  68978. Potree.resourcePath + '/icons/circle.svg',
  68979. '[title]tt.circle_measurement',
  68980. () => {
  68981. $('#menu_measurements').next().slideDown();
  68982. let measurement = this.measuringTool.startInsertion({
  68983. showDistances: false,
  68984. showHeight: false,
  68985. showArea: false,
  68986. showCircle: true,
  68987. showEdges: false,
  68988. closed: false,
  68989. maxMarkers: 3,
  68990. minMarkers:3,
  68991. measureType: 'Circle'
  68992. });
  68993. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  68994. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  68995. $.jstree.reference(jsonNode.id).deselect_all();
  68996. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  68997. }
  68998. ));
  68999. // AZIMUTH
  69000. elToolbar.append(this.createToolIcon(
  69001. Potree.resourcePath + '/icons/azimuth.svg',
  69002. 'Azimuth',
  69003. () => {
  69004. $('#menu_measurements').next().slideDown();
  69005. let measurement = this.measuringTool.startInsertion({
  69006. showDistances: false,
  69007. showHeight: false,
  69008. showArea: false,
  69009. showCircle: false,
  69010. showEdges: false,
  69011. showAzimuth: true,
  69012. closed: false,
  69013. maxMarkers: 2,
  69014. minMarkers:2,
  69015. measureType: 'Azimuth'});
  69016. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69017. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69018. $.jstree.reference(jsonNode.id).deselect_all();
  69019. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69020. }
  69021. ));
  69022. // AREA
  69023. elToolbar.append(this.createToolIcon(
  69024. Potree.resourcePath + '/icons/area.svg',
  69025. '[title]tt.area_measurement',
  69026. () => {
  69027. $('#menu_measurements').next().slideDown();
  69028. let measurement = this.measuringTool.startInsertion({
  69029. showDistances: true,
  69030. showArea: true,
  69031. closed: true,
  69032. minMarkers:3,
  69033. //showGuideLine: true: true,
  69034. measureType: 'Area'});
  69035. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69036. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69037. $.jstree.reference(jsonNode.id).deselect_all();
  69038. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69039. }
  69040. ));
  69041. //Hor AREA
  69042. elToolbar.append(this.createToolIcon(
  69043. Potree.resourcePath + '/icons/area.svg',
  69044. '[title]tt.Hor Area',
  69045. () => {
  69046. $('#menu_measurements').next().slideDown();
  69047. let measurement = this.measuringTool.startInsertion({
  69048. showDistances: true,
  69049. showArea: true,
  69050. closed: true,
  69051. minMarkers:3,
  69052. measureType: 'Hor Area'});
  69053. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69054. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69055. $.jstree.reference(jsonNode.id).deselect_all();
  69056. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69057. }
  69058. ));
  69059. // Ver Area
  69060. elToolbar.append(this.createToolIcon(
  69061. Potree.resourcePath + '/icons/area.svg',
  69062. '[title]tt.Ver Area',
  69063. () => {
  69064. $('#menu_measurements').next().slideDown();
  69065. let measurement = this.measuringTool.startInsertion({
  69066. showDistances: true,
  69067. showArea: true,
  69068. closed: true,
  69069. minMarkers:3,
  69070. measureType: 'Ver Area'});
  69071. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69072. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69073. $.jstree.reference(jsonNode.id).deselect_all();
  69074. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69075. }
  69076. ));
  69077. // rect area freedom direction
  69078. elToolbar.append(this.createToolIcon(
  69079. Potree.resourcePath + '/icons/area.svg',
  69080. '[title]tt.area_freedom_rect',
  69081. () => {
  69082. $('#menu_measurements').next().slideDown();
  69083. let measurement = this.measuringTool.startInsertion({
  69084. showDistances: true,
  69085. showArea: true,
  69086. closed: true,
  69087. minMarkers:4,
  69088. maxMarkers:4,
  69089. //showGuideLine: true: true,
  69090. isRect:true,
  69091. measureType: 'Rect Area'});
  69092. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69093. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69094. $.jstree.reference(jsonNode.id).deselect_all();
  69095. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69096. }
  69097. ));
  69098. // rect area horizontal
  69099. elToolbar.append(this.createToolIcon(
  69100. Potree.resourcePath + '/icons/area.svg',
  69101. '[title]tt.area_horizontal_rect',
  69102. () => {
  69103. $('#menu_measurements').next().slideDown();
  69104. let measurement = this.measuringTool.startInsertion({
  69105. showDistances: true,
  69106. showArea: true,
  69107. closed: true,
  69108. minMarkers:4,
  69109. maxMarkers:4,
  69110. //showGuideLine: true: true,
  69111. isRect:true,
  69112. faceDirection:"horizontal",
  69113. measureType: 'Hor Rect Area'});
  69114. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69115. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69116. $.jstree.reference(jsonNode.id).deselect_all();
  69117. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69118. }
  69119. ));
  69120. // rect area vertical
  69121. elToolbar.append(this.createToolIcon(
  69122. Potree.resourcePath + '/icons/area.svg',
  69123. '[title]tt.area_vertical_rect',
  69124. () => {
  69125. $('#menu_measurements').next().slideDown();
  69126. let measurement = this.measuringTool.startInsertion({
  69127. showDistances: true,
  69128. showArea: true,
  69129. closed: true,
  69130. minMarkers:4,
  69131. maxMarkers:4,
  69132. //showGuideLine: true: true,
  69133. isRect:true,
  69134. faceDirection:"vertical",
  69135. measureType: 'Ver Rect Area'});
  69136. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69137. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
  69138. $.jstree.reference(jsonNode.id).deselect_all();
  69139. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69140. }
  69141. ));
  69142. // VOLUME
  69143. elToolbar.append(this.createToolIcon(
  69144. Potree.resourcePath + '/icons/volume.svg',
  69145. '[title]tt.volume_measurement',
  69146. () => {
  69147. let volume = this.volumeTool.startInsertion();
  69148. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69149. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === volume.uuid);
  69150. $.jstree.reference(jsonNode.id).deselect_all();
  69151. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69152. }
  69153. ));
  69154. // SPHERE VOLUME
  69155. elToolbar.append(this.createToolIcon(
  69156. Potree.resourcePath + '/icons/sphere_distances.svg',
  69157. '[title]tt.volume_measurement',
  69158. () => {
  69159. let volume = this.volumeTool.startInsertion({type: SphereVolume});
  69160. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69161. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === volume.uuid);
  69162. $.jstree.reference(jsonNode.id).deselect_all();
  69163. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69164. }
  69165. ));
  69166. // PROFILE
  69167. elToolbar.append(this.createToolIcon(
  69168. Potree.resourcePath + '/icons/profile.svg',
  69169. '[title]tt.height_profile',
  69170. () => {
  69171. $('#menu_measurements').next().slideDown(); ;
  69172. let profile = this.profileTool.startInsertion();
  69173. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69174. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === profile.uuid);
  69175. $.jstree.reference(jsonNode.id).deselect_all();
  69176. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69177. }
  69178. ));
  69179. // ANNOTATION
  69180. elToolbar.append(this.createToolIcon(
  69181. Potree.resourcePath + '/icons/annotation.svg',
  69182. '[title]tt.annotation',
  69183. () => {
  69184. $('#menu_measurements').next().slideDown(); ;
  69185. let annotation = this.viewer.annotationTool.startInsertion();
  69186. let annotationsRoot = $("#jstree_scene").jstree().get_json("annotations");
  69187. let jsonNode = annotationsRoot.children.find(child => child.data.uuid === annotation.uuid);
  69188. $.jstree.reference(jsonNode.id).deselect_all();
  69189. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69190. }
  69191. ));
  69192. // REMOVE ALL
  69193. elToolbar.append(this.createToolIcon(
  69194. Potree.resourcePath + '/icons/reset_tools.svg',
  69195. '[title]tt.remove_all_measurement',
  69196. () => {
  69197. this.viewer.scene.removeAllMeasurements();
  69198. }
  69199. ));
  69200. { // SHOW / HIDE Measurements
  69201. let elShow = $("#measurement_options_show");
  69202. elShow.selectgroup({title: "Show/Hide labels"});
  69203. elShow.find("input").click( (e) => {
  69204. const show = e.target.value === "SHOW";
  69205. this.measuringTool.showLabels = show;
  69206. });
  69207. let currentShow = this.measuringTool.showLabels ? "SHOW" : "HIDE";
  69208. elShow.find(`input[value=${currentShow}]`).trigger("click");
  69209. }
  69210. }
  69211. initScene(){
  69212. let elScene = $("#menu_scene");
  69213. let elObjects = elScene.next().find("#scene_objects");
  69214. let elProperties = elScene.next().find("#scene_object_properties");
  69215. {
  69216. let elExport = elScene.next().find("#scene_export");
  69217. let geoJSONIcon = `${Potree.resourcePath}/icons/file_geojson.svg`;
  69218. let dxfIcon = `${Potree.resourcePath}/icons/file_dxf.svg`;
  69219. let potreeIcon = `${Potree.resourcePath}/icons/file_potree.svg`;
  69220. elExport.append(`
  69221. Export: <br>
  69222. <a href="#" download="measure.json"><img name="geojson_export_button" src="${geoJSONIcon}" class="button-icon" style="height: 24px" /></a>
  69223. <a href="#" download="measure.dxf"><img name="dxf_export_button" src="${dxfIcon}" class="button-icon" style="height: 24px" /></a>
  69224. <a href="#" download="potree.json5"><img name="potree_export_button" src="${potreeIcon}" class="button-icon" style="height: 24px" /></a>
  69225. `);
  69226. let elDownloadJSON = elExport.find("img[name=geojson_export_button]").parent();
  69227. elDownloadJSON.click( (event) => {
  69228. let scene = this.viewer.scene;
  69229. let measurements = [...scene.measurements, ...scene.profiles, ...scene.volumes];
  69230. if(measurements.length > 0){
  69231. let geoJson = GeoJSONExporter.toString(measurements);
  69232. let url = window.URL.createObjectURL(new Blob([geoJson], {type: 'data:application/octet-stream'}));
  69233. elDownloadJSON.attr('href', url);
  69234. }else {
  69235. this.viewer.postError("nothing to export");
  69236. event.preventDefault();
  69237. }
  69238. });
  69239. let elDownloadDXF = elExport.find("img[name=dxf_export_button]").parent();
  69240. elDownloadDXF.click( (event) => {
  69241. let scene = this.viewer.scene;
  69242. let measurements = [...scene.measurements, ...scene.profiles, ...scene.volumes];
  69243. if(measurements.length > 0){
  69244. let dxf = DXFExporter.toString(measurements);
  69245. let url = window.URL.createObjectURL(new Blob([dxf], {type: 'data:application/octet-stream'}));
  69246. elDownloadDXF.attr('href', url);
  69247. }else {
  69248. this.viewer.postError("no measurements to export");
  69249. event.preventDefault();
  69250. }
  69251. });
  69252. let elDownloadPotree = elExport.find("img[name=potree_export_button]").parent();
  69253. elDownloadPotree.click( (event) => {
  69254. let data = Potree.saveProject(this.viewer);
  69255. let dataString = lib.stringify(data, null, "\t");
  69256. let url = window.URL.createObjectURL(new Blob([dataString], {type: 'data:application/octet-stream'}));
  69257. elDownloadPotree.attr('href', url);
  69258. });
  69259. }
  69260. let propertiesPanel = new PropertiesPanel(elProperties, this.viewer);
  69261. propertiesPanel.setScene(this.viewer.scene);
  69262. localStorage.removeItem('jstree');
  69263. let tree = $(`<div id="jstree_scene"></div>`);
  69264. elObjects.append(tree);
  69265. tree.jstree({
  69266. 'plugins': ["checkbox", "state"],
  69267. 'core': {
  69268. "dblclick_toggle": false,
  69269. "state": {
  69270. "checked" : true
  69271. },
  69272. 'check_callback': true,
  69273. "expand_selected_onload": true
  69274. },
  69275. "checkbox" : {
  69276. "keep_selected_style": true,
  69277. "three_state": false,
  69278. "whole_node": false,
  69279. "tie_selection": false,
  69280. },
  69281. });
  69282. let createNode = (parent, text, icon, object) => {
  69283. let nodeID = tree.jstree('create_node', parent, {
  69284. "text": text,
  69285. "icon": icon,
  69286. "data": object
  69287. },
  69288. "last", false, false);
  69289. if(object.visible){
  69290. tree.jstree('check_node', nodeID);
  69291. }else {
  69292. tree.jstree('uncheck_node', nodeID);
  69293. }
  69294. return nodeID;
  69295. };
  69296. let pcID = tree.jstree('create_node', "#", { "text": "<b>Point Clouds</b>", "id": "pointclouds"}, "last", false, false);
  69297. let measurementID = tree.jstree('create_node', "#", { "text": "<b>Measurements</b>", "id": "measurements" }, "last", false, false);
  69298. let annotationsID = tree.jstree('create_node', "#", { "text": "<b>Annotations</b>", "id": "annotations" }, "last", false, false);
  69299. let otherID = tree.jstree('create_node', "#", { "text": "<b>Other</b>", "id": "other" }, "last", false, false);
  69300. let vectorsID = tree.jstree('create_node', "#", { "text": "<b>Vectors</b>", "id": "vectors" }, "last", false, false);
  69301. let imagesID = tree.jstree('create_node', "#", { "text": "<b> Images</b>", "id": "images" }, "last", false, false);
  69302. tree.jstree("check_node", pcID);
  69303. tree.jstree("check_node", measurementID);
  69304. tree.jstree("check_node", annotationsID);
  69305. tree.jstree("check_node", otherID);
  69306. tree.jstree("check_node", vectorsID);
  69307. tree.jstree("check_node", imagesID);
  69308. tree.on('create_node.jstree', (e, data) => {
  69309. tree.jstree("open_all");
  69310. });
  69311. tree.on("select_node.jstree", (e, data) => {
  69312. let object = data.node.data;
  69313. propertiesPanel.set(object);
  69314. this.viewer.inputHandler.deselectAll();
  69315. if(object instanceof Volume){
  69316. this.viewer.inputHandler.toggleSelection(object);
  69317. }
  69318. $(this.viewer.renderer.domElement).focus();
  69319. });
  69320. tree.on("deselect_node.jstree", (e, data) => {
  69321. propertiesPanel.set(null);
  69322. });
  69323. tree.on("delete_node.jstree", (e, data) => {
  69324. propertiesPanel.set(null);
  69325. });
  69326. tree.on('dblclick','.jstree-anchor', (e) => {
  69327. let instance = $.jstree.reference(e.target);
  69328. let node = instance.get_node(e.target);
  69329. let object = node.data;
  69330. // ignore double click on checkbox
  69331. if(e.target.classList.contains("jstree-checkbox")){
  69332. return;
  69333. }
  69334. if(object instanceof PointCloudTree){
  69335. let box = this.viewer.getBoundingBox([object]);
  69336. let node = new Object3D();
  69337. node.boundingBox = box;
  69338. this.viewer.zoomTo(node, 1, 500);
  69339. }else if(object instanceof Measure){
  69340. let points = object.points.map(p => p.position);
  69341. let box = new Box3().setFromPoints(points);
  69342. if(box.getSize(new Vector3()).length() == 0){
  69343. box.min = box.max.clone();//禁止相同
  69344. box.expandByVector(new Vector3(1,1,1));
  69345. }
  69346. let node = new Object3D();
  69347. node.boundingBox = box;
  69348. this.viewer.zoomTo(node, 2, 500);
  69349. }else if(object instanceof Profile){
  69350. let points = object.points;
  69351. let box = new Box3().setFromPoints(points);
  69352. if(box.getSize(new Vector3()).length() > 0){
  69353. let node = new Object3D();
  69354. node.boundingBox = box;
  69355. this.viewer.zoomTo(node, 1, 500);
  69356. }
  69357. }else if(object instanceof Volume){
  69358. let box = object.boundingBox.clone().applyMatrix4(object.matrixWorld);
  69359. if(box.getSize(new Vector3()).length() > 0){
  69360. let node = new Object3D();
  69361. node.boundingBox = box;
  69362. this.viewer.zoomTo(node, 1, 500);
  69363. }
  69364. }else if(object instanceof Annotation){
  69365. object.moveHere(this.viewer.scene.getActiveCamera());
  69366. }else if(object instanceof PolygonClipVolume){
  69367. let dir = object.camera.getWorldDirection(new Vector3());
  69368. let target;
  69369. if(object.camera instanceof OrthographicCamera){
  69370. dir.multiplyScalar(object.camera.right);
  69371. target = new Vector3().addVectors(object.camera.position, dir);
  69372. this.viewer.setCameraMode(CameraMode.ORTHOGRAPHIC);
  69373. }else if(object.camera instanceof PerspectiveCamera){
  69374. dir.multiplyScalar(this.viewer.scene.view.radius);
  69375. target = new Vector3().addVectors(object.camera.position, dir);
  69376. this.viewer.setCameraMode(CameraMode.PERSPECTIVE);
  69377. }
  69378. this.viewer.scene.view.position.copy(object.camera.position);
  69379. this.viewer.scene.view.lookAt(target);
  69380. }else if(object.type === "SpotLight"){
  69381. let distance = (object.distance > 0) ? object.distance / 4 : 5 * 1000;
  69382. let position = object.position;
  69383. let target = new Vector3().addVectors(
  69384. position,
  69385. object.getWorldDirection(new Vector3()).multiplyScalar(distance));
  69386. this.viewer.scene.view.position.copy(object.position);
  69387. this.viewer.scene.view.lookAt(target);
  69388. }else if(object instanceof Object3D){
  69389. let box = new Box3().setFromObject(object);
  69390. if(box.getSize(new Vector3()).length() > 0){
  69391. let node = new Object3D();
  69392. node.boundingBox = box;
  69393. this.viewer.zoomTo(node, 1, 500);
  69394. }
  69395. }else if(object instanceof OrientedImage){
  69396. // TODO zoom to images
  69397. // let box = new THREE.Box3().setFromObject(object);
  69398. // if(box.getSize(new THREE.Vector3()).length() > 0){
  69399. // let node = new THREE.Object3D();
  69400. // node.boundingBox = box;
  69401. // this.viewer.zoomTo(node, 1, 500);
  69402. // }
  69403. }else if(object instanceof Images360){
  69404. // TODO
  69405. }else if(object instanceof Geopackage){
  69406. // TODO
  69407. }
  69408. });
  69409. tree.on("uncheck_node.jstree", (e, data) => {
  69410. let object = data.node.data;
  69411. if(object){
  69412. object.visible = false;
  69413. }
  69414. });
  69415. tree.on("check_node.jstree", (e, data) => {
  69416. let object = data.node.data;
  69417. if(object){
  69418. object.visible = true;
  69419. }
  69420. });
  69421. let onPointCloudAdded = (e) => {
  69422. let pointcloud = e.pointcloud;
  69423. let cloudIcon = `${Potree.resourcePath}/icons/cloud.svg`;
  69424. let node = createNode(pcID, pointcloud.name, cloudIcon, pointcloud);
  69425. pointcloud.addEventListener("visibility_changed", () => {
  69426. if(pointcloud.visible){
  69427. tree.jstree('check_node', node);
  69428. }else {
  69429. tree.jstree('uncheck_node', node);
  69430. }
  69431. });
  69432. };
  69433. let onMeasurementAdded = (e) => {
  69434. let measurement = e.measurement;
  69435. let icon = Utils.getMeasurementIcon(measurement);
  69436. createNode(measurementID, measurement.name, icon, measurement);
  69437. };
  69438. let onVolumeAdded = (e) => {
  69439. let volume = e.volume;
  69440. let icon = Utils.getMeasurementIcon(volume);
  69441. let node = createNode(measurementID, volume.name, icon, volume);
  69442. volume.addEventListener("visibility_changed", () => {
  69443. if(volume.visible){
  69444. tree.jstree('check_node', node);
  69445. }else {
  69446. tree.jstree('uncheck_node', node);
  69447. }
  69448. });
  69449. };
  69450. let onProfileAdded = (e) => {
  69451. let profile = e.profile;
  69452. let icon = Utils.getMeasurementIcon(profile);
  69453. createNode(measurementID, profile.name, icon, profile);
  69454. };
  69455. let onAnnotationAdded = (e) => {
  69456. let annotation = e.annotation;
  69457. let annotationIcon = `${Potree.resourcePath}/icons/annotation.svg`;
  69458. let parentID = this.annotationMapping.get(annotation.parent);
  69459. let annotationID = createNode(parentID, annotation.title, annotationIcon, annotation);
  69460. this.annotationMapping.set(annotation, annotationID);
  69461. annotation.addEventListener("annotation_changed", (e) => {
  69462. let annotationsRoot = $("#jstree_scene").jstree().get_json("annotations");
  69463. let jsonNode = annotationsRoot.children.find(child => child.data.uuid === annotation.uuid);
  69464. $.jstree.reference(jsonNode.id).rename_node(jsonNode.id, annotation.title);
  69465. });
  69466. };
  69467. let onCameraAnimationAdded = (e) => {
  69468. const animation = e.animation;
  69469. const animationIcon = `${Potree.resourcePath}/icons/camera_animation.svg`;
  69470. createNode(otherID, "animation", animationIcon, animation);
  69471. };
  69472. let onOrientedImagesAdded = (e) => {
  69473. const images = e.images;
  69474. const imagesIcon = `${Potree.resourcePath}/icons/picture.svg`;
  69475. const node = createNode(imagesID, "images", imagesIcon, images);
  69476. images.addEventListener("visibility_changed", () => {
  69477. if(images.visible){
  69478. tree.jstree('check_node', node);
  69479. }else {
  69480. tree.jstree('uncheck_node', node);
  69481. }
  69482. });
  69483. };
  69484. let onImages360Added = (e) => {
  69485. const images = e.images;
  69486. const imagesIcon = `${Potree.resourcePath}/icons/picture.svg`;
  69487. const node = createNode(imagesID, "360° images", imagesIcon, images);
  69488. images.addEventListener("visibility_changed", () => {
  69489. if(images.visible){
  69490. tree.jstree('check_node', node);
  69491. }else {
  69492. tree.jstree('uncheck_node', node);
  69493. }
  69494. });
  69495. };
  69496. const onGeopackageAdded = (e) => {
  69497. const geopackage = e.geopackage;
  69498. const geopackageIcon = `${Potree.resourcePath}/icons/triangle.svg`;
  69499. const tree = $(`#jstree_scene`);
  69500. const parentNode = "vectors";
  69501. for(const layer of geopackage.node.children){
  69502. const name = layer.name;
  69503. let shpPointsID = tree.jstree('create_node', parentNode, {
  69504. "text": name,
  69505. "icon": geopackageIcon,
  69506. "object": layer,
  69507. "data": layer,
  69508. },
  69509. "last", false, false);
  69510. tree.jstree(layer.visible ? "check_node" : "uncheck_node", shpPointsID);
  69511. }
  69512. };
  69513. this.viewer.scene.addEventListener("pointcloud_added", onPointCloudAdded);
  69514. this.viewer.scene.addEventListener("measurement_added", onMeasurementAdded);
  69515. this.viewer.scene.addEventListener("profile_added", onProfileAdded);
  69516. this.viewer.scene.addEventListener("volume_added", onVolumeAdded);
  69517. this.viewer.scene.addEventListener("camera_animation_added", onCameraAnimationAdded);
  69518. this.viewer.scene.addEventListener("oriented_images_added", onOrientedImagesAdded);
  69519. this.viewer.scene.addEventListener("360_images_added", onImages360Added);
  69520. this.viewer.scene.addEventListener("geopackage_added", onGeopackageAdded);
  69521. this.viewer.scene.addEventListener("polygon_clip_volume_added", onVolumeAdded);
  69522. this.viewer.scene.annotations.addEventListener("annotation_added", onAnnotationAdded);
  69523. let onMeasurementRemoved = (e) => {
  69524. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69525. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.measurement.uuid);
  69526. tree.jstree("delete_node", jsonNode.id);
  69527. };
  69528. let onVolumeRemoved = (e) => {
  69529. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69530. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.volume.uuid);
  69531. tree.jstree("delete_node", jsonNode.id);
  69532. };
  69533. let onPolygonClipVolumeRemoved = (e) => {
  69534. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69535. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.volume.uuid);
  69536. tree.jstree("delete_node", jsonNode.id);
  69537. };
  69538. let onProfileRemoved = (e) => {
  69539. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69540. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.profile.uuid);
  69541. tree.jstree("delete_node", jsonNode.id);
  69542. };
  69543. this.viewer.scene.addEventListener("measurement_removed", onMeasurementRemoved);
  69544. this.viewer.scene.addEventListener("volume_removed", onVolumeRemoved);
  69545. this.viewer.scene.addEventListener("polygon_clip_volume_removed", onPolygonClipVolumeRemoved);
  69546. this.viewer.scene.addEventListener("profile_removed", onProfileRemoved);
  69547. {
  69548. let annotationIcon = `${Potree.resourcePath}/icons/annotation.svg`;
  69549. this.annotationMapping = new Map();
  69550. this.annotationMapping.set(this.viewer.scene.annotations, annotationsID);
  69551. this.viewer.scene.annotations.traverseDescendants(annotation => {
  69552. let parentID = this.annotationMapping.get(annotation.parent);
  69553. let annotationID = createNode(parentID, annotation.title, annotationIcon, annotation);
  69554. this.annotationMapping.set(annotation, annotationID);
  69555. });
  69556. }
  69557. const scene = this.viewer.scene;
  69558. for(let pointcloud of scene.pointclouds){
  69559. onPointCloudAdded({pointcloud: pointcloud});
  69560. }
  69561. for(let measurement of scene.measurements){
  69562. onMeasurementAdded({measurement: measurement});
  69563. }
  69564. for(let volume of [...scene.volumes, ...scene.polygonClipVolumes]){
  69565. onVolumeAdded({volume: volume});
  69566. }
  69567. for(let animation of scene.cameraAnimations){
  69568. onCameraAnimationAdded({animation: animation});
  69569. }
  69570. for(let images of scene.orientedImages){
  69571. onOrientedImagesAdded({images: images});
  69572. }
  69573. for(let images of scene.images360){
  69574. onImages360Added({images: images});
  69575. }
  69576. for(const geopackage of scene.geopackages){
  69577. onGeopackageAdded({geopackage: geopackage});
  69578. }
  69579. for(let profile of scene.profiles){
  69580. onProfileAdded({profile: profile});
  69581. }
  69582. {
  69583. createNode(otherID, "Camera", null, new Camera());
  69584. }
  69585. this.viewer.addEventListener("scene_changed", (e) => {
  69586. propertiesPanel.setScene(e.scene);
  69587. e.oldScene.removeEventListener("pointcloud_added", onPointCloudAdded);
  69588. e.oldScene.removeEventListener("measurement_added", onMeasurementAdded);
  69589. e.oldScene.removeEventListener("profile_added", onProfileAdded);
  69590. e.oldScene.removeEventListener("volume_added", onVolumeAdded);
  69591. e.oldScene.removeEventListener("polygon_clip_volume_added", onVolumeAdded);
  69592. e.oldScene.removeEventListener("measurement_removed", onMeasurementRemoved);
  69593. e.scene.addEventListener("pointcloud_added", onPointCloudAdded);
  69594. e.scene.addEventListener("measurement_added", onMeasurementAdded);
  69595. e.scene.addEventListener("profile_added", onProfileAdded);
  69596. e.scene.addEventListener("volume_added", onVolumeAdded);
  69597. e.scene.addEventListener("polygon_clip_volume_added", onVolumeAdded);
  69598. e.scene.addEventListener("measurement_removed", onMeasurementRemoved);
  69599. });
  69600. }
  69601. initClippingTool(){
  69602. this.viewer.addEventListener("cliptask_changed", (event) => {
  69603. console.log("TODO");
  69604. });
  69605. this.viewer.addEventListener("clipmethod_changed", (event) => {
  69606. console.log("TODO");
  69607. });
  69608. {
  69609. let elClipTask = $("#cliptask_options");
  69610. elClipTask.selectgroup({title: "Clip Task"});
  69611. elClipTask.find("input").click( (e) => {
  69612. this.viewer.setClipTask(ClipTask[e.target.value]);
  69613. });
  69614. let currentClipTask = Object.keys(ClipTask)
  69615. .filter(key => ClipTask[key] === this.viewer.clipTask);
  69616. elClipTask.find(`input[value=${currentClipTask}]`).trigger("click");
  69617. }
  69618. {
  69619. let elClipMethod = $("#clipmethod_options");
  69620. elClipMethod.selectgroup({title: "Clip Method"});
  69621. elClipMethod.find("input").click( (e) => {
  69622. this.viewer.setClipMethod(ClipMethod[e.target.value]);
  69623. });
  69624. let currentClipMethod = Object.keys(ClipMethod)
  69625. .filter(key => ClipMethod[key] === this.viewer.clipMethod);
  69626. elClipMethod.find(`input[value=${currentClipMethod}]`).trigger("click");
  69627. }
  69628. let clippingToolBar = $("#clipping_tools");
  69629. // CLIP VOLUME
  69630. clippingToolBar.append(this.createToolIcon(
  69631. Potree.resourcePath + '/icons/clip_volume.svg',
  69632. '[title]tt.clip_volume',
  69633. () => {
  69634. let item = this.volumeTool.startInsertion({clip: true});
  69635. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69636. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === item.uuid);
  69637. $.jstree.reference(jsonNode.id).deselect_all();
  69638. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69639. }
  69640. ));
  69641. // CLIP POLYGON
  69642. clippingToolBar.append(this.createToolIcon(
  69643. Potree.resourcePath + "/icons/clip-polygon.svg",
  69644. "[title]tt.clip_polygon",
  69645. () => {
  69646. let item = this.viewer.clippingTool.startInsertion({type: "polygon"});
  69647. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69648. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === item.uuid);
  69649. $.jstree.reference(jsonNode.id).deselect_all();
  69650. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69651. }
  69652. ));
  69653. {// SCREEN BOX SELECT
  69654. let boxSelectTool = new ScreenBoxSelectTool(this.viewer);
  69655. clippingToolBar.append(this.createToolIcon(
  69656. Potree.resourcePath + "/icons/clip-screen.svg",
  69657. "[title]tt.screen_clip_box",
  69658. () => {
  69659. if(!(this.viewer.scene.getActiveCamera() instanceof OrthographicCamera)){
  69660. this.viewer.postMessage(`Switch to Orthographic Camera Mode before using the Screen-Box-Select tool.`,
  69661. {duration: 2000});
  69662. return;
  69663. }
  69664. let item = boxSelectTool.startInsertion();
  69665. let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
  69666. let jsonNode = measurementsRoot.children.find(child => child.data.uuid === item.uuid);
  69667. $.jstree.reference(jsonNode.id).deselect_all();
  69668. $.jstree.reference(jsonNode.id).select_node(jsonNode.id);
  69669. }
  69670. ));
  69671. }
  69672. { // REMOVE CLIPPING TOOLS
  69673. clippingToolBar.append(this.createToolIcon(
  69674. Potree.resourcePath + "/icons/remove.svg",
  69675. "[title]tt.remove_all_clipping_volumes",
  69676. () => {
  69677. this.viewer.scene.removeAllClipVolumes();
  69678. }
  69679. ));
  69680. }
  69681. }
  69682. initFilters(){
  69683. this.initClassificationList();
  69684. this.initReturnFilters();
  69685. this.initGPSTimeFilters();
  69686. this.initPointSourceIDFilters();
  69687. }
  69688. initReturnFilters(){
  69689. let elReturnFilterPanel = $('#return_filter_panel');
  69690. { // RETURN NUMBER
  69691. let sldReturnNumber = elReturnFilterPanel.find('#sldReturnNumber');
  69692. let lblReturnNumber = elReturnFilterPanel.find('#lblReturnNumber');
  69693. sldReturnNumber.slider({
  69694. range: true,
  69695. min: 0, max: 7, step: 1,
  69696. values: [0, 7],
  69697. slide: (event, ui) => {
  69698. this.viewer.setFilterReturnNumberRange(ui.values[0], ui.values[1]);
  69699. }
  69700. });
  69701. let onReturnNumberChanged = (event) => {
  69702. let [from, to] = this.viewer.filterReturnNumberRange;
  69703. lblReturnNumber[0].innerHTML = `${from} to ${to}`;
  69704. sldReturnNumber.slider({values: [from, to]});
  69705. };
  69706. this.viewer.addEventListener('filter_return_number_range_changed', onReturnNumberChanged);
  69707. onReturnNumberChanged();
  69708. }
  69709. { // NUMBER OF RETURNS
  69710. let sldNumberOfReturns = elReturnFilterPanel.find('#sldNumberOfReturns');
  69711. let lblNumberOfReturns = elReturnFilterPanel.find('#lblNumberOfReturns');
  69712. sldNumberOfReturns.slider({
  69713. range: true,
  69714. min: 0, max: 7, step: 1,
  69715. values: [0, 7],
  69716. slide: (event, ui) => {
  69717. this.viewer.setFilterNumberOfReturnsRange(ui.values[0], ui.values[1]);
  69718. }
  69719. });
  69720. let onNumberOfReturnsChanged = (event) => {
  69721. let [from, to] = this.viewer.filterNumberOfReturnsRange;
  69722. lblNumberOfReturns[0].innerHTML = `${from} to ${to}`;
  69723. sldNumberOfReturns.slider({values: [from, to]});
  69724. };
  69725. this.viewer.addEventListener('filter_number_of_returns_range_changed', onNumberOfReturnsChanged);
  69726. onNumberOfReturnsChanged();
  69727. }
  69728. }
  69729. initGPSTimeFilters(){
  69730. let elGPSTimeFilterPanel = $('#gpstime_filter_panel');
  69731. {
  69732. let slider = new HierarchicalSlider({
  69733. levels: 4,
  69734. slide: (event) => {
  69735. this.viewer.setFilterGPSTimeRange(...event.values);
  69736. },
  69737. });
  69738. let initialized = false;
  69739. let initialize = () => {
  69740. let elRangeContainer = $("#gpstime_multilevel_range_container");
  69741. elRangeContainer[0].prepend(slider.element);
  69742. let extent = this.viewer.getGpsTimeExtent();
  69743. slider.setRange(extent);
  69744. slider.setValues(extent);
  69745. initialized = true;
  69746. };
  69747. this.viewer.addEventListener("update", (e) => {
  69748. let extent = this.viewer.getGpsTimeExtent();
  69749. let gpsTimeAvailable = extent[0] !== Infinity;
  69750. if(!initialized && gpsTimeAvailable){
  69751. initialize();
  69752. }
  69753. slider.setRange(extent);
  69754. });
  69755. }
  69756. {
  69757. const txtGpsTime = elGPSTimeFilterPanel.find("#txtGpsTime");
  69758. const btnFindGpsTime = elGPSTimeFilterPanel.find("#btnFindGpsTime");
  69759. let targetTime = null;
  69760. txtGpsTime.on("input", (e) => {
  69761. const str = txtGpsTime.val();
  69762. if(!isNaN(str)){
  69763. const value = parseFloat(str);
  69764. targetTime = value;
  69765. txtGpsTime.css("background-color", "");
  69766. }else {
  69767. targetTime = null;
  69768. txtGpsTime.css("background-color", "#ff9999");
  69769. }
  69770. });
  69771. btnFindGpsTime.click( () => {
  69772. if(targetTime !== null){
  69773. viewer.moveToGpsTimeVicinity(targetTime);
  69774. }
  69775. });
  69776. }
  69777. }
  69778. initPointSourceIDFilters() {
  69779. let elPointSourceIDFilterPanel = $('#pointsourceid_filter_panel');
  69780. {
  69781. let slider = new HierarchicalSlider({
  69782. levels: 4,
  69783. range: [0, 65535],
  69784. precision: 1,
  69785. slide: (event) => {
  69786. let values = event.values;
  69787. this.viewer.setFilterPointSourceIDRange(values[0], values[1]);
  69788. }
  69789. });
  69790. let initialized = false;
  69791. let initialize = () => {
  69792. elPointSourceIDFilterPanel[0].prepend(slider.element);
  69793. initialized = true;
  69794. };
  69795. this.viewer.addEventListener("update", (e) => {
  69796. let extent = this.viewer.filterPointSourceIDRange;
  69797. if(!initialized){
  69798. initialize();
  69799. slider.setValues(extent);
  69800. }
  69801. });
  69802. }
  69803. // let lblPointSourceID = elPointSourceIDFilterPanel.find("#lblPointSourceID");
  69804. // let elPointSourceID = elPointSourceIDFilterPanel.find("#spnPointSourceID");
  69805. // let slider = new ZoomableSlider();
  69806. // elPointSourceID[0].appendChild(slider.element);
  69807. // slider.update();
  69808. // slider.change( () => {
  69809. // let range = slider.chosenRange;
  69810. // this.viewer.setFilterPointSourceIDRange(range[0], range[1]);
  69811. // });
  69812. // let onPointSourceIDExtentChanged = (event) => {
  69813. // let range = this.viewer.filterPointSourceIDExtent;
  69814. // slider.setVisibleRange(range);
  69815. // };
  69816. // let onPointSourceIDChanged = (event) => {
  69817. // let range = this.viewer.filterPointSourceIDRange;
  69818. // let precision = 1;
  69819. // let from = `${Utils.addCommas(range[0].toFixed(precision))}`;
  69820. // let to = `${Utils.addCommas(range[1].toFixed(precision))}`;
  69821. // lblPointSourceID[0].innerHTML = `${from} to ${to}`;
  69822. // slider.setRange(range);
  69823. // };
  69824. // this.viewer.addEventListener('filter_point_source_id_range_changed', onPointSourceIDChanged);
  69825. // this.viewer.addEventListener('filter_point_source_id_extent_changed', onPointSourceIDExtentChanged);
  69826. }
  69827. initClassificationList(){
  69828. let elClassificationList = $('#classificationList');
  69829. let addClassificationItem = (code, name) => {
  69830. const classification = this.viewer.classifications[code];
  69831. const inputID = 'chkClassification_' + code;
  69832. const colorPickerID = 'colorPickerClassification_' + code;
  69833. const checked = classification.visible ? "checked" : "";
  69834. let element = $(`
  69835. <li>
  69836. <label style="whitespace: nowrap; display: flex">
  69837. <input id="${inputID}" type="checkbox" ${checked}/>
  69838. <span style="flex-grow: 1">${name}</span>
  69839. <input id="${colorPickerID}" style="zoom: 0.5" />
  69840. </label>
  69841. </li>
  69842. `);
  69843. const elInput = element.find('input');
  69844. const elColorPicker = element.find(`#${colorPickerID}`);
  69845. elInput.click(event => {
  69846. this.viewer.setClassificationVisibility(code, event.target.checked);
  69847. });
  69848. let defaultColor = classification.color.map(c => c * 255).join(", ");
  69849. defaultColor = `rgb(${defaultColor})`;
  69850. elColorPicker.spectrum({
  69851. // flat: true,
  69852. color: defaultColor,
  69853. showInput: true,
  69854. preferredFormat: 'rgb',
  69855. cancelText: '',
  69856. chooseText: 'Apply',
  69857. move: color => {
  69858. let rgb = color.toRgb();
  69859. const c = [rgb.r / 255, rgb.g / 255, rgb.b / 255, 1];
  69860. classification.color = c;
  69861. },
  69862. change: color => {
  69863. let rgb = color.toRgb();
  69864. const c = [rgb.r / 255, rgb.g / 255, rgb.b / 255, 1];
  69865. classification.color = c;
  69866. }
  69867. });
  69868. elClassificationList.append(element);
  69869. };
  69870. const addToggleAllButton = () => { // toggle all button
  69871. const element = $(`
  69872. <li>
  69873. <label style="whitespace: nowrap">
  69874. <input id="toggleClassificationFilters" type="checkbox" checked/>
  69875. <span>show/hide all</span>
  69876. </label>
  69877. </li>
  69878. `);
  69879. let elInput = element.find('input');
  69880. elInput.click(event => {
  69881. this.viewer.toggleAllClassificationsVisibility();
  69882. });
  69883. elClassificationList.append(element);
  69884. };
  69885. const addInvertButton = () => {
  69886. const element = $(`
  69887. <li>
  69888. <input type="button" value="invert" />
  69889. </li>
  69890. `);
  69891. let elInput = element.find('input');
  69892. elInput.click( () => {
  69893. const classifications = this.viewer.classifications;
  69894. for(let key of Object.keys(classifications)){
  69895. let value = classifications[key];
  69896. this.viewer.setClassificationVisibility(key, !value.visible);
  69897. }
  69898. });
  69899. elClassificationList.append(element);
  69900. };
  69901. const populate = () => {
  69902. addToggleAllButton();
  69903. for (let classID in this.viewer.classifications) {
  69904. addClassificationItem(classID, this.viewer.classifications[classID].name);
  69905. }
  69906. addInvertButton();
  69907. };
  69908. populate();
  69909. this.viewer.addEventListener("classifications_changed", () => {
  69910. elClassificationList.empty();
  69911. populate();
  69912. });
  69913. this.viewer.addEventListener("classification_visibility_changed", () => {
  69914. { // set checked state of classification buttons
  69915. for(const classID of Object.keys(this.viewer.classifications)){
  69916. const classValue = this.viewer.classifications[classID];
  69917. let elItem = elClassificationList.find(`#chkClassification_${classID}`);
  69918. elItem.prop("checked", classValue.visible);
  69919. }
  69920. }
  69921. { // set checked state of toggle button based on state of all other buttons
  69922. let numVisible = 0;
  69923. let numItems = 0;
  69924. for(const key of Object.keys(this.viewer.classifications)){
  69925. if(this.viewer.classifications[key].visible){
  69926. numVisible++;
  69927. }
  69928. numItems++;
  69929. }
  69930. const allVisible = numVisible === numItems;
  69931. let elToggle = elClassificationList.find("#toggleClassificationFilters");
  69932. elToggle.prop("checked", allVisible);
  69933. }
  69934. });
  69935. }
  69936. initAccordion(){
  69937. $('.accordion > h3').each(function(){
  69938. let header = $(this);
  69939. let content = $(this).next();
  69940. //header.addClass('accordion-header ui-widget');
  69941. //content.addClass('accordion-content ui-widget');
  69942. content.hide();
  69943. header.click(() => {
  69944. content.slideToggle();
  69945. });
  69946. });
  69947. let languages = [
  69948. ["EN", "en"],
  69949. ["FR", "fr"],
  69950. ["DE", "de"],
  69951. ["JP", "jp"],
  69952. ["ES", "es"],
  69953. ["SE", "se"],
  69954. ["ZH", "zh"]
  69955. ];
  69956. let elLanguages = $('#potree_languages');
  69957. for(let i = 0; i < languages.length; i++){
  69958. let [key, value] = languages[i];
  69959. let element = $(`<a>${key}</a>`);
  69960. element.click(() => this.viewer.setLanguage(value));
  69961. if(i === 0){
  69962. element.css("margin-left", "30px");
  69963. }
  69964. elLanguages.append(element);
  69965. if(i < languages.length - 1){
  69966. elLanguages.append($(document.createTextNode(' - ')));
  69967. }
  69968. }
  69969. // to close all, call
  69970. // $(".accordion > div").hide()
  69971. // to open the, for example, tool menu, call:
  69972. // $("#menu_tools").next().show()
  69973. }
  69974. initAppearance(){
  69975. const sldPointBudget = this.dom.find('#sldPointBudget');
  69976. sldPointBudget.slider({
  69977. value: this.viewer.getPointBudget(),
  69978. min: 100 * 1000,
  69979. max: 10 * 1000 * 1000,
  69980. step: 1000,
  69981. slide: (event, ui) => { this.viewer.setPointBudget(ui.value); }
  69982. });
  69983. this.dom.find('#sldFOV').slider({
  69984. value: this.viewer.getFOV(),
  69985. min: 20,
  69986. max: 100,
  69987. step: 1,
  69988. slide: (event, ui) => { this.viewer.setFOV(ui.value); }
  69989. });
  69990. $('#sldEDLRadius').slider({
  69991. value: this.viewer.getEDLRadius(),
  69992. min: 1,
  69993. max: 4,
  69994. step: 0.01,
  69995. slide: (event, ui) => { this.viewer.setEDLRadius(ui.value); }
  69996. });
  69997. $('#sldEDLStrength').slider({
  69998. value: this.viewer.getEDLStrength(),
  69999. min: 0,
  70000. max: 5,
  70001. step: 0.01,
  70002. slide: (event, ui) => { this.viewer.setEDLStrength(ui.value); }
  70003. });
  70004. $('#sldEDLOpacity').slider({
  70005. value: this.viewer.getEDLOpacity(),
  70006. min: 0,
  70007. max: 1,
  70008. step: 0.01,
  70009. slide: (event, ui) => { this.viewer.setEDLOpacity(ui.value); }
  70010. });
  70011. this.viewer.addEventListener('point_budget_changed', (event) => {
  70012. $('#lblPointBudget')[0].innerHTML = Utils.addCommas(this.viewer.getPointBudget());
  70013. sldPointBudget.slider({value: this.viewer.getPointBudget()});
  70014. });
  70015. this.viewer.addEventListener('fov_changed', (event) => {
  70016. $('#lblFOV')[0].innerHTML = parseInt(this.viewer.getFOV());
  70017. $('#sldFOV').slider({value: this.viewer.getFOV()});
  70018. });
  70019. this.viewer.addEventListener('use_edl_changed', (event) => {
  70020. $('#chkEDLEnabled')[0].checked = this.viewer.getEDLEnabled();
  70021. });
  70022. this.viewer.addEventListener('edl_radius_changed', (event) => {
  70023. $('#lblEDLRadius')[0].innerHTML = this.viewer.getEDLRadius().toFixed(1);
  70024. $('#sldEDLRadius').slider({value: this.viewer.getEDLRadius()});
  70025. });
  70026. this.viewer.addEventListener('edl_strength_changed', (event) => {
  70027. $('#lblEDLStrength')[0].innerHTML = this.viewer.getEDLStrength().toFixed(1);
  70028. $('#sldEDLStrength').slider({value: this.viewer.getEDLStrength()});
  70029. });
  70030. this.viewer.addEventListener('background_changed', (event) => {
  70031. $("input[name=background][value='" + this.viewer.getBackground() + "']").prop('checked', true);
  70032. });
  70033. $('#lblPointBudget')[0].innerHTML = Utils.addCommas(this.viewer.getPointBudget());
  70034. $('#lblFOV')[0].innerHTML = parseInt(this.viewer.getFOV());
  70035. $('#lblEDLRadius')[0].innerHTML = this.viewer.getEDLRadius().toFixed(1);
  70036. $('#lblEDLStrength')[0].innerHTML = this.viewer.getEDLStrength().toFixed(1);
  70037. $('#chkEDLEnabled')[0].checked = this.viewer.getEDLEnabled();
  70038. {
  70039. let elBackground = $(`#background_options`);
  70040. elBackground.selectgroup();
  70041. elBackground.find("input").click( (e) => {
  70042. this.viewer.setBackground(e.target.value);
  70043. });
  70044. let currentBackground = this.viewer.getBackground();
  70045. try{
  70046. $(`input[name=background_options][value=${currentBackground}]`).trigger("click");
  70047. }catch(e){}
  70048. }
  70049. $('#chkEDLEnabled').click( () => {
  70050. this.viewer.setEDLEnabled($('#chkEDLEnabled').prop("checked"));
  70051. });
  70052. }
  70053. initNavigation(){
  70054. let elNavigation = $('#navigation');
  70055. let sldMoveSpeed = $('#sldMoveSpeed');
  70056. let lblMoveSpeed = $('#lblMoveSpeed');
  70057. elNavigation.append(this.createToolIcon(
  70058. Potree.resourcePath + '/icons/earth_controls_1.png',
  70059. '[title]tt.earth_control',
  70060. () => { this.viewer.setControls(this.viewer.earthControls); }
  70061. ));
  70062. elNavigation.append(this.createToolIcon(
  70063. Potree.resourcePath + '/icons/fps_controls.svg',
  70064. '[title]tt.flight_control',
  70065. () => {
  70066. this.viewer.setControls(this.viewer.fpControls);
  70067. this.viewer.fpControls.lockElevation = false;
  70068. }
  70069. ));
  70070. elNavigation.append(this.createToolIcon(
  70071. Potree.resourcePath + '/icons/helicopter_controls.svg',
  70072. '[title]tt.heli_control',
  70073. () => {
  70074. this.viewer.setControls(this.viewer.fpControls);
  70075. this.viewer.fpControls.lockElevation = true;
  70076. }
  70077. ));
  70078. elNavigation.append(this.createToolIcon(
  70079. Potree.resourcePath + '/icons/orbit_controls.svg',
  70080. '[title]tt.orbit_control',
  70081. () => { this.viewer.setControls(this.viewer.orbitControls); }
  70082. ));
  70083. elNavigation.append(this.createToolIcon(
  70084. Potree.resourcePath + '/icons/focus.svg',
  70085. '[title]tt.focus_control',
  70086. () => { this.viewer.fitToScreen(); }
  70087. ));
  70088. elNavigation.append(this.createToolIcon(
  70089. Potree.resourcePath + "/icons/navigation_cube.svg",
  70090. "[title]tt.navigation_cube_control",
  70091. () => {this.viewer.toggleNavigationCube();}
  70092. ));
  70093. elNavigation.append(this.createToolIcon(
  70094. Potree.resourcePath + "/images/compas.svg",
  70095. "[title]tt.compass",
  70096. () => {
  70097. const visible = !this.viewer.compass.isVisible();
  70098. this.viewer.compass.setVisible(visible);
  70099. }
  70100. ));
  70101. elNavigation.append(this.createToolIcon(
  70102. Potree.resourcePath + "/icons/camera_animation.svg",
  70103. "[title]tt.camera_animation",
  70104. () => {
  70105. const animation = CameraAnimation.defaultFromView(this.viewer);
  70106. viewer.scene.addCameraAnimation(animation);
  70107. }
  70108. ));
  70109. elNavigation.append("<br>");
  70110. elNavigation.append(this.createToolIcon(
  70111. Potree.resourcePath + "/icons/left.svg",
  70112. "[title]tt.left_view_control",
  70113. () => {this.viewer.setLeftView();}
  70114. ));
  70115. elNavigation.append(this.createToolIcon(
  70116. Potree.resourcePath + "/icons/right.svg",
  70117. "[title]tt.right_view_control",
  70118. () => {this.viewer.setRightView();}
  70119. ));
  70120. elNavigation.append(this.createToolIcon(
  70121. Potree.resourcePath + "/icons/front.svg",
  70122. "[title]tt.front_view_control",
  70123. () => {this.viewer.setFrontView();}
  70124. ));
  70125. elNavigation.append(this.createToolIcon(
  70126. Potree.resourcePath + "/icons/back.svg",
  70127. "[title]tt.back_view_control",
  70128. () => {this.viewer.setBackView();}
  70129. ));
  70130. elNavigation.append(this.createToolIcon(
  70131. Potree.resourcePath + "/icons/top.svg",
  70132. "[title]tt.top_view_control",
  70133. () => {this.viewer.setTopView();}
  70134. ));
  70135. elNavigation.append(this.createToolIcon(
  70136. Potree.resourcePath + "/icons/bottom.svg",
  70137. "[title]tt.bottom_view_control",
  70138. () => {this.viewer.setBottomView();}
  70139. ));
  70140. let elCameraProjection = $(`
  70141. <selectgroup id="camera_projection_options">
  70142. <option id="camera_projection_options_perspective" value="PERSPECTIVE">Perspective</option>
  70143. <option id="camera_projection_options_orthigraphic" value="ORTHOGRAPHIC">Orthographic</option>
  70144. </selectgroup>
  70145. `);
  70146. elNavigation.append(elCameraProjection);
  70147. elCameraProjection.selectgroup({title: "Camera Projection"});
  70148. elCameraProjection.find("input").click( (e) => {
  70149. this.viewer.setCameraMode(CameraMode[e.target.value]);
  70150. });
  70151. let cameraMode = Object.keys(CameraMode)
  70152. .filter(key => CameraMode[key] === this.viewer.scene.cameraMode);
  70153. elCameraProjection.find(`input[value=${cameraMode}]`).trigger("click");
  70154. let speedRange = new Vector2$1(1, 10 * 1000);
  70155. let toLinearSpeed = (value) => {
  70156. return Math.pow(value, 4) * speedRange.y + speedRange.x;
  70157. };
  70158. let toExpSpeed = (value) => {
  70159. return Math.pow((value - speedRange.x) / speedRange.y, 1 / 4);
  70160. };
  70161. sldMoveSpeed.slider({
  70162. value: toExpSpeed(this.viewer.getMoveSpeed()),
  70163. min: 0,
  70164. max: 1,
  70165. step: 0.01,
  70166. slide: (event, ui) => { this.viewer.setMoveSpeed(toLinearSpeed(ui.value)); }
  70167. });
  70168. this.viewer.addEventListener('move_speed_changed', (event) => {
  70169. lblMoveSpeed.html(this.viewer.getMoveSpeed().toFixed(1));
  70170. sldMoveSpeed.slider({value: toExpSpeed(this.viewer.getMoveSpeed())});
  70171. });
  70172. lblMoveSpeed.html(this.viewer.getMoveSpeed().toFixed(1));
  70173. }
  70174. initSettings(){
  70175. {
  70176. $('#sldMinNodeSize').slider({
  70177. value: this.viewer.getMinNodeSize(),
  70178. min: 0,
  70179. max: 1000,
  70180. step: 0.01,
  70181. slide: (event, ui) => { this.viewer.setMinNodeSize(ui.value); }
  70182. });
  70183. this.viewer.addEventListener('minnodesize_changed', (event) => {
  70184. $('#lblMinNodeSize').html(parseInt(this.viewer.getMinNodeSize()));
  70185. $('#sldMinNodeSize').slider({value: this.viewer.getMinNodeSize()});
  70186. });
  70187. $('#lblMinNodeSize').html(parseInt(this.viewer.getMinNodeSize()));
  70188. }
  70189. {
  70190. let elSplatQuality = $("#splat_quality_options");
  70191. elSplatQuality.selectgroup({title: "Splat Quality"});
  70192. elSplatQuality.find("input").click( (e) => {
  70193. if(e.target.value === "standard"){
  70194. this.viewer.useHQ = false;
  70195. }else if(e.target.value === "hq"){
  70196. this.viewer.useHQ = true;
  70197. }
  70198. });
  70199. let currentQuality = this.viewer.useHQ ? "hq" : "standard";
  70200. elSplatQuality.find(`input[value=${currentQuality}]`).trigger("click");
  70201. }
  70202. $('#show_bounding_box').click(() => {
  70203. this.viewer.setShowBoundingBox($('#show_bounding_box').prop("checked"));
  70204. });
  70205. $('#set_freeze').click(() => {
  70206. this.viewer.setFreeze($('#set_freeze').prop("checked"));
  70207. });
  70208. }
  70209. }
  70210. class AnnotationTool extends EventDispatcher{
  70211. constructor (viewer) {
  70212. super();
  70213. this.viewer = viewer;
  70214. this.renderer = viewer.renderer;
  70215. this.sg = new SphereGeometry(0.1);
  70216. this.sm = new MeshNormalMaterial();
  70217. this.s = new Mesh(this.sg, this.sm);
  70218. }
  70219. startInsertion (args = {}) {
  70220. let domElement = this.viewer.renderer.domElement;
  70221. let annotation = new Annotation({
  70222. position: [589748.270, 231444.540, 753.675],
  70223. title: "Annotation Title",
  70224. description: `Annotation Description`,
  70225. radius: 1,//add
  70226. cameraPosition: [589748.270, 231444.540, 753.675],//add
  70227. });
  70228. this.dispatchEvent({type: 'start_inserting_annotation', annotation: annotation});
  70229. const annotations = this.viewer.scene.annotations;
  70230. annotations.add(annotation);
  70231. let callbacks = {
  70232. cancel: null,
  70233. finish: null,
  70234. };
  70235. let insertionCallback = (e) => {
  70236. if (e.button === MOUSE.LEFT) {
  70237. callbacks.finish();
  70238. } else if (e.button === MOUSE.RIGHT) {
  70239. callbacks.cancel();
  70240. }
  70241. };
  70242. callbacks.cancel = e => {
  70243. annotations.remove(annotation);
  70244. domElement.removeEventListener('mouseup', insertionCallback, true);
  70245. };
  70246. callbacks.finish = e => {
  70247. domElement.removeEventListener('mouseup', insertionCallback, true);
  70248. };
  70249. domElement.addEventListener('mouseup', insertionCallback, true);
  70250. let drag = (e) => {
  70251. let camera = e.viewer.scene.getActiveCamera();
  70252. /* let I = Utils.getMousePointCloudIntersection(
  70253. e.drag.end,
  70254. camera,
  70255. e.viewer,
  70256. e.viewer.scene.pointclouds,
  70257. {pickClipped: true}); */
  70258. let I = e.viewer.inputHandler.intersectPoint;
  70259. if (I) {
  70260. this.s.position.copy(I.location);
  70261. annotation.position.copy(I.location);
  70262. annotation.cameraTarget.copy(I.location);//add
  70263. annotation.cameraPosition.copy(camera.position);//add
  70264. }
  70265. };
  70266. let drop = (e) => {
  70267. viewer.scene.scene.remove(this.s);
  70268. this.s.removeEventListener("drag", drag);
  70269. this.s.removeEventListener("drop", drop);
  70270. };
  70271. this.s.addEventListener('drag', drag);
  70272. this.s.addEventListener('drop', drop);
  70273. this.viewer.scene.scene.add(this.s);
  70274. this.viewer.inputHandler.startDragging(this.s);
  70275. return annotation;
  70276. }
  70277. update(){
  70278. // let camera = this.viewer.scene.getActiveCamera();
  70279. // let domElement = this.renderer.domElement;
  70280. // let measurements = this.viewer.scene.measurements;
  70281. // const renderAreaSize = this.renderer.getSize(new THREE.Vector2());
  70282. // let clientWidth = renderAreaSize.width;
  70283. // let clientHeight = renderAreaSize.height;
  70284. }
  70285. render(){
  70286. //this.viewer.renderer.render(this.scene, this.viewer.scene.getActiveCamera());
  70287. }
  70288. };
  70289. class NavigationCube extends Object3D {
  70290. constructor(viewer){
  70291. super();
  70292. this.viewer = viewer;
  70293. let createPlaneMaterial = (img) => {
  70294. let material = new MeshBasicMaterial( {
  70295. depthTest: true,
  70296. depthWrite: true,
  70297. side: DoubleSide
  70298. });
  70299. new TextureLoader().load(
  70300. exports.resourcePath + '/textures/navigation/' + img,
  70301. function(texture) {
  70302. texture.anisotropy = viewer.renderer.capabilities.getMaxAnisotropy();
  70303. material.map = texture;
  70304. material.needsUpdate = true;
  70305. });
  70306. return material;
  70307. };
  70308. let planeGeometry = new PlaneGeometry(1, 1);
  70309. this.front = new Mesh(planeGeometry, createPlaneMaterial('F.png'));
  70310. this.front.position.y = -0.5;
  70311. this.front.rotation.x = Math.PI / 2.0;
  70312. this.front.updateMatrixWorld();
  70313. this.front.name = "F";
  70314. this.add(this.front);
  70315. this.back = new Mesh(planeGeometry, createPlaneMaterial('B.png'));
  70316. this.back.position.y = 0.5;
  70317. this.back.rotation.x = Math.PI / 2.0;
  70318. this.back.updateMatrixWorld();
  70319. this.back.name = "B";
  70320. this.add(this.back);
  70321. this.left = new Mesh(planeGeometry, createPlaneMaterial('L.png'));
  70322. this.left.position.x = -0.5;
  70323. this.left.rotation.y = Math.PI / 2.0;
  70324. this.left.updateMatrixWorld();
  70325. this.left.name = "L";
  70326. this.add(this.left);
  70327. this.right = new Mesh(planeGeometry, createPlaneMaterial('R.png'));
  70328. this.right.position.x = 0.5;
  70329. this.right.rotation.y = Math.PI / 2.0;
  70330. this.right.updateMatrixWorld();
  70331. this.right.name = "R";
  70332. this.add(this.right);
  70333. this.bottom = new Mesh(planeGeometry, createPlaneMaterial('D.png'));
  70334. this.bottom.position.z = -0.5;
  70335. this.bottom.updateMatrixWorld();
  70336. this.bottom.name = "D";
  70337. this.add(this.bottom);
  70338. this.top = new Mesh(planeGeometry, createPlaneMaterial('U.png'));
  70339. this.top.position.z = 0.5;
  70340. this.top.updateMatrixWorld();
  70341. this.top.name = "U";
  70342. this.add(this.top);
  70343. this.width = 150; // in px
  70344. this.camera = new OrthographicCamera(-1, 1, 1, -1, -1, 1);
  70345. this.camera.position.copy(new Vector3(0, 0, 0));
  70346. this.camera.lookAt(new Vector3(0, 1, 0));
  70347. this.camera.updateMatrixWorld();
  70348. this.camera.rotation.order = "ZXY";
  70349. let onMouseDown = (event) => {
  70350. if (!this.visible) {
  70351. return;
  70352. }
  70353. this.pickedFace = null;
  70354. let mouse = new Vector2$1();
  70355. mouse.x = event.clientX - (window.innerWidth - this.width);
  70356. mouse.y = event.clientY;
  70357. if(mouse.x < 0 || mouse.y > this.width) return;
  70358. mouse.x = (mouse.x / this.width) * 2 - 1;
  70359. mouse.y = -(mouse.y / this.width) * 2 + 1;
  70360. let raycaster = new Raycaster();
  70361. raycaster.setFromCamera(mouse, this.camera);
  70362. raycaster.ray.origin.sub(this.camera.getWorldDirection(new Vector3()));
  70363. let intersects = raycaster.intersectObjects(this.children);
  70364. let minDistance = 1000;
  70365. for (let i = 0; i < intersects.length; i++) {
  70366. if(intersects[i].distance < minDistance) {
  70367. this.pickedFace = intersects[i].object.name;
  70368. minDistance = intersects[i].distance;
  70369. }
  70370. }
  70371. if(this.pickedFace) {
  70372. this.viewer.setView(this.pickedFace);
  70373. }
  70374. };
  70375. this.viewer.renderer.domElement.addEventListener('mousedown', onMouseDown, false);
  70376. }
  70377. update(rotation) {
  70378. this.camera.rotation.copy(rotation);
  70379. this.camera.updateMatrixWorld();
  70380. }
  70381. }
  70382. /**
  70383. * @author mschuetz / http://mschuetz.at
  70384. *
  70385. * adapted from THREE.OrbitControls by
  70386. *
  70387. * @author qiao / https://github.com/qiao
  70388. * @author mrdoob / http://mrdoob.com
  70389. * @author alteredq / http://alteredqualia.com/
  70390. * @author WestLangley / http://github.com/WestLangley
  70391. * @author erich666 / http://erichaines.com
  70392. *
  70393. *
  70394. *
  70395. */
  70396. class OrbitControls extends EventDispatcher{
  70397. constructor(viewer){
  70398. super();
  70399. this.viewer = viewer;
  70400. this.renderer = viewer.renderer;
  70401. this.scene = null;
  70402. this.sceneControls = new Scene();
  70403. this.rotationSpeed = 3; //旋转速度
  70404. this.fadeFactor = 100;
  70405. this.yawDelta = 0;
  70406. this.pitchDelta = 0;
  70407. this.panDelta = new Vector2$1(0, 0);
  70408. this.radiusDelta = 0;
  70409. this.doubleClockZoomEnabled = true;
  70410. this.tweens = [];
  70411. this.dollyStart = new Vector2$1;
  70412. this.dollyEnd = new Vector2$1;
  70413. let drag = (e) => {
  70414. if(!this.enabled)return
  70415. let viewport = e.dragViewport;
  70416. if(!viewport || viewport.camera.type == "OrthographicCamera" )return
  70417. //let camera = viewport.camera
  70418. if (e.drag.object !== null) {
  70419. return;
  70420. }
  70421. let mode;
  70422. if(e.isTouch){
  70423. if(e.touches.length == 1){
  70424. mode = 'rotate';
  70425. }else {
  70426. mode = 'scale-pan';
  70427. }
  70428. }else {
  70429. mode = e.buttons === Buttons.LEFT ? 'rotate' : 'pan';
  70430. }
  70431. if (e.drag.startHandled === undefined) {
  70432. e.drag.startHandled = true;
  70433. this.dispatchEvent({type: 'start'});
  70434. }
  70435. let ndrag = e.drag.pointerDelta.clone();//.add(new THREE.Vector2(1,1)).multiplyScalar(0.5)
  70436. ndrag.y *= -1;
  70437. if (mode == 'rotate') {
  70438. this.yawDelta += ndrag.x * this.rotationSpeed;
  70439. this.pitchDelta += ndrag.y * this.rotationSpeed;
  70440. } else if(mode == 'pan'){
  70441. this.panDelta.x += ndrag.x;
  70442. this.panDelta.y += ndrag.y;
  70443. }else if(mode == 'scale-pan'){ //add
  70444. this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  70445. var scale = this.dollyEnd.length() / this.dollyStart.length();
  70446. this.dollyStart.copy(this.dollyEnd);
  70447. this.radiusDelta = (1-scale) * this.scene.view.radius;
  70448. //------------------------
  70449. //平移
  70450. let pointer = new Vector2$1().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
  70451. let delta = new Vector2$1().subVectors(pointer, this.lastScalePointer);
  70452. delta.y *= -1;
  70453. this.panDelta.add(delta);
  70454. this.lastScalePointer = pointer.clone();
  70455. //console.log('scale ',scale, this.radiusDelta)
  70456. }
  70457. this.stopTweens();
  70458. };
  70459. let drop = e => {
  70460. if(!this.enabled)return
  70461. this.dispatchEvent({type: 'end'});
  70462. };
  70463. let scroll = (e) => {
  70464. if(!this.enabled)return
  70465. let resolvedRadius = this.scene.view.radius + this.radiusDelta;
  70466. if(resolvedRadius < 0.1 && e.delta>0)return; //防止缩放太小,导致很慢
  70467. this.radiusDelta += -e.delta * resolvedRadius * 0.1;
  70468. this.stopTweens();
  70469. };
  70470. let dblclick = (e) => {
  70471. if(!this.enabled)return
  70472. if(this.doubleClockZoomEnabled){
  70473. this.zoomToLocation(e.mouse);
  70474. }
  70475. };
  70476. let previousTouch = null;
  70477. let touchStart = e => {
  70478. previousTouch = e;
  70479. };
  70480. let touchEnd = e => {
  70481. previousTouch = e;
  70482. };
  70483. let touchMove = e => {
  70484. if(!this.enabled)return
  70485. if (e.touches.length === 2 && previousTouch.touches.length === 2){
  70486. let prev = previousTouch;
  70487. let curr = e;
  70488. let prevDX = prev.touches[0].pageX - prev.touches[1].pageX;
  70489. let prevDY = prev.touches[0].pageY - prev.touches[1].pageY;
  70490. let prevDist = Math.sqrt(prevDX * prevDX + prevDY * prevDY);
  70491. let currDX = curr.touches[0].pageX - curr.touches[1].pageX;
  70492. let currDY = curr.touches[0].pageY - curr.touches[1].pageY;
  70493. let currDist = Math.sqrt(currDX * currDX + currDY * currDY);
  70494. let delta = currDist / prevDist;
  70495. let resolvedRadius = this.scene.view.radius + this.radiusDelta;
  70496. let newRadius = resolvedRadius / delta;
  70497. this.radiusDelta = newRadius - resolvedRadius;
  70498. this.stopTweens();
  70499. }else if(e.touches.length === 3 && previousTouch.touches.length === 3){
  70500. let prev = previousTouch;
  70501. let curr = e;
  70502. let prevMeanX = (prev.touches[0].pageX + prev.touches[1].pageX + prev.touches[2].pageX) / 3;
  70503. let prevMeanY = (prev.touches[0].pageY + prev.touches[1].pageY + prev.touches[2].pageY) / 3;
  70504. let currMeanX = (curr.touches[0].pageX + curr.touches[1].pageX + curr.touches[2].pageX) / 3;
  70505. let currMeanY = (curr.touches[0].pageY + curr.touches[1].pageY + curr.touches[2].pageY) / 3;
  70506. let delta = {
  70507. x: (currMeanX - prevMeanX) / this.renderer.domElement.clientWidth,
  70508. y: (currMeanY - prevMeanY) / this.renderer.domElement.clientHeight
  70509. };
  70510. this.panDelta.x += delta.x;
  70511. this.panDelta.y += delta.y;
  70512. this.stopTweens();
  70513. }
  70514. previousTouch = e;
  70515. };
  70516. this.addEventListener('touchstart', touchStart);
  70517. this.addEventListener('touchend', touchEnd);
  70518. this.addEventListener('touchmove', touchMove);
  70519. this.viewer.addEventListener('global_drag', drag);
  70520. this.viewer.addEventListener('global_drop', drop);
  70521. this.viewer.addEventListener('global_mousewheel', scroll);
  70522. this.viewer.addEventListener('global_dblclick', dblclick);
  70523. this.viewer.addEventListener('global_touchmove', (e)=>{
  70524. if(e.touches.length>1){//单指的就触发上一句
  70525. //console.log('global_touchmove' )
  70526. drag(e);
  70527. }
  70528. });
  70529. let prepareScale = (e)=>{//触屏的scale
  70530. this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  70531. this.lastScalePointer = new Vector2$1().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
  70532. };
  70533. this.viewer.addEventListener('global_touchstart', (e)=>{
  70534. if(this.enabled && e.touches.length==2){//只监听开头两个指头
  70535. prepareScale(e);
  70536. }
  70537. });
  70538. /* this.viewer.addEventListener('global_touchend', (e)=>{
  70539. if(!this.enabled)return
  70540. if(e.touches.length==1){//停止scale,开始rotate
  70541. prepareRotate(e)
  70542. //this.pointerDragStart = null
  70543. //console.log('只剩一个', e.pointer.toArray())
  70544. }
  70545. }) */
  70546. }
  70547. setScene (scene) {
  70548. this.scene = scene;
  70549. }
  70550. setEnable(enabled){
  70551. this.enabled = enabled;
  70552. }
  70553. stop(){
  70554. this.yawDelta = 0;
  70555. this.pitchDelta = 0;
  70556. this.radiusDelta = 0;
  70557. this.panDelta.set(0, 0);
  70558. }
  70559. /* zoomToLocation(mouse){
  70560. if(!this.enabled)return
  70561. let camera = this.scene.getActiveCamera();
  70562. let I = Utils.getMousePointCloudIntersection(
  70563. null, mouse, this.viewer.inputHandler.pointer,
  70564. camera,
  70565. this.viewer,
  70566. this.scene.pointclouds,
  70567. {pickClipped: true});
  70568. if (I === null) {
  70569. return;
  70570. }
  70571. let targetRadius = 0;
  70572. {
  70573. let minimumJumpDistance = 0.2;
  70574. let domElement = this.renderer.domElement;
  70575. let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer , camera, domElement.clientWidth, domElement.clientHeight);
  70576. let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
  70577. let lastNode = nodes[nodes.length - 1];
  70578. let radius = lastNode.getBoundingSphere(new THREE.Sphere()).radius;
  70579. targetRadius = Math.min(this.scene.view.radius, radius);
  70580. targetRadius = Math.max(minimumJumpDistance, targetRadius);
  70581. }
  70582. let d = this.scene.view.direction.multiplyScalar(-1);
  70583. let cameraTargetPosition = new THREE.Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
  70584. // TODO Unused: let controlsTargetPosition = I.location;
  70585. let animationDuration = 600;
  70586. let easing = TWEEN.Easing.Quartic.Out;
  70587. { // animate
  70588. let value = {x: 0};
  70589. let tween = new TWEEN.Tween(value).to({x: 1}, animationDuration);
  70590. tween.easing(easing);
  70591. this.tweens.push(tween);
  70592. let startPos = this.scene.view.position.clone();
  70593. let targetPos = cameraTargetPosition.clone();
  70594. let startRadius = this.scene.view.radius;
  70595. let targetRadius = cameraTargetPosition.distanceTo(I.location);
  70596. tween.onUpdate(() => {
  70597. let t = value.x;
  70598. this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
  70599. this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
  70600. this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
  70601. this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
  70602. this.viewer.setMoveSpeed(this.scene.view.radius);
  70603. });
  70604. tween.onComplete(() => {
  70605. this.tweens = this.tweens.filter(e => e !== tween);
  70606. });
  70607. tween.start();
  70608. }
  70609. } */
  70610. zoomToLocation(mouse){
  70611. let I = viewer.inputHandler.intersect;
  70612. if(I){
  70613. I = I.location;
  70614. }
  70615. if(!I)return;
  70616. let dis = this.scene.view.position.distanceTo(I);
  70617. let distance = MathUtils.clamp(dis, 0.3, 3);
  70618. viewer.focusOnObject({ position:I }, 'point', null, {distance});
  70619. }
  70620. stopTweens () {
  70621. this.tweens.forEach(e => e.stop());
  70622. this.tweens = [];
  70623. }
  70624. update (delta) {
  70625. if(!this.enabled)return
  70626. let view = this.scene.view;
  70627. { // apply rotation
  70628. let progression = Math.min(1, this.fadeFactor * delta);
  70629. let yaw = view.yaw;
  70630. let pitch = view.pitch;
  70631. let pivot = view.getPivot();
  70632. yaw -= progression * this.yawDelta;
  70633. pitch -= progression * this.pitchDelta;
  70634. view.yaw = yaw;
  70635. view.pitch = pitch;
  70636. let V = this.scene.view.direction.multiplyScalar(-view.radius);
  70637. let position = new Vector3().addVectors(pivot, V);
  70638. view.position.copy(position);
  70639. }
  70640. { // apply pan
  70641. /* let progression = Math.min(1, this.fadeFactor * delta);
  70642. let panDistance = progression * view.radius * 3; */
  70643. let camera = this.scene.getActiveCamera();
  70644. let panDistance = 2 * view.radius * Math.tan(MathUtils.degToRad(camera.fov / 2));//参照4dkk。 平移target(也就是平移镜头位置),但还是难以保证跟手(navvis也不一定跟手,但是很奇怪在居中时中心点居然是跟手的,可能计算方式不同)
  70645. //计算了下确实是这么算的。 平移pivot。
  70646. let px = -this.panDelta.x * panDistance;
  70647. let py = this.panDelta.y * panDistance;
  70648. view.pan(px, py);
  70649. }
  70650. { // apply zoom
  70651. let progression = 1;//Math.min(1, this.fadeFactor * delta);
  70652. // let radius = view.radius + progression * this.radiusDelta * view.radius * 0.1;
  70653. let radius = view.radius + progression * this.radiusDelta;
  70654. let V = view.direction.multiplyScalar(-radius);
  70655. let position = new Vector3().addVectors(view.getPivot(), V);
  70656. view.radius = radius;
  70657. view.position.copy(position);
  70658. }
  70659. {
  70660. let speed = view.radius;
  70661. this.viewer.setMoveSpeed(speed);
  70662. }
  70663. { // decelerate over time
  70664. /* let progression = Math.min(1, this.fadeFactor * delta);
  70665. let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
  70666. this.yawDelta *= attenuation;
  70667. this.pitchDelta *= attenuation;
  70668. this.panDelta.multiplyScalar(attenuation);
  70669. // this.radiusDelta *= attenuation;
  70670. this.radiusDelta -= progression * this.radiusDelta; */
  70671. //取消衰减,直接stop
  70672. this.stop();
  70673. }
  70674. }
  70675. };
  70676. class EarthControls extends EventDispatcher {
  70677. constructor (viewer) {
  70678. super(viewer);
  70679. this.viewer = viewer;
  70680. this.renderer = viewer.renderer;
  70681. this.scene = null;
  70682. this.sceneControls = new Scene();
  70683. this.rotationSpeed = 10;
  70684. this.fadeFactor = 20;
  70685. this.wheelDelta = 0;
  70686. this.zoomDelta = new Vector3();
  70687. this.camStart = null;
  70688. this.tweens = [];
  70689. {
  70690. let sg = new SphereGeometry(1, 16, 16);
  70691. let sm = new MeshNormalMaterial();
  70692. this.pivotIndicator = new Mesh(sg, sm);
  70693. this.pivotIndicator.visible = false;
  70694. this.sceneControls.add(this.pivotIndicator);
  70695. }
  70696. let drag = (e) => {
  70697. if (e.drag.object !== null) {
  70698. return;
  70699. }
  70700. if (!this.pivot) {
  70701. return;
  70702. }
  70703. if (e.drag.startHandled === undefined) {
  70704. e.drag.startHandled = true;
  70705. this.dispatchEvent({type: 'start'});
  70706. }
  70707. let camStart = this.camStart;
  70708. let camera = this.scene.getActiveCamera();
  70709. let view = this.viewer.scene.view;
  70710. // let camera = this.viewer.scene.camera;
  70711. let Buttons = e.drag.end;
  70712. let domElement = this.viewer.renderer.domElement;
  70713. if (e.drag.Buttons === Buttons.LEFT) {
  70714. let ray = Utils.ButtonsToRay(this.viewer.inputHandler.pointer/* Buttons */, camera, domElement.clientWidth, domElement.clientHeight);
  70715. let plane = new Plane().setFromNormalAndCoplanarPoint(
  70716. new Vector3(0, 0, 1),
  70717. this.pivot);
  70718. let distanceToPlane = ray.distanceToPlane(plane);
  70719. if (distanceToPlane > 0) {
  70720. let I = new Vector3().addVectors(
  70721. camStart.position,
  70722. ray.direction.clone().multiplyScalar(distanceToPlane));
  70723. let movedBy = new Vector3().subVectors(
  70724. I, this.pivot);
  70725. let newCamPos = camStart.position.clone().sub(movedBy);
  70726. view.position.copy(newCamPos);
  70727. {
  70728. let distance = newCamPos.distanceTo(this.pivot);
  70729. view.radius = distance;
  70730. let speed = view.radius / 2.5;
  70731. this.viewer.setMoveSpeed(speed);
  70732. }
  70733. }
  70734. } else if (e.drag.Buttons === Buttons.RIGHT) {
  70735. let ndrag = {
  70736. x: e.drag.ButtonsDelta.x / this.renderer.domElement.clientWidth,
  70737. y: e.drag.ButtonsDelta.y / this.renderer.domElement.clientHeight
  70738. };
  70739. let yawDelta = -ndrag.x * this.rotationSpeed * 0.5;
  70740. let pitchDelta = -ndrag.y * this.rotationSpeed * 0.2;
  70741. let originalPitch = view.pitch;
  70742. let tmpView = view.clone();
  70743. tmpView.pitch = tmpView.pitch + pitchDelta;
  70744. pitchDelta = tmpView.pitch - originalPitch;
  70745. let pivotToCam = new Vector3().subVectors(view.position, this.pivot);
  70746. let pivotToCamTarget = new Vector3().subVectors(view.getPivot(), this.pivot);
  70747. let side = view.getSide();
  70748. pivotToCam.applyAxisAngle(side, pitchDelta);
  70749. pivotToCamTarget.applyAxisAngle(side, pitchDelta);
  70750. pivotToCam.applyAxisAngle(new Vector3(0, 0, 1), yawDelta);
  70751. pivotToCamTarget.applyAxisAngle(new Vector3(0, 0, 1), yawDelta);
  70752. let newCam = new Vector3().addVectors(this.pivot, pivotToCam);
  70753. // TODO: Unused: let newCamTarget = new THREE.Vector3().addVectors(this.pivot, pivotToCamTarget);
  70754. view.position.copy(newCam);
  70755. view.yaw += yawDelta;
  70756. view.pitch += pitchDelta;
  70757. }
  70758. };
  70759. let onButtonsDown = e => {
  70760. let I = Utils.getButtonsPointCloudIntersection(
  70761. e.Buttons,
  70762. this.scene.getActiveCamera(),
  70763. this.viewer,
  70764. this.scene.pointclouds,
  70765. {pickClipped: false});
  70766. if (I) {
  70767. this.pivot = I.location;
  70768. this.camStart = this.scene.getActiveCamera().clone();
  70769. this.pivotIndicator.visible = true;
  70770. this.pivotIndicator.position.copy(I.location);
  70771. }
  70772. };
  70773. let drop = e => {
  70774. this.dispatchEvent({type: 'end'});
  70775. };
  70776. let onButtonsUp = e => {
  70777. this.camStart = null;
  70778. this.pivot = null;
  70779. this.pivotIndicator.visible = false;
  70780. };
  70781. let scroll = (e) => {
  70782. this.wheelDelta += e.delta;
  70783. };
  70784. let dblclick = (e) => {
  70785. this.zoomToLocation(e.Buttons);
  70786. };
  70787. this.addEventListener('drag', drag);
  70788. this.addEventListener('drop', drop);
  70789. this.addEventListener('Buttonswheel', scroll);
  70790. this.addEventListener('Buttonsdown', onButtonsDown);
  70791. this.addEventListener('Buttonsup', onButtonsUp);
  70792. this.addEventListener('dblclick', dblclick);
  70793. }
  70794. setScene (scene) {
  70795. this.scene = scene;
  70796. }
  70797. stop(){
  70798. this.wheelDelta = 0;
  70799. this.zoomDelta.set(0, 0, 0);
  70800. }
  70801. zoomToLocation(Buttons){
  70802. let camera = this.scene.getActiveCamera();
  70803. let I = Utils.getButtonsPointCloudIntersection(
  70804. Buttons,
  70805. camera,
  70806. this.viewer,
  70807. this.scene.pointclouds);
  70808. if (I === null) {
  70809. return;
  70810. }
  70811. let targetRadius = 0;
  70812. {
  70813. let minimumJumpDistance = 0.2;
  70814. let domElement = this.renderer.domElement;
  70815. let ray = Utils.ButtonsToRay(this.viewer.inputHandler.pointer, camera, domElement.clientWidth, domElement.clientHeight);
  70816. let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
  70817. let lastNode = nodes[nodes.length - 1];
  70818. let radius = lastNode.getBoundingSphere(new Sphere()).radius;
  70819. targetRadius = Math.min(this.scene.view.radius, radius);
  70820. targetRadius = Math.max(minimumJumpDistance, targetRadius);
  70821. }
  70822. let d = this.scene.view.direction.multiplyScalar(-1);
  70823. let cameraTargetPosition = new Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
  70824. // TODO Unused: let controlsTargetPosition = I.location;
  70825. let animationDuration = 600;
  70826. let easing = TWEEN.Easing.Quartic.Out;
  70827. { // animate
  70828. let value = {x: 0};
  70829. let tween = new TWEEN.Tween(value).to({x: 1}, animationDuration);
  70830. tween.easing(easing);
  70831. this.tweens.push(tween);
  70832. let startPos = this.scene.view.position.clone();
  70833. let targetPos = cameraTargetPosition.clone();
  70834. let startRadius = this.scene.view.radius;
  70835. let targetRadius = cameraTargetPosition.distanceTo(I.location);
  70836. tween.onUpdate(() => {
  70837. let t = value.x;
  70838. this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
  70839. this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
  70840. this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
  70841. this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
  70842. this.viewer.setMoveSpeed(this.scene.view.radius / 2.5);
  70843. });
  70844. tween.onComplete(() => {
  70845. this.tweens = this.tweens.filter(e => e !== tween);
  70846. });
  70847. tween.start();
  70848. }
  70849. }
  70850. update (delta) {
  70851. let view = this.scene.view;
  70852. let fade = Math.pow(0.5, this.fadeFactor * delta);
  70853. let progression = 1 - fade;
  70854. let camera = this.scene.getActiveCamera();
  70855. // compute zoom
  70856. if (this.wheelDelta !== 0) {
  70857. let I = Utils.getButtonsPointCloudIntersection(
  70858. this.viewer.inputHandler.Buttons,
  70859. this.scene.getActiveCamera(),
  70860. this.viewer,
  70861. this.scene.pointclouds);
  70862. if (I) {
  70863. let resolvedPos = new Vector3().addVectors(view.position, this.zoomDelta);
  70864. let distance = I.location.distanceTo(resolvedPos);
  70865. let jumpDistance = distance * 0.2 * this.wheelDelta;
  70866. let targetDir = new Vector3().subVectors(I.location, view.position);
  70867. targetDir.normalize();
  70868. resolvedPos.add(targetDir.multiplyScalar(jumpDistance));
  70869. this.zoomDelta.subVectors(resolvedPos, view.position);
  70870. {
  70871. let distance = resolvedPos.distanceTo(I.location);
  70872. view.radius = distance;
  70873. let speed = view.radius / 2.5;
  70874. this.viewer.setMoveSpeed(speed);
  70875. }
  70876. }
  70877. }
  70878. // apply zoom
  70879. if (this.zoomDelta.length() !== 0) {
  70880. let p = this.zoomDelta.clone().multiplyScalar(progression);
  70881. let newPos = new Vector3().addVectors(view.position, p);
  70882. view.position.copy(newPos);
  70883. }
  70884. if (this.pivotIndicator.visible) {
  70885. let distance = this.pivotIndicator.position.distanceTo(view.position);
  70886. let pixelwidth = this.renderer.domElement.clientwidth;
  70887. let pixelHeight = this.renderer.domElement.clientHeight;
  70888. let pr = Utils.projectedRadius(1, camera, distance, pixelwidth, pixelHeight);
  70889. let scale = (10 / pr);
  70890. this.pivotIndicator.scale.set(scale, scale, scale);
  70891. }
  70892. // decelerate over time
  70893. {
  70894. this.zoomDelta.multiplyScalar(fade);
  70895. this.wheelDelta = 0;
  70896. }
  70897. }
  70898. };
  70899. /**
  70900. * @author chrisl / Geodan
  70901. *
  70902. * adapted from Potree.FirstPersonControls by
  70903. *
  70904. * @author mschuetz / http://mschuetz.at
  70905. *
  70906. * and THREE.DeviceOrientationControls by
  70907. *
  70908. * @author richt / http://richt.me
  70909. * @author WestLangley / http://github.com/WestLangley
  70910. *
  70911. *
  70912. *
  70913. */
  70914. class DeviceOrientationControls extends EventDispatcher{
  70915. constructor(viewer){
  70916. super();
  70917. this.viewer = viewer;
  70918. this.renderer = viewer.renderer;
  70919. this.scene = null;
  70920. this.sceneControls = new Scene();
  70921. this.screenOrientation = window.orientation || 0;
  70922. let deviceOrientationChange = e => {
  70923. this.deviceOrientation = e;
  70924. };
  70925. let screenOrientationChange = e => {
  70926. this.screenOrientation = window.orientation || 0;
  70927. };
  70928. if ('ondeviceorientationabsolute' in window) {
  70929. window.addEventListener('deviceorientationabsolute', deviceOrientationChange);
  70930. } else if ('ondeviceorientation' in window) {
  70931. window.addEventListener('deviceorientation', deviceOrientationChange);
  70932. } else {
  70933. console.warn("No device orientation found.");
  70934. }
  70935. // window.addEventListener('deviceorientation', deviceOrientationChange);
  70936. window.addEventListener('orientationchange', screenOrientationChange);
  70937. }
  70938. setScene (scene) {
  70939. this.scene = scene;
  70940. }
  70941. update (delta) {
  70942. let computeQuaternion = function (alpha, beta, gamma, orient) {
  70943. let quaternion = new Quaternion();
  70944. let zee = new Vector3(0, 0, 1);
  70945. let euler = new Euler();
  70946. let q0 = new Quaternion();
  70947. euler.set(beta, gamma, alpha, 'ZXY');
  70948. quaternion.setFromEuler(euler);
  70949. quaternion.multiply(q0.setFromAxisAngle(zee, -orient));
  70950. return quaternion;
  70951. };
  70952. if (typeof this.deviceOrientation !== 'undefined') {
  70953. let alpha = this.deviceOrientation.alpha ? MathUtils.degToRad(this.deviceOrientation.alpha) : 0;
  70954. let beta = this.deviceOrientation.beta ? MathUtils.degToRad(this.deviceOrientation.beta) : 0;
  70955. let gamma = this.deviceOrientation.gamma ? MathUtils.degToRad(this.deviceOrientation.gamma) : 0;
  70956. let orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation) : 0;
  70957. let quaternion = computeQuaternion(alpha, beta, gamma, orient);
  70958. viewer.scene.cameraP.quaternion.set(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
  70959. }
  70960. }
  70961. };
  70962. const _taskCache = new WeakMap();
  70963. class DRACOLoader extends Loader {
  70964. constructor( manager ) {
  70965. super( manager );
  70966. this.decoderPath = '';
  70967. this.decoderConfig = {};
  70968. this.decoderBinary = null;
  70969. this.decoderPending = null;
  70970. this.workerLimit = 4;
  70971. this.workerPool = [];
  70972. this.workerNextTaskID = 1;
  70973. this.workerSourceURL = '';
  70974. this.defaultAttributeIDs = {
  70975. position: 'POSITION',
  70976. normal: 'NORMAL',
  70977. color: 'COLOR',
  70978. uv: 'TEX_COORD'
  70979. };
  70980. this.defaultAttributeTypes = {
  70981. position: 'Float32Array',
  70982. normal: 'Float32Array',
  70983. color: 'Float32Array',
  70984. uv: 'Float32Array'
  70985. };
  70986. }
  70987. setDecoderPath( path ) {
  70988. this.decoderPath = path;
  70989. return this;
  70990. }
  70991. setDecoderConfig( config ) {
  70992. this.decoderConfig = config;
  70993. return this;
  70994. }
  70995. setWorkerLimit( workerLimit ) {
  70996. this.workerLimit = workerLimit;
  70997. return this;
  70998. }
  70999. load( url, onLoad, onProgress, onError ) {
  71000. const loader = new FileLoader( this.manager );
  71001. loader.setPath( this.path );
  71002. loader.setResponseType( 'arraybuffer' );
  71003. loader.setRequestHeader( this.requestHeader );
  71004. loader.setWithCredentials( this.withCredentials );
  71005. loader.load( url, ( buffer ) => {
  71006. const taskConfig = {
  71007. attributeIDs: this.defaultAttributeIDs,
  71008. attributeTypes: this.defaultAttributeTypes,
  71009. useUniqueIDs: false
  71010. };
  71011. this.decodeGeometry( buffer, taskConfig )
  71012. .then( onLoad )
  71013. .catch( onError );
  71014. }, onProgress, onError );
  71015. }
  71016. /** @deprecated Kept for backward-compatibility with previous DRACOLoader versions. */
  71017. decodeDracoFile( buffer, callback, attributeIDs, attributeTypes ) {
  71018. const taskConfig = {
  71019. attributeIDs: attributeIDs || this.defaultAttributeIDs,
  71020. attributeTypes: attributeTypes || this.defaultAttributeTypes,
  71021. useUniqueIDs: !! attributeIDs
  71022. };
  71023. this.decodeGeometry( buffer, taskConfig ).then( callback );
  71024. }
  71025. decodeGeometry( buffer, taskConfig ) {
  71026. // TODO: For backward-compatibility, support 'attributeTypes' objects containing
  71027. // references (rather than names) to typed array constructors. These must be
  71028. // serialized before sending them to the worker.
  71029. for ( const attribute in taskConfig.attributeTypes ) {
  71030. const type = taskConfig.attributeTypes[ attribute ];
  71031. if ( type.BYTES_PER_ELEMENT !== undefined ) {
  71032. taskConfig.attributeTypes[ attribute ] = type.name;
  71033. }
  71034. }
  71035. //
  71036. const taskKey = JSON.stringify( taskConfig );
  71037. // Check for an existing task using this buffer. A transferred buffer cannot be transferred
  71038. // again from this thread.
  71039. if ( _taskCache.has( buffer ) ) {
  71040. const cachedTask = _taskCache.get( buffer );
  71041. if ( cachedTask.key === taskKey ) {
  71042. return cachedTask.promise;
  71043. } else if ( buffer.byteLength === 0 ) {
  71044. // Technically, it would be possible to wait for the previous task to complete,
  71045. // transfer the buffer back, and decode again with the second configuration. That
  71046. // is complex, and I don't know of any reason to decode a Draco buffer twice in
  71047. // different ways, so this is left unimplemented.
  71048. throw new Error(
  71049. 'THREE.DRACOLoader: Unable to re-decode a buffer with different ' +
  71050. 'settings. Buffer has already been transferred.'
  71051. );
  71052. }
  71053. }
  71054. //
  71055. let worker;
  71056. const taskID = this.workerNextTaskID ++;
  71057. const taskCost = buffer.byteLength;
  71058. // Obtain a worker and assign a task, and construct a geometry instance
  71059. // when the task completes.
  71060. const geometryPending = this._getWorker( taskID, taskCost )
  71061. .then( ( _worker ) => {
  71062. worker = _worker;
  71063. return new Promise( ( resolve, reject ) => {
  71064. worker._callbacks[ taskID ] = { resolve, reject };
  71065. worker.postMessage( { type: 'decode', id: taskID, taskConfig, buffer }, [ buffer ] );
  71066. // this.debug();
  71067. } );
  71068. } )
  71069. .then( ( message ) => this._createGeometry( message.geometry ) );
  71070. // Remove task from the task list.
  71071. // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416)
  71072. geometryPending
  71073. .catch( () => true )
  71074. .then( () => {
  71075. if ( worker && taskID ) {
  71076. this._releaseTask( worker, taskID );
  71077. // this.debug();
  71078. }
  71079. } );
  71080. // Cache the task result.
  71081. _taskCache.set( buffer, {
  71082. key: taskKey,
  71083. promise: geometryPending
  71084. } );
  71085. return geometryPending;
  71086. }
  71087. _createGeometry( geometryData ) {
  71088. const geometry = new BufferGeometry();
  71089. if ( geometryData.index ) {
  71090. geometry.setIndex( new BufferAttribute( geometryData.index.array, 1 ) );
  71091. }
  71092. for ( let i = 0; i < geometryData.attributes.length; i ++ ) {
  71093. const attribute = geometryData.attributes[ i ];
  71094. const name = attribute.name;
  71095. const array = attribute.array;
  71096. const itemSize = attribute.itemSize;
  71097. geometry.setAttribute( name, new BufferAttribute( array, itemSize ) );
  71098. }
  71099. return geometry;
  71100. }
  71101. _loadLibrary( url, responseType ) {
  71102. const loader = new FileLoader( this.manager );
  71103. loader.setPath( this.decoderPath );
  71104. loader.setResponseType( responseType );
  71105. loader.setWithCredentials( this.withCredentials );
  71106. return new Promise( ( resolve, reject ) => {
  71107. loader.load( url, resolve, undefined, reject );
  71108. } );
  71109. }
  71110. preload() {
  71111. this._initDecoder();
  71112. return this;
  71113. }
  71114. _initDecoder() {
  71115. if ( this.decoderPending ) return this.decoderPending;
  71116. const useJS = typeof WebAssembly !== 'object' || this.decoderConfig.type === 'js';
  71117. const librariesPending = [];
  71118. if ( useJS ) {
  71119. librariesPending.push( this._loadLibrary( 'draco_decoder.js', 'text' ) );
  71120. } else {
  71121. librariesPending.push( this._loadLibrary( 'draco_wasm_wrapper.js', 'text' ) );
  71122. librariesPending.push( this._loadLibrary( 'draco_decoder.wasm', 'arraybuffer' ) );
  71123. }
  71124. this.decoderPending = Promise.all( librariesPending )
  71125. .then( ( libraries ) => {
  71126. const jsContent = libraries[ 0 ];
  71127. if ( ! useJS ) {
  71128. this.decoderConfig.wasmBinary = libraries[ 1 ];
  71129. }
  71130. const fn = DRACOWorker.toString();
  71131. const body = [
  71132. '/* draco decoder */',
  71133. jsContent,
  71134. '',
  71135. '/* worker */',
  71136. fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) )
  71137. ].join( '\n' );
  71138. this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) );
  71139. } );
  71140. return this.decoderPending;
  71141. }
  71142. _getWorker( taskID, taskCost ) {
  71143. return this._initDecoder().then( () => {
  71144. if ( this.workerPool.length < this.workerLimit ) {
  71145. const worker = new Worker( this.workerSourceURL );
  71146. worker._callbacks = {};
  71147. worker._taskCosts = {};
  71148. worker._taskLoad = 0;
  71149. worker.postMessage( { type: 'init', decoderConfig: this.decoderConfig } );
  71150. worker.onmessage = function ( e ) {
  71151. const message = e.data;
  71152. switch ( message.type ) {
  71153. case 'decode':
  71154. worker._callbacks[ message.id ].resolve( message );
  71155. break;
  71156. case 'error':
  71157. worker._callbacks[ message.id ].reject( message );
  71158. break;
  71159. default:
  71160. console.error( 'THREE.DRACOLoader: Unexpected message, "' + message.type + '"' );
  71161. }
  71162. };
  71163. this.workerPool.push( worker );
  71164. } else {
  71165. this.workerPool.sort( function ( a, b ) {
  71166. return a._taskLoad > b._taskLoad ? - 1 : 1;
  71167. } );
  71168. }
  71169. const worker = this.workerPool[ this.workerPool.length - 1 ];
  71170. worker._taskCosts[ taskID ] = taskCost;
  71171. worker._taskLoad += taskCost;
  71172. return worker;
  71173. } );
  71174. }
  71175. _releaseTask( worker, taskID ) {
  71176. worker._taskLoad -= worker._taskCosts[ taskID ];
  71177. delete worker._callbacks[ taskID ];
  71178. delete worker._taskCosts[ taskID ];
  71179. }
  71180. debug() {
  71181. console.log( 'Task load: ', this.workerPool.map( ( worker ) => worker._taskLoad ) );
  71182. }
  71183. dispose() {
  71184. for ( let i = 0; i < this.workerPool.length; ++ i ) {
  71185. this.workerPool[ i ].terminate();
  71186. }
  71187. this.workerPool.length = 0;
  71188. return this;
  71189. }
  71190. }
  71191. /* WEB WORKER */
  71192. function DRACOWorker() {
  71193. let decoderConfig;
  71194. let decoderPending;
  71195. onmessage = function ( e ) {
  71196. const message = e.data;
  71197. switch ( message.type ) {
  71198. case 'init':
  71199. decoderConfig = message.decoderConfig;
  71200. decoderPending = new Promise( function ( resolve/*, reject*/ ) {
  71201. decoderConfig.onModuleLoaded = function ( draco ) {
  71202. // Module is Promise-like. Wrap before resolving to avoid loop.
  71203. resolve( { draco: draco } );
  71204. };
  71205. DracoDecoderModule( decoderConfig ); // eslint-disable-line no-undef
  71206. } );
  71207. break;
  71208. case 'decode':
  71209. const buffer = message.buffer;
  71210. const taskConfig = message.taskConfig;
  71211. decoderPending.then( ( module ) => {
  71212. const draco = module.draco;
  71213. const decoder = new draco.Decoder();
  71214. const decoderBuffer = new draco.DecoderBuffer();
  71215. decoderBuffer.Init( new Int8Array( buffer ), buffer.byteLength );
  71216. try {
  71217. const geometry = decodeGeometry( draco, decoder, decoderBuffer, taskConfig );
  71218. const buffers = geometry.attributes.map( ( attr ) => attr.array.buffer );
  71219. if ( geometry.index ) buffers.push( geometry.index.array.buffer );
  71220. self.postMessage( { type: 'decode', id: message.id, geometry }, buffers );
  71221. } catch ( error ) {
  71222. console.error( error );
  71223. self.postMessage( { type: 'error', id: message.id, error: error.message } );
  71224. } finally {
  71225. draco.destroy( decoderBuffer );
  71226. draco.destroy( decoder );
  71227. }
  71228. } );
  71229. break;
  71230. }
  71231. };
  71232. function decodeGeometry( draco, decoder, decoderBuffer, taskConfig ) {
  71233. const attributeIDs = taskConfig.attributeIDs;
  71234. const attributeTypes = taskConfig.attributeTypes;
  71235. let dracoGeometry;
  71236. let decodingStatus;
  71237. const geometryType = decoder.GetEncodedGeometryType( decoderBuffer );
  71238. if ( geometryType === draco.TRIANGULAR_MESH ) {
  71239. dracoGeometry = new draco.Mesh();
  71240. decodingStatus = decoder.DecodeBufferToMesh( decoderBuffer, dracoGeometry );
  71241. } else if ( geometryType === draco.POINT_CLOUD ) {
  71242. dracoGeometry = new draco.PointCloud();
  71243. decodingStatus = decoder.DecodeBufferToPointCloud( decoderBuffer, dracoGeometry );
  71244. } else {
  71245. throw new Error( 'THREE.DRACOLoader: Unexpected geometry type.' );
  71246. }
  71247. if ( ! decodingStatus.ok() || dracoGeometry.ptr === 0 ) {
  71248. throw new Error( 'THREE.DRACOLoader: Decoding failed: ' + decodingStatus.error_msg() );
  71249. }
  71250. const geometry = { index: null, attributes: [] };
  71251. // Gather all vertex attributes.
  71252. for ( const attributeName in attributeIDs ) {
  71253. const attributeType = self[ attributeTypes[ attributeName ] ];
  71254. let attribute;
  71255. let attributeID;
  71256. // A Draco file may be created with default vertex attributes, whose attribute IDs
  71257. // are mapped 1:1 from their semantic name (POSITION, NORMAL, ...). Alternatively,
  71258. // a Draco file may contain a custom set of attributes, identified by known unique
  71259. // IDs. glTF files always do the latter, and `.drc` files typically do the former.
  71260. if ( taskConfig.useUniqueIDs ) {
  71261. attributeID = attributeIDs[ attributeName ];
  71262. attribute = decoder.GetAttributeByUniqueId( dracoGeometry, attributeID );
  71263. } else {
  71264. attributeID = decoder.GetAttributeId( dracoGeometry, draco[ attributeIDs[ attributeName ] ] );
  71265. if ( attributeID === - 1 ) continue;
  71266. attribute = decoder.GetAttribute( dracoGeometry, attributeID );
  71267. }
  71268. geometry.attributes.push( decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) );
  71269. }
  71270. // Add index.
  71271. if ( geometryType === draco.TRIANGULAR_MESH ) {
  71272. geometry.index = decodeIndex( draco, decoder, dracoGeometry );
  71273. }
  71274. draco.destroy( dracoGeometry );
  71275. return geometry;
  71276. }
  71277. function decodeIndex( draco, decoder, dracoGeometry ) {
  71278. const numFaces = dracoGeometry.num_faces();
  71279. const numIndices = numFaces * 3;
  71280. const byteLength = numIndices * 4;
  71281. const ptr = draco._malloc( byteLength );
  71282. decoder.GetTrianglesUInt32Array( dracoGeometry, byteLength, ptr );
  71283. const index = new Uint32Array( draco.HEAPF32.buffer, ptr, numIndices ).slice();
  71284. draco._free( ptr );
  71285. return { array: index, itemSize: 1 };
  71286. }
  71287. function decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) {
  71288. const numComponents = attribute.num_components();
  71289. const numPoints = dracoGeometry.num_points();
  71290. const numValues = numPoints * numComponents;
  71291. const byteLength = numValues * attributeType.BYTES_PER_ELEMENT;
  71292. const dataType = getDracoDataType( draco, attributeType );
  71293. const ptr = draco._malloc( byteLength );
  71294. decoder.GetAttributeDataArrayForAllPoints( dracoGeometry, attribute, dataType, byteLength, ptr );
  71295. const array = new attributeType( draco.HEAPF32.buffer, ptr, numValues ).slice();
  71296. draco._free( ptr );
  71297. return {
  71298. name: attributeName,
  71299. array: array,
  71300. itemSize: numComponents
  71301. };
  71302. }
  71303. function getDracoDataType( draco, attributeType ) {
  71304. switch ( attributeType ) {
  71305. case Float32Array: return draco.DT_FLOAT32;
  71306. case Int8Array: return draco.DT_INT8;
  71307. case Int16Array: return draco.DT_INT16;
  71308. case Int32Array: return draco.DT_INT32;
  71309. case Uint8Array: return draco.DT_UINT8;
  71310. case Uint16Array: return draco.DT_UINT16;
  71311. case Uint32Array: return draco.DT_UINT32;
  71312. }
  71313. }
  71314. }
  71315. /**
  71316. * @author Deepkolos / https://github.com/deepkolos
  71317. */
  71318. class WorkerPool$1 {
  71319. constructor( pool = 4 ) {
  71320. this.pool = pool;
  71321. this.queue = [];
  71322. this.workers = [];
  71323. this.workersResolve = [];
  71324. this.workerStatus = 0;
  71325. }
  71326. _initWorker( workerId ) {
  71327. if ( ! this.workers[ workerId ] ) {
  71328. const worker = this.workerCreator();
  71329. worker.addEventListener( 'message', this._onMessage.bind( this, workerId ) );
  71330. this.workers[ workerId ] = worker;
  71331. }
  71332. }
  71333. _getIdleWorker() {
  71334. for ( let i = 0; i < this.pool; i ++ )
  71335. if ( ! ( this.workerStatus & ( 1 << i ) ) ) return i;
  71336. return - 1;
  71337. }
  71338. _onMessage( workerId, msg ) {
  71339. const resolve = this.workersResolve[ workerId ];
  71340. resolve && resolve( msg );
  71341. if ( this.queue.length ) {
  71342. const { resolve, msg, transfer } = this.queue.shift();
  71343. this.workersResolve[ workerId ] = resolve;
  71344. this.workers[ workerId ].postMessage( msg, transfer );
  71345. } else {
  71346. this.workerStatus ^= 1 << workerId;
  71347. }
  71348. }
  71349. setWorkerCreator( workerCreator ) {
  71350. this.workerCreator = workerCreator;
  71351. }
  71352. setWorkerLimit( pool ) {
  71353. this.pool = pool;
  71354. }
  71355. postMessage( msg, transfer ) {
  71356. return new Promise( ( resolve ) => {
  71357. const workerId = this._getIdleWorker();
  71358. if ( workerId !== - 1 ) {
  71359. this._initWorker( workerId );
  71360. this.workerStatus |= 1 << workerId;
  71361. this.workersResolve[ workerId ] = resolve;
  71362. this.workers[ workerId ].postMessage( msg, transfer );
  71363. } else {
  71364. this.queue.push( { resolve, msg, transfer } );
  71365. }
  71366. } );
  71367. }
  71368. dispose() {
  71369. this.workers.forEach( ( worker ) => worker.terminate() );
  71370. this.workersResolve.length = 0;
  71371. this.workers.length = 0;
  71372. this.queue.length = 0;
  71373. this.workerStatus = 0;
  71374. }
  71375. }
  71376. const t=0,e$1=1,n$1=2,i$2=3,s=0,a$1=0,r=2,o$1=0,l$1=1,f=160,U$1=161,c$3=162,h$2=163,_$1=0,p=1,g=0,y=1,x$2=2,u$2=3,b$1=4,d=5,m=6,w$1=7,D=8,B=9,L=10,A=11,k=12,v=13,S$1=14,I=15,O=16,T$1=17,V=18,E=0,F=1,P=2,C=3,z=4,M$1=5,W=6,N=7,H=8,K=9,X=10,j=11,R=0,Y=1,q=2,G=13,J=14,Q=15,Z=128,$$1=64,tt=32,et=16,nt=0,it=1,st=2,at=3,rt=4,ot=5,lt=6,ft=7,Ut=8,ct=9,ht=10,_t=13,pt=14,gt=15,yt=16,xt=17,ut=20,bt=21,dt=22,mt=23,wt=24,Dt=27,Bt=28,Lt=29,At=30,kt=31,vt=34,St=35,It=36,Ot=37,Tt=38,Vt=41,Et=42,Ft=43,Pt=44,Ct=45,zt=48,Mt=49,Wt=50,Nt=58,Ht=59,Kt=62,Xt=63,jt=64,Rt=65,Yt=68,qt=69,Gt=70,Jt=71,Qt=74,Zt=75,$t=76,te=77,ee=78,ne=81,ie=82,se=83,ae=84,re=85,oe=88,le=89,fe=90,Ue=91,ce=92,he=95,_e=96,pe=97,ge=98,ye=99,xe=100,ue=101,be=102,de=103,me=104,we=105,De=106,Be=107,Le=108,Ae=109,ke=110,ve=111,Se=112,Ie=113,Oe=114,Te=115,Ve=116,Ee=117,Fe=118,Pe=119,Ce=120,ze=121,Me=122,We=123,Ne=124,He=125,Ke=126,Xe=127,je=128,Re=129,Ye=130,qe=131,Ge=132,Je=133,Qe=134,Ze=135,$e=136,tn=137,en=138,nn=139,sn=140,an=141,rn=142,on=143,ln=144,fn=145,Un=146,cn=147,hn=148,_n=149,pn=150,gn=151,yn=152,xn=153,un=154,bn=155,dn=156,mn=157,wn=158,Dn=159,Bn=160,Ln=161,An=162,kn=163,vn=164,Sn=165,In=166,On=167,Tn=168,Vn=169,En=170,Fn=171,Pn=172,Cn=173,zn=174,Mn=175,Wn=176,Nn=177,Hn=178,Kn=179,Xn=180,jn=181,Rn=182,Yn=183,qn=184,Gn=1000156007,Jn=1000156008,Qn=1000156009,Zn=1000156010,$n=1000156011,ti=1000156017,ei=1000156018,ni=1000156019,ii=1000156020,si=1000156021,ai=1000054e3,ri=1000054001,oi=1000054002,li=1000054003,fi=1000054004,Ui=1000054005,ci=1000054006,hi=1000054007,_i=1000066e3,pi=1000066001,gi=1000066002,yi=1000066003,xi=1000066004,ui=1000066005,bi=1000066006,di=1000066007,mi=1000066008,wi=1000066009,Di=1000066010,Bi=1000066011,Li=1000066012,Ai=1000066013,ki=100034e4,vi=1000340001;class Si{constructor(){this.vkFormat=0,this.typeSize=1,this.pixelWidth=0,this.pixelHeight=0,this.pixelDepth=0,this.layerCount=0,this.faceCount=1,this.supercompressionScheme=0,this.levels=[],this.dataFormatDescriptor=[{vendorId:0,descriptorType:0,descriptorBlockSize:0,versionNumber:2,colorModel:0,colorPrimaries:1,transferFunction:2,flags:0,texelBlockDimension:[0,0,0,0],bytesPlane:[0,0,0,0,0,0,0,0],samples:[]}],this.keyValue={},this.globalData=null;}}class Ii{constructor(t,e,n,i){this._dataView=new DataView(t.buffer,t.byteOffset+e,n),this._littleEndian=i,this._offset=0;}_nextUint8(){const t=this._dataView.getUint8(this._offset);return this._offset+=1,t}_nextUint16(){const t=this._dataView.getUint16(this._offset,this._littleEndian);return this._offset+=2,t}_nextUint32(){const t=this._dataView.getUint32(this._offset,this._littleEndian);return this._offset+=4,t}_nextUint64(){const t=this._dataView.getUint32(this._offset,this._littleEndian)+2**32*this._dataView.getUint32(this._offset+4,this._littleEndian);return this._offset+=8,t}_nextInt32(){const t=this._dataView.getInt32(this._offset,this._littleEndian);return this._offset+=4,t}_skip(t){return this._offset+=t,this}_scan(t,e=0){const n=this._offset;let i=0;for(;this._dataView.getUint8(this._offset)!==e&&i<t;)i++,this._offset++;return i<t&&this._offset++,new Uint8Array(this._dataView.buffer,this._dataView.byteOffset+n,i)}}const Oi=new Uint8Array([0]),Ti=[171,75,84,88,32,50,48,187,13,10,26,10];function Vi(t){return "undefined"!=typeof TextEncoder?(new TextEncoder).encode(t):Buffer.from(t)}function Ei(t){return "undefined"!=typeof TextDecoder?(new TextDecoder).decode(t):Buffer.from(t).toString("utf8")}function Fi(t){let e=0;for(const n of t)e+=n.byteLength;const n=new Uint8Array(e);let i=0;for(const e of t)n.set(new Uint8Array(e),i),i+=e.byteLength;return n}function Pi(t){const e=new Uint8Array(t.buffer,t.byteOffset,Ti.length);if(e[0]!==Ti[0]||e[1]!==Ti[1]||e[2]!==Ti[2]||e[3]!==Ti[3]||e[4]!==Ti[4]||e[5]!==Ti[5]||e[6]!==Ti[6]||e[7]!==Ti[7]||e[8]!==Ti[8]||e[9]!==Ti[9]||e[10]!==Ti[10]||e[11]!==Ti[11])throw new Error("Missing KTX 2.0 identifier.");const n=new Si,i=17*Uint32Array.BYTES_PER_ELEMENT,s=new Ii(t,Ti.length,i,!0);n.vkFormat=s._nextUint32(),n.typeSize=s._nextUint32(),n.pixelWidth=s._nextUint32(),n.pixelHeight=s._nextUint32(),n.pixelDepth=s._nextUint32(),n.layerCount=s._nextUint32(),n.faceCount=s._nextUint32();const a=s._nextUint32();n.supercompressionScheme=s._nextUint32();const r=s._nextUint32(),o=s._nextUint32(),l=s._nextUint32(),f=s._nextUint32(),U=s._nextUint64(),c=s._nextUint64(),h=new Ii(t,Ti.length+i,3*a*8,!0);for(let e=0;e<a;e++)n.levels.push({levelData:new Uint8Array(t.buffer,t.byteOffset+h._nextUint64(),h._nextUint64()),uncompressedByteLength:h._nextUint64()});const _=new Ii(t,r,o,!0),p={vendorId:_._skip(4)._nextUint16(),descriptorType:_._nextUint16(),versionNumber:_._nextUint16(),descriptorBlockSize:_._nextUint16(),colorModel:_._nextUint8(),colorPrimaries:_._nextUint8(),transferFunction:_._nextUint8(),flags:_._nextUint8(),texelBlockDimension:[_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8()],bytesPlane:[_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8()],samples:[]},g=(p.descriptorBlockSize/4-6)/4;for(let t=0;t<g;t++){const e={bitOffset:_._nextUint16(),bitLength:_._nextUint8(),channelType:_._nextUint8(),samplePosition:[_._nextUint8(),_._nextUint8(),_._nextUint8(),_._nextUint8()],sampleLower:-Infinity,sampleUpper:Infinity};64&e.channelType?(e.sampleLower=_._nextInt32(),e.sampleUpper=_._nextInt32()):(e.sampleLower=_._nextUint32(),e.sampleUpper=_._nextUint32()),p.samples[t]=e;}n.dataFormatDescriptor.length=0,n.dataFormatDescriptor.push(p);const y=new Ii(t,l,f,!0);for(;y._offset<f;){const t=y._nextUint32(),e=y._scan(t),i=Ei(e),s=y._scan(t-e.byteLength);n.keyValue[i]=i.match(/^ktx/i)?Ei(s):s,y._offset%4&&y._skip(4-y._offset%4);}if(c<=0)return n;const x=new Ii(t,U,c,!0),u=x._nextUint16(),b=x._nextUint16(),d=x._nextUint32(),m=x._nextUint32(),w=x._nextUint32(),D=x._nextUint32(),B=[];for(let t=0;t<a;t++)B.push({imageFlags:x._nextUint32(),rgbSliceByteOffset:x._nextUint32(),rgbSliceByteLength:x._nextUint32(),alphaSliceByteOffset:x._nextUint32(),alphaSliceByteLength:x._nextUint32()});const L=U+x._offset,A=L+d,k=A+m,v=k+w,S=new Uint8Array(t.buffer,t.byteOffset+L,d),I=new Uint8Array(t.buffer,t.byteOffset+A,m),O=new Uint8Array(t.buffer,t.byteOffset+k,w),T=new Uint8Array(t.buffer,t.byteOffset+v,D);return n.globalData={endpointCount:u,selectorCount:b,imageDescs:B,endpointsData:S,selectorsData:I,tablesData:O,extendedData:T},n}function Ci(){return (Ci=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i]);}return t}).apply(this,arguments)}const zi={keepWriter:!1};function Mi(t,e={}){e=Ci({},zi,e);let n=new ArrayBuffer(0);if(t.globalData){const e=new ArrayBuffer(20+5*t.globalData.imageDescs.length*4),i=new DataView(e);i.setUint16(0,t.globalData.endpointCount,!0),i.setUint16(2,t.globalData.selectorCount,!0),i.setUint32(4,t.globalData.endpointsData.byteLength,!0),i.setUint32(8,t.globalData.selectorsData.byteLength,!0),i.setUint32(12,t.globalData.tablesData.byteLength,!0),i.setUint32(16,t.globalData.extendedData.byteLength,!0);for(let e=0;e<t.globalData.imageDescs.length;e++){const n=t.globalData.imageDescs[e];i.setUint32(20+5*e*4+0,n.imageFlags,!0),i.setUint32(20+5*e*4+4,n.rgbSliceByteOffset,!0),i.setUint32(20+5*e*4+8,n.rgbSliceByteLength,!0),i.setUint32(20+5*e*4+12,n.alphaSliceByteOffset,!0),i.setUint32(20+5*e*4+16,n.alphaSliceByteLength,!0);}n=Fi([e,t.globalData.endpointsData,t.globalData.selectorsData,t.globalData.tablesData,t.globalData.extendedData]);}const i=[];let s=t.keyValue;e.keepWriter||(s=Ci({},t.keyValue,{KTXwriter:"KTX-Parse v0.3.1"}));for(const t in s){const e=s[t],n=Vi(t),a="string"==typeof e?Vi(e):e,r=n.byteLength+1+a.byteLength+1,o=r%4?4-r%4:0;i.push(Fi([new Uint32Array([r]),n,Oi,a,Oi,new Uint8Array(o).fill(0)]));}const a=Fi(i);if(1!==t.dataFormatDescriptor.length||0!==t.dataFormatDescriptor[0].descriptorType)throw new Error("Only BASICFORMAT Data Format Descriptor output supported.");const r=t.dataFormatDescriptor[0],o=new ArrayBuffer(28+16*r.samples.length),l=new DataView(o),f=24+16*r.samples.length;if(l.setUint32(0,o.byteLength,!0),l.setUint16(4,r.vendorId,!0),l.setUint16(6,r.descriptorType,!0),l.setUint16(8,r.versionNumber,!0),l.setUint16(10,f,!0),l.setUint8(12,r.colorModel),l.setUint8(13,r.colorPrimaries),l.setUint8(14,r.transferFunction),l.setUint8(15,r.flags),!Array.isArray(r.texelBlockDimension))throw new Error("texelBlockDimension is now an array. For dimensionality `d`, set `d - 1`.");l.setUint8(16,r.texelBlockDimension[0]),l.setUint8(17,r.texelBlockDimension[1]),l.setUint8(18,r.texelBlockDimension[2]),l.setUint8(19,r.texelBlockDimension[3]);for(let t=0;t<8;t++)l.setUint8(20+t,r.bytesPlane[t]);for(let t=0;t<r.samples.length;t++){const e=r.samples[t],n=28+16*t;if(e.channelID)throw new Error("channelID has been renamed to channelType.");l.setUint16(n+0,e.bitOffset,!0),l.setUint8(n+2,e.bitLength),l.setUint8(n+3,e.channelType),l.setUint8(n+4,e.samplePosition[0]),l.setUint8(n+5,e.samplePosition[1]),l.setUint8(n+6,e.samplePosition[2]),l.setUint8(n+7,e.samplePosition[3]),64&e.channelType?(l.setInt32(n+8,e.sampleLower,!0),l.setInt32(n+12,e.sampleUpper,!0)):(l.setUint32(n+8,e.sampleLower,!0),l.setUint32(n+12,e.sampleUpper,!0));}const U=Ti.length+68+3*t.levels.length*8,c=U+o.byteLength;let h=n.byteLength>0?c+a.byteLength:0;h%8&&(h+=8-h%8);const _=[],p=new DataView(new ArrayBuffer(3*t.levels.length*8));let g=(h||c+a.byteLength)+n.byteLength;for(let e=0;e<t.levels.length;e++){const n=t.levels[e];_.push(n.levelData),p.setBigUint64(24*e+0,BigInt(g),!0),p.setBigUint64(24*e+8,BigInt(n.levelData.byteLength),!0),p.setBigUint64(24*e+16,BigInt(n.uncompressedByteLength),!0),g+=n.levelData.byteLength;}const y=new ArrayBuffer(68),x=new DataView(y);return x.setUint32(0,t.vkFormat,!0),x.setUint32(4,t.typeSize,!0),x.setUint32(8,t.pixelWidth,!0),x.setUint32(12,t.pixelHeight,!0),x.setUint32(16,t.pixelDepth,!0),x.setUint32(20,t.layerCount,!0),x.setUint32(24,t.faceCount,!0),x.setUint32(28,t.levels.length,!0),x.setUint32(32,t.supercompressionScheme,!0),x.setUint32(36,U,!0),x.setUint32(40,o.byteLength,!0),x.setUint32(44,c,!0),x.setUint32(48,a.byteLength,!0),x.setBigUint64(52,BigInt(n.byteLength>0?h:0),!0),x.setBigUint64(60,BigInt(n.byteLength),!0),new Uint8Array(Fi([new Uint8Array(Ti).buffer,y,p.buffer,o,a,h>0?new ArrayBuffer(h-(c+a.byteLength)):new ArrayBuffer(0),n,..._]))}
  71377. var KTX = /*#__PURE__*/Object.freeze({
  71378. __proto__: null,
  71379. KHR_DF_CHANNEL_RGBSDA_ALPHA: Q,
  71380. KHR_DF_CHANNEL_RGBSDA_BLUE: q,
  71381. KHR_DF_CHANNEL_RGBSDA_DEPTH: J,
  71382. KHR_DF_CHANNEL_RGBSDA_GREEN: Y,
  71383. KHR_DF_CHANNEL_RGBSDA_RED: R,
  71384. KHR_DF_CHANNEL_RGBSDA_STENCIL: G,
  71385. KHR_DF_FLAG_ALPHA_PREMULTIPLIED: p,
  71386. KHR_DF_FLAG_ALPHA_STRAIGHT: _$1,
  71387. KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT: s,
  71388. KHR_DF_MODEL_ASTC: c$3,
  71389. KHR_DF_MODEL_ETC1: f,
  71390. KHR_DF_MODEL_ETC1S: h$2,
  71391. KHR_DF_MODEL_ETC2: U$1,
  71392. KHR_DF_MODEL_RGBSDA: l$1,
  71393. KHR_DF_MODEL_UNSPECIFIED: o$1,
  71394. KHR_DF_PRIMARIES_ACES: W,
  71395. KHR_DF_PRIMARIES_ACESCC: N,
  71396. KHR_DF_PRIMARIES_ADOBERGB: j,
  71397. KHR_DF_PRIMARIES_BT2020: z,
  71398. KHR_DF_PRIMARIES_BT601_EBU: P,
  71399. KHR_DF_PRIMARIES_BT601_SMPTE: C,
  71400. KHR_DF_PRIMARIES_BT709: F,
  71401. KHR_DF_PRIMARIES_CIEXYZ: M$1,
  71402. KHR_DF_PRIMARIES_DISPLAYP3: X,
  71403. KHR_DF_PRIMARIES_NTSC1953: H,
  71404. KHR_DF_PRIMARIES_PAL525: K,
  71405. KHR_DF_PRIMARIES_UNSPECIFIED: E,
  71406. KHR_DF_SAMPLE_DATATYPE_EXPONENT: tt,
  71407. KHR_DF_SAMPLE_DATATYPE_FLOAT: Z,
  71408. KHR_DF_SAMPLE_DATATYPE_LINEAR: et,
  71409. KHR_DF_SAMPLE_DATATYPE_SIGNED: $$1,
  71410. KHR_DF_TRANSFER_ACESCC: O,
  71411. KHR_DF_TRANSFER_ACESCCT: T$1,
  71412. KHR_DF_TRANSFER_ADOBERGB: V,
  71413. KHR_DF_TRANSFER_BT1886: w$1,
  71414. KHR_DF_TRANSFER_DCIP3: k,
  71415. KHR_DF_TRANSFER_HLG_EOTF: B,
  71416. KHR_DF_TRANSFER_HLG_OETF: D,
  71417. KHR_DF_TRANSFER_ITU: u$2,
  71418. KHR_DF_TRANSFER_LINEAR: y,
  71419. KHR_DF_TRANSFER_NTSC: b$1,
  71420. KHR_DF_TRANSFER_PAL625_EOTF: S$1,
  71421. KHR_DF_TRANSFER_PAL_OETF: v,
  71422. KHR_DF_TRANSFER_PQ_EOTF: L,
  71423. KHR_DF_TRANSFER_PQ_OETF: A,
  71424. KHR_DF_TRANSFER_SLOG: d,
  71425. KHR_DF_TRANSFER_SLOG2: m,
  71426. KHR_DF_TRANSFER_SRGB: x$2,
  71427. KHR_DF_TRANSFER_ST240: I,
  71428. KHR_DF_TRANSFER_UNSPECIFIED: g,
  71429. KHR_DF_VENDORID_KHRONOS: a$1,
  71430. KHR_DF_VERSION: r,
  71431. KHR_SUPERCOMPRESSION_BASISLZ: e$1,
  71432. KHR_SUPERCOMPRESSION_NONE: t,
  71433. KHR_SUPERCOMPRESSION_ZLIB: i$2,
  71434. KHR_SUPERCOMPRESSION_ZSTD: n$1,
  71435. KTX2Container: Si,
  71436. VK_FORMAT_A1R5G5B5_UNORM_PACK16: Ut,
  71437. VK_FORMAT_A2B10G10R10_SINT_PACK32: qt,
  71438. VK_FORMAT_A2B10G10R10_SNORM_PACK32: Rt,
  71439. VK_FORMAT_A2B10G10R10_UINT_PACK32: Yt,
  71440. VK_FORMAT_A2B10G10R10_UNORM_PACK32: jt,
  71441. VK_FORMAT_A2R10G10B10_SINT_PACK32: Xt,
  71442. VK_FORMAT_A2R10G10B10_SNORM_PACK32: Ht,
  71443. VK_FORMAT_A2R10G10B10_UINT_PACK32: Kt,
  71444. VK_FORMAT_A2R10G10B10_UNORM_PACK32: Nt,
  71445. VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: vi,
  71446. VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: ki,
  71447. VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: Bi,
  71448. VK_FORMAT_ASTC_10x10_SRGB_BLOCK: Xn,
  71449. VK_FORMAT_ASTC_10x10_UNORM_BLOCK: Kn,
  71450. VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT: mi,
  71451. VK_FORMAT_ASTC_10x5_SRGB_BLOCK: zn,
  71452. VK_FORMAT_ASTC_10x5_UNORM_BLOCK: Cn,
  71453. VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT: wi,
  71454. VK_FORMAT_ASTC_10x6_SRGB_BLOCK: Wn,
  71455. VK_FORMAT_ASTC_10x6_UNORM_BLOCK: Mn,
  71456. VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT: Di,
  71457. VK_FORMAT_ASTC_10x8_SRGB_BLOCK: Hn,
  71458. VK_FORMAT_ASTC_10x8_UNORM_BLOCK: Nn,
  71459. VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: Li,
  71460. VK_FORMAT_ASTC_12x10_SRGB_BLOCK: Rn,
  71461. VK_FORMAT_ASTC_12x10_UNORM_BLOCK: jn,
  71462. VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: Ai,
  71463. VK_FORMAT_ASTC_12x12_SRGB_BLOCK: qn,
  71464. VK_FORMAT_ASTC_12x12_UNORM_BLOCK: Yn,
  71465. VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT: _i,
  71466. VK_FORMAT_ASTC_4x4_SRGB_BLOCK: wn,
  71467. VK_FORMAT_ASTC_4x4_UNORM_BLOCK: mn,
  71468. VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT: pi,
  71469. VK_FORMAT_ASTC_5x4_SRGB_BLOCK: Bn,
  71470. VK_FORMAT_ASTC_5x4_UNORM_BLOCK: Dn,
  71471. VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT: gi,
  71472. VK_FORMAT_ASTC_5x5_SRGB_BLOCK: An,
  71473. VK_FORMAT_ASTC_5x5_UNORM_BLOCK: Ln,
  71474. VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT: yi,
  71475. VK_FORMAT_ASTC_6x5_SRGB_BLOCK: vn,
  71476. VK_FORMAT_ASTC_6x5_UNORM_BLOCK: kn,
  71477. VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT: xi,
  71478. VK_FORMAT_ASTC_6x6_SRGB_BLOCK: In,
  71479. VK_FORMAT_ASTC_6x6_UNORM_BLOCK: Sn,
  71480. VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT: ui,
  71481. VK_FORMAT_ASTC_8x5_SRGB_BLOCK: Tn,
  71482. VK_FORMAT_ASTC_8x5_UNORM_BLOCK: On,
  71483. VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT: bi,
  71484. VK_FORMAT_ASTC_8x6_SRGB_BLOCK: En,
  71485. VK_FORMAT_ASTC_8x6_UNORM_BLOCK: Vn,
  71486. VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT: di,
  71487. VK_FORMAT_ASTC_8x8_SRGB_BLOCK: Pn,
  71488. VK_FORMAT_ASTC_8x8_UNORM_BLOCK: Fn,
  71489. VK_FORMAT_B10G11R11_UFLOAT_PACK32: Me,
  71490. VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: $n,
  71491. VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: si,
  71492. VK_FORMAT_B4G4R4A4_UNORM_PACK16: at,
  71493. VK_FORMAT_B5G5R5A1_UNORM_PACK16: ft,
  71494. VK_FORMAT_B5G6R5_UNORM_PACK16: ot,
  71495. VK_FORMAT_B8G8R8A8_SINT: Mt,
  71496. VK_FORMAT_B8G8R8A8_SNORM: Ct,
  71497. VK_FORMAT_B8G8R8A8_SRGB: Wt,
  71498. VK_FORMAT_B8G8R8A8_UINT: zt,
  71499. VK_FORMAT_B8G8R8A8_UNORM: Pt,
  71500. VK_FORMAT_B8G8R8_SINT: St,
  71501. VK_FORMAT_B8G8R8_SNORM: kt,
  71502. VK_FORMAT_B8G8R8_SRGB: It,
  71503. VK_FORMAT_B8G8R8_UINT: vt,
  71504. VK_FORMAT_B8G8R8_UNORM: At,
  71505. VK_FORMAT_BC1_RGBA_SRGB_BLOCK: Qe,
  71506. VK_FORMAT_BC1_RGBA_UNORM_BLOCK: Je,
  71507. VK_FORMAT_BC1_RGB_SRGB_BLOCK: Ge,
  71508. VK_FORMAT_BC1_RGB_UNORM_BLOCK: qe,
  71509. VK_FORMAT_BC2_SRGB_BLOCK: $e,
  71510. VK_FORMAT_BC2_UNORM_BLOCK: Ze,
  71511. VK_FORMAT_BC3_SRGB_BLOCK: en,
  71512. VK_FORMAT_BC3_UNORM_BLOCK: tn,
  71513. VK_FORMAT_BC4_SNORM_BLOCK: sn,
  71514. VK_FORMAT_BC4_UNORM_BLOCK: nn,
  71515. VK_FORMAT_BC5_SNORM_BLOCK: rn,
  71516. VK_FORMAT_BC5_UNORM_BLOCK: an,
  71517. VK_FORMAT_BC6H_SFLOAT_BLOCK: ln,
  71518. VK_FORMAT_BC6H_UFLOAT_BLOCK: on,
  71519. VK_FORMAT_BC7_SRGB_BLOCK: Un,
  71520. VK_FORMAT_BC7_UNORM_BLOCK: fn,
  71521. VK_FORMAT_D16_UNORM: Ne,
  71522. VK_FORMAT_D16_UNORM_S8_UINT: je,
  71523. VK_FORMAT_D24_UNORM_S8_UINT: Re,
  71524. VK_FORMAT_D32_SFLOAT: Ke,
  71525. VK_FORMAT_D32_SFLOAT_S8_UINT: Ye,
  71526. VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: We,
  71527. VK_FORMAT_EAC_R11G11_SNORM_BLOCK: dn,
  71528. VK_FORMAT_EAC_R11G11_UNORM_BLOCK: bn,
  71529. VK_FORMAT_EAC_R11_SNORM_BLOCK: un,
  71530. VK_FORMAT_EAC_R11_UNORM_BLOCK: xn,
  71531. VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: pn,
  71532. VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: _n,
  71533. VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: yn,
  71534. VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: gn,
  71535. VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: hn,
  71536. VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: cn,
  71537. VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: Zn,
  71538. VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: ii,
  71539. VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: fi,
  71540. VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: ai,
  71541. VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: Ui,
  71542. VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: ri,
  71543. VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: ci,
  71544. VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: oi,
  71545. VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: hi,
  71546. VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: li,
  71547. VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: Qn,
  71548. VK_FORMAT_R10X6G10X6_UNORM_2PACK16: Jn,
  71549. VK_FORMAT_R10X6_UNORM_PACK16: Gn,
  71550. VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: ni,
  71551. VK_FORMAT_R12X4G12X4_UNORM_2PACK16: ei,
  71552. VK_FORMAT_R12X4_UNORM_PACK16: ti,
  71553. VK_FORMAT_R16G16B16A16_SFLOAT: pe,
  71554. VK_FORMAT_R16G16B16A16_SINT: _e,
  71555. VK_FORMAT_R16G16B16A16_SNORM: ce,
  71556. VK_FORMAT_R16G16B16A16_UINT: he,
  71557. VK_FORMAT_R16G16B16A16_UNORM: Ue,
  71558. VK_FORMAT_R16G16B16_SFLOAT: fe,
  71559. VK_FORMAT_R16G16B16_SINT: le,
  71560. VK_FORMAT_R16G16B16_SNORM: re,
  71561. VK_FORMAT_R16G16B16_UINT: oe,
  71562. VK_FORMAT_R16G16B16_UNORM: ae,
  71563. VK_FORMAT_R16G16_SFLOAT: se,
  71564. VK_FORMAT_R16G16_SINT: ie,
  71565. VK_FORMAT_R16G16_SNORM: ee,
  71566. VK_FORMAT_R16G16_UINT: ne,
  71567. VK_FORMAT_R16G16_UNORM: te,
  71568. VK_FORMAT_R16_SFLOAT: $t,
  71569. VK_FORMAT_R16_SINT: Zt,
  71570. VK_FORMAT_R16_SNORM: Jt,
  71571. VK_FORMAT_R16_UINT: Qt,
  71572. VK_FORMAT_R16_UNORM: Gt,
  71573. VK_FORMAT_R32G32B32A32_SFLOAT: Ae,
  71574. VK_FORMAT_R32G32B32A32_SINT: Le,
  71575. VK_FORMAT_R32G32B32A32_UINT: Be,
  71576. VK_FORMAT_R32G32B32_SFLOAT: De,
  71577. VK_FORMAT_R32G32B32_SINT: we,
  71578. VK_FORMAT_R32G32B32_UINT: me,
  71579. VK_FORMAT_R32G32_SFLOAT: de,
  71580. VK_FORMAT_R32G32_SINT: be,
  71581. VK_FORMAT_R32G32_UINT: ue,
  71582. VK_FORMAT_R32_SFLOAT: xe,
  71583. VK_FORMAT_R32_SINT: ye,
  71584. VK_FORMAT_R32_UINT: ge,
  71585. VK_FORMAT_R4G4B4A4_UNORM_PACK16: st,
  71586. VK_FORMAT_R4G4_UNORM_PACK8: it,
  71587. VK_FORMAT_R5G5B5A1_UNORM_PACK16: lt,
  71588. VK_FORMAT_R5G6B5_UNORM_PACK16: rt,
  71589. VK_FORMAT_R64G64B64A64_SFLOAT: ze,
  71590. VK_FORMAT_R64G64B64A64_SINT: Ce,
  71591. VK_FORMAT_R64G64B64A64_UINT: Pe,
  71592. VK_FORMAT_R64G64B64_SFLOAT: Fe,
  71593. VK_FORMAT_R64G64B64_SINT: Ee,
  71594. VK_FORMAT_R64G64B64_UINT: Ve,
  71595. VK_FORMAT_R64G64_SFLOAT: Te,
  71596. VK_FORMAT_R64G64_SINT: Oe,
  71597. VK_FORMAT_R64G64_UINT: Ie,
  71598. VK_FORMAT_R64_SFLOAT: Se,
  71599. VK_FORMAT_R64_SINT: ve,
  71600. VK_FORMAT_R64_UINT: ke,
  71601. VK_FORMAT_R8G8B8A8_SINT: Et,
  71602. VK_FORMAT_R8G8B8A8_SNORM: Tt,
  71603. VK_FORMAT_R8G8B8A8_SRGB: Ft,
  71604. VK_FORMAT_R8G8B8A8_UINT: Vt,
  71605. VK_FORMAT_R8G8B8A8_UNORM: Ot,
  71606. VK_FORMAT_R8G8B8_SINT: Bt,
  71607. VK_FORMAT_R8G8B8_SNORM: wt,
  71608. VK_FORMAT_R8G8B8_SRGB: Lt,
  71609. VK_FORMAT_R8G8B8_UINT: Dt,
  71610. VK_FORMAT_R8G8B8_UNORM: mt,
  71611. VK_FORMAT_R8G8_SINT: bt,
  71612. VK_FORMAT_R8G8_SNORM: xt,
  71613. VK_FORMAT_R8G8_SRGB: dt,
  71614. VK_FORMAT_R8G8_UINT: ut,
  71615. VK_FORMAT_R8G8_UNORM: yt,
  71616. VK_FORMAT_R8_SINT: pt,
  71617. VK_FORMAT_R8_SNORM: ht,
  71618. VK_FORMAT_R8_SRGB: gt,
  71619. VK_FORMAT_R8_UINT: _t,
  71620. VK_FORMAT_R8_UNORM: ct,
  71621. VK_FORMAT_S8_UINT: Xe,
  71622. VK_FORMAT_UNDEFINED: nt,
  71623. VK_FORMAT_X8_D24_UNORM_PACK32: He,
  71624. read: Pi,
  71625. write: Mi
  71626. });
  71627. /**
  71628. * Loader for KTX 2.0 GPU Texture containers.
  71629. *
  71630. * KTX 2.0 is a container format for various GPU texture formats. The loader
  71631. * supports Basis Universal GPU textures, which can be quickly transcoded to
  71632. * a wide variety of GPU texture compression formats, as well as some
  71633. * uncompressed DataTexture and Data3DTexture formats.
  71634. *
  71635. * References:
  71636. * - KTX: http://github.khronos.org/KTX-Specification/
  71637. * - DFD: https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#basicdescriptor
  71638. */
  71639. const {
  71640. read: read$1,
  71641. KHR_DF_FLAG_ALPHA_PREMULTIPLIED,
  71642. KHR_DF_TRANSFER_SRGB,
  71643. VK_FORMAT_UNDEFINED,
  71644. VK_FORMAT_R16_SFLOAT,
  71645. VK_FORMAT_R16G16_SFLOAT,
  71646. VK_FORMAT_R16G16B16A16_SFLOAT,
  71647. VK_FORMAT_R32_SFLOAT,
  71648. VK_FORMAT_R32G32_SFLOAT,
  71649. VK_FORMAT_R32G32B32A32_SFLOAT,
  71650. VK_FORMAT_R8_SRGB,
  71651. VK_FORMAT_R8_UNORM,
  71652. VK_FORMAT_R8G8_SRGB,
  71653. VK_FORMAT_R8G8_UNORM,
  71654. VK_FORMAT_R8G8B8A8_SRGB,
  71655. VK_FORMAT_R8G8B8A8_UNORM,
  71656. } = KTX; // eslint-disable-line no-undef
  71657. const _taskCache$1 = new WeakMap();
  71658. let _activeLoaders = 0;
  71659. class KTX2Loader extends Loader {
  71660. constructor( manager ) {
  71661. super( manager );
  71662. this.transcoderPath = '';
  71663. this.transcoderBinary = null;
  71664. this.transcoderPending = null;
  71665. this.workerPool = new WorkerPool$1();
  71666. this.workerSourceURL = '';
  71667. this.workerConfig = null;
  71668. if ( typeof MSC_TRANSCODER !== 'undefined' ) {
  71669. console.warn(
  71670. 'THREE.KTX2Loader: Please update to latest "basis_transcoder".'
  71671. + ' "msc_basis_transcoder" is no longer supported in three.js r125+.'
  71672. );
  71673. }
  71674. }
  71675. setTranscoderPath( path ) {
  71676. this.transcoderPath = path;
  71677. return this;
  71678. }
  71679. setWorkerLimit( num ) {
  71680. this.workerPool.setWorkerLimit( num );
  71681. return this;
  71682. }
  71683. detectSupport( renderer ) {
  71684. this.workerConfig = {
  71685. astcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' ),
  71686. etc1Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc1' ),
  71687. etc2Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc' ),
  71688. dxtSupported: renderer.extensions.has( 'WEBGL_compressed_texture_s3tc' ),
  71689. bptcSupported: renderer.extensions.has( 'EXT_texture_compression_bptc' ),
  71690. pvrtcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_pvrtc' )
  71691. || renderer.extensions.has( 'WEBKIT_WEBGL_compressed_texture_pvrtc' )
  71692. };
  71693. if ( renderer.capabilities.isWebGL2 ) {
  71694. // https://github.com/mrdoob/three.js/pull/22928
  71695. this.workerConfig.etc1Supported = false;
  71696. }
  71697. return this;
  71698. }
  71699. init() {
  71700. if ( ! this.transcoderPending ) {
  71701. // Load transcoder wrapper.
  71702. const jsLoader = new FileLoader( this.manager );
  71703. jsLoader.setPath( this.transcoderPath );
  71704. jsLoader.setWithCredentials( this.withCredentials );
  71705. const jsContent = jsLoader.loadAsync( 'basis_transcoder.js' );
  71706. // Load transcoder WASM binary.
  71707. const binaryLoader = new FileLoader( this.manager );
  71708. binaryLoader.setPath( this.transcoderPath );
  71709. binaryLoader.setResponseType( 'arraybuffer' );
  71710. binaryLoader.setWithCredentials( this.withCredentials );
  71711. const binaryContent = binaryLoader.loadAsync( 'basis_transcoder.wasm' );
  71712. this.transcoderPending = Promise.all( [ jsContent, binaryContent ] )
  71713. .then( ( [ jsContent, binaryContent ] ) => {
  71714. const fn = KTX2Loader.BasisWorker.toString();
  71715. const body = [
  71716. '/* constants */',
  71717. 'let _EngineFormat = ' + JSON.stringify( KTX2Loader.EngineFormat ),
  71718. 'let _TranscoderFormat = ' + JSON.stringify( KTX2Loader.TranscoderFormat ),
  71719. 'let _BasisFormat = ' + JSON.stringify( KTX2Loader.BasisFormat ),
  71720. '/* basis_transcoder.js */',
  71721. jsContent,
  71722. '/* worker */',
  71723. fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) )
  71724. ].join( '\n' );
  71725. this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) );
  71726. this.transcoderBinary = binaryContent;
  71727. this.workerPool.setWorkerCreator( () => {
  71728. const worker = new Worker( this.workerSourceURL );
  71729. const transcoderBinary = this.transcoderBinary.slice( 0 );
  71730. worker.postMessage( { type: 'init', config: this.workerConfig, transcoderBinary }, [ transcoderBinary ] );
  71731. return worker;
  71732. } );
  71733. } );
  71734. if ( _activeLoaders > 0 ) {
  71735. // Each instance loads a transcoder and allocates workers, increasing network and memory cost.
  71736. console.warn(
  71737. 'THREE.KTX2Loader: Multiple active KTX2 loaders may cause performance issues.'
  71738. + ' Use a single KTX2Loader instance, or call .dispose() on old instances.'
  71739. );
  71740. }
  71741. _activeLoaders ++;
  71742. }
  71743. return this.transcoderPending;
  71744. }
  71745. load( url, onLoad, onProgress, onError ) {
  71746. if ( this.workerConfig === null ) {
  71747. throw new Error( 'THREE.KTX2Loader: Missing initialization with `.detectSupport( renderer )`.' );
  71748. }
  71749. const loader = new FileLoader( this.manager );
  71750. loader.setResponseType( 'arraybuffer' );
  71751. loader.setWithCredentials( this.withCredentials );
  71752. loader.load( url, ( buffer ) => {
  71753. // Check for an existing task using this buffer. A transferred buffer cannot be transferred
  71754. // again from this thread.
  71755. if ( _taskCache$1.has( buffer ) ) {
  71756. const cachedTask = _taskCache$1.get( buffer );
  71757. return cachedTask.promise.then( onLoad ).catch( onError );
  71758. }
  71759. this._createTexture( buffer )
  71760. .then( ( texture ) => onLoad ? onLoad( texture ) : null )
  71761. .catch( onError );
  71762. }, onProgress, onError );
  71763. }
  71764. _createTextureFrom( transcodeResult ) {
  71765. const { mipmaps, width, height, format, type, error, dfdTransferFn, dfdFlags } = transcodeResult;
  71766. if ( type === 'error' ) return Promise.reject( error );
  71767. const texture = new CompressedTexture( mipmaps, width, height, format, UnsignedByteType );
  71768. texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter;
  71769. texture.magFilter = LinearFilter;
  71770. texture.generateMipmaps = false;
  71771. texture.needsUpdate = true;
  71772. texture.encoding = dfdTransferFn === KHR_DF_TRANSFER_SRGB ? sRGBEncoding : LinearEncoding;
  71773. texture.premultiplyAlpha = !! ( dfdFlags & KHR_DF_FLAG_ALPHA_PREMULTIPLIED );
  71774. return texture;
  71775. }
  71776. /**
  71777. * @param {ArrayBuffer} buffer
  71778. * @param {object?} config
  71779. * @return {Promise<CompressedTexture|DataTexture|Data3DTexture>}
  71780. */
  71781. _createTexture( buffer, config = {} ) {
  71782. const container = read$1( new Uint8Array( buffer ) );
  71783. if ( container.vkFormat !== VK_FORMAT_UNDEFINED ) {
  71784. return createDataTexture( container );
  71785. }
  71786. //
  71787. const taskConfig = config;
  71788. const texturePending = this.init().then( () => {
  71789. return this.workerPool.postMessage( { type: 'transcode', buffer, taskConfig: taskConfig }, [ buffer ] );
  71790. } ).then( ( e ) => this._createTextureFrom( e.data ) );
  71791. // Cache the task result.
  71792. _taskCache$1.set( buffer, { promise: texturePending } );
  71793. return texturePending;
  71794. }
  71795. dispose() {
  71796. this.workerPool.dispose();
  71797. if ( this.workerSourceURL ) URL.revokeObjectURL( this.workerSourceURL );
  71798. _activeLoaders --;
  71799. return this;
  71800. }
  71801. }
  71802. /* CONSTANTS */
  71803. KTX2Loader.BasisFormat = {
  71804. ETC1S: 0,
  71805. UASTC_4x4: 1,
  71806. };
  71807. KTX2Loader.TranscoderFormat = {
  71808. ETC1: 0,
  71809. ETC2: 1,
  71810. BC1: 2,
  71811. BC3: 3,
  71812. BC4: 4,
  71813. BC5: 5,
  71814. BC7_M6_OPAQUE_ONLY: 6,
  71815. BC7_M5: 7,
  71816. PVRTC1_4_RGB: 8,
  71817. PVRTC1_4_RGBA: 9,
  71818. ASTC_4x4: 10,
  71819. ATC_RGB: 11,
  71820. ATC_RGBA_INTERPOLATED_ALPHA: 12,
  71821. RGBA32: 13,
  71822. RGB565: 14,
  71823. BGR565: 15,
  71824. RGBA4444: 16,
  71825. };
  71826. KTX2Loader.EngineFormat = {
  71827. RGBAFormat: RGBAFormat,
  71828. RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
  71829. RGBA_BPTC_Format: RGBA_BPTC_Format,
  71830. RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
  71831. RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
  71832. RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format$1,
  71833. RGB_ETC1_Format: RGB_ETC1_Format,
  71834. RGB_ETC2_Format: RGB_ETC2_Format,
  71835. RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
  71836. RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format,
  71837. };
  71838. /* WEB WORKER */
  71839. KTX2Loader.BasisWorker = function () {
  71840. let config;
  71841. let transcoderPending;
  71842. let BasisModule;
  71843. const EngineFormat = _EngineFormat; // eslint-disable-line no-undef
  71844. const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef
  71845. const BasisFormat = _BasisFormat; // eslint-disable-line no-undef
  71846. self.addEventListener( 'message', function ( e ) {
  71847. const message = e.data;
  71848. switch ( message.type ) {
  71849. case 'init':
  71850. config = message.config;
  71851. init( message.transcoderBinary );
  71852. break;
  71853. case 'transcode':
  71854. transcoderPending.then( () => {
  71855. try {
  71856. const { width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags } = transcode( message.buffer );
  71857. const buffers = [];
  71858. for ( let i = 0; i < mipmaps.length; ++ i ) {
  71859. buffers.push( mipmaps[ i ].data.buffer );
  71860. }
  71861. self.postMessage( { type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags }, buffers );
  71862. } catch ( error ) {
  71863. console.error( error );
  71864. self.postMessage( { type: 'error', id: message.id, error: error.message } );
  71865. }
  71866. } );
  71867. break;
  71868. }
  71869. } );
  71870. function init( wasmBinary ) {
  71871. transcoderPending = new Promise( ( resolve ) => {
  71872. BasisModule = { wasmBinary, onRuntimeInitialized: resolve };
  71873. BASIS( BasisModule ); // eslint-disable-line no-undef
  71874. } ).then( () => {
  71875. BasisModule.initializeBasis();
  71876. if ( BasisModule.KTX2File === undefined ) {
  71877. console.warn( 'THREE.KTX2Loader: Please update Basis Universal transcoder.' );
  71878. }
  71879. } );
  71880. }
  71881. function transcode( buffer ) {
  71882. const ktx2File = new BasisModule.KTX2File( new Uint8Array( buffer ) );
  71883. function cleanup() {
  71884. ktx2File.close();
  71885. ktx2File.delete();
  71886. }
  71887. if ( ! ktx2File.isValid() ) {
  71888. cleanup();
  71889. throw new Error( 'THREE.KTX2Loader: Invalid or unsupported .ktx2 file' );
  71890. }
  71891. const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
  71892. const width = ktx2File.getWidth();
  71893. const height = ktx2File.getHeight();
  71894. const levels = ktx2File.getLevels();
  71895. const hasAlpha = ktx2File.getHasAlpha();
  71896. const dfdTransferFn = ktx2File.getDFDTransferFunc();
  71897. const dfdFlags = ktx2File.getDFDFlags();
  71898. const { transcoderFormat, engineFormat } = getTranscoderFormat( basisFormat, width, height, hasAlpha );
  71899. if ( ! width || ! height || ! levels ) {
  71900. cleanup();
  71901. throw new Error( 'THREE.KTX2Loader: Invalid texture' );
  71902. }
  71903. if ( ! ktx2File.startTranscoding() ) {
  71904. cleanup();
  71905. throw new Error( 'THREE.KTX2Loader: .startTranscoding failed' );
  71906. }
  71907. const mipmaps = [];
  71908. for ( let mip = 0; mip < levels; mip ++ ) {
  71909. const levelInfo = ktx2File.getImageLevelInfo( mip, 0, 0 );
  71910. const mipWidth = levelInfo.origWidth;
  71911. const mipHeight = levelInfo.origHeight;
  71912. const dst = new Uint8Array( ktx2File.getImageTranscodedSizeInBytes( mip, 0, 0, transcoderFormat ) );
  71913. const status = ktx2File.transcodeImage(
  71914. dst,
  71915. mip,
  71916. 0,
  71917. 0,
  71918. transcoderFormat,
  71919. 0,
  71920. - 1,
  71921. - 1,
  71922. );
  71923. if ( ! status ) {
  71924. cleanup();
  71925. throw new Error( 'THREE.KTX2Loader: .transcodeImage failed.' );
  71926. }
  71927. mipmaps.push( { data: dst, width: mipWidth, height: mipHeight } );
  71928. }
  71929. cleanup();
  71930. return { width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags };
  71931. }
  71932. //
  71933. // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),
  71934. // device capabilities, and texture dimensions. The list below ranks the formats separately
  71935. // for ETC1S and UASTC.
  71936. //
  71937. // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at
  71938. // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently
  71939. // chooses RGBA32 only as a last resort and does not expose that option to the caller.
  71940. const FORMAT_OPTIONS = [
  71941. {
  71942. if: 'astcSupported',
  71943. basisFormat: [ BasisFormat.UASTC_4x4 ],
  71944. transcoderFormat: [ TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4 ],
  71945. engineFormat: [ EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format ],
  71946. priorityETC1S: Infinity,
  71947. priorityUASTC: 1,
  71948. needsPowerOfTwo: false,
  71949. },
  71950. {
  71951. if: 'bptcSupported',
  71952. basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
  71953. transcoderFormat: [ TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5 ],
  71954. engineFormat: [ EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format ],
  71955. priorityETC1S: 3,
  71956. priorityUASTC: 2,
  71957. needsPowerOfTwo: false,
  71958. },
  71959. {
  71960. if: 'dxtSupported',
  71961. basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
  71962. transcoderFormat: [ TranscoderFormat.BC1, TranscoderFormat.BC3 ],
  71963. engineFormat: [ EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ],
  71964. priorityETC1S: 4,
  71965. priorityUASTC: 5,
  71966. needsPowerOfTwo: false,
  71967. },
  71968. {
  71969. if: 'etc2Supported',
  71970. basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
  71971. transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC2 ],
  71972. engineFormat: [ EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format ],
  71973. priorityETC1S: 1,
  71974. priorityUASTC: 3,
  71975. needsPowerOfTwo: false,
  71976. },
  71977. {
  71978. if: 'etc1Supported',
  71979. basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
  71980. transcoderFormat: [ TranscoderFormat.ETC1 ],
  71981. engineFormat: [ EngineFormat.RGB_ETC1_Format ],
  71982. priorityETC1S: 2,
  71983. priorityUASTC: 4,
  71984. needsPowerOfTwo: false,
  71985. },
  71986. {
  71987. if: 'pvrtcSupported',
  71988. basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
  71989. transcoderFormat: [ TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA ],
  71990. engineFormat: [ EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format ],
  71991. priorityETC1S: 5,
  71992. priorityUASTC: 6,
  71993. needsPowerOfTwo: true,
  71994. },
  71995. ];
  71996. const ETC1S_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {
  71997. return a.priorityETC1S - b.priorityETC1S;
  71998. } );
  71999. const UASTC_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {
  72000. return a.priorityUASTC - b.priorityUASTC;
  72001. } );
  72002. function getTranscoderFormat( basisFormat, width, height, hasAlpha ) {
  72003. let transcoderFormat;
  72004. let engineFormat;
  72005. const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;
  72006. for ( let i = 0; i < options.length; i ++ ) {
  72007. const opt = options[ i ];
  72008. if ( ! config[ opt.if ] ) continue;
  72009. if ( ! opt.basisFormat.includes( basisFormat ) ) continue;
  72010. if ( hasAlpha && opt.transcoderFormat.length < 2 ) continue;
  72011. if ( opt.needsPowerOfTwo && ! ( isPowerOfTwo( width ) && isPowerOfTwo( height ) ) ) continue;
  72012. transcoderFormat = opt.transcoderFormat[ hasAlpha ? 1 : 0 ];
  72013. engineFormat = opt.engineFormat[ hasAlpha ? 1 : 0 ];
  72014. return { transcoderFormat, engineFormat };
  72015. }
  72016. console.warn( 'THREE.KTX2Loader: No suitable compressed texture format found. Decoding to RGBA32.' );
  72017. transcoderFormat = TranscoderFormat.RGBA32;
  72018. engineFormat = EngineFormat.RGBAFormat;
  72019. return { transcoderFormat, engineFormat };
  72020. }
  72021. function isPowerOfTwo( value ) {
  72022. if ( value <= 2 ) return true;
  72023. return ( value & ( value - 1 ) ) === 0 && value !== 0;
  72024. }
  72025. };
  72026. //
  72027. // DataTexture and Data3DTexture parsing.
  72028. const FORMAT_MAP = {
  72029. [ VK_FORMAT_R32G32B32A32_SFLOAT ]: RGBAFormat,
  72030. [ VK_FORMAT_R16G16B16A16_SFLOAT ]: RGBAFormat,
  72031. [ VK_FORMAT_R8G8B8A8_UNORM ]: RGBAFormat,
  72032. [ VK_FORMAT_R8G8B8A8_SRGB ]: RGBAFormat,
  72033. [ VK_FORMAT_R32G32_SFLOAT ]: RGFormat,
  72034. [ VK_FORMAT_R16G16_SFLOAT ]: RGFormat,
  72035. [ VK_FORMAT_R8G8_UNORM ]: RGFormat,
  72036. [ VK_FORMAT_R8G8_SRGB ]: RGFormat,
  72037. [ VK_FORMAT_R32_SFLOAT ]: RedFormat,
  72038. [ VK_FORMAT_R16_SFLOAT ]: RedFormat,
  72039. [ VK_FORMAT_R8_SRGB ]: RedFormat,
  72040. [ VK_FORMAT_R8_UNORM ]: RedFormat,
  72041. };
  72042. const TYPE_MAP = {
  72043. [ VK_FORMAT_R32G32B32A32_SFLOAT ]: FloatType,
  72044. [ VK_FORMAT_R16G16B16A16_SFLOAT ]: HalfFloatType,
  72045. [ VK_FORMAT_R8G8B8A8_UNORM ]: UnsignedByteType,
  72046. [ VK_FORMAT_R8G8B8A8_SRGB ]: UnsignedByteType,
  72047. [ VK_FORMAT_R32G32_SFLOAT ]: FloatType,
  72048. [ VK_FORMAT_R16G16_SFLOAT ]: HalfFloatType,
  72049. [ VK_FORMAT_R8G8_UNORM ]: UnsignedByteType,
  72050. [ VK_FORMAT_R8G8_SRGB ]: UnsignedByteType,
  72051. [ VK_FORMAT_R32_SFLOAT ]: FloatType,
  72052. [ VK_FORMAT_R16_SFLOAT ]: HalfFloatType,
  72053. [ VK_FORMAT_R8_SRGB ]: UnsignedByteType,
  72054. [ VK_FORMAT_R8_UNORM ]: UnsignedByteType,
  72055. };
  72056. const ENCODING_MAP = {
  72057. [ VK_FORMAT_R8G8B8A8_SRGB ]: sRGBEncoding,
  72058. [ VK_FORMAT_R8G8_SRGB ]: sRGBEncoding,
  72059. [ VK_FORMAT_R8_SRGB ]: sRGBEncoding,
  72060. };
  72061. function createDataTexture( container ) {
  72062. const { vkFormat, pixelWidth, pixelHeight, pixelDepth } = container;
  72063. if ( FORMAT_MAP[ vkFormat ] === undefined ) {
  72064. throw new Error( 'THREE.KTX2Loader: Unsupported vkFormat.' );
  72065. }
  72066. //
  72067. let view;
  72068. const levelData = container.levels[ 0 ].levelData;
  72069. if ( TYPE_MAP[ vkFormat ] === FloatType ) {
  72070. view = new Float32Array(
  72071. levelData.buffer,
  72072. levelData.byteOffset,
  72073. levelData.byteLength / Float32Array.BYTES_PER_ELEMENT
  72074. );
  72075. } else if ( TYPE_MAP[ vkFormat ] === HalfFloatType ) {
  72076. view = new Uint16Array(
  72077. levelData.buffer,
  72078. levelData.byteOffset,
  72079. levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT
  72080. );
  72081. } else {
  72082. view = levelData;
  72083. }
  72084. //
  72085. const texture = pixelDepth === 0
  72086. ? new DataTexture( view, pixelWidth, pixelHeight )
  72087. : new Data3DTexture( view, pixelWidth, pixelHeight, pixelDepth );
  72088. texture.type = TYPE_MAP[ vkFormat ];
  72089. texture.format = FORMAT_MAP[ vkFormat ];
  72090. texture.encoding = ENCODING_MAP[ vkFormat ] || LinearEncoding;
  72091. texture.needsUpdate = true;
  72092. //
  72093. return Promise.resolve( texture );
  72094. }
  72095. // This file is part of meshoptimizer library and is distributed under the terms of MIT License.
  72096. // Copyright (C) 2016-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
  72097. var MeshoptDecoder = (function() {
  72098. "use strict";
  72099. // Built with clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0160ad802e899c2922bc9b29564080c22eb0908c)
  72100. // Built from meshoptimizer 0.14
  72101. var wasm_base = "B9h9z9tFBBBF8fL9gBB9gLaaaaaFa9gEaaaB9gFaFa9gEaaaFaEMcBFFFGGGEIIILF9wFFFLEFBFKNFaFCx/IFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBF8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBGy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBEn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBIi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBKI9z9iqlBOc+x8ycGBM/qQFTa8jUUUUBCU/EBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAGTkUUUBRNCUoBAG9uC/wgBZHKCUGAKCUG9JyRVAECFJRICBRcGXEXAcAF9PQFAVAFAclAcAVJAF9JyRMGXGXAG9FQBAMCbJHKC9wZRSAKCIrCEJCGrRQANCUGJRfCBRbAIRTEXGXAOATlAQ9PQBCBRISEMATAQJRIGXAS9FQBCBRtCBREEXGXAOAIlCi9PQBCBRISLMANCU/CBJAEJRKGXGXGXGXGXATAECKrJ2BBAtCKZrCEZfIBFGEBMAKhB83EBAKCNJhB83EBSEMAKAI2BIAI2BBHmCKrHYAYCE6HYy86BBAKCFJAICIJAYJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCGJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCEJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCIJAYAmJHY2BBAI2BFHmCKrHPAPCE6HPy86BBAKCLJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCKJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCOJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCNJAYAmJHY2BBAI2BGHmCKrHPAPCE6HPy86BBAKCVJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCcJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCMJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCSJAYAmJHm2BBAI2BEHICKrHYAYCE6HYy86BBAKCQJAmAYJHm2BBAICIrCEZHYAYCE6HYy86BBAKCfJAmAYJHm2BBAICGrCEZHYAYCE6HYy86BBAKCbJAmAYJHK2BBAICEZHIAICE6HIy86BBAKAIJRISGMAKAI2BNAI2BBHmCIrHYAYCb6HYy86BBAKCFJAICNJAYJHY2BBAmCbZHmAmCb6Hmy86BBAKCGJAYAmJHm2BBAI2BFHYCIrHPAPCb6HPy86BBAKCEJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCIJAmAYJHm2BBAI2BGHYCIrHPAPCb6HPy86BBAKCLJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCKJAmAYJHm2BBAI2BEHYCIrHPAPCb6HPy86BBAKCOJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCNJAmAYJHm2BBAI2BIHYCIrHPAPCb6HPy86BBAKCVJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCcJAmAYJHm2BBAI2BLHYCIrHPAPCb6HPy86BBAKCMJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCSJAmAYJHm2BBAI2BKHYCIrHPAPCb6HPy86BBAKCQJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCfJAmAYJHm2BBAI2BOHICIrHYAYCb6HYy86BBAKCbJAmAYJHK2BBAICbZHIAICb6HIy86BBAKAIJRISFMAKAI8pBB83BBAKCNJAICNJ8pBB83BBAICTJRIMAtCGJRtAECTJHEAS9JQBMMGXAIQBCBRISEMGXAM9FQBANAbJ2BBRtCBRKAfREEXAEANCU/CBJAKJ2BBHTCFrCBATCFZl9zAtJHt86BBAEAGJREAKCFJHKAM9HQBMMAfCFJRfAIRTAbCFJHbAG9HQBMMABAcAG9sJANCUGJAMAG9sTkUUUBpANANCUGJAMCaJAG9sJAGTkUUUBpMAMCBAIyAcJRcAIQBMC9+RKSFMCBC99AOAIlAGCAAGCA9Ly6yRKMALCU/EBJ8kUUUUBAKM+OmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUFT+JUUUBpALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM+lLKFaF99GaG99FaG99GXGXAGCI9HQBAF9FQFEXGXGX9DBBB8/9DBBB+/ABCGJHG1BB+yAB1BBHE+yHI+L+TABCFJHL1BBHK+yHO+L+THN9DBBBB9gHVyAN9DBB/+hANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE86BBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG86BBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG86BBABCIJRBAFCaJHFQBSGMMAF9FQBEXGXGX9DBBB8/9DBBB+/ABCIJHG8uFB+yAB8uFBHE+yHI+L+TABCGJHL8uFBHK+yHO+L+THN9DBBBB9gHVyAN9DB/+g6ANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE87FBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG87FBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG87FBABCNJRBAFCaJHFQBMMM/SEIEaE99EaF99GXAF9FQBCBREABRIEXGXGX9D/zI818/AICKJ8uFBHLCEq+y+VHKAI8uFB+y+UHO9DB/+g6+U9DBBB8/9DBBB+/AO9DBBBB9gy+SHN+L9DBBB9P9d9FQBAN+oRVSFMCUUUU94RVMAICIJ8uFBRcAICGJ8uFBRMABALCFJCEZAEqCFWJAV87FBGXGXAKAM+y+UHN9DB/+g6+U9DBBB8/9DBBB+/AN9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRMSFMCUUUU94RMMABALCGJCEZAEqCFWJAM87FBGXGXAKAc+y+UHK9DB/+g6+U9DBBB8/9DBBB+/AK9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRcSFMCUUUU94RcMABALCaJCEZAEqCFWJAc87FBGXGX9DBBU8/AOAO+U+TANAN+U+TAKAK+U+THO9DBBBBAO9DBBBB9gy+R9DB/+g6+U9DBBB8/+SHO+L9DBBB9P9d9FQBAO+oRcSFMCUUUU94RcMABALCEZAEqCFWJAc87FBAICNJRIAECIJREAFCaJHFQBMMM9JBGXAGCGrAF9sHF9FQBEXABAB8oGBHGCNWCN91+yAGCi91CnWCUUU/8EJ+++U84GBABCIJRBAFCaJHFQBMMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEM/lFFFaGXGXAFABqCEZ9FQBABRESFMGXGXAGCT9PQBABRESFMABREEXAEAF8oGBjGBAECIJAFCIJ8oGBjGBAECNJAFCNJ8oGBjGBAECSJAFCSJ8oGBjGBAECTJREAFCTJRFAGC9wJHGCb9LQBMMAGCI9JQBEXAEAF8oGBjGBAFCIJRFAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF2BB86BBAECFJREAFCFJRFAGCaJHGQBMMABMoFFGaGXGXABCEZ9FQBABRESFMAFCgFZC+BwsN9sRIGXGXAGCT9PQBABRESFMABREEXAEAIjGBAECSJAIjGBAECNJAIjGBAECIJAIjGBAECTJREAGC9wJHGCb9LQBMMAGCI9JQBEXAEAIjGBAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF86BBAECFJREAGCaJHGQBMMABMMMFBCUNMIT9kBB";
  72102. var wasm_simd = "B9h9z9tFBBBFiI9gBB9gLaaaaaFa9gEaaaB9gFaFaEMcBBFBFFGGGEILF9wFFFLEFBFKNFaFCx/aFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBG8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBIy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBKi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBOn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBNI9z9iqlBVc+N9IcIBTEM9+FLa8jUUUUBCTlRBCBRFEXCBRGCBREEXABCNJAGJAECUaAFAGrCFZHIy86BBAEAIJREAGCFJHGCN9HQBMAFCx+YUUBJAE86BBAFCEWCxkUUBJAB8pEN83EBAFCFJHFCUG9HQBMMk8lLbaE97F9+FaL978jUUUUBCU/KBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAG/8cBBCUoBAG9uC/wgBZHKCUGAKCUG9JyRNAECFJRKCBRVGXEXAVAF9PQFANAFAVlAVANJAF9JyRcGXGXAG9FQBAcCbJHIC9wZHMCE9sRSAMCFWRQAICIrCEJCGrRfCBRbEXAKRTCBRtGXEXGXAOATlAf9PQBCBRKSLMALCU/CBJAtAM9sJRmATAfJRKCBREGXAMCoB9JQBAOAKlC/gB9JQBCBRIEXAmAIJREGXGXGXGXGXATAICKrJ2BBHYCEZfIBFGEBMAECBDtDMIBSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAEAKDBBBDMIBAKCTJRKMGXGXGXGXGXAYCGrCEZfIBFGEBMAECBDtDMITSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAEAKDBBBDMITAKCTJRKMGXGXGXGXGXAYCIrCEZfIBFGEBMAECBDtDMIASEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAEAKDBBBDMIAAKCTJRKMGXGXGXGXGXAYCKrfIBFGEBMAECBDtDMI8wSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCIJAeDeBJAYCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCNJAeDeBJAYCx+YUUBJ2BBJRKSFMAEAKDBBBDMI8wAKCTJRKMAICoBJREAICUFJAM9LQFAERIAOAKlC/fB9LQBMMGXAEAM9PQBAECErRIEXGXAOAKlCi9PQBCBRKSOMAmAEJRYGXGXGXGXGXATAECKrJ2BBAICKZrCEZfIBFGEBMAYCBDtDMIBSEMAYAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAYAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAYAKDBBBDMIBAKCTJRKMAICGJRIAECTJHEAM9JQBMMGXAK9FQBAKRTAtCFJHtCI6QGSFMMCBRKSEMGXAM9FQBALCUGJAbJREALAbJDBGBReCBRYEXAEALCU/CBJAYJHIDBIBHdCFD9tAdCFDbHPD9OD9hD9RHdAIAMJDBIBH8ZCFD9tA8ZAPD9OD9hD9RH8ZDQBTFtGmEYIPLdKeOnHpAIAQJDBIBHyCFD9tAyAPD9OD9hD9RHyAIASJDBIBH8cCFD9tA8cAPD9OD9hD9RH8cDQBTFtGmEYIPLdKeOnH8dDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGEAeD9uHeDyBjGBAEAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJHIAeApA8dDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHeDyBjGBAIAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJHIAeAdA8ZDQNiV8ZcpMyS8cQ8df8eb8fHdAyA8cDQNiV8ZcpMyS8cQ8df8eb8fH8ZDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGED9uHeDyBjGBAIAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJHIAeAdA8ZDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHeDyBjGBAIAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJREAYCTJHYAM9JQBMMAbCIJHbAG9JQBMMABAVAG9sJALCUGJAcAG9s/8cBBALALCUGJAcCaJAG9sJAG/8cBBMAcCBAKyAVJRVAKQBMC9+RKSFMCBC99AOAKlAGCAAGCA9Ly6yRKMALCU/KBJ8kUUUUBAKMNBT+BUUUBM+KmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUF/8MBALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM/dLEK97FaF97GXGXAGCI9HQBAF9FQFCBRGEXABABDBBBHECiD+rFCiD+sFD/6FHIAECND+rFCiD+sFD/6FAID/gFAECTD+rFCiD+sFD/6FHLD/gFD/kFD/lFHKCBDtD+2FHOAICUUUU94DtHND9OD9RD/kFHI9DBB/+hDYAIAID/mFAKAKD/mFALAOALAND9OD9RD/kFHIAID/mFD/kFD/kFD/jFD/nFHLD/mF9DBBX9LDYHOD/kFCgFDtD9OAECUUU94DtD9OD9QAIALD/mFAOD/kFCND+rFCU/+EDtD9OD9QAKALD/mFAOD/kFCTD+rFCUU/8ODtD9OD9QDMBBABCTJRBAGCIJHGAF9JQBSGMMAF9FQBCBRGEXABCTJHVAVDBBBHECBDtHOCUU98D8cFCUU98D8cEHND9OABDBBBHKAEDQILKOSQfbPden8c8d8e8fCggFDtD9OD/6FAKAEDQBFGENVcMTtmYi8ZpyHECTD+sFD/6FHID/gFAECTD+rFCTD+sFD/6FHLD/gFD/kFD/lFHE9DB/+g6DYALAEAOD+2FHOALCUUUU94DtHcD9OD9RD/kFHLALD/mFAEAED/mFAIAOAIAcD9OD9RD/kFHEAED/mFD/kFD/kFD/jFD/nFHID/mF9DBBX9LDYHOD/kFCTD+rFALAID/mFAOD/kFCggEDtD9OD9QHLAEAID/mFAOD/kFCaDbCBDnGCBDnECBDnKCBDnOCBDncCBDnMCBDnfCBDnbD9OHEDQNVi8ZcMpySQ8c8dfb8e8fD9QDMBBABAKAND9OALAEDQBFTtGEmYILPdKOenD9QDMBBABCAJRBAGCIJHGAF9JQBMMM/hEIGaF97FaL978jUUUUBCTlREGXAF9FQBCBRIEXAEABDBBBHLABCTJHKDBBBHODQILKOSQfbPden8c8d8e8fHNCTD+sFHVCID+rFDMIBAB9DBBU8/DY9D/zI818/DYAVCEDtD9QD/6FD/nFHVALAODQBFGENVcMTtmYi8ZpyHLCTD+rFCTD+sFD/6FD/mFHOAOD/mFAVALCTD+sFD/6FD/mFHcAcD/mFAVANCTD+rFCTD+sFD/6FD/mFHNAND/mFD/kFD/kFD/lFCBDtD+4FD/jF9DB/+g6DYHVD/mF9DBBX9LDYHLD/kFCggEDtHMD9OAcAVD/mFALD/kFCTD+rFD9QHcANAVD/mFALD/kFCTD+rFAOAVD/mFALD/kFAMD9OD9QHVDQBFTtGEmYILPdKOenHLD8dBAEDBIBDyB+t+J83EBABCNJALD8dFAEDBIBDyF+t+J83EBAKAcAVDQNVi8ZcMpySQ8c8dfb8e8fHVD8dBAEDBIBDyG+t+J83EBABCiJAVD8dFAEDBIBDyE+t+J83EBABCAJRBAICIJHIAF9JQBMMM9jFF97GXAGCGrAF9sHG9FQBCBRFEXABABDBBBHECND+rFCND+sFD/6FAECiD+sFCnD+rFCUUU/8EDtD+uFD/mFDMBBABCTJRBAFCIJHFAG9JQBMMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEMMMFBCUNMIT9tBB";
  72103. // Uses bulk-memory and simd extensions
  72104. var detector = new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,3,2,0,0,5,3,1,0,1,12,1,0,10,22,2,12,0,65,0,65,0,65,0,252,10,0,0,11,7,0,65,0,253,15,26,11]);
  72105. // Used to unpack wasm
  72106. var wasmpack = new Uint8Array([32,0,65,253,3,1,2,34,4,106,6,5,11,8,7,20,13,33,12,16,128,9,116,64,19,113,127,15,10,21,22,14,255,66,24,54,136,107,18,23,192,26,114,118,132,17,77,101,130,144,27,87,131,44,45,74,156,154,70,167]);
  72107. if (typeof WebAssembly !== 'object') {
  72108. // This module requires WebAssembly to function
  72109. return {
  72110. supported: false,
  72111. };
  72112. }
  72113. var wasm = wasm_base;
  72114. if (WebAssembly.validate(detector)) {
  72115. wasm = wasm_simd;
  72116. console.log("Warning: meshopt_decoder is using experimental SIMD support");
  72117. }
  72118. var instance;
  72119. var promise =
  72120. WebAssembly.instantiate(unpack(wasm), {})
  72121. .then(function(result) {
  72122. instance = result.instance;
  72123. instance.exports.__wasm_call_ctors();
  72124. });
  72125. function unpack(data) {
  72126. var result = new Uint8Array(data.length);
  72127. for (var i = 0; i < data.length; ++i) {
  72128. var ch = data.charCodeAt(i);
  72129. result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62;
  72130. }
  72131. var write = 0;
  72132. for (var i = 0; i < data.length; ++i) {
  72133. result[write++] = (result[i] < 60) ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i];
  72134. }
  72135. return result.buffer.slice(0, write);
  72136. }
  72137. function decode(fun, target, count, size, source, filter) {
  72138. var sbrk = instance.exports.sbrk;
  72139. var count4 = (count + 3) & ~3; // pad for SIMD filter
  72140. var tp = sbrk(count4 * size);
  72141. var sp = sbrk(source.length);
  72142. var heap = new Uint8Array(instance.exports.memory.buffer);
  72143. heap.set(source, sp);
  72144. var res = fun(tp, count, size, sp, source.length);
  72145. if (res == 0 && filter) {
  72146. filter(tp, count4, size);
  72147. }
  72148. target.set(heap.subarray(tp, tp + count * size));
  72149. sbrk(tp - sbrk(0));
  72150. if (res != 0) {
  72151. throw new Error("Malformed buffer data: " + res);
  72152. }
  72153. };
  72154. var filters = {
  72155. // legacy index-based enums for glTF
  72156. 0: "",
  72157. 1: "meshopt_decodeFilterOct",
  72158. 2: "meshopt_decodeFilterQuat",
  72159. 3: "meshopt_decodeFilterExp",
  72160. // string-based enums for glTF
  72161. NONE: "",
  72162. OCTAHEDRAL: "meshopt_decodeFilterOct",
  72163. QUATERNION: "meshopt_decodeFilterQuat",
  72164. EXPONENTIAL: "meshopt_decodeFilterExp",
  72165. };
  72166. var decoders = {
  72167. // legacy index-based enums for glTF
  72168. 0: "meshopt_decodeVertexBuffer",
  72169. 1: "meshopt_decodeIndexBuffer",
  72170. 2: "meshopt_decodeIndexSequence",
  72171. // string-based enums for glTF
  72172. ATTRIBUTES: "meshopt_decodeVertexBuffer",
  72173. TRIANGLES: "meshopt_decodeIndexBuffer",
  72174. INDICES: "meshopt_decodeIndexSequence",
  72175. };
  72176. return {
  72177. ready: promise,
  72178. supported: true,
  72179. decodeVertexBuffer: function(target, count, size, source, filter) {
  72180. decode(instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]);
  72181. },
  72182. decodeIndexBuffer: function(target, count, size, source) {
  72183. decode(instance.exports.meshopt_decodeIndexBuffer, target, count, size, source);
  72184. },
  72185. decodeIndexSequence: function(target, count, size, source) {
  72186. decode(instance.exports.meshopt_decodeIndexSequence, target, count, size, source);
  72187. },
  72188. decodeGltfBuffer: function(target, count, size, source, mode, filter) {
  72189. decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
  72190. }
  72191. };
  72192. })();
  72193. var DDSLoader = function ( manager ) {
  72194. CompressedTextureLoader.call( this, manager );
  72195. };
  72196. DDSLoader.prototype = Object.assign( Object.create( CompressedTextureLoader.prototype ), {
  72197. constructor: DDSLoader,
  72198. parse: function ( buffer, loadMipmaps ) {
  72199. var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 };
  72200. // Adapted from @toji's DDS utils
  72201. // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js
  72202. // All values and structures referenced from:
  72203. // http://msdn.microsoft.com/en-us/library/bb943991.aspx/
  72204. var DDS_MAGIC = 0x20534444;
  72205. // var DDSD_CAPS = 0x1;
  72206. // var DDSD_HEIGHT = 0x2;
  72207. // var DDSD_WIDTH = 0x4;
  72208. // var DDSD_PITCH = 0x8;
  72209. // var DDSD_PIXELFORMAT = 0x1000;
  72210. var DDSD_MIPMAPCOUNT = 0x20000;
  72211. // var DDSD_LINEARSIZE = 0x80000;
  72212. // var DDSD_DEPTH = 0x800000;
  72213. // var DDSCAPS_COMPLEX = 0x8;
  72214. // var DDSCAPS_MIPMAP = 0x400000;
  72215. // var DDSCAPS_TEXTURE = 0x1000;
  72216. var DDSCAPS2_CUBEMAP = 0x200;
  72217. var DDSCAPS2_CUBEMAP_POSITIVEX = 0x400;
  72218. var DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800;
  72219. var DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000;
  72220. var DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000;
  72221. var DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000;
  72222. var DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000;
  72223. // var DDSCAPS2_VOLUME = 0x200000;
  72224. // var DDPF_ALPHAPIXELS = 0x1;
  72225. // var DDPF_ALPHA = 0x2;
  72226. var DDPF_FOURCC = 0x4;
  72227. // var DDPF_RGB = 0x40;
  72228. // var DDPF_YUV = 0x200;
  72229. // var DDPF_LUMINANCE = 0x20000;
  72230. function fourCCToInt32( value ) {
  72231. return value.charCodeAt( 0 ) +
  72232. ( value.charCodeAt( 1 ) << 8 ) +
  72233. ( value.charCodeAt( 2 ) << 16 ) +
  72234. ( value.charCodeAt( 3 ) << 24 );
  72235. }
  72236. function int32ToFourCC( value ) {
  72237. return String.fromCharCode(
  72238. value & 0xff,
  72239. ( value >> 8 ) & 0xff,
  72240. ( value >> 16 ) & 0xff,
  72241. ( value >> 24 ) & 0xff
  72242. );
  72243. }
  72244. function loadARGBMip( buffer, dataOffset, width, height ) {
  72245. var dataLength = width * height * 4;
  72246. var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength );
  72247. var byteArray = new Uint8Array( dataLength );
  72248. var dst = 0;
  72249. var src = 0;
  72250. for ( var y = 0; y < height; y ++ ) {
  72251. for ( var x = 0; x < width; x ++ ) {
  72252. var b = srcBuffer[ src ]; src ++;
  72253. var g = srcBuffer[ src ]; src ++;
  72254. var r = srcBuffer[ src ]; src ++;
  72255. var a = srcBuffer[ src ]; src ++;
  72256. byteArray[ dst ] = r; dst ++; //r
  72257. byteArray[ dst ] = g; dst ++; //g
  72258. byteArray[ dst ] = b; dst ++; //b
  72259. byteArray[ dst ] = a; dst ++; //a
  72260. }
  72261. }
  72262. return byteArray;
  72263. }
  72264. var FOURCC_DXT1 = fourCCToInt32( 'DXT1' );
  72265. var FOURCC_DXT3 = fourCCToInt32( 'DXT3' );
  72266. var FOURCC_DXT5 = fourCCToInt32( 'DXT5' );
  72267. var FOURCC_ETC1 = fourCCToInt32( 'ETC1' );
  72268. var headerLengthInt = 31; // The header length in 32 bit ints
  72269. // Offsets into the header array
  72270. var off_magic = 0;
  72271. var off_size = 1;
  72272. var off_flags = 2;
  72273. var off_height = 3;
  72274. var off_width = 4;
  72275. var off_mipmapCount = 7;
  72276. var off_pfFlags = 20;
  72277. var off_pfFourCC = 21;
  72278. var off_RGBBitCount = 22;
  72279. var off_RBitMask = 23;
  72280. var off_GBitMask = 24;
  72281. var off_BBitMask = 25;
  72282. var off_ABitMask = 26;
  72283. // var off_caps = 27;
  72284. var off_caps2 = 28;
  72285. // var off_caps3 = 29;
  72286. // var off_caps4 = 30;
  72287. // Parse header
  72288. var header = new Int32Array( buffer, 0, headerLengthInt );
  72289. if ( header[ off_magic ] !== DDS_MAGIC ) {
  72290. console.error( 'THREE.DDSLoader.parse: Invalid magic number in DDS header.' );
  72291. return dds;
  72292. }
  72293. if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {
  72294. console.error( 'THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.' );
  72295. return dds;
  72296. }
  72297. var blockBytes;
  72298. var fourCC = header[ off_pfFourCC ];
  72299. var isRGBAUncompressed = false;
  72300. switch ( fourCC ) {
  72301. case FOURCC_DXT1:
  72302. blockBytes = 8;
  72303. dds.format = RGB_S3TC_DXT1_Format;
  72304. break;
  72305. case FOURCC_DXT3:
  72306. blockBytes = 16;
  72307. dds.format = RGBA_S3TC_DXT3_Format;
  72308. break;
  72309. case FOURCC_DXT5:
  72310. blockBytes = 16;
  72311. dds.format = RGBA_S3TC_DXT5_Format$1;
  72312. break;
  72313. case FOURCC_ETC1:
  72314. blockBytes = 8;
  72315. dds.format = RGB_ETC1_Format;
  72316. break;
  72317. default:
  72318. if ( header[ off_RGBBitCount ] === 32
  72319. && header[ off_RBitMask ] & 0xff0000
  72320. && header[ off_GBitMask ] & 0xff00
  72321. && header[ off_BBitMask ] & 0xff
  72322. && header[ off_ABitMask ] & 0xff000000 ) {
  72323. isRGBAUncompressed = true;
  72324. blockBytes = 64;
  72325. dds.format = RGBAFormat;
  72326. } else {
  72327. console.error( 'THREE.DDSLoader.parse: Unsupported FourCC code ', int32ToFourCC( fourCC ) );
  72328. return dds;
  72329. }
  72330. }
  72331. dds.mipmapCount = 1;
  72332. if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {
  72333. dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );
  72334. }
  72335. var caps2 = header[ off_caps2 ];
  72336. dds.isCubemap = caps2 & DDSCAPS2_CUBEMAP ? true : false;
  72337. if ( dds.isCubemap && (
  72338. ! ( caps2 & DDSCAPS2_CUBEMAP_POSITIVEX ) ||
  72339. ! ( caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX ) ||
  72340. ! ( caps2 & DDSCAPS2_CUBEMAP_POSITIVEY ) ||
  72341. ! ( caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY ) ||
  72342. ! ( caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ ) ||
  72343. ! ( caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ )
  72344. ) ) {
  72345. console.error( 'THREE.DDSLoader.parse: Incomplete cubemap faces' );
  72346. return dds;
  72347. }
  72348. dds.width = header[ off_width ];
  72349. dds.height = header[ off_height ];
  72350. var dataOffset = header[ off_size ] + 4;
  72351. // Extract mipmaps buffers
  72352. var faces = dds.isCubemap ? 6 : 1;
  72353. for ( var face = 0; face < faces; face ++ ) {
  72354. var width = dds.width;
  72355. var height = dds.height;
  72356. for ( var i = 0; i < dds.mipmapCount; i ++ ) {
  72357. if ( isRGBAUncompressed ) {
  72358. var byteArray = loadARGBMip( buffer, dataOffset, width, height );
  72359. var dataLength = byteArray.length;
  72360. } else {
  72361. var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
  72362. var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
  72363. }
  72364. var mipmap = { 'data': byteArray, 'width': width, 'height': height };
  72365. dds.mipmaps.push( mipmap );
  72366. dataOffset += dataLength;
  72367. width = Math.max( width >> 1, 1 );
  72368. height = Math.max( height >> 1, 1 );
  72369. }
  72370. }
  72371. return dds;
  72372. }
  72373. } );
  72374. var GLTFLoader = ( function () {
  72375. function GLTFLoader( manager, renderer, urlPrefix) {
  72376. Loader.call( this, manager );
  72377. /* this.dracoLoader = null;
  72378. this.ddsLoader = null;
  72379. this.ktx2Loader = null;
  72380. this.meshoptDecoder = null; */
  72381. //xzw add:
  72382. this.dracoLoader = new DRACOLoader;
  72383. this.ktx2Loader = new KTX2Loader;
  72384. this.meshoptDecoder = MeshoptDecoder;
  72385. this.ddsLoader = new DDSLoader; //这个没测过
  72386. //路径相对于index.html
  72387. this.dracoLoader.setDecoderPath( urlPrefix + 'three.js/loaders/draco/' /* '../libs/three.js/loaders/draco/' */ /* 'static/lib/three.js/loaders/draco/' */); //这两个路径可以自己改。在laser的环境也要放一份这个路径
  72388. this.ktx2Loader.setTranscoderPath(urlPrefix + 'three.js/loaders/ktx/' /* '../libs/three.js/loaders/ktx/' */ /* 'static/lib/three.js/loaders/ktx/' */ ).detectSupport( renderer );
  72389. //------------
  72390. this.pluginCallbacks = [];
  72391. this.register( function ( parser ) {
  72392. return new GLTFMaterialsClearcoatExtension( parser );
  72393. } );
  72394. this.register( function ( parser ) {
  72395. return new GLTFTextureBasisUExtension( parser );
  72396. } );
  72397. this.register( function ( parser ) {
  72398. return new GLTFTextureWebPExtension( parser );
  72399. } );
  72400. this.register( function ( parser ) {
  72401. return new GLTFMaterialsTransmissionExtension( parser );
  72402. } );
  72403. this.register( function ( parser ) {
  72404. return new GLTFLightsExtension( parser );
  72405. } );
  72406. this.register( function ( parser ) {
  72407. return new GLTFMeshoptCompression( parser );
  72408. } );
  72409. }
  72410. GLTFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  72411. constructor: GLTFLoader,
  72412. load: function ( url, onLoad, onProgress, onError ) {
  72413. var scope = this;
  72414. var resourcePath;
  72415. if ( this.resourcePath !== '' ) {
  72416. resourcePath = this.resourcePath;
  72417. } else if ( this.path !== '' ) {
  72418. resourcePath = this.path;
  72419. } else {
  72420. resourcePath = LoaderUtils.extractUrlBase( url );
  72421. }
  72422. // Tells the LoadingManager to track an extra item, which resolves after
  72423. // the model is fully loaded. This means the count of items loaded will
  72424. // be incorrect, but ensures manager.onLoad() does not fire early.
  72425. this.manager.itemStart( url );
  72426. var _onError = function ( e ) {
  72427. if ( onError ) {
  72428. onError( e );
  72429. } else {
  72430. console.error( e );
  72431. }
  72432. scope.manager.itemError( url );
  72433. scope.manager.itemEnd( url );
  72434. };
  72435. var loader = new FileLoader( this.manager );
  72436. loader.setPath( this.path );
  72437. loader.setResponseType( 'arraybuffer' );
  72438. loader.setRequestHeader( this.requestHeader );
  72439. loader.setWithCredentials( this.withCredentials );
  72440. loader.load( url, function ( data, total ) {// xzw add total
  72441. try {
  72442. scope.parse( data, resourcePath, function ( gltf ) {
  72443. onLoad( gltf, total );
  72444. scope.manager.itemEnd( url );
  72445. }, _onError );
  72446. } catch ( e ) {
  72447. _onError( e );
  72448. }
  72449. }, onProgress, _onError );
  72450. },
  72451. setDRACOLoader: function ( dracoLoader ) {
  72452. this.dracoLoader = dracoLoader;
  72453. return this;
  72454. },
  72455. setDDSLoader: function ( ddsLoader ) {
  72456. this.ddsLoader = ddsLoader;
  72457. return this;
  72458. },
  72459. setKTX2Loader: function ( ktx2Loader ) {
  72460. this.ktx2Loader = ktx2Loader;
  72461. return this;
  72462. },
  72463. setMeshoptDecoder: function ( meshoptDecoder ) {
  72464. this.meshoptDecoder = meshoptDecoder;
  72465. return this;
  72466. },
  72467. register: function ( callback ) {
  72468. if ( this.pluginCallbacks.indexOf( callback ) === - 1 ) {
  72469. this.pluginCallbacks.push( callback );
  72470. }
  72471. return this;
  72472. },
  72473. unregister: function ( callback ) {
  72474. if ( this.pluginCallbacks.indexOf( callback ) !== - 1 ) {
  72475. this.pluginCallbacks.splice( this.pluginCallbacks.indexOf( callback ), 1 );
  72476. }
  72477. return this;
  72478. },
  72479. parse: function ( data, path, onLoad, onError ) {
  72480. var content;
  72481. var extensions = {};
  72482. var plugins = {};
  72483. if ( typeof data === 'string' ) {
  72484. content = data;
  72485. } else {
  72486. var magic = LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
  72487. if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
  72488. try {
  72489. extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
  72490. } catch ( error ) {
  72491. if ( onError ) onError( error );
  72492. return;
  72493. }
  72494. content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
  72495. } else {
  72496. content = LoaderUtils.decodeText( new Uint8Array( data ) );
  72497. }
  72498. }
  72499. var json = JSON.parse( content );
  72500. if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
  72501. if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) );
  72502. return;
  72503. }
  72504. var parser = new GLTFParser( json, {
  72505. path: path || this.resourcePath || '',
  72506. crossOrigin: this.crossOrigin,
  72507. manager: this.manager,
  72508. ktx2Loader: this.ktx2Loader,
  72509. meshoptDecoder: this.meshoptDecoder
  72510. } );
  72511. parser.fileLoader.setRequestHeader( this.requestHeader );
  72512. for ( var i = 0; i < this.pluginCallbacks.length; i ++ ) {
  72513. var plugin = this.pluginCallbacks[ i ]( parser );
  72514. plugins[ plugin.name ] = plugin;
  72515. // Workaround to avoid determining as unknown extension
  72516. // in addUnknownExtensionsToUserData().
  72517. // Remove this workaround if we move all the existing
  72518. // extension handlers to plugin system
  72519. extensions[ plugin.name ] = true;
  72520. }
  72521. if ( json.extensionsUsed ) {
  72522. for ( var i = 0; i < json.extensionsUsed.length; ++ i ) {
  72523. var extensionName = json.extensionsUsed[ i ];
  72524. var extensionsRequired = json.extensionsRequired || [];
  72525. switch ( extensionName ) {
  72526. case EXTENSIONS.KHR_MATERIALS_UNLIT:
  72527. extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
  72528. break;
  72529. case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
  72530. extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
  72531. break;
  72532. case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
  72533. extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
  72534. break;
  72535. case EXTENSIONS.MSFT_TEXTURE_DDS:
  72536. extensions[ extensionName ] = new GLTFTextureDDSExtension( this.ddsLoader );
  72537. break;
  72538. case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
  72539. extensions[ extensionName ] = new GLTFTextureTransformExtension();
  72540. break;
  72541. case EXTENSIONS.KHR_MESH_QUANTIZATION:
  72542. extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
  72543. break;
  72544. default:
  72545. if ( extensionsRequired.indexOf( extensionName ) >= 0 && plugins[ extensionName ] === undefined ) {
  72546. console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
  72547. }
  72548. }
  72549. }
  72550. }
  72551. parser.setExtensions( extensions );
  72552. parser.setPlugins( plugins );
  72553. parser.parse( onLoad, onError );
  72554. }
  72555. } );
  72556. /* GLTFREGISTRY */
  72557. function GLTFRegistry() {
  72558. var objects = {};
  72559. return {
  72560. get: function ( key ) {
  72561. return objects[ key ];
  72562. },
  72563. add: function ( key, object ) {
  72564. objects[ key ] = object;
  72565. },
  72566. remove: function ( key ) {
  72567. delete objects[ key ];
  72568. },
  72569. removeAll: function () {
  72570. objects = {};
  72571. }
  72572. };
  72573. }
  72574. /*********************************/
  72575. /********** EXTENSIONS ***********/
  72576. /*********************************/
  72577. var EXTENSIONS = {
  72578. KHR_BINARY_GLTF: 'KHR_binary_glTF',
  72579. KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
  72580. KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
  72581. KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
  72582. KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
  72583. KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
  72584. KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
  72585. KHR_TEXTURE_BASISU: 'KHR_texture_basisu',
  72586. KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
  72587. KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
  72588. EXT_TEXTURE_WEBP: 'EXT_texture_webp',
  72589. EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression',
  72590. MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
  72591. };
  72592. /**
  72593. * DDS Texture Extension
  72594. *
  72595. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds
  72596. *
  72597. */
  72598. function GLTFTextureDDSExtension( ddsLoader ) {
  72599. if ( ! ddsLoader ) {
  72600. throw new Error( 'THREE.GLTFLoader: Attempting to load .dds texture without importing DDSLoader' );
  72601. }
  72602. this.name = EXTENSIONS.MSFT_TEXTURE_DDS;
  72603. this.ddsLoader = ddsLoader;
  72604. }
  72605. /**
  72606. * Punctual Lights Extension
  72607. *
  72608. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
  72609. */
  72610. function GLTFLightsExtension( parser ) {
  72611. this.parser = parser;
  72612. this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL;
  72613. // Object3D instance caches
  72614. this.cache = { refs: {}, uses: {} };
  72615. }
  72616. GLTFLightsExtension.prototype._markDefs = function () {
  72617. var parser = this.parser;
  72618. var nodeDefs = this.parser.json.nodes || [];
  72619. for ( var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
  72620. var nodeDef = nodeDefs[ nodeIndex ];
  72621. if ( nodeDef.extensions
  72622. && nodeDef.extensions[ this.name ]
  72623. && nodeDef.extensions[ this.name ].light !== undefined ) {
  72624. parser._addNodeRef( this.cache, nodeDef.extensions[ this.name ].light );
  72625. }
  72626. }
  72627. };
  72628. GLTFLightsExtension.prototype._loadLight = function ( lightIndex ) {
  72629. var parser = this.parser;
  72630. var cacheKey = 'light:' + lightIndex;
  72631. var dependency = parser.cache.get( cacheKey );
  72632. if ( dependency ) return dependency;
  72633. var json = parser.json;
  72634. var extensions = ( json.extensions && json.extensions[ this.name ] ) || {};
  72635. var lightDefs = extensions.lights || [];
  72636. var lightDef = lightDefs[ lightIndex ];
  72637. var lightNode;
  72638. var color = new Color( 0xffffff );
  72639. if ( lightDef.color !== undefined ) color.fromArray( lightDef.color );
  72640. var range = lightDef.range !== undefined ? lightDef.range : 0;
  72641. switch ( lightDef.type ) {
  72642. case 'directional':
  72643. lightNode = new DirectionalLight( color );
  72644. lightNode.target.position.set( 0, 0, - 1 );
  72645. lightNode.add( lightNode.target );
  72646. break;
  72647. case 'point':
  72648. lightNode = new PointLight( color );
  72649. lightNode.distance = range;
  72650. break;
  72651. case 'spot':
  72652. lightNode = new SpotLight( color );
  72653. lightNode.distance = range;
  72654. // Handle spotlight properties.
  72655. lightDef.spot = lightDef.spot || {};
  72656. lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0;
  72657. lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
  72658. lightNode.angle = lightDef.spot.outerConeAngle;
  72659. lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;
  72660. lightNode.target.position.set( 0, 0, - 1 );
  72661. lightNode.add( lightNode.target );
  72662. break;
  72663. default:
  72664. throw new Error( 'THREE.GLTFLoader: Unexpected light type: ' + lightDef.type );
  72665. }
  72666. // Some lights (e.g. spot) default to a position other than the origin. Reset the position
  72667. // here, because node-level parsing will only override position if explicitly specified.
  72668. lightNode.position.set( 0, 0, 0 );
  72669. lightNode.decay = 2;
  72670. if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
  72671. lightNode.name = parser.createUniqueName( lightDef.name || ( 'light_' + lightIndex ) );
  72672. dependency = Promise.resolve( lightNode );
  72673. parser.cache.add( cacheKey, dependency );
  72674. return dependency;
  72675. };
  72676. GLTFLightsExtension.prototype.createNodeAttachment = function ( nodeIndex ) {
  72677. var self = this;
  72678. var parser = this.parser;
  72679. var json = parser.json;
  72680. var nodeDef = json.nodes[ nodeIndex ];
  72681. var lightDef = ( nodeDef.extensions && nodeDef.extensions[ this.name ] ) || {};
  72682. var lightIndex = lightDef.light;
  72683. if ( lightIndex === undefined ) return null;
  72684. return this._loadLight( lightIndex ).then( function ( light ) {
  72685. return parser._getNodeRef( self.cache, lightIndex, light );
  72686. } );
  72687. };
  72688. /**
  72689. * Unlit Materials Extension
  72690. *
  72691. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit
  72692. */
  72693. function GLTFMaterialsUnlitExtension() {
  72694. this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;
  72695. }
  72696. GLTFMaterialsUnlitExtension.prototype.getMaterialType = function () {
  72697. return MeshBasicMaterial;
  72698. };
  72699. GLTFMaterialsUnlitExtension.prototype.extendParams = function ( materialParams, materialDef, parser ) {
  72700. var pending = [];
  72701. materialParams.color = new Color( 1.0, 1.0, 1.0 );
  72702. materialParams.opacity = 1.0;
  72703. var metallicRoughness = materialDef.pbrMetallicRoughness;
  72704. if ( metallicRoughness ) {
  72705. if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
  72706. var array = metallicRoughness.baseColorFactor;
  72707. materialParams.color.fromArray( array );
  72708. materialParams.opacity = array[ 3 ];
  72709. }
  72710. if ( metallicRoughness.baseColorTexture !== undefined ) {
  72711. pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
  72712. }
  72713. }
  72714. return Promise.all( pending );
  72715. };
  72716. /**
  72717. * Clearcoat Materials Extension
  72718. *
  72719. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat
  72720. */
  72721. function GLTFMaterialsClearcoatExtension( parser ) {
  72722. this.parser = parser;
  72723. this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT;
  72724. }
  72725. GLTFMaterialsClearcoatExtension.prototype.getMaterialType = function ( materialIndex ) {
  72726. var parser = this.parser;
  72727. var materialDef = parser.json.materials[ materialIndex ];
  72728. if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
  72729. return MeshPhysicalMaterial;
  72730. };
  72731. GLTFMaterialsClearcoatExtension.prototype.extendMaterialParams = function ( materialIndex, materialParams ) {
  72732. var parser = this.parser;
  72733. var materialDef = parser.json.materials[ materialIndex ];
  72734. if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
  72735. return Promise.resolve();
  72736. }
  72737. var pending = [];
  72738. var extension = materialDef.extensions[ this.name ];
  72739. if ( extension.clearcoatFactor !== undefined ) {
  72740. materialParams.clearcoat = extension.clearcoatFactor;
  72741. }
  72742. if ( extension.clearcoatTexture !== undefined ) {
  72743. pending.push( parser.assignTexture( materialParams, 'clearcoatMap', extension.clearcoatTexture ) );
  72744. }
  72745. if ( extension.clearcoatRoughnessFactor !== undefined ) {
  72746. materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor;
  72747. }
  72748. if ( extension.clearcoatRoughnessTexture !== undefined ) {
  72749. pending.push( parser.assignTexture( materialParams, 'clearcoatRoughnessMap', extension.clearcoatRoughnessTexture ) );
  72750. }
  72751. if ( extension.clearcoatNormalTexture !== undefined ) {
  72752. pending.push( parser.assignTexture( materialParams, 'clearcoatNormalMap', extension.clearcoatNormalTexture ) );
  72753. if ( extension.clearcoatNormalTexture.scale !== undefined ) {
  72754. var scale = extension.clearcoatNormalTexture.scale;
  72755. materialParams.clearcoatNormalScale = new Vector2$1( scale, scale );
  72756. }
  72757. }
  72758. return Promise.all( pending );
  72759. };
  72760. /**
  72761. * Transmission Materials Extension
  72762. *
  72763. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission
  72764. * Draft: https://github.com/KhronosGroup/glTF/pull/1698
  72765. */
  72766. function GLTFMaterialsTransmissionExtension( parser ) {
  72767. this.parser = parser;
  72768. this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION;
  72769. }
  72770. GLTFMaterialsTransmissionExtension.prototype.getMaterialType = function ( materialIndex ) {
  72771. var parser = this.parser;
  72772. var materialDef = parser.json.materials[ materialIndex ];
  72773. if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
  72774. return MeshPhysicalMaterial;
  72775. };
  72776. GLTFMaterialsTransmissionExtension.prototype.extendMaterialParams = function ( materialIndex, materialParams ) {
  72777. var parser = this.parser;
  72778. var materialDef = parser.json.materials[ materialIndex ];
  72779. if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
  72780. return Promise.resolve();
  72781. }
  72782. var pending = [];
  72783. var extension = materialDef.extensions[ this.name ];
  72784. if ( extension.transmissionFactor !== undefined ) {
  72785. materialParams.transmission = extension.transmissionFactor;
  72786. }
  72787. if ( extension.transmissionTexture !== undefined ) {
  72788. pending.push( parser.assignTexture( materialParams, 'transmissionMap', extension.transmissionTexture ) );
  72789. }
  72790. return Promise.all( pending );
  72791. };
  72792. /**
  72793. * BasisU Texture Extension
  72794. *
  72795. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_basisu
  72796. */
  72797. function GLTFTextureBasisUExtension( parser ) {
  72798. this.parser = parser;
  72799. this.name = EXTENSIONS.KHR_TEXTURE_BASISU;
  72800. }
  72801. GLTFTextureBasisUExtension.prototype.loadTexture = function ( textureIndex ) {
  72802. var parser = this.parser;
  72803. var json = parser.json;
  72804. var textureDef = json.textures[ textureIndex ];
  72805. if ( ! textureDef.extensions || ! textureDef.extensions[ this.name ] ) {
  72806. return null;
  72807. }
  72808. var extension = textureDef.extensions[ this.name ];
  72809. var source = json.images[ extension.source ];
  72810. var loader = parser.options.ktx2Loader;
  72811. if ( ! loader ) {
  72812. if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) {
  72813. throw new Error( 'THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures' );
  72814. } else {
  72815. // Assumes that the extension is optional and that a fallback texture is present
  72816. return null;
  72817. }
  72818. }
  72819. return parser.loadTextureImage( textureIndex, source, loader );
  72820. };
  72821. /**
  72822. * WebP Texture Extension
  72823. *
  72824. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp
  72825. */
  72826. function GLTFTextureWebPExtension( parser ) {
  72827. this.parser = parser;
  72828. this.name = EXTENSIONS.EXT_TEXTURE_WEBP;
  72829. this.isSupported = null;
  72830. }
  72831. GLTFTextureWebPExtension.prototype.loadTexture = function ( textureIndex ) {
  72832. var name = this.name;
  72833. var parser = this.parser;
  72834. var json = parser.json;
  72835. var textureDef = json.textures[ textureIndex ];
  72836. if ( ! textureDef.extensions || ! textureDef.extensions[ name ] ) {
  72837. return null;
  72838. }
  72839. var extension = textureDef.extensions[ name ];
  72840. var source = json.images[ extension.source ];
  72841. var loader = source.uri ? parser.options.manager.getHandler( source.uri ) : parser.textureLoader;
  72842. return this.detectSupport().then( function ( isSupported ) {
  72843. if ( isSupported ) return parser.loadTextureImage( textureIndex, source, loader );
  72844. if ( json.extensionsRequired && json.extensionsRequired.indexOf( name ) >= 0 ) {
  72845. throw new Error( 'THREE.GLTFLoader: WebP required by asset but unsupported.' );
  72846. }
  72847. // Fall back to PNG or JPEG.
  72848. return parser.loadTexture( textureIndex );
  72849. } );
  72850. };
  72851. GLTFTextureWebPExtension.prototype.detectSupport = function () {
  72852. if ( ! this.isSupported ) {
  72853. this.isSupported = new Promise( function ( resolve ) {
  72854. var image = new Image();
  72855. // Lossy test image. Support for lossy images doesn't guarantee support for all
  72856. // WebP images, unfortunately.
  72857. image.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
  72858. image.onload = image.onerror = function () {
  72859. resolve( image.height === 1 );
  72860. };
  72861. } );
  72862. }
  72863. return this.isSupported;
  72864. };
  72865. /**
  72866. * meshopt BufferView Compression Extension
  72867. *
  72868. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_meshopt_compression
  72869. */
  72870. function GLTFMeshoptCompression( parser ) {
  72871. this.name = EXTENSIONS.EXT_MESHOPT_COMPRESSION;
  72872. this.parser = parser;
  72873. }
  72874. GLTFMeshoptCompression.prototype.loadBufferView = function ( index ) {
  72875. var json = this.parser.json;
  72876. var bufferView = json.bufferViews[ index ];
  72877. if ( bufferView.extensions && bufferView.extensions[ this.name ] ) {
  72878. var extensionDef = bufferView.extensions[ this.name ];
  72879. var buffer = this.parser.getDependency( 'buffer', extensionDef.buffer );
  72880. var decoder = this.parser.options.meshoptDecoder;
  72881. if ( ! decoder || ! decoder.supported ) {
  72882. if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) {
  72883. throw new Error( 'THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files' );
  72884. } else {
  72885. // Assumes that the extension is optional and that fallback buffer data is present
  72886. return null;
  72887. }
  72888. }
  72889. return Promise.all( [ buffer, decoder.ready ] ).then( function ( res ) {
  72890. var byteOffset = extensionDef.byteOffset || 0;
  72891. var byteLength = extensionDef.byteLength || 0;
  72892. var count = extensionDef.count;
  72893. var stride = extensionDef.byteStride;
  72894. var result = new ArrayBuffer( count * stride );
  72895. var source = new Uint8Array( res[ 0 ], byteOffset, byteLength );
  72896. decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
  72897. return result;
  72898. } );
  72899. } else {
  72900. return null;
  72901. }
  72902. };
  72903. /* BINARY EXTENSION */
  72904. var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
  72905. var BINARY_EXTENSION_HEADER_LENGTH = 12;
  72906. var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
  72907. function GLTFBinaryExtension( data ) {
  72908. this.name = EXTENSIONS.KHR_BINARY_GLTF;
  72909. this.content = null;
  72910. this.body = null;
  72911. var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
  72912. this.header = {
  72913. magic: LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
  72914. version: headerView.getUint32( 4, true ),
  72915. length: headerView.getUint32( 8, true )
  72916. };
  72917. if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
  72918. throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' );
  72919. } else if ( this.header.version < 2.0 ) {
  72920. throw new Error( 'THREE.GLTFLoader: Legacy binary file detected.' );
  72921. }
  72922. var chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );
  72923. var chunkIndex = 0;
  72924. while ( chunkIndex < chunkView.byteLength ) {
  72925. var chunkLength = chunkView.getUint32( chunkIndex, true );
  72926. chunkIndex += 4;
  72927. var chunkType = chunkView.getUint32( chunkIndex, true );
  72928. chunkIndex += 4;
  72929. if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
  72930. var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
  72931. this.content = LoaderUtils.decodeText( contentArray );
  72932. } else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
  72933. var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
  72934. this.body = data.slice( byteOffset, byteOffset + chunkLength );
  72935. }
  72936. // Clients must ignore chunks with unknown types.
  72937. chunkIndex += chunkLength;
  72938. }
  72939. if ( this.content === null ) {
  72940. throw new Error( 'THREE.GLTFLoader: JSON content not found.' );
  72941. }
  72942. }
  72943. /**
  72944. * DRACO Mesh Compression Extension
  72945. *
  72946. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
  72947. */
  72948. function GLTFDracoMeshCompressionExtension( json, dracoLoader ) {
  72949. if ( ! dracoLoader ) {
  72950. throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' );
  72951. }
  72952. this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
  72953. this.json = json;
  72954. this.dracoLoader = dracoLoader;
  72955. this.dracoLoader.preload();
  72956. }
  72957. GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) {
  72958. var json = this.json;
  72959. var dracoLoader = this.dracoLoader;
  72960. var bufferViewIndex = primitive.extensions[ this.name ].bufferView;
  72961. var gltfAttributeMap = primitive.extensions[ this.name ].attributes;
  72962. var threeAttributeMap = {};
  72963. var attributeNormalizedMap = {};
  72964. var attributeTypeMap = {};
  72965. for ( var attributeName in gltfAttributeMap ) {
  72966. var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
  72967. threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ];
  72968. }
  72969. for ( attributeName in primitive.attributes ) {
  72970. var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
  72971. if ( gltfAttributeMap[ attributeName ] !== undefined ) {
  72972. var accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
  72973. var componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
  72974. attributeTypeMap[ threeAttributeName ] = componentType;
  72975. attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true;
  72976. }
  72977. }
  72978. return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
  72979. return new Promise( function ( resolve ) {
  72980. dracoLoader.decodeDracoFile( bufferView, function ( geometry ) {
  72981. for ( var attributeName in geometry.attributes ) {
  72982. var attribute = geometry.attributes[ attributeName ];
  72983. var normalized = attributeNormalizedMap[ attributeName ];
  72984. if ( normalized !== undefined ) attribute.normalized = normalized;
  72985. }
  72986. resolve( geometry );
  72987. }, threeAttributeMap, attributeTypeMap );
  72988. } );
  72989. } );
  72990. };
  72991. /**
  72992. * Texture Transform Extension
  72993. *
  72994. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform
  72995. */
  72996. function GLTFTextureTransformExtension() {
  72997. this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;
  72998. }
  72999. GLTFTextureTransformExtension.prototype.extendTexture = function ( texture, transform ) {
  73000. texture = texture.clone();
  73001. if ( transform.offset !== undefined ) {
  73002. texture.offset.fromArray( transform.offset );
  73003. }
  73004. if ( transform.rotation !== undefined ) {
  73005. texture.rotation = transform.rotation;
  73006. }
  73007. if ( transform.scale !== undefined ) {
  73008. texture.repeat.fromArray( transform.scale );
  73009. }
  73010. if ( transform.texCoord !== undefined ) {
  73011. console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' );
  73012. }
  73013. texture.needsUpdate = true;
  73014. return texture;
  73015. };
  73016. /**
  73017. * Specular-Glossiness Extension
  73018. *
  73019. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness
  73020. */
  73021. /**
  73022. * A sub class of StandardMaterial with some of the functionality
  73023. * changed via the `onBeforeCompile` callback
  73024. * @pailhead
  73025. */
  73026. function GLTFMeshStandardSGMaterial( params ) {
  73027. MeshStandardMaterial.call( this );
  73028. this.isGLTFSpecularGlossinessMaterial = true;
  73029. //various chunks that need replacing
  73030. var specularMapParsFragmentChunk = [
  73031. '#ifdef USE_SPECULARMAP',
  73032. ' uniform sampler2D specularMap;',
  73033. '#endif'
  73034. ].join( '\n' );
  73035. var glossinessMapParsFragmentChunk = [
  73036. '#ifdef USE_GLOSSINESSMAP',
  73037. ' uniform sampler2D glossinessMap;',
  73038. '#endif'
  73039. ].join( '\n' );
  73040. var specularMapFragmentChunk = [
  73041. 'vec3 specularFactor = specular;',
  73042. '#ifdef USE_SPECULARMAP',
  73043. ' vec4 texelSpecular = texture2D( specularMap, vUv );',
  73044. ' texelSpecular = sRGBToLinear( texelSpecular );',
  73045. ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
  73046. ' specularFactor *= texelSpecular.rgb;',
  73047. '#endif'
  73048. ].join( '\n' );
  73049. var glossinessMapFragmentChunk = [
  73050. 'float glossinessFactor = glossiness;',
  73051. '#ifdef USE_GLOSSINESSMAP',
  73052. ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );',
  73053. ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture',
  73054. ' glossinessFactor *= texelGlossiness.a;',
  73055. '#endif'
  73056. ].join( '\n' );
  73057. var lightPhysicalFragmentChunk = [
  73058. 'PhysicalMaterial material;',
  73059. 'material.diffuseColor = diffuseColor.rgb * ( 1. - max( specularFactor.r, max( specularFactor.g, specularFactor.b ) ) );',
  73060. 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
  73061. 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',
  73062. 'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.',
  73063. 'material.specularRoughness += geometryRoughness;',
  73064. 'material.specularRoughness = min( material.specularRoughness, 1.0 );',
  73065. 'material.specularColor = specularFactor;',
  73066. ].join( '\n' );
  73067. var uniforms = {
  73068. specular: { value: new Color().setHex( 0xffffff ) },
  73069. glossiness: { value: 1 },
  73070. specularMap: { value: null },
  73071. glossinessMap: { value: null }
  73072. };
  73073. this._extraUniforms = uniforms;
  73074. this.onBeforeCompile = function ( shader ) {
  73075. for ( var uniformName in uniforms ) {
  73076. shader.uniforms[ uniformName ] = uniforms[ uniformName ];
  73077. }
  73078. shader.fragmentShader = shader.fragmentShader
  73079. .replace( 'uniform float roughness;', 'uniform vec3 specular;' )
  73080. .replace( 'uniform float metalness;', 'uniform float glossiness;' )
  73081. .replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
  73082. .replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk )
  73083. .replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk )
  73084. .replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk )
  73085. .replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk );
  73086. };
  73087. Object.defineProperties( this, {
  73088. specular: {
  73089. get: function () {
  73090. return uniforms.specular.value;
  73091. },
  73092. set: function ( v ) {
  73093. uniforms.specular.value = v;
  73094. }
  73095. },
  73096. specularMap: {
  73097. get: function () {
  73098. return uniforms.specularMap.value;
  73099. },
  73100. set: function ( v ) {
  73101. uniforms.specularMap.value = v;
  73102. if ( v ) {
  73103. this.defines.USE_SPECULARMAP = ''; // USE_UV is set by the renderer for specular maps
  73104. } else {
  73105. delete this.defines.USE_SPECULARMAP;
  73106. }
  73107. }
  73108. },
  73109. glossiness: {
  73110. get: function () {
  73111. return uniforms.glossiness.value;
  73112. },
  73113. set: function ( v ) {
  73114. uniforms.glossiness.value = v;
  73115. }
  73116. },
  73117. glossinessMap: {
  73118. get: function () {
  73119. return uniforms.glossinessMap.value;
  73120. },
  73121. set: function ( v ) {
  73122. uniforms.glossinessMap.value = v;
  73123. if ( v ) {
  73124. this.defines.USE_GLOSSINESSMAP = '';
  73125. this.defines.USE_UV = '';
  73126. } else {
  73127. delete this.defines.USE_GLOSSINESSMAP;
  73128. delete this.defines.USE_UV;
  73129. }
  73130. }
  73131. }
  73132. } );
  73133. delete this.metalness;
  73134. delete this.roughness;
  73135. delete this.metalnessMap;
  73136. delete this.roughnessMap;
  73137. this.setValues( params );
  73138. }
  73139. GLTFMeshStandardSGMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
  73140. GLTFMeshStandardSGMaterial.prototype.constructor = GLTFMeshStandardSGMaterial;
  73141. GLTFMeshStandardSGMaterial.prototype.copy = function ( source ) {
  73142. MeshStandardMaterial.prototype.copy.call( this, source );
  73143. this.specularMap = source.specularMap;
  73144. this.specular.copy( source.specular );
  73145. this.glossinessMap = source.glossinessMap;
  73146. this.glossiness = source.glossiness;
  73147. delete this.metalness;
  73148. delete this.roughness;
  73149. delete this.metalnessMap;
  73150. delete this.roughnessMap;
  73151. return this;
  73152. };
  73153. function GLTFMaterialsPbrSpecularGlossinessExtension() {
  73154. return {
  73155. name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,
  73156. specularGlossinessParams: [
  73157. 'color',
  73158. 'map',
  73159. 'lightMap',
  73160. 'lightMapIntensity',
  73161. 'aoMap',
  73162. 'aoMapIntensity',
  73163. 'emissive',
  73164. 'emissiveIntensity',
  73165. 'emissiveMap',
  73166. 'bumpMap',
  73167. 'bumpScale',
  73168. 'normalMap',
  73169. 'normalMapType',
  73170. 'displacementMap',
  73171. 'displacementScale',
  73172. 'displacementBias',
  73173. 'specularMap',
  73174. 'specular',
  73175. 'glossinessMap',
  73176. 'glossiness',
  73177. 'alphaMap',
  73178. 'envMap',
  73179. 'envMapIntensity',
  73180. 'refractionRatio',
  73181. ],
  73182. getMaterialType: function () {
  73183. return GLTFMeshStandardSGMaterial;
  73184. },
  73185. extendParams: function ( materialParams, materialDef, parser ) {
  73186. var pbrSpecularGlossiness = materialDef.extensions[ this.name ];
  73187. materialParams.color = new Color( 1.0, 1.0, 1.0 );
  73188. materialParams.opacity = 1.0;
  73189. var pending = [];
  73190. if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {
  73191. var array = pbrSpecularGlossiness.diffuseFactor;
  73192. materialParams.color.fromArray( array );
  73193. materialParams.opacity = array[ 3 ];
  73194. }
  73195. if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
  73196. pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture ) );
  73197. }
  73198. materialParams.emissive = new Color( 0.0, 0.0, 0.0 );
  73199. materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;
  73200. materialParams.specular = new Color( 1.0, 1.0, 1.0 );
  73201. if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) {
  73202. materialParams.specular.fromArray( pbrSpecularGlossiness.specularFactor );
  73203. }
  73204. if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
  73205. var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
  73206. pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
  73207. pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef ) );
  73208. }
  73209. return Promise.all( pending );
  73210. },
  73211. createMaterial: function ( materialParams ) {
  73212. var material = new GLTFMeshStandardSGMaterial( materialParams );
  73213. material.fog = true;
  73214. material.color = materialParams.color;
  73215. material.map = materialParams.map === undefined ? null : materialParams.map;
  73216. material.lightMap = null;
  73217. material.lightMapIntensity = 1.0;
  73218. material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap;
  73219. material.aoMapIntensity = 1.0;
  73220. material.emissive = materialParams.emissive;
  73221. material.emissiveIntensity = 1.0;
  73222. material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap;
  73223. material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap;
  73224. material.bumpScale = 1;
  73225. material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap;
  73226. material.normalMapType = TangentSpaceNormalMap;
  73227. if ( materialParams.normalScale ) material.normalScale = materialParams.normalScale;
  73228. material.displacementMap = null;
  73229. material.displacementScale = 1;
  73230. material.displacementBias = 0;
  73231. material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap;
  73232. material.specular = materialParams.specular;
  73233. material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap;
  73234. material.glossiness = materialParams.glossiness;
  73235. material.alphaMap = null;
  73236. material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap;
  73237. material.envMapIntensity = 1.0;
  73238. material.refractionRatio = 0.98;
  73239. return material;
  73240. },
  73241. };
  73242. }
  73243. /**
  73244. * Mesh Quantization Extension
  73245. *
  73246. * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization
  73247. */
  73248. function GLTFMeshQuantizationExtension() {
  73249. this.name = EXTENSIONS.KHR_MESH_QUANTIZATION;
  73250. }
  73251. /*********************************/
  73252. /********** INTERPOLATION ********/
  73253. /*********************************/
  73254. // Spline Interpolation
  73255. // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
  73256. function GLTFCubicSplineInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
  73257. Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
  73258. }
  73259. GLTFCubicSplineInterpolant.prototype = Object.create( Interpolant.prototype );
  73260. GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant;
  73261. GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function ( index ) {
  73262. // Copies a sample value to the result buffer. See description of glTF
  73263. // CUBICSPLINE values layout in interpolate_() function below.
  73264. var result = this.resultBuffer,
  73265. values = this.sampleValues,
  73266. valueSize = this.valueSize,
  73267. offset = index * valueSize * 3 + valueSize;
  73268. for ( var i = 0; i !== valueSize; i ++ ) {
  73269. result[ i ] = values[ offset + i ];
  73270. }
  73271. return result;
  73272. };
  73273. GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
  73274. GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
  73275. GLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) {
  73276. var result = this.resultBuffer;
  73277. var values = this.sampleValues;
  73278. var stride = this.valueSize;
  73279. var stride2 = stride * 2;
  73280. var stride3 = stride * 3;
  73281. var td = t1 - t0;
  73282. var p = ( t - t0 ) / td;
  73283. var pp = p * p;
  73284. var ppp = pp * p;
  73285. var offset1 = i1 * stride3;
  73286. var offset0 = offset1 - stride3;
  73287. var s2 = - 2 * ppp + 3 * pp;
  73288. var s3 = ppp - pp;
  73289. var s0 = 1 - s2;
  73290. var s1 = s3 - pp + p;
  73291. // Layout of keyframe output values for CUBICSPLINE animations:
  73292. // [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
  73293. for ( var i = 0; i !== stride; i ++ ) {
  73294. var p0 = values[ offset0 + i + stride ]; // splineVertex_k
  73295. var m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k)
  73296. var p1 = values[ offset1 + i + stride ]; // splineVertex_k+1
  73297. var m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k)
  73298. result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;
  73299. }
  73300. return result;
  73301. };
  73302. /*********************************/
  73303. /********** INTERNALS ************/
  73304. /*********************************/
  73305. /* CONSTANTS */
  73306. var WEBGL_CONSTANTS = {
  73307. FLOAT: 5126,
  73308. //FLOAT_MAT2: 35674,
  73309. FLOAT_MAT3: 35675,
  73310. FLOAT_MAT4: 35676,
  73311. FLOAT_VEC2: 35664,
  73312. FLOAT_VEC3: 35665,
  73313. FLOAT_VEC4: 35666,
  73314. LINEAR: 9729,
  73315. REPEAT: 10497,
  73316. SAMPLER_2D: 35678,
  73317. POINTS: 0,
  73318. LINES: 1,
  73319. LINE_LOOP: 2,
  73320. LINE_STRIP: 3,
  73321. TRIANGLES: 4,
  73322. TRIANGLE_STRIP: 5,
  73323. TRIANGLE_FAN: 6,
  73324. UNSIGNED_BYTE: 5121,
  73325. UNSIGNED_SHORT: 5123
  73326. };
  73327. var WEBGL_COMPONENT_TYPES = {
  73328. 5120: Int8Array,
  73329. 5121: Uint8Array,
  73330. 5122: Int16Array,
  73331. 5123: Uint16Array,
  73332. 5125: Uint32Array,
  73333. 5126: Float32Array
  73334. };
  73335. var WEBGL_FILTERS = {
  73336. 9728: NearestFilter,
  73337. 9729: LinearFilter,
  73338. 9984: NearestMipmapNearestFilter,
  73339. 9985: LinearMipmapNearestFilter,
  73340. 9986: NearestMipmapLinearFilter,
  73341. 9987: LinearMipmapLinearFilter
  73342. };
  73343. var WEBGL_WRAPPINGS = {
  73344. 33071: ClampToEdgeWrapping,
  73345. 33648: MirroredRepeatWrapping,
  73346. 10497: RepeatWrapping
  73347. };
  73348. var WEBGL_TYPE_SIZES = {
  73349. 'SCALAR': 1,
  73350. 'VEC2': 2,
  73351. 'VEC3': 3,
  73352. 'VEC4': 4,
  73353. 'MAT2': 4,
  73354. 'MAT3': 9,
  73355. 'MAT4': 16
  73356. };
  73357. var ATTRIBUTES = {
  73358. POSITION: 'position',
  73359. NORMAL: 'normal',
  73360. TANGENT: 'tangent',
  73361. TEXCOORD_0: 'uv',
  73362. TEXCOORD_1: 'uv2',
  73363. COLOR_0: 'color',
  73364. WEIGHTS_0: 'skinWeight',
  73365. JOINTS_0: 'skinIndex',
  73366. };
  73367. var PATH_PROPERTIES = {
  73368. scale: 'scale',
  73369. translation: 'position',
  73370. rotation: 'quaternion',
  73371. weights: 'morphTargetInfluences'
  73372. };
  73373. var INTERPOLATION = {
  73374. CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each
  73375. // keyframe track will be initialized with a default interpolation type, then modified.
  73376. LINEAR: InterpolateLinear,
  73377. STEP: InterpolateDiscrete
  73378. };
  73379. var ALPHA_MODES = {
  73380. OPAQUE: 'OPAQUE',
  73381. MASK: 'MASK',
  73382. BLEND: 'BLEND'
  73383. };
  73384. /* UTILITY FUNCTIONS */
  73385. function resolveURL( url, path ) {
  73386. // Invalid URL
  73387. if ( typeof url !== 'string' || url === '' ) return '';
  73388. // Host Relative URL
  73389. if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
  73390. path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );
  73391. }
  73392. // Absolute URL http://,https://,//
  73393. if ( /^(https?:)?\/\//i.test( url ) ) return url;
  73394. // Data URI
  73395. if ( /^data:.*,.*$/i.test( url ) ) return url;
  73396. // Blob URL
  73397. if ( /^blob:.*$/i.test( url ) ) return url;
  73398. // Relative URL
  73399. return path + url;
  73400. }
  73401. /**
  73402. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
  73403. */
  73404. function createDefaultMaterial( cache ) {
  73405. if ( cache[ 'DefaultMaterial' ] === undefined ) {
  73406. cache[ 'DefaultMaterial' ] = new MeshStandardMaterial( {
  73407. color: 0xFFFFFF,
  73408. emissive: 0x000000,
  73409. metalness: 1,
  73410. roughness: 1,
  73411. transparent: false,
  73412. depthTest: true,
  73413. side: FrontSide
  73414. } );
  73415. }
  73416. return cache[ 'DefaultMaterial' ];
  73417. }
  73418. function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) {
  73419. // Add unknown glTF extensions to an object's userData.
  73420. for ( var name in objectDef.extensions ) {
  73421. if ( knownExtensions[ name ] === undefined ) {
  73422. object.userData.gltfExtensions = object.userData.gltfExtensions || {};
  73423. object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ];
  73424. }
  73425. }
  73426. }
  73427. /**
  73428. * @param {Object3D|Material|BufferGeometry} object
  73429. * @param {GLTF.definition} gltfDef
  73430. */
  73431. function assignExtrasToUserData( object, gltfDef ) {
  73432. if ( gltfDef.extras !== undefined ) {
  73433. if ( typeof gltfDef.extras === 'object' ) {
  73434. Object.assign( object.userData, gltfDef.extras );
  73435. } else {
  73436. console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras );
  73437. }
  73438. }
  73439. }
  73440. /**
  73441. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
  73442. *
  73443. * @param {BufferGeometry} geometry
  73444. * @param {Array<GLTF.Target>} targets
  73445. * @param {GLTFParser} parser
  73446. * @return {Promise<BufferGeometry>}
  73447. */
  73448. function addMorphTargets( geometry, targets, parser ) {
  73449. var hasMorphPosition = false;
  73450. var hasMorphNormal = false;
  73451. for ( var i = 0, il = targets.length; i < il; i ++ ) {
  73452. var target = targets[ i ];
  73453. if ( target.POSITION !== undefined ) hasMorphPosition = true;
  73454. if ( target.NORMAL !== undefined ) hasMorphNormal = true;
  73455. if ( hasMorphPosition && hasMorphNormal ) break;
  73456. }
  73457. if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
  73458. var pendingPositionAccessors = [];
  73459. var pendingNormalAccessors = [];
  73460. for ( var i = 0, il = targets.length; i < il; i ++ ) {
  73461. var target = targets[ i ];
  73462. if ( hasMorphPosition ) {
  73463. var pendingAccessor = target.POSITION !== undefined
  73464. ? parser.getDependency( 'accessor', target.POSITION )
  73465. : geometry.attributes.position;
  73466. pendingPositionAccessors.push( pendingAccessor );
  73467. }
  73468. if ( hasMorphNormal ) {
  73469. var pendingAccessor = target.NORMAL !== undefined
  73470. ? parser.getDependency( 'accessor', target.NORMAL )
  73471. : geometry.attributes.normal;
  73472. pendingNormalAccessors.push( pendingAccessor );
  73473. }
  73474. }
  73475. return Promise.all( [
  73476. Promise.all( pendingPositionAccessors ),
  73477. Promise.all( pendingNormalAccessors )
  73478. ] ).then( function ( accessors ) {
  73479. var morphPositions = accessors[ 0 ];
  73480. var morphNormals = accessors[ 1 ];
  73481. if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
  73482. if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
  73483. geometry.morphTargetsRelative = true;
  73484. return geometry;
  73485. } );
  73486. }
  73487. /**
  73488. * @param {Mesh} mesh
  73489. * @param {GLTF.Mesh} meshDef
  73490. */
  73491. function updateMorphTargets( mesh, meshDef ) {
  73492. mesh.updateMorphTargets();
  73493. if ( meshDef.weights !== undefined ) {
  73494. for ( var i = 0, il = meshDef.weights.length; i < il; i ++ ) {
  73495. mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];
  73496. }
  73497. }
  73498. // .extras has user-defined data, so check that .extras.targetNames is an array.
  73499. if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) {
  73500. var targetNames = meshDef.extras.targetNames;
  73501. if ( mesh.morphTargetInfluences.length === targetNames.length ) {
  73502. mesh.morphTargetDictionary = {};
  73503. for ( var i = 0, il = targetNames.length; i < il; i ++ ) {
  73504. mesh.morphTargetDictionary[ targetNames[ i ] ] = i;
  73505. }
  73506. } else {
  73507. console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' );
  73508. }
  73509. }
  73510. }
  73511. function createPrimitiveKey( primitiveDef ) {
  73512. var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
  73513. var geometryKey;
  73514. if ( dracoExtension ) {
  73515. geometryKey = 'draco:' + dracoExtension.bufferView
  73516. + ':' + dracoExtension.indices
  73517. + ':' + createAttributesKey( dracoExtension.attributes );
  73518. } else {
  73519. geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
  73520. }
  73521. return geometryKey;
  73522. }
  73523. function createAttributesKey( attributes ) {
  73524. var attributesKey = '';
  73525. var keys = Object.keys( attributes ).sort();
  73526. for ( var i = 0, il = keys.length; i < il; i ++ ) {
  73527. attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
  73528. }
  73529. return attributesKey;
  73530. }
  73531. /* GLTF PARSER */
  73532. function GLTFParser( json, options ) {
  73533. this.json = json || {};
  73534. this.extensions = {};
  73535. this.plugins = {};
  73536. this.options = options || {};
  73537. // loader object cache
  73538. this.cache = new GLTFRegistry();
  73539. // associations between Three.js objects and glTF elements
  73540. this.associations = new Map();
  73541. // BufferGeometry caching
  73542. this.primitiveCache = {};
  73543. // Object3D instance caches
  73544. this.meshCache = { refs: {}, uses: {} };
  73545. this.cameraCache = { refs: {}, uses: {} };
  73546. this.lightCache = { refs: {}, uses: {} };
  73547. // Track node names, to ensure no duplicates
  73548. this.nodeNamesUsed = {};
  73549. // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
  73550. // expensive work of uploading a texture to the GPU off the main thread.
  73551. if ( typeof createImageBitmap !== 'undefined' && /Firefox/.test( navigator.userAgent ) === false ) {
  73552. this.textureLoader = new ImageBitmapLoader( this.options.manager );
  73553. } else {
  73554. this.textureLoader = new TextureLoader( this.options.manager );
  73555. }
  73556. this.textureLoader.setCrossOrigin( this.options.crossOrigin );
  73557. this.fileLoader = new FileLoader( this.options.manager );
  73558. this.fileLoader.setResponseType( 'arraybuffer' );
  73559. if ( this.options.crossOrigin === 'use-credentials' ) {
  73560. this.fileLoader.setWithCredentials( true );
  73561. }
  73562. }
  73563. GLTFParser.prototype.setExtensions = function ( extensions ) {
  73564. this.extensions = extensions;
  73565. };
  73566. GLTFParser.prototype.setPlugins = function ( plugins ) {
  73567. this.plugins = plugins;
  73568. };
  73569. GLTFParser.prototype.parse = function ( onLoad, onError ) {
  73570. var parser = this;
  73571. var json = this.json;
  73572. var extensions = this.extensions;
  73573. // Clear the loader cache
  73574. this.cache.removeAll();
  73575. // Mark the special nodes/meshes in json for efficient parse
  73576. this._invokeAll( function ( ext ) {
  73577. return ext._markDefs && ext._markDefs();
  73578. } );
  73579. Promise.all( [
  73580. this.getDependencies( 'scene' ),
  73581. this.getDependencies( 'animation' ),
  73582. this.getDependencies( 'camera' ),
  73583. ] ).then( function ( dependencies ) {
  73584. var result = {
  73585. scene: dependencies[ 0 ][ json.scene || 0 ],
  73586. scenes: dependencies[ 0 ],
  73587. animations: dependencies[ 1 ],
  73588. cameras: dependencies[ 2 ],
  73589. asset: json.asset,
  73590. parser: parser,
  73591. userData: {}
  73592. };
  73593. addUnknownExtensionsToUserData( extensions, result, json );
  73594. assignExtrasToUserData( result, json );
  73595. onLoad( result );
  73596. } ).catch( onError );
  73597. };
  73598. /**
  73599. * Marks the special nodes/meshes in json for efficient parse.
  73600. */
  73601. GLTFParser.prototype._markDefs = function () {
  73602. var nodeDefs = this.json.nodes || [];
  73603. var skinDefs = this.json.skins || [];
  73604. var meshDefs = this.json.meshes || [];
  73605. // Nothing in the node definition indicates whether it is a Bone or an
  73606. // Object3D. Use the skins' joint references to mark bones.
  73607. for ( var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) {
  73608. var joints = skinDefs[ skinIndex ].joints;
  73609. for ( var i = 0, il = joints.length; i < il; i ++ ) {
  73610. nodeDefs[ joints[ i ] ].isBone = true;
  73611. }
  73612. }
  73613. // Iterate over all nodes, marking references to shared resources,
  73614. // as well as skeleton joints.
  73615. for ( var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
  73616. var nodeDef = nodeDefs[ nodeIndex ];
  73617. if ( nodeDef.mesh !== undefined ) {
  73618. this._addNodeRef( this.meshCache, nodeDef.mesh );
  73619. // Nothing in the mesh definition indicates whether it is
  73620. // a SkinnedMesh or Mesh. Use the node's mesh reference
  73621. // to mark SkinnedMesh if node has skin.
  73622. if ( nodeDef.skin !== undefined ) {
  73623. meshDefs[ nodeDef.mesh ].isSkinnedMesh = true;
  73624. }
  73625. }
  73626. if ( nodeDef.camera !== undefined ) {
  73627. this._addNodeRef( this.cameraCache, nodeDef.camera );
  73628. }
  73629. }
  73630. };
  73631. /**
  73632. * Counts references to shared node / Object3D resources. These resources
  73633. * can be reused, or "instantiated", at multiple nodes in the scene
  73634. * hierarchy. Mesh, Camera, and Light instances are instantiated and must
  73635. * be marked. Non-scenegraph resources (like Materials, Geometries, and
  73636. * Textures) can be reused directly and are not marked here.
  73637. *
  73638. * Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
  73639. */
  73640. GLTFParser.prototype._addNodeRef = function ( cache, index ) {
  73641. if ( index === undefined ) return;
  73642. if ( cache.refs[ index ] === undefined ) {
  73643. cache.refs[ index ] = cache.uses[ index ] = 0;
  73644. }
  73645. cache.refs[ index ] ++;
  73646. };
  73647. /** Returns a reference to a shared resource, cloning it if necessary. */
  73648. GLTFParser.prototype._getNodeRef = function ( cache, index, object ) {
  73649. if ( cache.refs[ index ] <= 1 ) return object;
  73650. var ref = object.clone();
  73651. ref.name += '_instance_' + ( cache.uses[ index ] ++ );
  73652. return ref;
  73653. };
  73654. GLTFParser.prototype._invokeOne = function ( func ) {
  73655. var extensions = Object.values( this.plugins );
  73656. extensions.push( this );
  73657. for ( var i = 0; i < extensions.length; i ++ ) {
  73658. var result = func( extensions[ i ] );
  73659. if ( result ) return result;
  73660. }
  73661. };
  73662. GLTFParser.prototype._invokeAll = function ( func ) {
  73663. var extensions = Object.values( this.plugins );
  73664. extensions.unshift( this );
  73665. var pending = [];
  73666. for ( var i = 0; i < extensions.length; i ++ ) {
  73667. var result = func( extensions[ i ] );
  73668. if ( result ) pending.push( result );
  73669. }
  73670. return pending;
  73671. };
  73672. /**
  73673. * Requests the specified dependency asynchronously, with caching.
  73674. * @param {string} type
  73675. * @param {number} index
  73676. * @return {Promise<Object3D|Material|THREE.Texture|AnimationClip|ArrayBuffer|Object>}
  73677. */
  73678. GLTFParser.prototype.getDependency = function ( type, index ) {
  73679. var cacheKey = type + ':' + index;
  73680. var dependency = this.cache.get( cacheKey );
  73681. if ( ! dependency ) {
  73682. switch ( type ) {
  73683. case 'scene':
  73684. dependency = this.loadScene( index );
  73685. break;
  73686. case 'node':
  73687. dependency = this.loadNode( index );
  73688. break;
  73689. case 'mesh':
  73690. dependency = this._invokeOne( function ( ext ) {
  73691. return ext.loadMesh && ext.loadMesh( index );
  73692. } );
  73693. break;
  73694. case 'accessor':
  73695. dependency = this.loadAccessor( index );
  73696. break;
  73697. case 'bufferView':
  73698. dependency = this._invokeOne( function ( ext ) {
  73699. return ext.loadBufferView && ext.loadBufferView( index );
  73700. } );
  73701. break;
  73702. case 'buffer':
  73703. dependency = this.loadBuffer( index );
  73704. break;
  73705. case 'material':
  73706. dependency = this._invokeOne( function ( ext ) {
  73707. return ext.loadMaterial && ext.loadMaterial( index );
  73708. } );
  73709. break;
  73710. case 'texture':
  73711. dependency = this._invokeOne( function ( ext ) {
  73712. return ext.loadTexture && ext.loadTexture( index );
  73713. } );
  73714. break;
  73715. case 'skin':
  73716. dependency = this.loadSkin( index );
  73717. break;
  73718. case 'animation':
  73719. dependency = this.loadAnimation( index );
  73720. break;
  73721. case 'camera':
  73722. dependency = this.loadCamera( index );
  73723. break;
  73724. default:
  73725. throw new Error( 'Unknown type: ' + type );
  73726. }
  73727. this.cache.add( cacheKey, dependency );
  73728. }
  73729. return dependency;
  73730. };
  73731. /**
  73732. * Requests all dependencies of the specified type asynchronously, with caching.
  73733. * @param {string} type
  73734. * @return {Promise<Array<Object>>}
  73735. */
  73736. GLTFParser.prototype.getDependencies = function ( type ) {
  73737. var dependencies = this.cache.get( type );
  73738. if ( ! dependencies ) {
  73739. var parser = this;
  73740. var defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || [];
  73741. dependencies = Promise.all( defs.map( function ( def, index ) {
  73742. return parser.getDependency( type, index );
  73743. } ) );
  73744. this.cache.add( type, dependencies );
  73745. }
  73746. return dependencies;
  73747. };
  73748. /**
  73749. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
  73750. * @param {number} bufferIndex
  73751. * @return {Promise<ArrayBuffer>}
  73752. */
  73753. GLTFParser.prototype.loadBuffer = function ( bufferIndex ) {
  73754. var bufferDef = this.json.buffers[ bufferIndex ];
  73755. var loader = this.fileLoader;
  73756. if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) {
  73757. throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' );
  73758. }
  73759. // If present, GLB container is required to be the first buffer.
  73760. if ( bufferDef.uri === undefined && bufferIndex === 0 ) {
  73761. return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body );
  73762. }
  73763. var options = this.options;
  73764. return new Promise( function ( resolve, reject ) {
  73765. loader.load( resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () {
  73766. reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) );
  73767. } );
  73768. } );
  73769. };
  73770. /**
  73771. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
  73772. * @param {number} bufferViewIndex
  73773. * @return {Promise<ArrayBuffer>}
  73774. */
  73775. GLTFParser.prototype.loadBufferView = function ( bufferViewIndex ) {
  73776. var bufferViewDef = this.json.bufferViews[ bufferViewIndex ];
  73777. return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
  73778. var byteLength = bufferViewDef.byteLength || 0;
  73779. var byteOffset = bufferViewDef.byteOffset || 0;
  73780. return buffer.slice( byteOffset, byteOffset + byteLength );
  73781. } );
  73782. };
  73783. /**
  73784. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
  73785. * @param {number} accessorIndex
  73786. * @return {Promise<BufferAttribute|InterleavedBufferAttribute>}
  73787. */
  73788. GLTFParser.prototype.loadAccessor = function ( accessorIndex ) {
  73789. var parser = this;
  73790. var json = this.json;
  73791. var accessorDef = this.json.accessors[ accessorIndex ];
  73792. if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) {
  73793. // Ignore empty accessors, which may be used to declare runtime
  73794. // information about attributes coming from another source (e.g. Draco
  73795. // compression extension).
  73796. return Promise.resolve( null );
  73797. }
  73798. var pendingBufferViews = [];
  73799. if ( accessorDef.bufferView !== undefined ) {
  73800. pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) );
  73801. } else {
  73802. pendingBufferViews.push( null );
  73803. }
  73804. if ( accessorDef.sparse !== undefined ) {
  73805. pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) );
  73806. pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) );
  73807. }
  73808. return Promise.all( pendingBufferViews ).then( function ( bufferViews ) {
  73809. var bufferView = bufferViews[ 0 ];
  73810. var itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
  73811. var TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
  73812. // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
  73813. var elementBytes = TypedArray.BYTES_PER_ELEMENT;
  73814. var itemBytes = elementBytes * itemSize;
  73815. var byteOffset = accessorDef.byteOffset || 0;
  73816. var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined;
  73817. var normalized = accessorDef.normalized === true;
  73818. var array, bufferAttribute;
  73819. // The buffer is not interleaved if the stride is the item size in bytes.
  73820. if ( byteStride && byteStride !== itemBytes ) {
  73821. // Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer
  73822. // This makes sure that IBA.count reflects accessor.count properly
  73823. var ibSlice = Math.floor( byteOffset / byteStride );
  73824. var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count;
  73825. var ib = parser.cache.get( ibCacheKey );
  73826. if ( ! ib ) {
  73827. array = new TypedArray( bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes );
  73828. // Integer parameters to IB/IBA are in array elements, not bytes.
  73829. ib = new InterleavedBuffer( array, byteStride / elementBytes );
  73830. parser.cache.add( ibCacheKey, ib );
  73831. }
  73832. bufferAttribute = new InterleavedBufferAttribute( ib, itemSize, ( byteOffset % byteStride ) / elementBytes, normalized );
  73833. } else {
  73834. if ( bufferView === null ) {
  73835. array = new TypedArray( accessorDef.count * itemSize );
  73836. } else {
  73837. array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize );
  73838. }
  73839. bufferAttribute = new BufferAttribute( array, itemSize, normalized );
  73840. }
  73841. // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
  73842. if ( accessorDef.sparse !== undefined ) {
  73843. var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
  73844. var TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ];
  73845. var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
  73846. var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
  73847. var sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices );
  73848. var sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize );
  73849. if ( bufferView !== null ) {
  73850. // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
  73851. bufferAttribute = new BufferAttribute( bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized );
  73852. }
  73853. for ( var i = 0, il = sparseIndices.length; i < il; i ++ ) {
  73854. var index = sparseIndices[ i ];
  73855. bufferAttribute.setX( index, sparseValues[ i * itemSize ] );
  73856. if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] );
  73857. if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] );
  73858. if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] );
  73859. if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.' );
  73860. }
  73861. }
  73862. return bufferAttribute;
  73863. } );
  73864. };
  73865. /**
  73866. * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
  73867. * @param {number} textureIndex
  73868. * @return {Promise<THREE.Texture>}
  73869. */
  73870. GLTFParser.prototype.loadTexture = function ( textureIndex ) {
  73871. var parser = this;
  73872. var json = this.json;
  73873. var options = this.options;
  73874. var textureDef = json.textures[ textureIndex ];
  73875. var textureExtensions = textureDef.extensions || {};
  73876. var source;
  73877. if ( textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] ) {
  73878. source = json.images[ textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].source ];
  73879. } else {
  73880. source = json.images[ textureDef.source ];
  73881. }
  73882. var loader;
  73883. if ( source.uri ) {
  73884. loader = options.manager.getHandler( source.uri );
  73885. }
  73886. if ( ! loader ) {
  73887. loader = textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ]
  73888. ? parser.extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].ddsLoader
  73889. : this.textureLoader;
  73890. }
  73891. return this.loadTextureImage( textureIndex, source, loader );
  73892. };
  73893. GLTFParser.prototype.loadTextureImage = function ( textureIndex, source, loader ) {
  73894. var parser = this;
  73895. var json = this.json;
  73896. var options = this.options;
  73897. var textureDef = json.textures[ textureIndex ];
  73898. var URL = self.URL || self.webkitURL;
  73899. var sourceURI = source.uri;
  73900. var isObjectURL = false;
  73901. var hasAlpha = true;
  73902. if ( source.mimeType === 'image/jpeg' ) hasAlpha = false;
  73903. if ( source.bufferView !== undefined ) {
  73904. // Load binary image data from bufferView, if provided.
  73905. sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
  73906. if ( source.mimeType === 'image/png' ) {
  73907. // Inspect the PNG 'IHDR' chunk to determine whether the image could have an
  73908. // alpha channel. This check is conservative — the image could have an alpha
  73909. // channel with all values == 1, and the indexed type (colorType == 3) only
  73910. // sometimes contains alpha.
  73911. //
  73912. // https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
  73913. var colorType = new DataView( bufferView, 25, 1 ).getUint8( 0, false );
  73914. hasAlpha = colorType === 6 || colorType === 4 || colorType === 3;
  73915. }
  73916. isObjectURL = true;
  73917. var blob = new Blob( [ bufferView ], { type: source.mimeType } );
  73918. sourceURI = URL.createObjectURL( blob );
  73919. return sourceURI;
  73920. } );
  73921. }
  73922. return Promise.resolve( sourceURI ).then( function ( sourceURI ) {
  73923. return new Promise( function ( resolve, reject ) {
  73924. var onLoad = resolve;
  73925. if ( loader.isImageBitmapLoader === true ) {
  73926. onLoad = function ( imageBitmap ) {
  73927. resolve( new CanvasTexture( imageBitmap ) );
  73928. };
  73929. }
  73930. loader.load( resolveURL( sourceURI, options.path ), onLoad, undefined, reject );
  73931. } );
  73932. } ).then( function ( texture ) {
  73933. // Clean up resources and configure Texture.
  73934. if ( isObjectURL === true ) {
  73935. URL.revokeObjectURL( sourceURI );
  73936. }
  73937. texture.flipY = false;
  73938. if ( textureDef.name ) texture.name = textureDef.name;
  73939. // When there is definitely no alpha channel in the texture, set RGBFormat to save space.
  73940. if ( ! hasAlpha ) texture.format = RGBFormat;
  73941. var samplers = json.samplers || {};
  73942. var sampler = samplers[ textureDef.sampler ] || {};
  73943. texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
  73944. texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
  73945. texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
  73946. texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
  73947. parser.associations.set( texture, {
  73948. type: 'textures',
  73949. index: textureIndex
  73950. } );
  73951. return texture;
  73952. } );
  73953. };
  73954. /**
  73955. * Asynchronously assigns a texture to the given material parameters.
  73956. * @param {Object} materialParams
  73957. * @param {string} mapName
  73958. * @param {Object} mapDef
  73959. * @return {Promise}
  73960. */
  73961. GLTFParser.prototype.assignTexture = function ( materialParams, mapName, mapDef ) {
  73962. var parser = this;
  73963. return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
  73964. // Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured
  73965. // However, we will copy UV set 0 to UV set 1 on demand for aoMap
  73966. if ( mapDef.texCoord !== undefined && mapDef.texCoord != 0 && ! ( mapName === 'aoMap' && mapDef.texCoord == 1 ) ) {
  73967. console.warn( 'THREE.GLTFLoader: Custom UV set ' + mapDef.texCoord + ' for texture ' + mapName + ' not yet supported.' );
  73968. }
  73969. if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
  73970. var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
  73971. if ( transform ) {
  73972. var gltfReference = parser.associations.get( texture );
  73973. texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );
  73974. parser.associations.set( texture, gltfReference );
  73975. }
  73976. }
  73977. materialParams[ mapName ] = texture;
  73978. } );
  73979. };
  73980. /**
  73981. * Assigns final material to a Mesh, Line, or Points instance. The instance
  73982. * already has a material (generated from the glTF material options alone)
  73983. * but reuse of the same glTF material may require multiple threejs materials
  73984. * to accomodate different primitive types, defines, etc. New materials will
  73985. * be created if necessary, and reused from a cache.
  73986. * @param {Object3D} mesh Mesh, Line, or Points instance.
  73987. */
  73988. GLTFParser.prototype.assignFinalMaterial = function ( mesh ) {
  73989. var geometry = mesh.geometry;
  73990. var material = mesh.material;
  73991. var useVertexTangents = geometry.attributes.tangent !== undefined;
  73992. var useVertexColors = geometry.attributes.color !== undefined;
  73993. var useFlatShading = geometry.attributes.normal === undefined;
  73994. var useSkinning = mesh.isSkinnedMesh === true;
  73995. var useMorphTargets = Object.keys( geometry.morphAttributes ).length > 0;
  73996. var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;
  73997. if ( mesh.isPoints ) {
  73998. var cacheKey = 'PointsMaterial:' + material.uuid;
  73999. var pointsMaterial = this.cache.get( cacheKey );
  74000. if ( ! pointsMaterial ) {
  74001. pointsMaterial = new PointsMaterial();
  74002. Material.prototype.copy.call( pointsMaterial, material );
  74003. pointsMaterial.color.copy( material.color );
  74004. pointsMaterial.map = material.map;
  74005. pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
  74006. this.cache.add( cacheKey, pointsMaterial );
  74007. }
  74008. material = pointsMaterial;
  74009. } else if ( mesh.isLine ) {
  74010. var cacheKey = 'LineBasicMaterial:' + material.uuid;
  74011. var lineMaterial = this.cache.get( cacheKey );
  74012. if ( ! lineMaterial ) {
  74013. lineMaterial = new LineBasicMaterial();
  74014. Material.prototype.copy.call( lineMaterial, material );
  74015. lineMaterial.color.copy( material.color );
  74016. this.cache.add( cacheKey, lineMaterial );
  74017. }
  74018. material = lineMaterial;
  74019. }
  74020. // Clone the material if it will be modified
  74021. if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
  74022. var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
  74023. if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
  74024. if ( useSkinning ) cacheKey += 'skinning:';
  74025. if ( useVertexTangents ) cacheKey += 'vertex-tangents:';
  74026. if ( useVertexColors ) cacheKey += 'vertex-colors:';
  74027. if ( useFlatShading ) cacheKey += 'flat-shading:';
  74028. if ( useMorphTargets ) cacheKey += 'morph-targets:';
  74029. if ( useMorphNormals ) cacheKey += 'morph-normals:';
  74030. var cachedMaterial = this.cache.get( cacheKey );
  74031. if ( ! cachedMaterial ) {
  74032. cachedMaterial = material.clone();
  74033. if ( useSkinning ) cachedMaterial.skinning = true;
  74034. if ( useVertexTangents ) cachedMaterial.vertexTangents = true;
  74035. if ( useVertexColors ) cachedMaterial.vertexColors = true;
  74036. if ( useFlatShading ) cachedMaterial.flatShading = true;
  74037. if ( useMorphTargets ) cachedMaterial.morphTargets = true;
  74038. if ( useMorphNormals ) cachedMaterial.morphNormals = true;
  74039. this.cache.add( cacheKey, cachedMaterial );
  74040. this.associations.set( cachedMaterial, this.associations.get( material ) );
  74041. }
  74042. material = cachedMaterial;
  74043. }
  74044. // workarounds for mesh and geometry
  74045. if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) {
  74046. geometry.setAttribute( 'uv2', geometry.attributes.uv );
  74047. }
  74048. // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
  74049. if ( material.normalScale && ! useVertexTangents ) {
  74050. material.normalScale.y = - material.normalScale.y;
  74051. }
  74052. if ( material.clearcoatNormalScale && ! useVertexTangents ) {
  74053. material.clearcoatNormalScale.y = - material.clearcoatNormalScale.y;
  74054. }
  74055. mesh.material = material;
  74056. };
  74057. GLTFParser.prototype.getMaterialType = function ( /* materialIndex */ ) {
  74058. return MeshStandardMaterial;
  74059. };
  74060. /**
  74061. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
  74062. * @param {number} materialIndex
  74063. * @return {Promise<Material>}
  74064. */
  74065. GLTFParser.prototype.loadMaterial = function ( materialIndex ) {
  74066. var parser = this;
  74067. var json = this.json;
  74068. var extensions = this.extensions;
  74069. var materialDef = json.materials[ materialIndex ];
  74070. var materialType;
  74071. var materialParams = {};
  74072. var materialExtensions = materialDef.extensions || {};
  74073. var pending = [];
  74074. if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
  74075. var sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
  74076. materialType = sgExtension.getMaterialType();
  74077. pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
  74078. } else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
  74079. var kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
  74080. materialType = kmuExtension.getMaterialType();
  74081. pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) );
  74082. } else {
  74083. // Specification:
  74084. // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
  74085. var metallicRoughness = materialDef.pbrMetallicRoughness || {};
  74086. materialParams.color = new Color( 1.0, 1.0, 1.0 );
  74087. materialParams.opacity = 1.0;
  74088. if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
  74089. var array = metallicRoughness.baseColorFactor;
  74090. materialParams.color.fromArray( array );
  74091. materialParams.opacity = array[ 3 ];
  74092. }
  74093. if ( metallicRoughness.baseColorTexture !== undefined ) {
  74094. pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
  74095. }
  74096. materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
  74097. materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
  74098. if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
  74099. pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
  74100. pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );
  74101. }
  74102. materialType = this._invokeOne( function ( ext ) {
  74103. return ext.getMaterialType && ext.getMaterialType( materialIndex );
  74104. } );
  74105. pending.push( Promise.all( this._invokeAll( function ( ext ) {
  74106. return ext.extendMaterialParams && ext.extendMaterialParams( materialIndex, materialParams );
  74107. } ) ) );
  74108. }
  74109. if ( materialDef.doubleSided === true ) {
  74110. materialParams.side = DoubleSide;
  74111. }
  74112. var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
  74113. if ( alphaMode === ALPHA_MODES.BLEND ) {
  74114. materialParams.transparent = true;
  74115. // See: https://github.com/mrdoob/three.js/issues/17706
  74116. materialParams.depthWrite = false;
  74117. } else {
  74118. materialParams.transparent = false;
  74119. if ( alphaMode === ALPHA_MODES.MASK ) {
  74120. materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
  74121. }
  74122. }
  74123. if ( materialDef.normalTexture !== undefined && materialType !== MeshBasicMaterial ) {
  74124. pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );
  74125. materialParams.normalScale = new Vector2$1( 1, 1 );
  74126. if ( materialDef.normalTexture.scale !== undefined ) {
  74127. materialParams.normalScale.set( materialDef.normalTexture.scale, materialDef.normalTexture.scale );
  74128. }
  74129. }
  74130. if ( materialDef.occlusionTexture !== undefined && materialType !== MeshBasicMaterial ) {
  74131. pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );
  74132. if ( materialDef.occlusionTexture.strength !== undefined ) {
  74133. materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
  74134. }
  74135. }
  74136. if ( materialDef.emissiveFactor !== undefined && materialType !== MeshBasicMaterial ) {
  74137. materialParams.emissive = new Color().fromArray( materialDef.emissiveFactor );
  74138. }
  74139. if ( materialDef.emissiveTexture !== undefined && materialType !== MeshBasicMaterial ) {
  74140. pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );
  74141. }
  74142. return Promise.all( pending ).then( function () {
  74143. var material;
  74144. if ( materialType === GLTFMeshStandardSGMaterial ) {
  74145. material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams );
  74146. } else {
  74147. material = new materialType( materialParams );
  74148. }
  74149. if ( materialDef.name ) material.name = materialDef.name;
  74150. // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
  74151. if ( material.map ) material.map.encoding = sRGBEncoding;
  74152. if ( material.emissiveMap ) material.emissiveMap.encoding = sRGBEncoding;
  74153. assignExtrasToUserData( material, materialDef );
  74154. parser.associations.set( material, { type: 'materials', index: materialIndex } );
  74155. if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef );
  74156. return material;
  74157. } );
  74158. };
  74159. /** When Object3D instances are targeted by animation, they need unique names. */
  74160. GLTFParser.prototype.createUniqueName = function ( originalName ) {
  74161. var sanitizedName = PropertyBinding.sanitizeNodeName( originalName || '' );
  74162. var name = sanitizedName;
  74163. for ( var i = 1; this.nodeNamesUsed[ name ]; ++ i ) {
  74164. name = sanitizedName + '_' + i;
  74165. }
  74166. this.nodeNamesUsed[ name ] = true;
  74167. return name;
  74168. };
  74169. /**
  74170. * @param {BufferGeometry} geometry
  74171. * @param {GLTF.Primitive} primitiveDef
  74172. * @param {GLTFParser} parser
  74173. */
  74174. function computeBounds( geometry, primitiveDef, parser ) {
  74175. var attributes = primitiveDef.attributes;
  74176. var box = new Box3();
  74177. if ( attributes.POSITION !== undefined ) {
  74178. var accessor = parser.json.accessors[ attributes.POSITION ];
  74179. var min = accessor.min;
  74180. var max = accessor.max;
  74181. // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
  74182. if ( min !== undefined && max !== undefined ) {
  74183. box.set(
  74184. new Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
  74185. new Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
  74186. } else {
  74187. console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
  74188. return;
  74189. }
  74190. } else {
  74191. return;
  74192. }
  74193. var targets = primitiveDef.targets;
  74194. if ( targets !== undefined ) {
  74195. var maxDisplacement = new Vector3();
  74196. var vector = new Vector3();
  74197. for ( var i = 0, il = targets.length; i < il; i ++ ) {
  74198. var target = targets[ i ];
  74199. if ( target.POSITION !== undefined ) {
  74200. var accessor = parser.json.accessors[ target.POSITION ];
  74201. var min = accessor.min;
  74202. var max = accessor.max;
  74203. // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
  74204. if ( min !== undefined && max !== undefined ) {
  74205. // we need to get max of absolute components because target weight is [-1,1]
  74206. vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
  74207. vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
  74208. vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
  74209. // Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative
  74210. // to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets
  74211. // are used to implement key-frame animations and as such only two are active at a time - this results in very large
  74212. // boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size.
  74213. maxDisplacement.max( vector );
  74214. } else {
  74215. console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
  74216. }
  74217. }
  74218. }
  74219. // As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets.
  74220. box.expandByVector( maxDisplacement );
  74221. }
  74222. geometry.boundingBox = box;
  74223. var sphere = new Sphere();
  74224. box.getCenter( sphere.center );
  74225. sphere.radius = box.min.distanceTo( box.max ) / 2;
  74226. geometry.boundingSphere = sphere;
  74227. }
  74228. /**
  74229. * @param {BufferGeometry} geometry
  74230. * @param {GLTF.Primitive} primitiveDef
  74231. * @param {GLTFParser} parser
  74232. * @return {Promise<BufferGeometry>}
  74233. */
  74234. function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
  74235. var attributes = primitiveDef.attributes;
  74236. var pending = [];
  74237. function assignAttributeAccessor( accessorIndex, attributeName ) {
  74238. return parser.getDependency( 'accessor', accessorIndex )
  74239. .then( function ( accessor ) {
  74240. geometry.setAttribute( attributeName, accessor );
  74241. } );
  74242. }
  74243. for ( var gltfAttributeName in attributes ) {
  74244. var threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase();
  74245. // Skip attributes already provided by e.g. Draco extension.
  74246. if ( threeAttributeName in geometry.attributes ) continue;
  74247. pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) );
  74248. }
  74249. if ( primitiveDef.indices !== undefined && ! geometry.index ) {
  74250. var accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) {
  74251. geometry.setIndex( accessor );
  74252. } );
  74253. pending.push( accessor );
  74254. }
  74255. assignExtrasToUserData( geometry, primitiveDef );
  74256. computeBounds( geometry, primitiveDef, parser );
  74257. return Promise.all( pending ).then( function () {
  74258. return primitiveDef.targets !== undefined
  74259. ? addMorphTargets( geometry, primitiveDef.targets, parser )
  74260. : geometry;
  74261. } );
  74262. }
  74263. /**
  74264. * @param {BufferGeometry} geometry
  74265. * @param {Number} drawMode
  74266. * @return {BufferGeometry}
  74267. */
  74268. function toTrianglesDrawMode( geometry, drawMode ) {
  74269. var index = geometry.getIndex();
  74270. // generate index if not present
  74271. if ( index === null ) {
  74272. var indices = [];
  74273. var position = geometry.getAttribute( 'position' );
  74274. if ( position !== undefined ) {
  74275. for ( var i = 0; i < position.count; i ++ ) {
  74276. indices.push( i );
  74277. }
  74278. geometry.setIndex( indices );
  74279. index = geometry.getIndex();
  74280. } else {
  74281. console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' );
  74282. return geometry;
  74283. }
  74284. }
  74285. //
  74286. var numberOfTriangles = index.count - 2;
  74287. var newIndices = [];
  74288. if ( drawMode === TriangleFanDrawMode ) {
  74289. // gl.TRIANGLE_FAN
  74290. for ( var i = 1; i <= numberOfTriangles; i ++ ) {
  74291. newIndices.push( index.getX( 0 ) );
  74292. newIndices.push( index.getX( i ) );
  74293. newIndices.push( index.getX( i + 1 ) );
  74294. }
  74295. } else {
  74296. // gl.TRIANGLE_STRIP
  74297. for ( var i = 0; i < numberOfTriangles; i ++ ) {
  74298. if ( i % 2 === 0 ) {
  74299. newIndices.push( index.getX( i ) );
  74300. newIndices.push( index.getX( i + 1 ) );
  74301. newIndices.push( index.getX( i + 2 ) );
  74302. } else {
  74303. newIndices.push( index.getX( i + 2 ) );
  74304. newIndices.push( index.getX( i + 1 ) );
  74305. newIndices.push( index.getX( i ) );
  74306. }
  74307. }
  74308. }
  74309. if ( ( newIndices.length / 3 ) !== numberOfTriangles ) {
  74310. console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' );
  74311. }
  74312. // build final geometry
  74313. var newGeometry = geometry.clone();
  74314. newGeometry.setIndex( newIndices );
  74315. return newGeometry;
  74316. }
  74317. /**
  74318. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
  74319. *
  74320. * Creates BufferGeometries from primitives.
  74321. *
  74322. * @param {Array<GLTF.Primitive>} primitives
  74323. * @return {Promise<Array<BufferGeometry>>}
  74324. */
  74325. GLTFParser.prototype.loadGeometries = function ( primitives ) {
  74326. var parser = this;
  74327. var extensions = this.extensions;
  74328. var cache = this.primitiveCache;
  74329. function createDracoPrimitive( primitive ) {
  74330. return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]
  74331. .decodePrimitive( primitive, parser )
  74332. .then( function ( geometry ) {
  74333. return addPrimitiveAttributes( geometry, primitive, parser );
  74334. } );
  74335. }
  74336. var pending = [];
  74337. for ( var i = 0, il = primitives.length; i < il; i ++ ) {
  74338. var primitive = primitives[ i ];
  74339. var cacheKey = createPrimitiveKey( primitive );
  74340. // See if we've already created this geometry
  74341. var cached = cache[ cacheKey ];
  74342. if ( cached ) {
  74343. // Use the cached geometry if it exists
  74344. pending.push( cached.promise );
  74345. } else {
  74346. var geometryPromise;
  74347. if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
  74348. // Use DRACO geometry if available
  74349. geometryPromise = createDracoPrimitive( primitive );
  74350. } else {
  74351. // Otherwise create a new geometry
  74352. geometryPromise = addPrimitiveAttributes( new BufferGeometry(), primitive, parser );
  74353. }
  74354. // Cache this geometry
  74355. cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
  74356. pending.push( geometryPromise );
  74357. }
  74358. }
  74359. return Promise.all( pending );
  74360. };
  74361. /**
  74362. * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
  74363. * @param {number} meshIndex
  74364. * @return {Promise<Group|Mesh|SkinnedMesh>}
  74365. */
  74366. GLTFParser.prototype.loadMesh = function ( meshIndex ) {
  74367. var parser = this;
  74368. var json = this.json;
  74369. var extensions = this.extensions;
  74370. var meshDef = json.meshes[ meshIndex ];
  74371. var primitives = meshDef.primitives;
  74372. var pending = [];
  74373. for ( var i = 0, il = primitives.length; i < il; i ++ ) {
  74374. var material = primitives[ i ].material === undefined
  74375. ? createDefaultMaterial( this.cache )
  74376. : this.getDependency( 'material', primitives[ i ].material );
  74377. pending.push( material );
  74378. }
  74379. pending.push( parser.loadGeometries( primitives ) );
  74380. return Promise.all( pending ).then( function ( results ) {
  74381. var materials = results.slice( 0, results.length - 1 );
  74382. var geometries = results[ results.length - 1 ];
  74383. var meshes = [];
  74384. for ( var i = 0, il = geometries.length; i < il; i ++ ) {
  74385. var geometry = geometries[ i ];
  74386. var primitive = primitives[ i ];
  74387. // 1. create Mesh
  74388. var mesh;
  74389. var material = materials[ i ];
  74390. if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
  74391. primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
  74392. primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
  74393. primitive.mode === undefined ) {
  74394. // .isSkinnedMesh isn't in glTF spec. See ._markDefs()
  74395. mesh = meshDef.isSkinnedMesh === true
  74396. ? new SkinnedMesh( geometry, material )
  74397. : new Mesh( geometry, material );
  74398. if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
  74399. // we normalize floating point skin weight array to fix malformed assets (see #15319)
  74400. // it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
  74401. mesh.normalizeSkinWeights();
  74402. }
  74403. if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
  74404. mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleStripDrawMode );
  74405. } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
  74406. mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleFanDrawMode );
  74407. }
  74408. } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
  74409. mesh = new LineSegments( geometry, material );
  74410. } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
  74411. mesh = new Line( geometry, material );
  74412. } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
  74413. mesh = new LineLoop( geometry, material );
  74414. } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
  74415. mesh = new Points( geometry, material );
  74416. } else {
  74417. throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
  74418. }
  74419. if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
  74420. updateMorphTargets( mesh, meshDef );
  74421. }
  74422. mesh.name = parser.createUniqueName( meshDef.name || ( 'mesh_' + meshIndex ) );
  74423. assignExtrasToUserData( mesh, meshDef );
  74424. if ( primitive.extensions ) addUnknownExtensionsToUserData( extensions, mesh, primitive );
  74425. parser.assignFinalMaterial( mesh );
  74426. meshes.push( mesh );
  74427. }
  74428. if ( meshes.length === 1 ) {
  74429. return meshes[ 0 ];
  74430. }
  74431. var group = new Group();
  74432. for ( var i = 0, il = meshes.length; i < il; i ++ ) {
  74433. group.add( meshes[ i ] );
  74434. }
  74435. return group;
  74436. } );
  74437. };
  74438. /**
  74439. * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
  74440. * @param {number} cameraIndex
  74441. * @return {Promise<THREE.Camera>}
  74442. */
  74443. GLTFParser.prototype.loadCamera = function ( cameraIndex ) {
  74444. var camera;
  74445. var cameraDef = this.json.cameras[ cameraIndex ];
  74446. var params = cameraDef[ cameraDef.type ];
  74447. if ( ! params ) {
  74448. console.warn( 'THREE.GLTFLoader: Missing camera parameters.' );
  74449. return;
  74450. }
  74451. if ( cameraDef.type === 'perspective' ) {
  74452. camera = new PerspectiveCamera( MathUtils.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 );
  74453. } else if ( cameraDef.type === 'orthographic' ) {
  74454. camera = new OrthographicCamera( - params.xmag, params.xmag, params.ymag, - params.ymag, params.znear, params.zfar );
  74455. }
  74456. if ( cameraDef.name ) camera.name = this.createUniqueName( cameraDef.name );
  74457. assignExtrasToUserData( camera, cameraDef );
  74458. return Promise.resolve( camera );
  74459. };
  74460. /**
  74461. * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
  74462. * @param {number} skinIndex
  74463. * @return {Promise<Object>}
  74464. */
  74465. GLTFParser.prototype.loadSkin = function ( skinIndex ) {
  74466. var skinDef = this.json.skins[ skinIndex ];
  74467. var skinEntry = { joints: skinDef.joints };
  74468. if ( skinDef.inverseBindMatrices === undefined ) {
  74469. return Promise.resolve( skinEntry );
  74470. }
  74471. return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) {
  74472. skinEntry.inverseBindMatrices = accessor;
  74473. return skinEntry;
  74474. } );
  74475. };
  74476. /**
  74477. * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
  74478. * @param {number} animationIndex
  74479. * @return {Promise<AnimationClip>}
  74480. */
  74481. GLTFParser.prototype.loadAnimation = function ( animationIndex ) {
  74482. var json = this.json;
  74483. var animationDef = json.animations[ animationIndex ];
  74484. var pendingNodes = [];
  74485. var pendingInputAccessors = [];
  74486. var pendingOutputAccessors = [];
  74487. var pendingSamplers = [];
  74488. var pendingTargets = [];
  74489. for ( var i = 0, il = animationDef.channels.length; i < il; i ++ ) {
  74490. var channel = animationDef.channels[ i ];
  74491. var sampler = animationDef.samplers[ channel.sampler ];
  74492. var target = channel.target;
  74493. var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
  74494. var input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input;
  74495. var output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output;
  74496. pendingNodes.push( this.getDependency( 'node', name ) );
  74497. pendingInputAccessors.push( this.getDependency( 'accessor', input ) );
  74498. pendingOutputAccessors.push( this.getDependency( 'accessor', output ) );
  74499. pendingSamplers.push( sampler );
  74500. pendingTargets.push( target );
  74501. }
  74502. return Promise.all( [
  74503. Promise.all( pendingNodes ),
  74504. Promise.all( pendingInputAccessors ),
  74505. Promise.all( pendingOutputAccessors ),
  74506. Promise.all( pendingSamplers ),
  74507. Promise.all( pendingTargets )
  74508. ] ).then( function ( dependencies ) {
  74509. var nodes = dependencies[ 0 ];
  74510. var inputAccessors = dependencies[ 1 ];
  74511. var outputAccessors = dependencies[ 2 ];
  74512. var samplers = dependencies[ 3 ];
  74513. var targets = dependencies[ 4 ];
  74514. var tracks = [];
  74515. for ( var i = 0, il = nodes.length; i < il; i ++ ) {
  74516. var node = nodes[ i ];
  74517. var inputAccessor = inputAccessors[ i ];
  74518. var outputAccessor = outputAccessors[ i ];
  74519. var sampler = samplers[ i ];
  74520. var target = targets[ i ];
  74521. if ( node === undefined ) continue;
  74522. node.updateMatrix();
  74523. node.matrixAutoUpdate = true;
  74524. var TypedKeyframeTrack;
  74525. switch ( PATH_PROPERTIES[ target.path ] ) {
  74526. case PATH_PROPERTIES.weights:
  74527. TypedKeyframeTrack = NumberKeyframeTrack;
  74528. break;
  74529. case PATH_PROPERTIES.rotation:
  74530. TypedKeyframeTrack = QuaternionKeyframeTrack;
  74531. break;
  74532. case PATH_PROPERTIES.position:
  74533. case PATH_PROPERTIES.scale:
  74534. default:
  74535. TypedKeyframeTrack = VectorKeyframeTrack;
  74536. break;
  74537. }
  74538. var targetName = node.name ? node.name : node.uuid;
  74539. var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : InterpolateLinear;
  74540. var targetNames = [];
  74541. if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
  74542. // Node may be a Group (glTF mesh with several primitives) or a Mesh.
  74543. node.traverse( function ( object ) {
  74544. if ( object.isMesh === true && object.morphTargetInfluences ) {
  74545. targetNames.push( object.name ? object.name : object.uuid );
  74546. }
  74547. } );
  74548. } else {
  74549. targetNames.push( targetName );
  74550. }
  74551. var outputArray = outputAccessor.array;
  74552. if ( outputAccessor.normalized ) {
  74553. var scale;
  74554. if ( outputArray.constructor === Int8Array ) {
  74555. scale = 1 / 127;
  74556. } else if ( outputArray.constructor === Uint8Array ) {
  74557. scale = 1 / 255;
  74558. } else if ( outputArray.constructor == Int16Array ) {
  74559. scale = 1 / 32767;
  74560. } else if ( outputArray.constructor === Uint16Array ) {
  74561. scale = 1 / 65535;
  74562. } else {
  74563. throw new Error( 'THREE.GLTFLoader: Unsupported output accessor component type.' );
  74564. }
  74565. var scaled = new Float32Array( outputArray.length );
  74566. for ( var j = 0, jl = outputArray.length; j < jl; j ++ ) {
  74567. scaled[ j ] = outputArray[ j ] * scale;
  74568. }
  74569. outputArray = scaled;
  74570. }
  74571. for ( var j = 0, jl = targetNames.length; j < jl; j ++ ) {
  74572. var track = new TypedKeyframeTrack(
  74573. targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ],
  74574. inputAccessor.array,
  74575. outputArray,
  74576. interpolation
  74577. );
  74578. // Override interpolation with custom factory method.
  74579. if ( sampler.interpolation === 'CUBICSPLINE' ) {
  74580. track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) {
  74581. // A CUBICSPLINE keyframe in glTF has three output values for each input value,
  74582. // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
  74583. // must be divided by three to get the interpolant's sampleSize argument.
  74584. return new GLTFCubicSplineInterpolant( this.times, this.values, this.getValueSize() / 3, result );
  74585. };
  74586. // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants.
  74587. track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
  74588. }
  74589. tracks.push( track );
  74590. }
  74591. }
  74592. var name = animationDef.name ? animationDef.name : 'animation_' + animationIndex;
  74593. return new AnimationClip( name, undefined, tracks );
  74594. } );
  74595. };
  74596. /**
  74597. * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
  74598. * @param {number} nodeIndex
  74599. * @return {Promise<Object3D>}
  74600. */
  74601. GLTFParser.prototype.loadNode = function ( nodeIndex ) {
  74602. var json = this.json;
  74603. var extensions = this.extensions;
  74604. var parser = this;
  74605. var nodeDef = json.nodes[ nodeIndex ];
  74606. // reserve node's name before its dependencies, so the root has the intended name.
  74607. var nodeName = nodeDef.name ? parser.createUniqueName( nodeDef.name ) : '';
  74608. return ( function () {
  74609. var pending = [];
  74610. if ( nodeDef.mesh !== undefined ) {
  74611. pending.push( parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
  74612. var node = parser._getNodeRef( parser.meshCache, nodeDef.mesh, mesh );
  74613. // if weights are provided on the node, override weights on the mesh.
  74614. if ( nodeDef.weights !== undefined ) {
  74615. node.traverse( function ( o ) {
  74616. if ( ! o.isMesh ) return;
  74617. for ( var i = 0, il = nodeDef.weights.length; i < il; i ++ ) {
  74618. o.morphTargetInfluences[ i ] = nodeDef.weights[ i ];
  74619. }
  74620. } );
  74621. }
  74622. return node;
  74623. } ) );
  74624. }
  74625. if ( nodeDef.camera !== undefined ) {
  74626. pending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
  74627. return parser._getNodeRef( parser.cameraCache, nodeDef.camera, camera );
  74628. } ) );
  74629. }
  74630. parser._invokeAll( function ( ext ) {
  74631. return ext.createNodeAttachment && ext.createNodeAttachment( nodeIndex );
  74632. } ).forEach( function ( promise ) {
  74633. pending.push( promise );
  74634. } );
  74635. return Promise.all( pending );
  74636. }() ).then( function ( objects ) {
  74637. var node;
  74638. // .isBone isn't in glTF spec. See ._markDefs
  74639. if ( nodeDef.isBone === true ) {
  74640. node = new Bone();
  74641. } else if ( objects.length > 1 ) {
  74642. node = new Group();
  74643. } else if ( objects.length === 1 ) {
  74644. node = objects[ 0 ];
  74645. } else {
  74646. node = new Object3D();
  74647. }
  74648. if ( node !== objects[ 0 ] ) {
  74649. for ( var i = 0, il = objects.length; i < il; i ++ ) {
  74650. node.add( objects[ i ] );
  74651. }
  74652. }
  74653. if ( nodeDef.name ) {
  74654. node.userData.name = nodeDef.name;
  74655. node.name = nodeName;
  74656. }
  74657. assignExtrasToUserData( node, nodeDef );
  74658. if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef );
  74659. if ( nodeDef.matrix !== undefined ) {
  74660. var matrix = new Matrix4();
  74661. matrix.fromArray( nodeDef.matrix );
  74662. node.applyMatrix4( matrix );
  74663. } else {
  74664. if ( nodeDef.translation !== undefined ) {
  74665. node.position.fromArray( nodeDef.translation );
  74666. }
  74667. if ( nodeDef.rotation !== undefined ) {
  74668. node.quaternion.fromArray( nodeDef.rotation );
  74669. }
  74670. if ( nodeDef.scale !== undefined ) {
  74671. node.scale.fromArray( nodeDef.scale );
  74672. }
  74673. }
  74674. parser.associations.set( node, { type: 'nodes', index: nodeIndex } );
  74675. return node;
  74676. } );
  74677. };
  74678. /**
  74679. * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
  74680. * @param {number} sceneIndex
  74681. * @return {Promise<Group>}
  74682. */
  74683. GLTFParser.prototype.loadScene = function () {
  74684. // scene node hierachy builder
  74685. function buildNodeHierachy( nodeId, parentObject, json, parser ) {
  74686. var nodeDef = json.nodes[ nodeId ];
  74687. return parser.getDependency( 'node', nodeId ).then( function ( node ) {
  74688. if ( nodeDef.skin === undefined ) return node;
  74689. // build skeleton here as well
  74690. var skinEntry;
  74691. return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) {
  74692. skinEntry = skin;
  74693. var pendingJoints = [];
  74694. for ( var i = 0, il = skinEntry.joints.length; i < il; i ++ ) {
  74695. pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) );
  74696. }
  74697. return Promise.all( pendingJoints );
  74698. } ).then( function ( jointNodes ) {
  74699. node.traverse( function ( mesh ) {
  74700. if ( ! mesh.isMesh ) return;
  74701. var bones = [];
  74702. var boneInverses = [];
  74703. for ( var j = 0, jl = jointNodes.length; j < jl; j ++ ) {
  74704. var jointNode = jointNodes[ j ];
  74705. if ( jointNode ) {
  74706. bones.push( jointNode );
  74707. var mat = new Matrix4();
  74708. if ( skinEntry.inverseBindMatrices !== undefined ) {
  74709. mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 );
  74710. }
  74711. boneInverses.push( mat );
  74712. } else {
  74713. console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] );
  74714. }
  74715. }
  74716. mesh.bind( new Skeleton( bones, boneInverses ), mesh.matrixWorld );
  74717. } );
  74718. return node;
  74719. } );
  74720. } ).then( function ( node ) {
  74721. // build node hierachy
  74722. parentObject.add( node );
  74723. var pending = [];
  74724. if ( nodeDef.children ) {
  74725. var children = nodeDef.children;
  74726. for ( var i = 0, il = children.length; i < il; i ++ ) {
  74727. var child = children[ i ];
  74728. pending.push( buildNodeHierachy( child, node, json, parser ) );
  74729. }
  74730. }
  74731. return Promise.all( pending );
  74732. } );
  74733. }
  74734. return function loadScene( sceneIndex ) {
  74735. var json = this.json;
  74736. var extensions = this.extensions;
  74737. var sceneDef = this.json.scenes[ sceneIndex ];
  74738. var parser = this;
  74739. // Loader returns Group, not Scene.
  74740. // See: https://github.com/mrdoob/three.js/issues/18342#issuecomment-578981172
  74741. var scene = new Group();
  74742. if ( sceneDef.name ) scene.name = parser.createUniqueName( sceneDef.name );
  74743. assignExtrasToUserData( scene, sceneDef );
  74744. if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef );
  74745. var nodeIds = sceneDef.nodes || [];
  74746. var pending = [];
  74747. for ( var i = 0, il = nodeIds.length; i < il; i ++ ) {
  74748. pending.push( buildNodeHierachy( nodeIds[ i ], scene, json, parser ) );
  74749. }
  74750. return Promise.all( pending ).then( function () {
  74751. return scene;
  74752. } );
  74753. };
  74754. }();
  74755. return GLTFLoader;
  74756. } )();
  74757. /**
  74758. * @webxr-input-profiles/motion-controllers 1.0.0 https://github.com/immersive-web/webxr-input-profiles
  74759. */
  74760. const Constants = {
  74761. Handedness: Object.freeze({
  74762. NONE: 'none',
  74763. LEFT: 'left',
  74764. RIGHT: 'right'
  74765. }),
  74766. ComponentState: Object.freeze({
  74767. DEFAULT: 'default',
  74768. TOUCHED: 'touched',
  74769. PRESSED: 'pressed'
  74770. }),
  74771. ComponentProperty: Object.freeze({
  74772. BUTTON: 'button',
  74773. X_AXIS: 'xAxis',
  74774. Y_AXIS: 'yAxis',
  74775. STATE: 'state'
  74776. }),
  74777. ComponentType: Object.freeze({
  74778. TRIGGER: 'trigger',
  74779. SQUEEZE: 'squeeze',
  74780. TOUCHPAD: 'touchpad',
  74781. THUMBSTICK: 'thumbstick',
  74782. BUTTON: 'button'
  74783. }),
  74784. ButtonTouchThreshold: 0.05,
  74785. AxisTouchThreshold: 0.1,
  74786. VisualResponseProperty: Object.freeze({
  74787. TRANSFORM: 'transform',
  74788. VISIBILITY: 'visibility'
  74789. })
  74790. };
  74791. /**
  74792. * @description Static helper function to fetch a JSON file and turn it into a JS object
  74793. * @param {string} path - Path to JSON file to be fetched
  74794. */
  74795. async function fetchJsonFile(path) {
  74796. const response = await fetch(path);
  74797. if (!response.ok) {
  74798. throw new Error(response.statusText);
  74799. } else {
  74800. return response.json();
  74801. }
  74802. }
  74803. async function fetchProfilesList(basePath) {
  74804. if (!basePath) {
  74805. throw new Error('No basePath supplied');
  74806. }
  74807. const profileListFileName = 'profilesList.json';
  74808. const profilesList = await fetchJsonFile(`${basePath}/${profileListFileName}`);
  74809. return profilesList;
  74810. }
  74811. async function fetchProfile(xrInputSource, basePath, defaultProfile = null, getAssetPath = true) {
  74812. if (!xrInputSource) {
  74813. throw new Error('No xrInputSource supplied');
  74814. }
  74815. if (!basePath) {
  74816. throw new Error('No basePath supplied');
  74817. }
  74818. // Get the list of profiles
  74819. const supportedProfilesList = await fetchProfilesList(basePath);
  74820. // Find the relative path to the first requested profile that is recognized
  74821. let match;
  74822. xrInputSource.profiles.some((profileId) => {
  74823. const supportedProfile = supportedProfilesList[profileId];
  74824. if (supportedProfile) {
  74825. match = {
  74826. profileId,
  74827. profilePath: `${basePath}/${supportedProfile.path}`,
  74828. deprecated: !!supportedProfile.deprecated
  74829. };
  74830. }
  74831. return !!match;
  74832. });
  74833. if (!match) {
  74834. if (!defaultProfile) {
  74835. throw new Error('No matching profile name found');
  74836. }
  74837. const supportedProfile = supportedProfilesList[defaultProfile];
  74838. if (!supportedProfile) {
  74839. throw new Error(`No matching profile name found and default profile "${defaultProfile}" missing.`);
  74840. }
  74841. match = {
  74842. profileId: defaultProfile,
  74843. profilePath: `${basePath}/${supportedProfile.path}`,
  74844. deprecated: !!supportedProfile.deprecated
  74845. };
  74846. }
  74847. const profile = await fetchJsonFile(match.profilePath);
  74848. let assetPath;
  74849. if (getAssetPath) {
  74850. let layout;
  74851. if (xrInputSource.handedness === 'any') {
  74852. layout = profile.layouts[Object.keys(profile.layouts)[0]];
  74853. } else {
  74854. layout = profile.layouts[xrInputSource.handedness];
  74855. }
  74856. if (!layout) {
  74857. throw new Error(
  74858. `No matching handedness, ${xrInputSource.handedness}, in profile ${match.profileId}`
  74859. );
  74860. }
  74861. if (layout.assetPath) {
  74862. assetPath = match.profilePath.replace('profile.json', layout.assetPath);
  74863. }
  74864. }
  74865. return { profile, assetPath };
  74866. }
  74867. /** @constant {Object} */
  74868. const defaultComponentValues = {
  74869. xAxis: 0,
  74870. yAxis: 0,
  74871. button: 0,
  74872. state: Constants.ComponentState.DEFAULT
  74873. };
  74874. /**
  74875. * @description Converts an X, Y coordinate from the range -1 to 1 (as reported by the Gamepad
  74876. * API) to the range 0 to 1 (for interpolation). Also caps the X, Y values to be bounded within
  74877. * a circle. This ensures that thumbsticks are not animated outside the bounds of their physical
  74878. * range of motion and touchpads do not report touch locations off their physical bounds.
  74879. * @param {number} x The original x coordinate in the range -1 to 1
  74880. * @param {number} y The original y coordinate in the range -1 to 1
  74881. */
  74882. function normalizeAxes(x = 0, y = 0) {
  74883. let xAxis = x;
  74884. let yAxis = y;
  74885. // Determine if the point is outside the bounds of the circle
  74886. // and, if so, place it on the edge of the circle
  74887. const hypotenuse = Math.sqrt((x * x) + (y * y));
  74888. if (hypotenuse > 1) {
  74889. const theta = Math.atan2(y, x);
  74890. xAxis = Math.cos(theta);
  74891. yAxis = Math.sin(theta);
  74892. }
  74893. // Scale and move the circle so values are in the interpolation range. The circle's origin moves
  74894. // from (0, 0) to (0.5, 0.5). The circle's radius scales from 1 to be 0.5.
  74895. const result = {
  74896. normalizedXAxis: (xAxis * 0.5) + 0.5,
  74897. normalizedYAxis: (yAxis * 0.5) + 0.5
  74898. };
  74899. return result;
  74900. }
  74901. /**
  74902. * Contains the description of how the 3D model should visually respond to a specific user input.
  74903. * This is accomplished by initializing the object with the name of a node in the 3D model and
  74904. * property that need to be modified in response to user input, the name of the nodes representing
  74905. * the allowable range of motion, and the name of the input which triggers the change. In response
  74906. * to the named input changing, this object computes the appropriate weighting to use for
  74907. * interpolating between the range of motion nodes.
  74908. */
  74909. class VisualResponse {
  74910. constructor(visualResponseDescription) {
  74911. this.componentProperty = visualResponseDescription.componentProperty;
  74912. this.states = visualResponseDescription.states;
  74913. this.valueNodeName = visualResponseDescription.valueNodeName;
  74914. this.valueNodeProperty = visualResponseDescription.valueNodeProperty;
  74915. if (this.valueNodeProperty === Constants.VisualResponseProperty.TRANSFORM) {
  74916. this.minNodeName = visualResponseDescription.minNodeName;
  74917. this.maxNodeName = visualResponseDescription.maxNodeName;
  74918. }
  74919. // Initializes the response's current value based on default data
  74920. this.value = 0;
  74921. this.updateFromComponent(defaultComponentValues);
  74922. }
  74923. /**
  74924. * Computes the visual response's interpolation weight based on component state
  74925. * @param {Object} componentValues - The component from which to update
  74926. * @param {number} xAxis - The reported X axis value of the component
  74927. * @param {number} yAxis - The reported Y axis value of the component
  74928. * @param {number} button - The reported value of the component's button
  74929. * @param {string} state - The component's active state
  74930. */
  74931. updateFromComponent({
  74932. xAxis, yAxis, button, state
  74933. }) {
  74934. const { normalizedXAxis, normalizedYAxis } = normalizeAxes(xAxis, yAxis);
  74935. switch (this.componentProperty) {
  74936. case Constants.ComponentProperty.X_AXIS:
  74937. this.value = (this.states.includes(state)) ? normalizedXAxis : 0.5;
  74938. break;
  74939. case Constants.ComponentProperty.Y_AXIS:
  74940. this.value = (this.states.includes(state)) ? normalizedYAxis : 0.5;
  74941. break;
  74942. case Constants.ComponentProperty.BUTTON:
  74943. this.value = (this.states.includes(state)) ? button : 0;
  74944. break;
  74945. case Constants.ComponentProperty.STATE:
  74946. if (this.valueNodeProperty === Constants.VisualResponseProperty.VISIBILITY) {
  74947. this.value = (this.states.includes(state));
  74948. } else {
  74949. this.value = this.states.includes(state) ? 1.0 : 0.0;
  74950. }
  74951. break;
  74952. default:
  74953. throw new Error(`Unexpected visualResponse componentProperty ${this.componentProperty}`);
  74954. }
  74955. }
  74956. }
  74957. class Component {
  74958. /**
  74959. * @param {Object} componentId - Id of the component
  74960. * @param {Object} componentDescription - Description of the component to be created
  74961. */
  74962. constructor(componentId, componentDescription) {
  74963. if (!componentId
  74964. || !componentDescription
  74965. || !componentDescription.visualResponses
  74966. || !componentDescription.gamepadIndices
  74967. || Object.keys(componentDescription.gamepadIndices).length === 0) {
  74968. throw new Error('Invalid arguments supplied');
  74969. }
  74970. this.id = componentId;
  74971. this.type = componentDescription.type;
  74972. this.rootNodeName = componentDescription.rootNodeName;
  74973. this.touchPointNodeName = componentDescription.touchPointNodeName;
  74974. // Build all the visual responses for this component
  74975. this.visualResponses = {};
  74976. Object.keys(componentDescription.visualResponses).forEach((responseName) => {
  74977. const visualResponse = new VisualResponse(componentDescription.visualResponses[responseName]);
  74978. this.visualResponses[responseName] = visualResponse;
  74979. });
  74980. // Set default values
  74981. this.gamepadIndices = Object.assign({}, componentDescription.gamepadIndices);
  74982. this.values = {
  74983. state: Constants.ComponentState.DEFAULT,
  74984. button: (this.gamepadIndices.button !== undefined) ? 0 : undefined,
  74985. xAxis: (this.gamepadIndices.xAxis !== undefined) ? 0 : undefined,
  74986. yAxis: (this.gamepadIndices.yAxis !== undefined) ? 0 : undefined
  74987. };
  74988. }
  74989. get data() {
  74990. const data = { id: this.id, ...this.values };
  74991. return data;
  74992. }
  74993. /**
  74994. * @description Poll for updated data based on current gamepad state
  74995. * @param {Object} gamepad - The gamepad object from which the component data should be polled
  74996. */
  74997. updateFromGamepad(gamepad) {
  74998. // Set the state to default before processing other data sources
  74999. this.values.state = Constants.ComponentState.DEFAULT;
  75000. // Get and normalize button
  75001. if (this.gamepadIndices.button !== undefined
  75002. && gamepad.buttons.length > this.gamepadIndices.button) {
  75003. const gamepadButton = gamepad.buttons[this.gamepadIndices.button];
  75004. this.values.button = gamepadButton.value;
  75005. this.values.button = (this.values.button < 0) ? 0 : this.values.button;
  75006. this.values.button = (this.values.button > 1) ? 1 : this.values.button;
  75007. // Set the state based on the button
  75008. if (gamepadButton.pressed || this.values.button === 1) {
  75009. this.values.state = Constants.ComponentState.PRESSED;
  75010. } else if (gamepadButton.touched || this.values.button > Constants.ButtonTouchThreshold) {
  75011. this.values.state = Constants.ComponentState.TOUCHED;
  75012. }
  75013. }
  75014. // Get and normalize x axis value
  75015. if (this.gamepadIndices.xAxis !== undefined
  75016. && gamepad.axes.length > this.gamepadIndices.xAxis) {
  75017. this.values.xAxis = gamepad.axes[this.gamepadIndices.xAxis];
  75018. this.values.xAxis = (this.values.xAxis < -1) ? -1 : this.values.xAxis;
  75019. this.values.xAxis = (this.values.xAxis > 1) ? 1 : this.values.xAxis;
  75020. // If the state is still default, check if the xAxis makes it touched
  75021. if (this.values.state === Constants.ComponentState.DEFAULT
  75022. && Math.abs(this.values.xAxis) > Constants.AxisTouchThreshold) {
  75023. this.values.state = Constants.ComponentState.TOUCHED;
  75024. }
  75025. }
  75026. // Get and normalize Y axis value
  75027. if (this.gamepadIndices.yAxis !== undefined
  75028. && gamepad.axes.length > this.gamepadIndices.yAxis) {
  75029. this.values.yAxis = gamepad.axes[this.gamepadIndices.yAxis];
  75030. this.values.yAxis = (this.values.yAxis < -1) ? -1 : this.values.yAxis;
  75031. this.values.yAxis = (this.values.yAxis > 1) ? 1 : this.values.yAxis;
  75032. // If the state is still default, check if the yAxis makes it touched
  75033. if (this.values.state === Constants.ComponentState.DEFAULT
  75034. && Math.abs(this.values.yAxis) > Constants.AxisTouchThreshold) {
  75035. this.values.state = Constants.ComponentState.TOUCHED;
  75036. }
  75037. }
  75038. // Update the visual response weights based on the current component data
  75039. Object.values(this.visualResponses).forEach((visualResponse) => {
  75040. visualResponse.updateFromComponent(this.values);
  75041. });
  75042. }
  75043. }
  75044. /**
  75045. * @description Builds a motion controller with components and visual responses based on the
  75046. * supplied profile description. Data is polled from the xrInputSource's gamepad.
  75047. * @author Nell Waliczek / https://github.com/NellWaliczek
  75048. */
  75049. class MotionController {
  75050. /**
  75051. * @param {Object} xrInputSource - The XRInputSource to build the MotionController around
  75052. * @param {Object} profile - The best matched profile description for the supplied xrInputSource
  75053. * @param {Object} assetUrl
  75054. */
  75055. constructor(xrInputSource, profile, assetUrl) {
  75056. if (!xrInputSource) {
  75057. throw new Error('No xrInputSource supplied');
  75058. }
  75059. if (!profile) {
  75060. throw new Error('No profile supplied');
  75061. }
  75062. this.xrInputSource = xrInputSource;
  75063. this.assetUrl = assetUrl;
  75064. this.id = profile.profileId;
  75065. // Build child components as described in the profile description
  75066. this.layoutDescription = profile.layouts[xrInputSource.handedness];
  75067. this.components = {};
  75068. Object.keys(this.layoutDescription.components).forEach((componentId) => {
  75069. const componentDescription = this.layoutDescription.components[componentId];
  75070. this.components[componentId] = new Component(componentId, componentDescription);
  75071. });
  75072. // Initialize components based on current gamepad state
  75073. this.updateFromGamepad();
  75074. }
  75075. get gripSpace() {
  75076. return this.xrInputSource.gripSpace;
  75077. }
  75078. get targetRaySpace() {
  75079. return this.xrInputSource.targetRaySpace;
  75080. }
  75081. /**
  75082. * @description Returns a subset of component data for simplified debugging
  75083. */
  75084. get data() {
  75085. const data = [];
  75086. Object.values(this.components).forEach((component) => {
  75087. data.push(component.data);
  75088. });
  75089. return data;
  75090. }
  75091. /**
  75092. * @description Poll for updated data based on current gamepad state
  75093. */
  75094. updateFromGamepad() {
  75095. Object.values(this.components).forEach((component) => {
  75096. component.updateFromGamepad(this.xrInputSource.gamepad);
  75097. });
  75098. }
  75099. }
  75100. const DEFAULT_PROFILES_PATH = 'https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles';
  75101. const DEFAULT_PROFILE = 'generic-trigger';
  75102. function XRControllerModel( ) {
  75103. Object3D.call( this );
  75104. this.motionController = null;
  75105. this.envMap = null;
  75106. }
  75107. XRControllerModel.prototype = Object.assign( Object.create( Object3D.prototype ), {
  75108. constructor: XRControllerModel,
  75109. setEnvironmentMap: function ( envMap ) {
  75110. if ( this.envMap == envMap ) {
  75111. return this;
  75112. }
  75113. this.envMap = envMap;
  75114. this.traverse( ( child ) => {
  75115. if ( child.isMesh ) {
  75116. child.material.envMap = this.envMap;
  75117. child.material.needsUpdate = true;
  75118. }
  75119. } );
  75120. return this;
  75121. },
  75122. /**
  75123. * Polls data from the XRInputSource and updates the model's components to match
  75124. * the real world data
  75125. */
  75126. updateMatrixWorld: function ( force ) {
  75127. Object3D.prototype.updateMatrixWorld.call( this, force );
  75128. if ( ! this.motionController ) return;
  75129. // Cause the MotionController to poll the Gamepad for data
  75130. this.motionController.updateFromGamepad();
  75131. // Update the 3D model to reflect the button, thumbstick, and touchpad state
  75132. Object.values( this.motionController.components ).forEach( ( component ) => {
  75133. // Update node data based on the visual responses' current states
  75134. Object.values( component.visualResponses ).forEach( ( visualResponse ) => {
  75135. const { valueNode, minNode, maxNode, value, valueNodeProperty } = visualResponse;
  75136. // Skip if the visual response node is not found. No error is needed,
  75137. // because it will have been reported at load time.
  75138. if ( ! valueNode ) return;
  75139. // Calculate the new properties based on the weight supplied
  75140. if ( valueNodeProperty === Constants.VisualResponseProperty.VISIBILITY ) {
  75141. valueNode.visible = value;
  75142. } else if ( valueNodeProperty === Constants.VisualResponseProperty.TRANSFORM ) {
  75143. Quaternion.slerp(
  75144. minNode.quaternion,
  75145. maxNode.quaternion,
  75146. valueNode.quaternion,
  75147. value
  75148. );
  75149. valueNode.position.lerpVectors(
  75150. minNode.position,
  75151. maxNode.position,
  75152. value
  75153. );
  75154. }
  75155. } );
  75156. } );
  75157. }
  75158. } );
  75159. /**
  75160. * Walks the model's tree to find the nodes needed to animate the components and
  75161. * saves them to the motionContoller components for use in the frame loop. When
  75162. * touchpads are found, attaches a touch dot to them.
  75163. */
  75164. function findNodes( motionController, scene ) {
  75165. // Loop through the components and find the nodes needed for each components' visual responses
  75166. Object.values( motionController.components ).forEach( ( component ) => {
  75167. const { type, touchPointNodeName, visualResponses } = component;
  75168. if ( type === Constants.ComponentType.TOUCHPAD ) {
  75169. component.touchPointNode = scene.getObjectByName( touchPointNodeName );
  75170. if ( component.touchPointNode ) {
  75171. // Attach a touch dot to the touchpad.
  75172. const sphereGeometry = new SphereBufferGeometry( 0.001 );
  75173. const material = new MeshBasicMaterial( { color: 0x0000FF } );
  75174. const sphere = new Mesh( sphereGeometry, material );
  75175. component.touchPointNode.add( sphere );
  75176. } else {
  75177. console.warn( `Could not find touch dot, ${component.touchPointNodeName}, in touchpad component ${component.id}` );
  75178. }
  75179. }
  75180. // Loop through all the visual responses to be applied to this component
  75181. Object.values( visualResponses ).forEach( ( visualResponse ) => {
  75182. const { valueNodeName, minNodeName, maxNodeName, valueNodeProperty } = visualResponse;
  75183. // If animating a transform, find the two nodes to be interpolated between.
  75184. if ( valueNodeProperty === Constants.VisualResponseProperty.TRANSFORM ) {
  75185. visualResponse.minNode = scene.getObjectByName( minNodeName );
  75186. visualResponse.maxNode = scene.getObjectByName( maxNodeName );
  75187. // If the extents cannot be found, skip this animation
  75188. if ( ! visualResponse.minNode ) {
  75189. console.warn( `Could not find ${minNodeName} in the model` );
  75190. return;
  75191. }
  75192. if ( ! visualResponse.maxNode ) {
  75193. console.warn( `Could not find ${maxNodeName} in the model` );
  75194. return;
  75195. }
  75196. }
  75197. // If the target node cannot be found, skip this animation
  75198. visualResponse.valueNode = scene.getObjectByName( valueNodeName );
  75199. if ( ! visualResponse.valueNode ) {
  75200. console.warn( `Could not find ${valueNodeName} in the model` );
  75201. }
  75202. } );
  75203. } );
  75204. }
  75205. function addAssetSceneToControllerModel( controllerModel, scene ) {
  75206. // Find the nodes needed for animation and cache them on the motionController.
  75207. findNodes( controllerModel.motionController, scene );
  75208. // Apply any environment map that the mesh already has set.
  75209. if ( controllerModel.envMap ) {
  75210. scene.traverse( ( child ) => {
  75211. if ( child.isMesh ) {
  75212. child.material.envMap = controllerModel.envMap;
  75213. child.material.needsUpdate = true;
  75214. }
  75215. } );
  75216. }
  75217. // Add the glTF scene to the controllerModel.
  75218. controllerModel.add( scene );
  75219. }
  75220. var XRControllerModelFactory = ( function () {
  75221. function XRControllerModelFactory( gltfLoader = null ) {
  75222. this.gltfLoader = gltfLoader;
  75223. this.path = DEFAULT_PROFILES_PATH;
  75224. this._assetCache = {};
  75225. // If a GLTFLoader wasn't supplied to the constructor create a new one.
  75226. if ( ! this.gltfLoader ) {
  75227. this.gltfLoader = new GLTFLoader();
  75228. }
  75229. }
  75230. XRControllerModelFactory.prototype = {
  75231. constructor: XRControllerModelFactory,
  75232. createControllerModel: function ( controller ) {
  75233. const controllerModel = new XRControllerModel();
  75234. let scene = null;
  75235. controller.addEventListener( 'connected', ( event ) => {
  75236. const xrInputSource = event.data;
  75237. if ( xrInputSource.targetRayMode !== 'tracked-pointer' || ! xrInputSource.gamepad ) return;
  75238. fetchProfile( xrInputSource, this.path, DEFAULT_PROFILE ).then( ( { profile, assetPath } ) => {
  75239. controllerModel.motionController = new MotionController(
  75240. xrInputSource,
  75241. profile,
  75242. assetPath
  75243. );
  75244. const cachedAsset = this._assetCache[ controllerModel.motionController.assetUrl ];
  75245. if ( cachedAsset ) {
  75246. scene = cachedAsset.scene.clone();
  75247. addAssetSceneToControllerModel( controllerModel, scene );
  75248. } else {
  75249. if ( ! this.gltfLoader ) {
  75250. throw new Error( 'GLTFLoader not set.' );
  75251. }
  75252. this.gltfLoader.setPath( '' );
  75253. this.gltfLoader.load( controllerModel.motionController.assetUrl, ( asset ) => {
  75254. this._assetCache[ controllerModel.motionController.assetUrl ] = asset;
  75255. scene = asset.scene.clone();
  75256. addAssetSceneToControllerModel( controllerModel, scene );
  75257. },
  75258. null,
  75259. () => {
  75260. throw new Error( `Asset ${controllerModel.motionController.assetUrl} missing or malformed.` );
  75261. } );
  75262. }
  75263. } ).catch( ( err ) => {
  75264. console.warn( err );
  75265. } );
  75266. } );
  75267. controller.addEventListener( 'disconnected', () => {
  75268. controllerModel.motionController = null;
  75269. controllerModel.remove( scene );
  75270. scene = null;
  75271. } );
  75272. return controllerModel;
  75273. }
  75274. };
  75275. return XRControllerModelFactory;
  75276. } )();
  75277. let fakeCam = new PerspectiveCamera();
  75278. function toScene(vec, ref){
  75279. let node = ref.clone();
  75280. node.updateMatrix();
  75281. node.updateMatrixWorld();
  75282. let result = vec.clone().applyMatrix4(node.matrix);
  75283. result.z -= 0.8 * node.scale.x;
  75284. return result;
  75285. };
  75286. function computeMove(vrControls, controller){
  75287. if(!controller || !controller.inputSource || !controller.inputSource.gamepad){
  75288. return null;
  75289. }
  75290. let pad = controller.inputSource.gamepad;
  75291. let axes = pad.axes;
  75292. // [0,1] are for touchpad, [2,3] for thumbsticks?
  75293. let y = 0;
  75294. if(axes.length === 2){
  75295. y = axes[1];
  75296. }else if(axes.length === 4){
  75297. y = axes[3];
  75298. }
  75299. y = Math.sign(y) * (2 * y) ** 2;
  75300. let maxSize = 0;
  75301. for(let pc of viewer.scene.pointclouds){
  75302. let size = pc.boundingBox.min.distanceTo(pc.boundingBox.max);
  75303. maxSize = Math.max(maxSize, size);
  75304. }
  75305. let multiplicator = Math.pow(maxSize, 0.5) / 2;
  75306. let scale = vrControls.node.scale.x;
  75307. let moveSpeed = viewer.getMoveSpeed();
  75308. let amount = multiplicator * y * (moveSpeed ** 0.5) / scale;
  75309. let rotation = new Quaternion().setFromEuler(controller.rotation);
  75310. let dir = new Vector3(0, 0, -1);
  75311. dir.applyQuaternion(rotation);
  75312. let move = dir.clone().multiplyScalar(amount);
  75313. let p1 = vrControls.toScene(controller.position);
  75314. let p2 = vrControls.toScene(controller.position.clone().add(move));
  75315. move = p2.clone().sub(p1);
  75316. return move;
  75317. };
  75318. class FlyMode{
  75319. constructor(vrControls){
  75320. this.moveFactor = 1;
  75321. this.dbgLabel = null;
  75322. }
  75323. start(vrControls){
  75324. if(!this.dbgLabel){
  75325. /* this.dbgLabel = new Potree.TextSprite("abc");
  75326. this.dbgLabel.name = "debug label";
  75327. vrControls.viewer.sceneVR.add(this.dbgLabel);
  75328. this.dbgLabel.visible = false; */
  75329. }
  75330. }
  75331. end(){
  75332. }
  75333. update(vrControls, delta){
  75334. let primary = vrControls.cPrimary;
  75335. let secondary = vrControls.cSecondary;
  75336. let move1 = computeMove(vrControls, primary);
  75337. let move2 = computeMove(vrControls, secondary);
  75338. if(!move1){
  75339. move1 = new Vector3();
  75340. }
  75341. if(!move2){
  75342. move2 = new Vector3();
  75343. }
  75344. let move = move1.clone().add(move2);
  75345. move.multiplyScalar(-delta * this.moveFactor);
  75346. vrControls.node.position.add(move);
  75347. let scale = vrControls.node.scale.x;
  75348. let camVR = vrControls.viewer.renderer.xr.getCamera(fakeCam);
  75349. let vrPos = camVR.getWorldPosition(new Vector3());
  75350. let vrDir = camVR.getWorldDirection(new Vector3());
  75351. let vrTarget = vrPos.clone().add(vrDir.multiplyScalar(scale));
  75352. let scenePos = toScene(vrPos, vrControls.node);
  75353. let sceneDir = toScene(vrPos.clone().add(vrDir), vrControls.node).sub(scenePos);
  75354. sceneDir.normalize().multiplyScalar(scale);
  75355. let sceneTarget = scenePos.clone().add(sceneDir);
  75356. vrControls.viewer.scene.view.setView(scenePos, sceneTarget);
  75357. if(Potree.debug.message){
  75358. this.dbgLabel.visible = true;
  75359. this.dbgLabel.setText(Potree.debug.message);
  75360. this.dbgLabel.scale.set(0.1, 0.1, 0.1);
  75361. this.dbgLabel.position.copy(primary.position);
  75362. }
  75363. }
  75364. };
  75365. class TranslationMode{
  75366. constructor(){
  75367. this.controller = null;
  75368. this.startPos = null;
  75369. this.debugLine = null;
  75370. }
  75371. start(vrControls){
  75372. this.controller = vrControls.triggered.values().next().value;
  75373. this.startPos = vrControls.node.position.clone();
  75374. }
  75375. end(vrControls){
  75376. }
  75377. update(vrControls, delta){
  75378. let start = this.controller.start.position;
  75379. let end = this.controller.position;
  75380. start = vrControls.toScene(start);
  75381. end = vrControls.toScene(end);
  75382. let diff = end.clone().sub(start);
  75383. diff.set(-diff.x, -diff.y, -diff.z);
  75384. let pos = new Vector3().addVectors(this.startPos, diff);
  75385. vrControls.node.position.copy(pos);
  75386. }
  75387. };
  75388. class RotScaleMode{
  75389. constructor(){
  75390. this.line = null;
  75391. this.startState = null;
  75392. }
  75393. start(vrControls){
  75394. if(!this.line){
  75395. this.line = Potree.Utils.debugLine(
  75396. vrControls.viewer.sceneVR,
  75397. new Vector3(0, 0, 0),
  75398. new Vector3(0, 0, 0),
  75399. 0xffff00,
  75400. );
  75401. this.dbgLabel = new Potree.TextSprite("abc");
  75402. this.dbgLabel.scale.set(0.1, 0.1, 0.1);
  75403. vrControls.viewer.sceneVR.add(this.dbgLabel);
  75404. }
  75405. this.line.node.visible = true;
  75406. this.startState = vrControls.node.clone();
  75407. }
  75408. end(vrControls){
  75409. this.line.node.visible = false;
  75410. this.dbgLabel.visible = false;
  75411. }
  75412. update(vrControls, delta){
  75413. let start_c1 = vrControls.cPrimary.start.position.clone();
  75414. let start_c2 = vrControls.cSecondary.start.position.clone();
  75415. let start_center = start_c1.clone().add(start_c2).multiplyScalar(0.5);
  75416. let start_c1_c2 = start_c2.clone().sub(start_c1);
  75417. let end_c1 = vrControls.cPrimary.position.clone();
  75418. let end_c2 = vrControls.cSecondary.position.clone();
  75419. let end_center = end_c1.clone().add(end_c2).multiplyScalar(0.5);
  75420. let end_c1_c2 = end_c2.clone().sub(end_c1);
  75421. let d1 = start_c1_c2.length();
  75422. let d2 = end_c1_c2.length();
  75423. let angleStart = new Vector2$1(start_c1_c2.x, start_c1_c2.z).angle();
  75424. let angleEnd = new Vector2$1(end_c1_c2.x, end_c1_c2.z).angle();
  75425. let angleDiff = angleEnd - angleStart;
  75426. let scale = d2 / d1;
  75427. let node = this.startState.clone();
  75428. node.updateMatrix();
  75429. node.matrixAutoUpdate = false;
  75430. let mToOrigin = new Matrix4().makeTranslation(...toScene(start_center, this.startState).multiplyScalar(-1).toArray());
  75431. let mToStart = new Matrix4().makeTranslation(...toScene(start_center, this.startState).toArray());
  75432. let mRotate = new Matrix4().makeRotationZ(angleDiff);
  75433. let mScale = new Matrix4().makeScale(1 / scale, 1 / scale, 1 / scale);
  75434. node.applyMatrix4(mToOrigin);
  75435. node.applyMatrix4(mRotate);
  75436. node.applyMatrix4(mScale);
  75437. node.applyMatrix4(mToStart);
  75438. let oldScenePos = toScene(start_center, this.startState);
  75439. let newScenePos = toScene(end_center, node);
  75440. let toNew = oldScenePos.clone().sub(newScenePos);
  75441. let mToNew = new Matrix4().makeTranslation(...toNew.toArray());
  75442. node.applyMatrix4(mToNew);
  75443. node.matrix.decompose(node.position, node.quaternion, node.scale );
  75444. vrControls.node.position.copy(node.position);
  75445. vrControls.node.quaternion.copy(node.quaternion);
  75446. vrControls.node.scale.copy(node.scale);
  75447. vrControls.node.updateMatrix();
  75448. {
  75449. let scale = vrControls.node.scale.x;
  75450. let camVR = vrControls.viewer.renderer.xr.getCamera(fakeCam);
  75451. let vrPos = camVR.getWorldPosition(new Vector3());
  75452. let vrDir = camVR.getWorldDirection(new Vector3());
  75453. let vrTarget = vrPos.clone().add(vrDir.multiplyScalar(scale));
  75454. let scenePos = toScene(vrPos, this.startState);
  75455. let sceneDir = toScene(vrPos.clone().add(vrDir), this.startState).sub(scenePos);
  75456. sceneDir.normalize().multiplyScalar(scale);
  75457. let sceneTarget = scenePos.clone().add(sceneDir);
  75458. vrControls.viewer.scene.view.setView(scenePos, sceneTarget);
  75459. vrControls.viewer.setMoveSpeed(scale);
  75460. }
  75461. { // update "GUI"
  75462. this.line.set(end_c1, end_c2);
  75463. let scale = vrControls.node.scale.x;
  75464. this.dbgLabel.visible = true;
  75465. this.dbgLabel.position.copy(end_center);
  75466. this.dbgLabel.setText(`scale: 1 : ${scale.toFixed(2)}`);
  75467. this.dbgLabel.scale.set(0.05, 0.05, 0.05);
  75468. }
  75469. }
  75470. };
  75471. class VRControls extends EventDispatcher{
  75472. constructor(viewer){
  75473. super(viewer);
  75474. this.viewer = viewer;
  75475. viewer.addEventListener("vr_start", this.onStart.bind(this));
  75476. viewer.addEventListener("vr_end", this.onEnd.bind(this));
  75477. this.node = new Object3D();
  75478. this.node.up.set(0, 0, 1);
  75479. this.triggered = new Set();
  75480. let xr = viewer.renderer.xr;
  75481. { // lights
  75482. const light = new PointLight( 0xffffff, 5, 0, 1 );
  75483. light.position.set(0, 2, 0);
  75484. this.viewer.sceneVR.add(light);
  75485. }
  75486. this.menu = null;
  75487. const controllerModelFactory = new XRControllerModelFactory();
  75488. let sg = new SphereGeometry(1, 32, 32);
  75489. let sm = new MeshNormalMaterial();
  75490. { // setup primary controller
  75491. let controller = xr.getController(0);
  75492. let grip = xr.getControllerGrip(0);
  75493. grip.name = "grip(0)";
  75494. // ADD CONTROLLERMODEL
  75495. grip.add( controllerModelFactory.createControllerModel( grip ) );
  75496. this.viewer.sceneVR.add(grip);
  75497. // ADD SPHERE
  75498. let sphere = new Mesh(sg, sm);
  75499. sphere.scale.set(0.005, 0.005, 0.005);
  75500. controller.add(sphere);
  75501. controller.visible = true;
  75502. this.viewer.sceneVR.add(controller);
  75503. { // ADD LINE
  75504. let lineGeometry = new LineGeometry();
  75505. lineGeometry.setPositions([
  75506. 0, 0, -0.15,
  75507. 0, 0, 0.05,
  75508. ]);
  75509. let lineMaterial = new LineMaterial({
  75510. color: 0xff0000,
  75511. lineWidth: 2,
  75512. resolution: new Vector2$1(1000, 1000),
  75513. });
  75514. const line = new Line2(lineGeometry, lineMaterial);
  75515. controller.add(line);
  75516. }
  75517. controller.addEventListener( 'connected', function ( event ) {
  75518. const xrInputSource = event.data;
  75519. controller.inputSource = xrInputSource;
  75520. // initInfo(controller);
  75521. });
  75522. controller.addEventListener( 'selectstart', () => {this.onTriggerStart(controller);});
  75523. controller.addEventListener( 'selectend', () => {this.onTriggerEnd(controller);});
  75524. this.cPrimary = controller;
  75525. }
  75526. { // setup secondary controller
  75527. let controller = xr.getController(1);
  75528. let grip = xr.getControllerGrip(1);
  75529. // ADD CONTROLLER MODEL
  75530. let model = controllerModelFactory.createControllerModel( grip );
  75531. grip.add(model);
  75532. this.viewer.sceneVR.add( grip );
  75533. // ADD SPHERE
  75534. let sphere = new Mesh(sg, sm);
  75535. sphere.scale.set(0.005, 0.005, 0.005);
  75536. controller.add(sphere);
  75537. controller.visible = true;
  75538. this.viewer.sceneVR.add(controller);
  75539. { // ADD LINE
  75540. let lineGeometry = new LineGeometry();
  75541. lineGeometry.setPositions([
  75542. 0, 0, -0.15,
  75543. 0, 0, 0.05,
  75544. ]);
  75545. let lineMaterial = new LineMaterial({
  75546. color: 0xff0000,
  75547. lineWidth: 2,
  75548. resolution: new Vector2$1(1000, 1000),
  75549. });
  75550. const line = new Line2(lineGeometry, lineMaterial);
  75551. controller.add(line);
  75552. }
  75553. controller.addEventListener( 'connected', (event) => {
  75554. const xrInputSource = event.data;
  75555. controller.inputSource = xrInputSource;
  75556. this.initMenu(controller);
  75557. });
  75558. controller.addEventListener( 'selectstart', () => {this.onTriggerStart(controller);});
  75559. controller.addEventListener( 'selectend', () => {this.onTriggerEnd(controller);});
  75560. this.cSecondary = controller;
  75561. }
  75562. this.mode_fly = new FlyMode();
  75563. this.mode_translate = new TranslationMode();
  75564. this.mode_rotScale = new RotScaleMode();
  75565. this.setMode(this.mode_fly);
  75566. }
  75567. createSlider(label, min, max){
  75568. let sg = new SphereGeometry(1, 8, 8);
  75569. let cg = new CylinderGeometry(1, 1, 1, 8);
  75570. let matHandle = new MeshBasicMaterial({color: 0xff0000});
  75571. let matScale = new MeshBasicMaterial({color: 0xff4444});
  75572. let matValue = new MeshNormalMaterial();
  75573. let node = new Object3D("slider");
  75574. let nLabel = new Potree.TextSprite(`${label}: 0`);
  75575. let nMax = new Mesh(sg, matHandle);
  75576. let nMin = new Mesh(sg, matHandle);
  75577. let nValue = new Mesh(sg, matValue);
  75578. let nScale = new Mesh(cg, matScale);
  75579. nLabel.scale.set(0.2, 0.2, 0.2);
  75580. nLabel.position.set(0, 0.35, 0);
  75581. nMax.scale.set(0.02, 0.02, 0.02);
  75582. nMax.position.set(0, 0.25, 0);
  75583. nMin.scale.set(0.02, 0.02, 0.02);
  75584. nMin.position.set(0, -0.25, 0);
  75585. nValue.scale.set(0.02, 0.02, 0.02);
  75586. nValue.position.set(0, 0, 0);
  75587. nScale.scale.set(0.005, 0.5, 0.005);
  75588. node.add(nLabel);
  75589. node.add(nMax);
  75590. node.add(nMin);
  75591. node.add(nValue);
  75592. node.add(nScale);
  75593. return node;
  75594. }
  75595. createInfo(){
  75596. let texture = new TextureLoader().load(`${Potree.resourcePath}/images/vr_controller_help.jpg`);
  75597. let plane = new PlaneBufferGeometry(1, 1, 1, 1);
  75598. let infoMaterial = new MeshBasicMaterial({map: texture});
  75599. let infoNode = new Mesh(plane, infoMaterial);
  75600. return infoNode;
  75601. }
  75602. initMenu(controller){
  75603. if(this.menu){
  75604. return;
  75605. }
  75606. let node = new Object3D("vr menu");
  75607. // let nSlider = this.createSlider("speed", 0, 1);
  75608. // let nInfo = this.createInfo();
  75609. // // node.add(nSlider);
  75610. // node.add(nInfo);
  75611. // {
  75612. // node.rotation.set(-1.5, 0, 0)
  75613. // node.scale.set(0.3, 0.3, 0.3);
  75614. // node.position.set(-0.2, -0.002, -0.1)
  75615. // // nInfo.position.set(0.5, 0, 0);
  75616. // nInfo.scale.set(0.8, 0.6, 0);
  75617. // // controller.add(node);
  75618. // }
  75619. // node.position.set(-0.3, 1.2, 0.2);
  75620. // node.scale.set(0.3, 0.2, 0.3);
  75621. // node.lookAt(new THREE.Vector3(0, 1.5, 0.1));
  75622. // this.viewer.sceneVR.add(node);
  75623. this.menu = node;
  75624. // window.vrSlider = nSlider;
  75625. window.vrMenu = node;
  75626. }
  75627. toScene(vec){
  75628. let camVR = this.getCamera();
  75629. let mat = camVR.matrixWorld;
  75630. let result = vec.clone().applyMatrix4(mat);
  75631. return result;
  75632. }
  75633. toVR(vec){
  75634. let camVR = this.getCamera();
  75635. let mat = camVR.matrixWorld.clone();
  75636. mat.invert();
  75637. let result = vec.clone().applyMatrix4(mat);
  75638. return result;
  75639. }
  75640. setMode(mode){
  75641. if(this.mode === mode){
  75642. return;
  75643. }
  75644. if(this.mode){
  75645. this.mode.end(this);
  75646. }
  75647. for(let controller of [this.cPrimary, this.cSecondary]){
  75648. let start = {
  75649. position: controller.position.clone(),
  75650. rotation: controller.rotation.clone(),
  75651. };
  75652. controller.start = start;
  75653. }
  75654. this.mode = mode;
  75655. this.mode.start(this);
  75656. }
  75657. onTriggerStart(controller){
  75658. this.triggered.add(controller);
  75659. if(this.triggered.size === 0){
  75660. this.setMode(this.mode_fly);
  75661. }else if(this.triggered.size === 1){
  75662. this.setMode(this.mode_translate);
  75663. }else if(this.triggered.size === 2){
  75664. this.setMode(this.mode_rotScale);
  75665. }
  75666. }
  75667. onTriggerEnd(controller){
  75668. this.triggered.delete(controller);
  75669. if(this.triggered.size === 0){
  75670. this.setMode(this.mode_fly);
  75671. }else if(this.triggered.size === 1){
  75672. this.setMode(this.mode_translate);
  75673. }else if(this.triggered.size === 2){
  75674. this.setMode(this.mode_rotScale);
  75675. }
  75676. }
  75677. onStart(){
  75678. let position = this.viewer.scene.view.position.clone();
  75679. let direction = this.viewer.scene.view.direction;
  75680. direction.multiplyScalar(-1);
  75681. let target = position.clone().add(direction);
  75682. target.z = position.z;
  75683. let scale = this.viewer.getMoveSpeed();
  75684. this.node.position.copy(position);
  75685. this.node.lookAt(target);
  75686. this.node.scale.set(scale, scale, scale);
  75687. this.node.updateMatrix();
  75688. this.node.updateMatrixWorld();
  75689. }
  75690. onEnd(){
  75691. }
  75692. setScene(scene){
  75693. this.scene = scene;
  75694. }
  75695. getCamera(){
  75696. let reference = this.viewer.scene.getActiveCamera();
  75697. let camera = new PerspectiveCamera();
  75698. // let scale = this.node.scale.x;
  75699. let scale = this.viewer.getMoveSpeed();
  75700. //camera.near = 0.01 / scale;
  75701. camera.near = 0.1;
  75702. camera.far = 1000;
  75703. // camera.near = reference.near / scale;
  75704. // camera.far = reference.far / scale;
  75705. camera.up.set(0, 0, 1);
  75706. camera.lookAt(new Vector3(0, -1, 0));
  75707. camera.updateMatrix();
  75708. camera.updateMatrixWorld();
  75709. camera.position.copy(this.node.position);
  75710. camera.rotation.copy(this.node.rotation);
  75711. camera.scale.set(scale, scale, scale);
  75712. camera.updateMatrix();
  75713. camera.updateMatrixWorld();
  75714. camera.matrixAutoUpdate = false;
  75715. camera.parent = camera;
  75716. return camera;
  75717. }
  75718. update(delta){
  75719. // if(this.mode === this.mode_fly){
  75720. // let ray = new THREE.Ray(origin, direction);
  75721. // for(let object of this.selectables){
  75722. // if(object.intersectsRay(ray)){
  75723. // object.onHit(ray);
  75724. // }
  75725. // }
  75726. // }
  75727. this.mode.update(this, delta);
  75728. }
  75729. };
  75730. // Adapted from three.js VRButton
  75731. class VRButton {
  75732. constructor(){
  75733. this.onStartListeners = [];
  75734. this.onEndListeners = [];
  75735. this.element = null;
  75736. }
  75737. onStart(callback){
  75738. this.onStartListeners.push(callback);
  75739. }
  75740. onEnd(callback){
  75741. this.onEndListeners.push(callback);
  75742. }
  75743. static async createButton( renderer, options ) {
  75744. if ( options ) {
  75745. console.error( 'THREE.VRButton: The "options" parameter has been removed. Please set the reference space type via renderer.xr.setReferenceSpaceType() instead.' );
  75746. }
  75747. const button = new VRButton();
  75748. const element = document.createElement( 'button' );
  75749. button.element = element;
  75750. function setEnter(){
  75751. button.element.innerHTML = `
  75752. <div style="font-size: 0.5em;">ENTER</div>
  75753. <div style="font-weight: bold;">VR</div>
  75754. `;
  75755. }
  75756. function setExit(){
  75757. button.element.innerHTML = `
  75758. <div style="font-size: 0.5em;">EXIT</div>
  75759. <div style="font-weight: bold;">VR</div>
  75760. `;
  75761. }
  75762. function showEnterVR( /*device*/ ) {
  75763. let currentSession = null;
  75764. function onSessionStarted( session ) {
  75765. session.addEventListener( 'end', onSessionEnded );
  75766. for(let listener of button.onStartListeners){
  75767. listener();
  75768. }
  75769. renderer.xr.setSession( session );
  75770. setExit();
  75771. currentSession = session;
  75772. }
  75773. function onSessionEnded( /*event*/ ) {
  75774. currentSession.removeEventListener( 'end', onSessionEnded );
  75775. for(let listener of button.onEndListeners){
  75776. listener();
  75777. }
  75778. setEnter();
  75779. currentSession = null;
  75780. }
  75781. //
  75782. button.element.style.display = '';
  75783. button.element.style.cursor = 'pointer';
  75784. setEnter();
  75785. button.element.onmouseenter = function () {
  75786. button.element.style.opacity = '1.0';
  75787. };
  75788. button.element.onmouseleave = function () {
  75789. button.element.style.opacity = '0.7';
  75790. };
  75791. button.element.onclick = function () {
  75792. if ( currentSession === null ) {
  75793. // WebXR's requestReferenceSpace only works if the corresponding feature
  75794. // was requested at session creation time. For simplicity, just ask for
  75795. // the interesting ones as optional features, but be aware that the
  75796. // requestReferenceSpace call will fail if it turns out to be unavailable.
  75797. // ('local' is always available for immersive sessions and doesn't need to
  75798. // be requested separately.)
  75799. const sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor', 'hand-tracking' ] };
  75800. navigator.xr.requestSession( 'immersive-vr', sessionInit ).then( onSessionStarted );
  75801. } else {
  75802. currentSession.end();
  75803. }
  75804. };
  75805. }
  75806. function stylizeElement( element ) {
  75807. element.style.position = 'absolute';
  75808. element.style.bottom = '20px';
  75809. element.style.padding = '12px 6px';
  75810. element.style.border = '1px solid #fff';
  75811. element.style.borderRadius = '4px';
  75812. element.style.background = 'rgba(0,0,0,0.1)';
  75813. element.style.color = '#fff';
  75814. element.style.font = 'normal 13px sans-serif';
  75815. element.style.textAlign = 'center';
  75816. element.style.opacity = '0.7';
  75817. element.style.outline = 'none';
  75818. element.style.zIndex = '999';
  75819. }
  75820. if ( 'xr' in navigator ) {
  75821. button.element.id = 'VRButton';
  75822. button.element.style.display = 'none';
  75823. stylizeElement( button.element );
  75824. let supported = await navigator.xr.isSessionSupported( 'immersive-vr' );
  75825. if(supported){
  75826. showEnterVR();
  75827. return button;
  75828. }else {
  75829. return null;
  75830. }
  75831. } else {
  75832. if ( window.isSecureContext === false ) {
  75833. console.log("WEBXR NEEDS HTTPS");
  75834. } else {
  75835. console.log("WEBXR not available");
  75836. }
  75837. return null;
  75838. }
  75839. }
  75840. }
  75841. //处理cursor优先级
  75842. var CursorDeal = {
  75843. priorityEvent : [//在前面的优先级高
  75844. {'hoverPano':'pointer'},
  75845. {'connectPano':`url({Potree.resourcePath}/images/connect.png),auto`},
  75846. {'disconnectPano':`url({Potree.resourcePath}/images/connect-dis.png),auto`},
  75847. {'hoverLine':'pointer'},
  75848. {'zoomInCloud':'zoom-in'},
  75849. {"movePointcloud":'move'},
  75850. {"polygon_isIntersectSelf":'not-allowed'},
  75851. {"polygon_AtWrongPlace":'not-allowed'},
  75852. {"markerMove":'grab'},
  75853. {'mapClipMove':'move'},
  75854. {'mapClipRotate':`url({Potree.resourcePath}/images/rotate-cursor.png),auto`},
  75855. {'rotatePointcloud':`url({Potree.resourcePath}/images/rotate-cursor.png),auto`},
  75856. {'siteModelFloorDrag':'row-resize'},
  75857. {'addSth':'cell'},//or crosshair
  75858. ],
  75859. list:[], //当前存在的cursor状态
  75860. currentCursorIndex:null,
  75861. init : function(viewer, viewers){
  75862. this.priorityEvent.forEach(e=>{//刚开始Potree.resourcePath没值,现在换
  75863. for(let i in e){
  75864. e[i] = Common.replaceAll(e[i],'{Potree.resourcePath}',Potree.resourcePath);
  75865. }
  75866. });
  75867. this.domElements = viewers.map(e=>e.renderArea);
  75868. viewer.addEventListener("CursorChange",(e)=>{
  75869. if(e.action == 'add'){
  75870. this.add(e.name);
  75871. }else {
  75872. this.remove(e.name);
  75873. }
  75874. });
  75875. },
  75876. add : function(name){
  75877. var priorityItem = this.priorityEvent.find(e=>e[name]);
  75878. if(!priorityItem){
  75879. console.error('CursorDeal 未定义优先级 name:'+ name);
  75880. return
  75881. }
  75882. if(!this.list.includes(name)){
  75883. this.judge({addItem: priorityItem, name});
  75884. this.list.push(name);
  75885. }
  75886. },
  75887. remove : function(name){
  75888. var index = this.list.indexOf(name);
  75889. if(index > -1){
  75890. this.list.splice(index, 1);
  75891. this.judge();
  75892. }
  75893. },
  75894. judge:function(o={}){
  75895. //console.log(o,this.list)
  75896. if(o.addItem){
  75897. var addIndex = this.priorityEvent.indexOf(o.addItem);
  75898. if(addIndex < this.currentCursorIndex || this.currentCursorIndex == void 0){
  75899. this.domElements.forEach(e=>e.style.cursor = o.addItem[o.name] );
  75900. this.currentCursorIndex = addIndex;
  75901. }
  75902. }else {
  75903. var levelMax = {index:Infinity, cursor:null };
  75904. this.list.forEach(name=>{
  75905. var priorityItem = this.priorityEvent.find(e=>e[name]);
  75906. var index = this.priorityEvent.indexOf(priorityItem);
  75907. if(index < levelMax.index){
  75908. levelMax.index = index;
  75909. levelMax.cursor = priorityItem[name];
  75910. }
  75911. });
  75912. this.currentCursorIndex = levelMax.index;
  75913. this.domElements.forEach(e=>e.style.cursor = levelMax.cursor || '');
  75914. }
  75915. }
  75916. };
  75917. let texLoader$5 = new TextureLoader();
  75918. let color$1 = new Color(config$1.clip.color);
  75919. let markerMats$1;
  75920. let markerSizeInfo$1 = {width2d:30};
  75921. class mapClipBox extends ctrlPolygon {
  75922. constructor (center, scale) {
  75923. center = center.clone().setZ(0);//所有Z都为0
  75924. let prop = {
  75925. points : getPoints(center, scale, 0),
  75926. closed : true,
  75927. isRect : true,
  75928. dimension : '2d'
  75929. };
  75930. super('mapClipBox', prop);
  75931. this.angle = 0;
  75932. this.createRotateBar();
  75933. this.edgeMarkers = [];
  75934. //addMarkers:
  75935. this.initData(prop);
  75936. {//areaPlane event 能拖动
  75937. this.areaPlane.addEventListener('mouseover',()=>{
  75938. viewer.dispatchEvent({
  75939. type : "CursorChange", action : "add", name:"mapClipMove"
  75940. });
  75941. });
  75942. this.areaPlane.addEventListener('mouseleave',()=>{
  75943. viewer.dispatchEvent({
  75944. type : "CursorChange", action : "remove", name:"mapClipMove"
  75945. });
  75946. });
  75947. let lastPos;
  75948. let drag = (e)=>{
  75949. let intersectPoint = e.intersectPoint.orthoIntersect;
  75950. if(lastPos){
  75951. let moveVec = new Vector3().subVectors(intersectPoint, lastPos).setZ(0);
  75952. this.center.add(moveVec);
  75953. this.updatePoints();
  75954. this.dispatchEvent({type:'repos'});
  75955. }
  75956. lastPos = intersectPoint.clone();
  75957. };
  75958. let drop = (e)=>{
  75959. lastPos = null;
  75960. };
  75961. this.areaPlane.addEventListener('drag', drag);
  75962. this.areaPlane.addEventListener('drop', drop);
  75963. }
  75964. /* this.addEventListener('dragChange',()=>{
  75965. this.updateTwoMidMarker(index+1)
  75966. }) */
  75967. viewer.setObjectLayers(this, 'mapObjects' );
  75968. }
  75969. getScale(){
  75970. return new Vector3(this.points[0].distanceTo(this.points[1]), this.points[1].distanceTo(this.points[2]) ,1)
  75971. }
  75972. addMarker(o={} ){
  75973. let marker = new Sprite$1({mat:this.getMarkerMaterial('default'), sizeInfo: markerSizeInfo$1, dontFixOrient: true, viewports:viewer.mapViewer.viewports, name:"mapClipBox_marker", } );
  75974. marker.renderOrder = 3;
  75975. //marker.markerSelectStates = {}
  75976. let edge = LineDraw.createLine([new Vector3,new Vector3],{color: color$1 });
  75977. let edgeMarker = new Sprite$1({mat:this.getMarkerMaterial('default'), sizeInfo: markerSizeInfo$1, dontFixOrient: true, viewports:viewer.mapViewer.viewports, name:"mapClipBox_edgePoint"} );
  75978. let mouseover = (e) => {
  75979. this.setMarkerSelected(e.object, true, 'single');
  75980. viewer.dispatchEvent({
  75981. type : "CursorChange", action : "add", name:"markerMove"
  75982. });
  75983. };
  75984. let mouseleave = (e) => {
  75985. this.setMarkerSelected(e.object, false, 'single');
  75986. viewer.dispatchEvent({
  75987. type : "CursorChange", action : "remove", name:"markerMove"
  75988. });
  75989. };
  75990. edgeMarker.addEventListener('mouseover', mouseover);
  75991. edgeMarker.addEventListener('mouseleave', mouseleave);
  75992. let dragInfo = {lastPos:null};
  75993. edgeMarker.addEventListener('drag', this.dragEdge.bind(this,dragInfo));
  75994. edgeMarker.addEventListener('drop', this.dropEdge.bind(this,dragInfo));
  75995. this.edgeMarkers.push(edgeMarker);
  75996. this.add(edgeMarker);
  75997. marker.dispatchEvent('addHoverEvent');
  75998. super.addMarker({point:o.point, marker:marker, edge});
  75999. }
  76000. dragEdge(dragInfo, e){//拖拽一个边(或一个边类型的marker),带动它的两个端点。 可以转化为拖拽marker往法线方向
  76001. var I, atMap;
  76002. atMap = e.dragViewport.name == 'mapViewport';
  76003. I = e.intersectPoint.orthoIntersect;
  76004. if (I && dragInfo.lastPos) {
  76005. let i = this.edgeMarkers.indexOf(e.drag.object);
  76006. if (i !== -1) {
  76007. let lineNormal = math.getNormal2d({p1:this.points[i], p2:this.points[(i+1)%4]});
  76008. let moveVec = new Vector3().subVectors(I, dragInfo.lastPos).setZ(0);//移动的向量
  76009. let dragVec = moveVec.projectOnVector(lineNormal).setZ(0);//在法线上移动的向量
  76010. let newPos = new Vector3().addVectors(this.points[i], dragVec); //marker应到的位置
  76011. this.dragChange(newPos, i, atMap); //转化为这个marker的拖拽
  76012. }
  76013. }
  76014. dragInfo.lastPos = I.clone();
  76015. }
  76016. dropEdge(dragInfo, e){
  76017. dragInfo.lastPos = null;
  76018. this.setMarkerSelected(e.drag.object, false, 'single'); //拖拽时似乎没有触发mouseout
  76019. }
  76020. createAreaPlane(){
  76021. var planeMat = new MeshBasicMaterial({
  76022. color: color$1,//"#00eeff",
  76023. side:DoubleSide,
  76024. opacity:0.3,
  76025. transparent:true,
  76026. depthTest:false
  76027. });
  76028. return super.createAreaPlane(planeMat)
  76029. }
  76030. getMarkerMaterial(type) {
  76031. if(!markerMats$1){
  76032. markerMats$1 = {
  76033. default: new MeshBasicMaterial({
  76034. transparent: !0,
  76035. color: color$1,
  76036. opacity: 0.8,
  76037. map: texLoader$5.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  76038. }),
  76039. select: new MeshBasicMaterial({
  76040. transparent: !0,
  76041. color: color$1,
  76042. opacity: 1,
  76043. map: texLoader$5.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  76044. }),
  76045. };
  76046. mapClipBox.markerMats = markerMats$1;
  76047. }
  76048. return markerMats$1[type]
  76049. }
  76050. setMarkerSelected(marker, state, hoverObject){
  76051. //console.warn(marker.id , state, hoverObject)
  76052. if(state == 'hover'){
  76053. marker.material = this.getMarkerMaterial('select');
  76054. }else {
  76055. marker.material = this.getMarkerMaterial('default');
  76056. }
  76057. /* marker.markerSelectStates[hoverObject] = state
  76058. let absoluteState = false
  76059. for(var i in marker.markerSelectStates){
  76060. if(marker.markerSelectStates[i]){
  76061. absoluteState = true; break;
  76062. }
  76063. }
  76064. if(absoluteState){
  76065. marker.material = this.getMarkerMaterial('select')
  76066. }else{
  76067. marker.material = this.getMarkerMaterial('default')
  76068. }
  76069. marker.selected = absoluteState */
  76070. viewer.mapViewer.dispatchEvent('content_changed');
  76071. }
  76072. createRotateBar(){
  76073. //中心点在线的一端,整体初始在box上方
  76074. const lineLen = 1.5, circleWidth = 2, barOpacity = 0.7;
  76075. let object = new Object3D;
  76076. let bar = new Sprite$1({mat:new MeshBasicMaterial({
  76077. side:DoubleSide,
  76078. opacity: barOpacity,
  76079. transparent:true,
  76080. depthTest:false,
  76081. map: texLoader$5.load(Potree.resourcePath+'/textures/rotation_circle.png' ),
  76082. }) ,
  76083. root:object,
  76084. sizeInfo: markerSizeInfo$1,
  76085. dontFixOrient: true,
  76086. viewports:viewer.mapViewer.viewports,
  76087. name:"mapClipRotateBar"
  76088. });
  76089. bar.position.set(0,lineLen+circleWidth/2,0);
  76090. bar.scale.set(circleWidth,circleWidth,circleWidth);
  76091. bar.addEventListener('mouseover',()=>{
  76092. bar.material.opacity = 1;
  76093. viewer.dispatchEvent({
  76094. type : "CursorChange", action : "add", name:"mapClipRotate"
  76095. });
  76096. viewer.mapViewer.dispatchEvent('content_changed');
  76097. });
  76098. let leave = ()=>{
  76099. bar.material.opacity = barOpacity;
  76100. viewer.dispatchEvent({
  76101. type : "CursorChange", action : "remove", name:"mapClipRotate"
  76102. });
  76103. viewer.mapViewer.dispatchEvent('content_changed');
  76104. };
  76105. bar.addEventListener('mouseleave',leave);
  76106. this.addEventListener('dispose', leave);
  76107. let lastPos;
  76108. bar.addEventListener('drag',(e)=>{
  76109. var intersectPoint = e.intersectPoint.orthoIntersect;
  76110. if(lastPos){
  76111. let vec1 = new Vector3().subVectors(lastPos, this.center).setZ(0);
  76112. let vec2 = new Vector3().subVectors(intersectPoint, this.center).setZ(0);
  76113. let angle = math.getAngle(vec1,vec2,'z');
  76114. this.angle += angle;
  76115. this.rotateBar.rotation.z = this.angle;
  76116. this.updatePoints();
  76117. this.dispatchEvent({type:'rotate', angle: this.angle});
  76118. }
  76119. lastPos = intersectPoint.clone();
  76120. });
  76121. bar.addEventListener('drop',()=>{
  76122. lastPos = null;
  76123. viewer.dispatchEvent({
  76124. type : "CursorChange", action : "remove", name:"mapClipRotate"
  76125. });
  76126. });
  76127. let line = LineDraw.createLine([new Vector3, new Vector3(0,lineLen,0)],{color: color$1});
  76128. object.add(bar);
  76129. object.add(line);
  76130. this.add(object);
  76131. this.rotateBar = object;
  76132. this.rotateBar.bar = bar;
  76133. }
  76134. updatePoints(scale){
  76135. this.points = getPoints(this.center, scale || this.getScale(), this.angle);
  76136. this.getPoint2dInfo(this.points);
  76137. this.update({ifUpdateMarkers:true});
  76138. }
  76139. update(options={}){
  76140. super.update(options);
  76141. {//update rotateBar
  76142. let center = new Vector3().addVectors(this.points[0], this.points[1]).multiplyScalar(0.5);
  76143. this.rotateBar.position.copy(center);
  76144. this.rotateBar.bar.update();//更新sprite matrix
  76145. }
  76146. {
  76147. for(let i=0;i<4;i++){
  76148. let current = this.points[i];
  76149. let next = this.points[(i+1)%4];
  76150. let mid = new Vector3().addVectors(current, next).multiplyScalar(0.5);
  76151. this.updateMarker(this.edgeMarkers[i], mid);
  76152. }
  76153. }
  76154. }
  76155. dispose(){
  76156. super.dispose();
  76157. this.dispatchEvent('dispose');
  76158. }
  76159. }
  76160. function getPoints(center, scale, angle=0){
  76161. let points = [
  76162. new Vector3(-scale.x/2, +scale.y/2, 0),
  76163. new Vector3(+scale.x/2, +scale.y/2, 0),
  76164. new Vector3(+scale.x/2, -scale.y/2, 0),
  76165. new Vector3(-scale.x/2, -scale.y/2, 0),
  76166. ];
  76167. var rotMatrix = new Matrix4().makeRotationAxis(new Vector3(0,0,1), angle);//再旋转
  76168. points.forEach(e=>{
  76169. e.applyMatrix4(rotMatrix);
  76170. e.add(center);
  76171. });
  76172. return points
  76173. }
  76174. const defaultBoxWidth = 6; //navvis: 10
  76175. //navvis position: si {x: 0, y: 0, z: 0}
  76176. var Clip = {
  76177. bus : new EventDispatcher,
  76178. selectedDatasets : [],
  76179. changeCallback(force){
  76180. if(Potree.settings.isOfficial){
  76181. Common.intervalTool.isWaiting('clipSelectedDatasets', ()=>{ //延时update,防止卡顿
  76182. let pointclouds = this.getIntersectPointcloud();
  76183. if(force || Common.getDifferenceSet(pointclouds,this.selectedDatasets).length){
  76184. this.selectedDatasets = pointclouds;
  76185. //console.error('clipSelectedDatasets',selectedDatasets)
  76186. this.bus.dispatchEvent({type:'updateSelectedDatasets', selectedDatasets:pointclouds.map(e=>e.dataset_id) });
  76187. force = false;
  76188. return true
  76189. }
  76190. }, 300);
  76191. }
  76192. },
  76193. enter:function(){
  76194. this.previousView = {
  76195. position: viewer.images360.position,
  76196. target: viewer.scene.view.getPivot(),
  76197. displayMode : Potree.settings.displayMode,
  76198. //---
  76199. ifShowMarker : Potree.settings.ifShowMarker,
  76200. };
  76201. let pointcloud = this.getPointcloud();
  76202. let bound = pointcloud.bound; //只选取其中一个数据集的bound,而非整体,是因为担心两个数据集中间有空隙,于是刚好落在没有点云的地方。
  76203. let boundSize = bound.getSize(new Vector3());
  76204. let target = this.getTarget(bound.getCenter(new Vector3())); //navvis的位置xy是用相机位置 this.ViewService.mainView.getCamera().position 我觉得也可以用第一个漫游点的,或者最接近bound中心的漫游点
  76205. let scale = new Vector3(defaultBoxWidth,defaultBoxWidth, boundSize.z);//z和navvis一样
  76206. let eyeDir = viewer.scene.view.direction.clone().setZ(0/* -boundSize.z/3 */).multiplyScalar(-defaultBoxWidth); //为了使所在楼层不变,不修改z
  76207. //let eyeDir = scale.clone().setZ(boundSize.z/3).multiplyScalar(1.3)
  76208. let position = new Vector3().addVectors(target, eyeDir);
  76209. Potree.settings.displayMode = 'showPointCloud';
  76210. viewer.setView({
  76211. position ,
  76212. target,
  76213. duration:300,
  76214. callback:function(){
  76215. }
  76216. });
  76217. viewer.setControls(viewer.orbitControls);
  76218. viewer.setLimitFar(false);
  76219. {
  76220. this.box = new BoxVolume({
  76221. clip:true
  76222. });
  76223. this.box.name = "ClipBox";
  76224. this.box.position.copy(target);
  76225. this.box.scale.copy(scale);
  76226. //带动mapBox
  76227. this.box.addEventListener('position_changed',e=>{
  76228. this.mapBox.center.setX(this.box.position.x);
  76229. this.mapBox.center.setY(this.box.position.y);
  76230. this.mapBox.updatePoints();
  76231. this.changeCallback();
  76232. });
  76233. this.box.addEventListener('scale_changed',e=>{
  76234. var scale = this.box.scale;
  76235. this.mapBox.updatePoints(scale);
  76236. this.changeCallback();
  76237. });
  76238. this.box.addEventListener('orientation_changed',e=>{
  76239. this.mapBox.angle = this.box.rotation.z;
  76240. this.mapBox.rotateBar.rotation.z = this.mapBox.angle;
  76241. this.mapBox.updatePoints();
  76242. this.changeCallback();
  76243. });
  76244. viewer.scene.addVolume(this.box);
  76245. }
  76246. {//map
  76247. let boxRotateBack = ()=>{//不知道是不是这么写。 因为可能z的旋转不一定都在z
  76248. this.box.rotation.x = 0;
  76249. this.box.rotation.y = 0;
  76250. };
  76251. this.mapBox = new mapClipBox(target, scale);
  76252. viewer.mapViewer.scene.add(this.mapBox);
  76253. //带动box
  76254. this.mapBox.addEventListener('repos',e=>{
  76255. this.box.position.setX(this.mapBox.center.x);
  76256. this.box.position.setY(this.mapBox.center.y);
  76257. boxRotateBack();
  76258. this.changeCallback();
  76259. });
  76260. this.mapBox.addEventListener('dragChange',e=>{
  76261. var scale = this.mapBox.getScale();
  76262. this.box.scale.setX(scale.x);
  76263. this.box.scale.setY(scale.y);
  76264. this.box.position.setX(this.mapBox.center.x);
  76265. this.box.position.setY(this.mapBox.center.y);
  76266. boxRotateBack();
  76267. this.changeCallback();
  76268. });
  76269. this.mapBox.addEventListener('rotate',e=>{
  76270. this.box.rotation.z = this.mapBox.angle;
  76271. boxRotateBack();
  76272. this.changeCallback();
  76273. });
  76274. }
  76275. {
  76276. viewer.setClipTask(ClipTask["SHOW_INSIDE"]);
  76277. //viewer.setClipMethod(ClipMethod["INSIDE_ANY"])
  76278. }
  76279. Potree.settings.unableNavigate = true;
  76280. Potree.settings.ifShowMarker = false;
  76281. viewer.updateVisible(viewer.measuringTool.scene, 'clipModel', false);
  76282. //viewer.updateVisible(viewer.mapViewer.cursor, 'clipModel', false)//隐藏地图游标
  76283. viewer.inputHandler.toggleSelection(this.box);
  76284. viewer.inputHandler.fixSelection = true;
  76285. viewer.transformationTool.frame.material.color.set(Potree.config.clip.color);//navvis 15899953
  76286. viewer.setPointStandardMat(true);
  76287. {
  76288. this.events = {
  76289. flyToPos : (e)=>{
  76290. let dis = 2;
  76291. let target = e.position;
  76292. //position = new THREE.Vector3().subVectors(target, this.scene.view.direction)
  76293. //永远朝向框的中心
  76294. /* let dir = new THREE.Vector3().subVectors(this.box.position, e.position).normalize()
  76295. position = new THREE.Vector3().subVectors(target, dir) */
  76296. target = this.box.position;
  76297. position = e.position;
  76298. //为了方便缩放操作,直接使用box中心作为target
  76299. let duration = 1000;
  76300. viewer.scene.view.setView({position, duration, target});
  76301. }
  76302. };
  76303. this.bus.addEventListener('flyToPos',this.events.flyToPos);
  76304. }
  76305. this.editing = true;
  76306. setTimeout(()=>{this.changeCallback(true);},1);
  76307. },
  76308. leave:function(){
  76309. viewer.inputHandler.fixSelection = false;
  76310. viewer.scene.removeVolume(this.box);
  76311. this.mapBox.dispose();
  76312. viewer.setControls(viewer.fpControls);
  76313. Potree.settings.unableNavigate = false;
  76314. Potree.settings.ifShowMarker = this.previousView.ifShowMarker;
  76315. viewer.updateVisible(viewer.measuringTool.scene, 'clipModel', true);
  76316. //viewer.updateVisible(viewer.mapViewer.cursor, 'clipModel', true)
  76317. viewer.setView(this.previousView);
  76318. viewer.setLimitFar(true);
  76319. viewer.setPointStandardMat(false);
  76320. {
  76321. this.bus.removeEventListener('flyToPos',this.events.flyToPos);
  76322. this.events = null;
  76323. }
  76324. this.editing = false;
  76325. },
  76326. getPointcloud:function(){ //找一个离当前最近的点云,且最好有漫游点
  76327. let pointclouds = viewer.scene.pointclouds.filter(e=>e.panos.length>0);
  76328. if(pointclouds.length == 0)pointclouds = viewer.scene.pointclouds;
  76329. let result = Common.sortByScore(pointclouds,[],[e=>{
  76330. let center = e.bound.getCenter(new Vector3);
  76331. let size = e.bound.getSize(new Vector3).length() / 2;
  76332. let posToCenter = viewer.images360.position.distanceTo(center);
  76333. return size / posToCenter
  76334. }]);
  76335. return result[0].item
  76336. },
  76337. getTarget:function(boundCenter){//box位置。要找一个有点云的地方。方案1相机位置, 方案2接近相机的漫游点, 方案3接近中心的漫游点。选择方案2,因最大概率有点云
  76338. var target = new Vector3();
  76339. var cameraPos = viewer.images360.position;
  76340. var pano = Common.find(viewer.images360.panos , [], [Images360.sortFunctions.floorDisSquaredToPoint(cameraPos)]);
  76341. if(pano){
  76342. target.copy(pano.position);
  76343. target.setZ(boundCenter.z);
  76344. }else {
  76345. target.copy(boundCenter);
  76346. }
  76347. return target
  76348. },
  76349. /* switchMap:function(state){
  76350. }, */
  76351. download:function( ){
  76352. if(this.getIntersectPointcloud().length == 0){
  76353. return null
  76354. }
  76355. var visiPointclouds = viewer.scene.pointclouds.filter(e=> viewer.getObjVisiByReason(e, 'datasetSelection'));
  76356. let data = {
  76357. transformation_matrix: visiPointclouds.map((cloud)=>{
  76358. let data = {
  76359. id: cloud.dataset_id,
  76360. matrix : this.getTransformationMatrix(cloud).elements,
  76361. modelMatrix:(new Matrix4).copy(cloud.transformMatrix).transpose().elements
  76362. };
  76363. return data
  76364. }) ,
  76365. aabb: "b-0.5 -0.5 -0.5 0.5 0.5 0.5" //剪裁空间( 所有点在乘上这个矩阵后, 还能落在 1 * 1 * 1的box内的点就是所裁剪的
  76366. };
  76367. return data
  76368. //https://testlaser.4dkankan.com/indoor/t-ia44BhY/api/pointcloud/crop
  76369. },
  76370. downloadNoCrop(){//不剪裁 下载整个点云
  76371. var visiPointclouds = viewer.scene.pointclouds.filter(e=> viewer.getObjVisiByReason(e, 'datasetSelection'));
  76372. let data = {
  76373. transformation_matrix: visiPointclouds.map((cloud)=>{
  76374. let data = {
  76375. id: cloud.dataset_id,
  76376. matrix : new Matrix4().elements, //固定值
  76377. modelMatrix:(new Matrix4).copy(cloud.transformMatrix).transpose().elements
  76378. };
  76379. return data
  76380. }) ,
  76381. aabb: "b-12742000 -12742000 -12742000 12742000 12742000 12742000" //固定剪裁空间
  76382. };
  76383. console.log(data);
  76384. return data
  76385. },
  76386. getTransformationMatrix:function(pointcloud) {//剪裁矩阵
  76387. var invMatrix = new Matrix4().getInverse(this.box.matrixWorld);
  76388. return (new Matrix4).multiplyMatrices(invMatrix, pointcloud.transformMatrix).transpose()
  76389. },
  76390. getIntersectPointcloud(){
  76391. var boxBound = new Box3(
  76392. new Vector3(-0.5,-0.5,-0.5), new Vector3(0.5,0.5,0.5),
  76393. ).applyMatrix4(this.box.matrixWorld); //large boundingbox
  76394. /* var boxTightPoints = this.box.children[0].geometry.vertices.map(e=>e.clone().applyMatrix4(this.matrixWorld))
  76395. console.log(boxTightPoints)
  76396. */
  76397. let boxMatrixInverse = new Matrix4().copy(this.box.matrixWorld).invert();
  76398. let boxPoints = [
  76399. new Vector3(boxBound.min.x, boxBound.min.y,0),
  76400. new Vector3(boxBound.max.x, boxBound.min.y,0),
  76401. new Vector3(boxBound.max.x, boxBound.max.y,0),
  76402. new Vector3(boxBound.min.x, boxBound.max.y,0)
  76403. ];
  76404. var intersect = (pointcloud)=>{
  76405. if(!pointcloud.bound.intersectsBox(boxBound))return false
  76406. //判断box和点云的tight bound是否相交(因为box可以任意旋转,且实在找不到三维中的立方体相交的函数,所以直接用boxBound)
  76407. var points = pointcloud.getUnrotBoundPoint('all');
  76408. let rings = math.getPolygonsMixedRings([points.slice(0,4), boxPoints] , true);
  76409. //console.log(pointcloud.dataset_id, pointcloud.name, rings.length)
  76410. if(rings.length > 1 )return false
  76411. {//再用frustum和数据集的sphere相交试试,能排除一些错误
  76412. let a = Potree.Utils.isInsideBox(points, boxMatrixInverse);
  76413. if(!a){
  76414. console.log('没能经过isInsideBox测试');
  76415. }
  76416. return a
  76417. }
  76418. return true
  76419. };
  76420. return viewer.scene.pointclouds.filter(e=>intersect(e))
  76421. }
  76422. /*
  76423. 裁剪点云时,2D界面显示全部平面图,按楼层切换显示。
  76424. */
  76425. };
  76426. class SplitScreen extends EventDispatcher{
  76427. constructor (args = {}) {
  76428. super();
  76429. }
  76430. splitStart(cameraProps){
  76431. let viewports = [];
  76432. let subViewports = [viewer.mainViewport];
  76433. if(viewer.mapViewer){
  76434. subViewports.push(viewer.mapViewer.viewports[0]);
  76435. }
  76436. let length = cameraProps.length;
  76437. for(let i=0;i<length;i++){
  76438. let prop = cameraProps[i];
  76439. let viewport;
  76440. let v = subViewports.find(e=>e.name == (prop.name2||prop.name));
  76441. if(v){
  76442. viewport = v;
  76443. viewport.left = prop.left; viewport.bottom = prop.bottom; viewport.width = prop.width; viewport.height = prop.height;
  76444. }
  76445. if(!viewport){
  76446. let view = new View();
  76447. if(prop.limitBound)view.limitBound = prop.limitBound;
  76448. viewport = new Viewport(view , this.getOrthoCamera(), prop );
  76449. //viewport.unableDepth = true //depthBasicMaterial等在此viewport中不开启depth
  76450. prop.direction && (view.direction = prop.direction);
  76451. }
  76452. if(viewport.camera.type == 'OrthographicCamera' ){
  76453. viewport.targetPlane = new Plane();
  76454. viewport.shiftTarget = new Vector3; //project在targetPlane上的位置
  76455. }
  76456. viewports.push(viewport);
  76457. }
  76458. viewer.viewports = viewports;
  76459. viewer.updateScreenSize({forceUpdateSize:true});
  76460. viewports.forEach(viewport=>{
  76461. if(viewport.name == 'MainView')return
  76462. this.viewportFitBound(viewport, viewer.bound.boundingBox , viewer.bound.center);
  76463. });
  76464. return viewports
  76465. }
  76466. unSplit(){
  76467. this.unfocusViewport();
  76468. viewer.viewports = [viewer.mainViewport];
  76469. viewer.mainViewport.width = 1;
  76470. viewer.mainViewport.height = 1;
  76471. viewer.mainViewport.left = 0;
  76472. viewer.mainViewport.bottom = 0;
  76473. viewer.updateScreenSize({forceUpdateSize:true});
  76474. }
  76475. viewportFitBound(viewport, bound, center, duration=0, margin){
  76476. let view = viewport.view;
  76477. let info = {bound};
  76478. viewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), viewer.bound.center );
  76479. viewport.targetPlane.projectPoint(center, viewport.shiftTarget); //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  76480. info.endPosition = this.getPosOutOfModel(viewport);
  76481. //if(viewport.name == 'mapViewport')info.endPosition.z = Math.max(Potree.config.map.cameraHeight, info.endPosition.z)
  76482. info.margin = margin || {x:30, y:30};
  76483. view.moveOrthoCamera(viewport, info , duration );
  76484. }
  76485. getPosOutOfModel(viewport){
  76486. let {boundSize, center} = viewer.bound;
  76487. let expand = 10;
  76488. let radius = boundSize.length() / 2;
  76489. let position = viewport.shiftTarget.clone().sub(viewport.view.direction.clone().multiplyScalar(radius + expand));
  76490. return position
  76491. }
  76492. updateCameraOutOfModel(){//因为移动模型导致模型超出相机外,所以更新位置
  76493. viewer.viewports.forEach((viewport, i )=>{
  76494. if(viewport != viewer.mainViewport){
  76495. viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), viewer.bound.center );
  76496. viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget); //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  76497. let endPosition = this.getPosOutOfModel(viewport.shiftTarget, viewport.view );
  76498. //if(viewport.name == 'mapViewport')endPosition.z = Math.max(Potree.config.map.cameraHeight, endPosition.z)
  76499. viewport.view.position.copy(endPosition);
  76500. }
  76501. });
  76502. }
  76503. rotateSideCamera(viewport, angle){//侧视图绕模型中心水平旋转
  76504. let {boundSize, center} = viewer.bound;
  76505. //找到平移向量
  76506. viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction , center );
  76507. viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget ); //target转换到过模型中心的平面,以保证镜头一定在模型外
  76508. let vec = new Vector3().subVectors(center, viewport.shiftTarget);//相对于中心的偏移值,旋转后偏移值也旋转
  76509. //旋转
  76510. var rotMatrix = new Matrix4().makeRotationAxis(new Vector3(0,0,1), angle);
  76511. viewport.view.direction = viewport.view.direction.applyMatrix4(rotMatrix);
  76512. vec.applyMatrix4(rotMatrix);
  76513. viewport.shiftTarget.subVectors(center,vec); //新的
  76514. viewport.view.position = this.getPosOutOfModel(viewport);
  76515. }
  76516. getOrthoCamera(){
  76517. return new OrthographicCamera(-100, 100, 100, 100, 0.01, 10000)
  76518. }
  76519. focusOnViewport(name){//全屏
  76520. viewer.viewports.forEach((viewport, i )=>{
  76521. if(viewport.name == name){
  76522. this.focusInfo = {
  76523. name,
  76524. left : viewport.left, bottom : viewport.bottom, height : viewport.height, width : viewport.width
  76525. };
  76526. viewport.left = 0; viewport.bottom = 0; viewport.height = 1; viewport.width = 1;
  76527. }else {
  76528. viewport.active = false;
  76529. }
  76530. });
  76531. viewer.updateScreenSize({forceUpdateSize:true});
  76532. }
  76533. unfocusViewport(){
  76534. if(!this.focusInfo)return
  76535. viewer.viewports.forEach((viewport, i )=>{
  76536. if(this.focusInfo.name == viewport.name){//全屏的恢复
  76537. viewport.left = this.focusInfo.left;
  76538. viewport.bottom = this.focusInfo.bottom;
  76539. viewport.height = this.focusInfo.height;
  76540. viewport.width = this.focusInfo.width;
  76541. }
  76542. viewport.active = true;
  76543. });
  76544. viewer.updateScreenSize({forceUpdateSize:true});
  76545. this.focusInfo = null;
  76546. }
  76547. }
  76548. const viewportProps = [
  76549. {
  76550. left:0.5,
  76551. bottom:0.5,
  76552. width: 0.5,height:0.5,
  76553. name : 'MainView',
  76554. //view: viewer.scene.view,
  76555. active: true,
  76556. },
  76557. {
  76558. left:0,
  76559. bottom:0.5,
  76560. width: 0.5,height:0.5,
  76561. name : 'top',
  76562. name2 : 'mapViewport',
  76563. axis:["x","y"],
  76564. direction : new Vector3(0,0,-1), //镜头朝向
  76565. //axisSign:[1,1],
  76566. active: true,
  76567. //相机位置在z轴正向
  76568. },
  76569. {
  76570. left:0.5,
  76571. bottom:0,
  76572. width: 0.5,height:0.5,
  76573. name : 'right',
  76574. axis:["y","z"],
  76575. direction : new Vector3(1,0,0),
  76576. //axisSign:[1,1],
  76577. active: true,
  76578. //相机位置在x轴负向 右下角屏
  76579. },
  76580. {
  76581. left:0,
  76582. bottom:0,
  76583. width: 0.5,height:0.5,
  76584. name : 'back',
  76585. axis:["x","z"],
  76586. direction : new Vector3(0,-1,0),
  76587. //axisSign:[-1,1], // 从镜头方向看 x向左 所以取负
  76588. active: true,
  76589. //相机位置在y轴正向 左下角屏
  76590. },
  76591. ];
  76592. var SplitScreen4Views = new SplitScreen();
  76593. SplitScreen4Views.split = function(o={}){
  76594. var defaultCamera = viewer.scene.getActiveCamera();
  76595. let {boundSize, center} = viewer.bound;
  76596. viewer.setLimitFar(false);
  76597. viewer.mapViewer.attachToMainViewer(true,'split4Screens','dontSet');
  76598. let viewports = this.splitStart(viewportProps);
  76599. //覆盖在map上、点云等其他物体之下的一层背景
  76600. let mapViewport = viewer.mapViewer.viewports[0];
  76601. mapViewport.noPointcloud = false;
  76602. //隐藏地图游标
  76603. //viewer.updateVisible(viewer.mapViewer.cursor, 'split4Screens', false)
  76604. /* viewer.images360.panos.forEach(pano=>{
  76605. viewer.updateVisible(pano.mapMarker, 'split4Screens', false) //希望这时候mapMarker已经建好了吧
  76606. }) */
  76607. //材质
  76608. this.statesBefore = {
  76609. pointDensity : Potree.settings.pointDensity,
  76610. displayMode : Potree.settings.displayMode,
  76611. position: viewer.images360.position,
  76612. target: viewer.scene.view.getPivot(),
  76613. //---
  76614. //ifShowMarker : Potree.settings.ifShowMarker,
  76615. };
  76616. viewer.setPointStandardMat(true,null,true); //切换到标准模式(主要为了mainViewport) 点云使用标准大小
  76617. var matBefore = {
  76618. opacity : new Map()
  76619. };
  76620. var newOpacityMap = new Map();
  76621. viewer.scene.pointclouds.forEach(e=>{
  76622. matBefore.opacity.set(e, e.temp.pointOpacity);
  76623. matBefore.colorType = e.material.activeAttributeName;
  76624. /* {
  76625. var map = new Map()
  76626. newOpacityMap.set(e, map )
  76627. var size = e.bound.getSize()
  76628. viewports.forEach(viewport=>{//根据bound设置opacity,越小的要靠越近,需要大的opacity。但似乎影响太大了
  76629. if(viewport.name == 'MainView')return;
  76630. var prop = viewportProps.find(v => viewport.name == v.name2||viewport.name == v.name)
  76631. let axis = prop.axis
  76632. var width = size[axis[0]]
  76633. var height = size[axis[1]]
  76634. var area = width * height
  76635. map.set(viewport, 5000/area);
  76636. })
  76637. } */
  76638. });
  76639. let beforeRender = function(){
  76640. viewer.scene.pointclouds.forEach(e=>{
  76641. if(this.name == "MainView"){
  76642. e.material.activeAttributeName = matBefore.colorType; // 'rgba'
  76643. e.material.useFilterByNormal = false;
  76644. e.changePointOpacity(matBefore.opacity.get(e)); //1 //恢复下 e.temp.pointOpacity 其实就是1
  76645. Potree.settings.pointDensity = 'fourViewportsMain';/* 'fourViewports' */ //本来想比另外三屏高一点质量,结果发现会闪烁,因为点云加载需要时间 (navvis仿版也是一样,以后看看能否优化)
  76646. }else {
  76647. e.material.activeAttributeName = "color";
  76648. e.material.useFilterByNormal = true;
  76649. Potree.settings.pointDensity = 'fourViewports'; //强制降低点云质量
  76650. e.changePointOpacity(0.6/* newOpacityMap.get(e).get(viewport), true */); //多数据集有的数据集很小,放大后显示特别淡
  76651. //console.log(e.name, viewport.name, e.temp.pointOpacity, e.material.opacity)
  76652. }
  76653. });
  76654. };
  76655. viewports.forEach(viewport=>{viewport.beforeRender = beforeRender;});
  76656. this.enableMap(false);
  76657. this.enableFloorplan(false);
  76658. viewer.mapViewer.setViewLimit('expand'); //多数据集距离远时可以任意远,所以不限制了。但是这样就会看到地图边界了怎么办?
  76659. //viewer.dispatchEvent({'type': 'beginSplitView' })
  76660. //viewer.updateScreenSize({forceUpdateSize:true})
  76661. //this.viewportFitBound(mapViewport, boundSize, center)
  76662. //Potree.settings.ifShowMarker = false
  76663. Potree.settings.displayMode = 'showPointCloud';
  76664. };
  76665. SplitScreen4Views.recover = function(){
  76666. this.unSplit();
  76667. /* const {width, height} = viewer.renderer.getSize(new THREE.Vector2());
  76668. viewer.renderer.setViewport(0,0,width,height)
  76669. viewer.renderer.setScissorTest( false ); */
  76670. viewer.setView({
  76671. position: this.statesBefore.position,
  76672. target: this.statesBefore.target,
  76673. duration:300,
  76674. callback:function(){
  76675. }
  76676. });
  76677. viewer.mainViewport.beforeRender = null;
  76678. viewer.setLimitFar(true);
  76679. let mapViewport = viewer.mapViewer.viewports[0];
  76680. viewer.mapViewer.attachToMainViewer(false);
  76681. //viewer.updateVisible(viewer.mapViewer.cursor, 'split4Screens', true)
  76682. /* viewer.images360.panos.forEach(pano=>{
  76683. viewer.updateVisible(pano.mapMarker, 'split4Screens', true)
  76684. }) */
  76685. mapViewport.noPointcloud = true;
  76686. {
  76687. this.enableMap(Potree.settings.mapEnable);
  76688. this.enableFloorplan(Potree.settings.floorplanEnable);
  76689. if(this.floorplanListener){
  76690. viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.floorplanListener );
  76691. this.floorplanListener = null;
  76692. }
  76693. }
  76694. Potree.settings.pointDensity = this.statesBefore.pointDensity;
  76695. if(!Potree.settings.isOfficial){
  76696. Potree.settings.displayMode = this.statesBefore.displayMode;
  76697. }
  76698. viewer.scene.pointclouds.forEach(e=>{
  76699. //e.material.color.set(this.statesBefore.mat.color)
  76700. //e.material.activeAttributeName = this.statesBefore.mat.colorType
  76701. e.material.useFilterByNormal = false;
  76702. //e.material.opacity = this.statesBefore.mat.opacity
  76703. });
  76704. viewer.setPointStandardMat(false);
  76705. viewer.mapViewer.setViewLimit('standard');
  76706. //Potree.settings.ifShowMarker = this.statesBefore.ifShowMarker
  76707. //viewer.dispatchEvent({'type': 'finishSplitView' })
  76708. //viewer.updateScreenSize({forceUpdateSize:true})
  76709. };
  76710. SplitScreen4Views.updateMapViewerBG = function(){
  76711. let mapViewport = viewer.mapViewer.viewports[0];
  76712. if(this.floorplanEnabled || this.mapEnabled){
  76713. mapViewport.background = 'overlayColor';
  76714. mapViewport.backgroundColor = new Color(0,0,0);
  76715. mapViewport.backgroundOpacity = 0.5;
  76716. }else {
  76717. mapViewport.background = null;
  76718. mapViewport.backgroundColor = null;
  76719. mapViewport.backgroundOpacity = null;
  76720. }
  76721. };
  76722. SplitScreen4Views.setFloorplanDisplay = function(e, show=false){
  76723. //viewer.updateVisible(e.floorplan.objectGroup, 'splitScreen', !!show)
  76724. //e.floorplan.objectGroup.visible = !!show
  76725. //viewer.mapViewer.mapLayer.needUpdate = true
  76726. e.floorplan.setEnable(show);
  76727. };
  76728. SplitScreen4Views.enableMap = function(enable){
  76729. let map = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'map');
  76730. //viewer.updateVisible(map.objectGroup, 'splitScreen', !!enable)
  76731. //map.objectGroup.visible = !!enable
  76732. //if(enable)viewer.mapViewer.mapLayer.needUpdate = true //加载地图
  76733. map.setEnable(!!enable);
  76734. //viewer.mapViewer.mapGradientBG = viewer.background == 'gradient' && !enable
  76735. this.mapEnabled = enable;
  76736. this.updateMapViewerBG();
  76737. },
  76738. //直接覆盖原设置
  76739. SplitScreen4Views.enableFloorplan = function(enable){ //是否让自定义的平面图显示
  76740. let floorplans = viewer.mapViewer.mapLayer.maps.filter(e=>e.name.includes('floorplan'));
  76741. if(this.floorplanListener){
  76742. viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.floorplanListener );
  76743. }
  76744. this.floorplanListener = (e)=>{
  76745. this.setFloorplanDisplay(e, enable);
  76746. };
  76747. viewer.mapViewer.mapLayer.addEventListener( 'floorplanLoaded', this.floorplanListener ); //万一之后才加载
  76748. if(!enable){
  76749. //隐藏平面图
  76750. floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},false));
  76751. }else {
  76752. floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},true));
  76753. }
  76754. if (enable && floorplans.length == 0) Potree.loadMapEntity('all',true);
  76755. this.floorplanEnabled = enable;
  76756. this.updateMapViewerBG();
  76757. },
  76758. /* viewportFitBound:function(viewport, boundSize, center){ //使一个viewport聚焦在某个范围
  76759. var prop = viewportProps.find(v => viewport.name == v.name2||viewport.name == v.name)
  76760. let axis = prop.axis
  76761. let expand = 10;
  76762. let position = center.clone()
  76763. var moveAtAxis = ['x','y','z'].find(e=>!(axis.includes(e)))
  76764. if(viewport.name == 'mapViewport'){
  76765. let ori = viewport.view.position[moveAtAxis]
  76766. position[moveAtAxis] = ori //不改变这个值,尤其是mapViewer中的z
  76767. }else{
  76768. position[moveAtAxis] += boundSize[moveAtAxis]/2+expand//移动到bounding边缘外
  76769. }
  76770. viewport.view.position.copy(position)
  76771. var width = Math.max(boundSize[axis[0]], boundSize[axis[1]] * viewport.camera.aspect)//视口宽度(米)
  76772. var margin = 50 //px
  76773. viewport.camera.zoom = (viewport.resolution.x - margin) / width
  76774. viewport.camera.updateProjectionMatrix()
  76775. },
  76776. */
  76777. SplitScreen4Views.focusOnPointCloud = function(pointcloud){//三个屏都聚焦在这个点云
  76778. var boundSize = pointcloud.bound.getSize(new Vector3);
  76779. var center = pointcloud.bound.getCenter(new Vector3);
  76780. let target = pointcloud.panosBound && pointcloud.panosBound.center; //看向pano集中的地方,也就是真正有点云的地方。(因为需要展示所有点云,所以没办法用这个做为center)
  76781. this.focusOnObject(pointcloud.bound, center,target);
  76782. viewer.flyToDataset({pointcloud, dontMoveMap:true, duration:0});
  76783. };
  76784. SplitScreen4Views.focusOnObject = function(bound, center, target, duration=0){
  76785. viewer.viewports.forEach(e=>{
  76786. if(e.name == 'MainView'){
  76787. /* let len = boundSize.length()
  76788. let distance = THREE.Math.clamp(e.view.position.distanceTo(center), len * 0.01, len*0.3 ) //距离限制
  76789. //viewer.focusOnObject({position:center}, 'point', duration, {distance, direction: e.view.direction,dontMoveMap:true} )//平移镜头
  76790. //为了方便定位,直接飞到中心位置:
  76791. e.view.setView({
  76792. position:center, duration, target
  76793. }) */
  76794. }else {
  76795. this.viewportFitBound(e, bound, center);
  76796. }
  76797. });
  76798. };
  76799. var Alignment = {
  76800. SplitScreen: SplitScreen4Views,
  76801. handleState:null, //操作状态 'translate'|'rotate'
  76802. bus: new EventDispatcher(),
  76803. history:[],
  76804. prepareRecord : true,
  76805. writeToHistory(content){
  76806. if(!this.prepareRecord)return;
  76807. this.prepareRecord = false;
  76808. this.history.push(content);
  76809. },
  76810. undo(){//撤销一步
  76811. let last = this.history.pop();
  76812. last && last.forEach(item=>{
  76813. this.applyTemp(item);
  76814. });
  76815. },
  76816. applyTemp(item){
  76817. var pointcloud = viewer.scene.pointclouds.find(p=>p.dataset_id+p.name == item.sid);
  76818. pointcloud.orientationUser = item.orientationUser;
  76819. pointcloud.translateUser = item.translateUser;
  76820. this.setMatrix( pointcloud );
  76821. },
  76822. getTemp(pointclouds){//记录最近一次保存后的状态,便于恢复
  76823. pointclouds = pointclouds || viewer.scene.pointclouds;
  76824. return pointclouds.map(e=>{
  76825. return {
  76826. sid : e.dataset_id+e.name,
  76827. orientationUser : e.orientationUser,
  76828. translateUser : e.translateUser.clone(),
  76829. }
  76830. } )
  76831. },
  76832. init:function(){
  76833. let rotateInfo;
  76834. viewer.fpControls.addEventListener("transformPointcloud",(e)=>{
  76835. if(e.pointclouds[0].dataset_id == Potree.settings.originDatasetId){//禁止手动移动初始数据集
  76836. return this.bus.dispatchEvent('forbitMoveOriginDataset')
  76837. }
  76838. this.writeToHistory(this.getTemp(e.pointclouds) );
  76839. if(this.handleState == 'translate'){
  76840. e.pointclouds.forEach(cloud=>Alignment.translate(cloud, e.moveVec));
  76841. }else if(this.handleState == 'rotate'){
  76842. if(Potree.settings.editType == 'pano'){
  76843. let center = e.intersectStart; //旋转中心是mousedown的位置
  76844. if(e.intersectPoint.equals(center))return
  76845. if(!rotateInfo){
  76846. rotateInfo = {
  76847. orientationUser : e.pointclouds[0].orientationUser,
  76848. //vecStart : e.moveVec, // 首次移动向量 只有八个方向,精度太小,所以延迟
  76849. pointclouds: e.pointclouds
  76850. };
  76851. this.bus.dispatchEvent({type:'rotateStart', startPoint:center});
  76852. return
  76853. }else if(!rotateInfo.vecStart){
  76854. let vec = new Vector3().subVectors(e.intersectPoint, center).setZ(0);
  76855. if(vec.length() * e.camera.zoom > 30){ //在屏幕上距离初始点有一定距离后开始算
  76856. //console.log('moveVec',vec)
  76857. rotateInfo.vecStart = vec;
  76858. }
  76859. }else {
  76860. let vec = new Vector3().subVectors(e.intersectPoint, center).setZ(0);
  76861. let angle = math.getAngle(rotateInfo.vecStart,vec,'z');
  76862. let diffAngle = rotateInfo.orientationUser + angle - rotateInfo.pointclouds[0].orientationUser;
  76863. rotateInfo.pointclouds.forEach(cloud=>{
  76864. /* let centerNoTranfrom = Potree.Utils.datasetPosTransform({ toDataset: true, pointcloud:cloud, position: center }) //中心点在数据集中的位置
  76865. Alignment.rotate(cloud, null, diffAngle)
  76866. let centerNow = Potree.Utils.datasetPosTransform({ fromDataset: true, pointcloud:cloud, position: centerNoTranfrom }) //中心点的现在位置
  76867. let shift = new THREE.Vector3().subVectors( center, centerNow); //偏移量
  76868. Alignment.translate(cloud,shift) //使center还保留在原位
  76869. //let centerNow1 = Potree.Utils.datasetPosTransform({ fromDataset: true, pointcloud:rotateInfo.pointcloud, position: centerNoTranfrom }) //中心点的现在位置
  76870. */
  76871. Alignment.rotateAround(center, cloud, null, diffAngle);
  76872. });
  76873. }
  76874. this.bus.dispatchEvent({type:'rotate', endPoint: e.intersectPoint});
  76875. }else {
  76876. let center = e.pointclouds[0].translateUser; //移动到的位置就是中心
  76877. if(e.intersectPoint.equals(center))return
  76878. if(!rotateInfo){
  76879. rotateInfo = {
  76880. orientationUser : e.pointclouds[0].orientationUser,
  76881. vecStart : new Vector3().subVectors(e.intersectStart, center).setZ(0),
  76882. //pointclouds: e.pointclouds
  76883. pointcloud: e.pointclouds[0]
  76884. };
  76885. }else {
  76886. let vec = new Vector3().subVectors(e.intersectPoint, center).setZ(0);
  76887. let angle = math.getAngle(rotateInfo.vecStart,vec,'z');
  76888. let diffAngle = rotateInfo.orientationUser + angle - rotateInfo.pointcloud.orientationUser;
  76889. Alignment.rotate(rotateInfo.pointcloud, null, diffAngle);
  76890. }
  76891. }
  76892. }
  76893. });
  76894. viewer.fpControls.addEventListener("end",(e)=>{
  76895. rotateInfo = null;
  76896. this.prepareRecord = true;
  76897. });
  76898. viewer.inputHandler.addEventListener('keydown',e=>{
  76899. if(e.keyCode == 90 && e.event.ctrlKey){//Z
  76900. this.undo();
  76901. }
  76902. });
  76903. // cursor:
  76904. let updateCursor = (e)=>{
  76905. if(e.drag)return //仅在鼠标不按下时更新:
  76906. let handleState = Alignment.handleState;
  76907. if(e.hoverViewport.alignment && handleState && e.hoverViewport.alignment[handleState]){
  76908. if(handleState == 'translate'){
  76909. if( e.intersectPoint && e.intersectPoint.location ){
  76910. viewer.dispatchEvent({
  76911. type : "CursorChange", action : "add", name:"movePointcloud"
  76912. });
  76913. }else {
  76914. viewer.dispatchEvent({
  76915. type : "CursorChange", action : "remove", name:"movePointcloud"
  76916. });
  76917. }
  76918. }else if(handleState == 'rotate'){
  76919. if( e.intersectPoint && e.intersectPoint.location ){
  76920. viewer.dispatchEvent({
  76921. type : "CursorChange", action : "add", name:"rotatePointcloud"
  76922. });
  76923. }else {
  76924. viewer.dispatchEvent({
  76925. type : "CursorChange", action : "remove", name:"rotatePointcloud"
  76926. });
  76927. }
  76928. }
  76929. }else {
  76930. //清空:
  76931. viewer.dispatchEvent({
  76932. type : "CursorChange", action : "remove", name:"movePointcloud"
  76933. });
  76934. viewer.dispatchEvent({
  76935. type : "CursorChange", action : "remove", name:"rotatePointcloud"
  76936. });
  76937. }
  76938. };
  76939. if(Potree.settings.editType != 'pano'){
  76940. viewer.addEventListener('global_mousemove',updateCursor);
  76941. viewer.addEventListener('global_drop',updateCursor);//拖拽结束
  76942. }
  76943. viewer.addEventListener('updateModelBound', (e)=>{
  76944. if(this.editing){
  76945. this.SplitScreen.updateCameraOutOfModel();
  76946. }
  76947. });
  76948. },
  76949. setMatrix : function(pointcloud){
  76950. var vec1 = pointcloud.position; //position为数据集内部的偏移,在navvis中对应的是dataset.pointCloudSceneNode的children[0].position
  76951. var vec2 = pointcloud.translateUser;
  76952. var angle = pointcloud.orientationUser;
  76953. var pos1Matrix = new Matrix4().setPosition(vec1);//先移动到点云本身应该在的初始位置(在4dkk里和其他应用中都是在这个位置的,也能和漫游点对应上)
  76954. var rotMatrix = new Matrix4().makeRotationAxis(new Vector3(0,0,1), angle);//再旋转
  76955. var pos2Matrix = new Matrix4().setPosition(vec2);//最后是平移
  76956. var matrix = new Matrix4().multiplyMatrices(pos2Matrix, rotMatrix);
  76957. pointcloud.transformMatrix = matrix.clone();//为该数据集的变化矩阵。 对应navvis的m2w_
  76958. pointcloud.transformInvMatrix.copy(matrix).invert();
  76959. pointcloud.rotateMatrix = rotMatrix;
  76960. pointcloud.rotateInvMatrix.copy(rotMatrix).invert();
  76961. pointcloud.panos.forEach(e=>e.transformByPointcloud());
  76962. matrix = new Matrix4().multiplyMatrices(matrix, pos1Matrix);
  76963. pointcloud.matrix = matrix;
  76964. //pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值)
  76965. pointcloud.updateMatrixWorld(true);
  76966. if(this.editing){
  76967. Alignment.changeCallBack && Alignment.changeCallBack();
  76968. }
  76969. if(pointcloud.spriteNodeRoot){
  76970. pointcloud.spriteNodeRoot.matrixWorld.copy(pointcloud.matrixWorld);//.multiplyMatrices(pointcloud.matrixWorld, pointcloud.matrixWorld);
  76971. }
  76972. viewer.updateModelBound();
  76973. //pointcloud.updateBound()
  76974. pointcloud.getPanosBound();
  76975. },
  76976. rotateAround(center, pointcloud, deg, angle){//绕center点转动
  76977. var angle = angle != void 0 ? angle : MathUtils.degToRad(deg);
  76978. let vec1 = new Vector3().subVectors(pointcloud.translateUser, center);
  76979. let rotMatrix = new Matrix4().makeRotationAxis(new Vector3(0,0,1), angle);
  76980. let vec2 = vec1.clone().applyMatrix4(rotMatrix); //将到旋转中心的偏差也转动
  76981. let vec3 = new Vector3().subVectors(vec2,vec1); //这个就是多出来的一步translateUser
  76982. this.rotate(pointcloud, deg, angle);
  76983. this.translate(pointcloud, vec3);
  76984. //绕点转动就是比普通转动多一步移动到相对center的某个位置。 1 初始点云移动到自己的position; 2 移动一个vec1 3绕原点旋转 4再移动一个原本的translateUser。 绘制出来后发现移动量就是第二步vec旋转后的偏移
  76985. },
  76986. rotate:function(pointcloud, deg, angle){//绕各自中心转动(各自的position) 假设点云位移position后0,0,0就是它的中心了(根据navvis观察这样做是绕同一个点旋转的)
  76987. var angle = angle != void 0 ? angle : MathUtils.degToRad(deg); //正逆负顺
  76988. pointcloud.orientationUser += angle;
  76989. Alignment.setMatrix(pointcloud);
  76990. },
  76991. translate:function(pointcloud, vec){
  76992. pointcloud.translateUser.add(vec);
  76993. Alignment.setMatrix(pointcloud);
  76994. },
  76995. enter:function(){
  76996. //this.saveTemp()
  76997. this.originData = this.getTemp();
  76998. this.SplitScreen.split({alignment:true});
  76999. viewer.images360.panos.forEach(pano=>{
  77000. viewer.updateVisible(pano.mapMarker, 'split4Screens', false);
  77001. });
  77002. viewer.viewports.find(e=>e.name == 'mapViewport').alignment = {rotate:true,translate:true};
  77003. viewer.viewports.find(e=>e.name == 'right').alignment = {translate:true};
  77004. viewer.viewports.find(e=>e.name == 'back').alignment = {translate:true};
  77005. this.editing = true;
  77006. viewer.updateFpVisiDatasets();
  77007. },
  77008. leave:function(){
  77009. this.switchHandle(null);
  77010. /* this.originData.forEach(e=>{//恢复
  77011. var pointcloud = viewer.scene.pointclouds.find(p=>p.dataset_id == e.id)
  77012. this.translate(pointcloud, new THREE.Vector3().subVectors(e.translateUser , pointcloud.translateUser))
  77013. this.rotate(pointcloud, null, e.orientationUser - pointcloud.orientationUser)
  77014. }) */
  77015. this.originData.forEach(e=>{//恢复
  77016. this.applyTemp(e);
  77017. });
  77018. this.SplitScreen.recover();
  77019. viewer.images360.panos.forEach(pano=>{
  77020. viewer.updateVisible(pano.mapMarker, 'split4Screens', true);
  77021. });
  77022. this.editing = false;
  77023. this.history.length = 0;
  77024. viewer.updateFpVisiDatasets();
  77025. }
  77026. ,
  77027. switchHandle:function(state){
  77028. this.handleState = state;
  77029. //清空:
  77030. viewer.dispatchEvent({
  77031. type : "CursorChange", action : "remove", name:"movePointcloud"
  77032. });
  77033. viewer.dispatchEvent({
  77034. type : "CursorChange", action : "remove", name:"rotatePointcloud"
  77035. });
  77036. this.bus.dispatchEvent({type:'switchHandle' , state });
  77037. },
  77038. save: function(){//保存所有数据集的位置和旋转
  77039. let callback = ()=>{//保存成功后
  77040. this.originData = this.getTemp(); //this.saveTemp();
  77041. //需要修改 测量线的position。漫游点已经实时修改了
  77042. viewer.scene.measurements.forEach(e=>e.transformByPointcloud());
  77043. viewer.images360.updateCube(viewer.bound);
  77044. };
  77045. var data = viewer.scene.pointclouds.map(e=>{
  77046. let pos = viewer.transform.lonlatToLocal.inverse(e.translateUser.clone());
  77047. return {
  77048. id: e.dataset_id,
  77049. orientation : e.orientationUser,
  77050. location:[pos.x, pos.y, pos.z],
  77051. //transformMatrix: e.transformMatrix.elements,
  77052. }
  77053. });
  77054. //data = JSON.stringify(data)
  77055. //test: 退出后保留结果
  77056. if(!Potree.settings.isOfficial){
  77057. callback();
  77058. }
  77059. return {data, callback}
  77060. }
  77061. };
  77062. let texLoader$6 = new TextureLoader();
  77063. let markerMats$2;
  77064. let markerSizeInfo$2 = {width2d:35};
  77065. let color$2 = new Color('#FFF');
  77066. let faceMats;
  77067. let getFaceMat = (name)=>{
  77068. if(!faceMats){ //navvis材质可以搜gridTexture
  77069. let gridTex = texLoader$6.load( Potree.resourcePath+'/textures/gridmap.png' );
  77070. gridTex.wrapS = gridTex.wrapT = RepeatWrapping;
  77071. //gridTex.repeat.set(0.5,0.5)//放大一些
  77072. faceMats = {
  77073. dataset: new MeshStandardMaterial({
  77074. color:812922,
  77075. side:DoubleSide,
  77076. opacity:0.2,
  77077. transparent:true,
  77078. depthTest:false,
  77079. wireframe:true
  77080. }),
  77081. building: new MeshStandardMaterial({
  77082. color:812922, metalness: 0.2, roughness:0.8,
  77083. side:DoubleSide,
  77084. opacity:0.1,
  77085. transparent:true,
  77086. depthTest:true
  77087. }),
  77088. buildingSelect: new MeshStandardMaterial({
  77089. color:36582, metalness: 0, roughness:1,
  77090. side:DoubleSide,
  77091. opacity:0.1,
  77092. transparent:true,
  77093. depthTest:true
  77094. }),
  77095. floor: new MeshStandardMaterial({
  77096. color:11708469, metalness: 0.1, roughness:1,
  77097. side:DoubleSide,//BackSide,
  77098. opacity:0.05,
  77099. transparent:true,
  77100. depthTest:true,
  77101. }),
  77102. /* floorSelect: new THREE.MeshStandardMaterial({
  77103. color:16707151, metalness: 0, roughness:1,
  77104. side:THREE.DoubleSide,
  77105. opacity:1,
  77106. transparent:true,
  77107. depthTest:true,
  77108. polygonOffset : true,//是否开启多边形偏移
  77109. polygonOffsetFactor : -0.75,//多边形偏移因子
  77110. polygonOffsetUnits : -4.0,//多边形偏移单位
  77111. map: gridTex,
  77112. }), */
  77113. floorSelect: new DepthBasicMaterial({
  77114. map: gridTex,
  77115. color:16707151,
  77116. side:DoubleSide,//BackSide,
  77117. opacity:1,
  77118. transparent:true,
  77119. useDepth : true,
  77120. /* polygonOffset : true,//是否开启多边形偏移
  77121. polygonOffsetFactor : -0.75,//多边形偏移因子
  77122. polygonOffsetUnits : -4.0,//多边形偏移单位 */
  77123. clipDistance : 1, occlusionDistance:1, /* occlusionDistance:变为backColor距离, clipDistance:opacity到达0或者1-maxClipFactor时的距离 */
  77124. maxClipFactor:0.4, backColor:'#efe' //backColor:"#669988" ,
  77125. }),
  77126. room: new MeshStandardMaterial({
  77127. color:"#ff44ee", metalness: 0, roughness:1,
  77128. side:DoubleSide,//BackSide,
  77129. opacity:0.08,
  77130. transparent:true,
  77131. depthTest:false,
  77132. }),
  77133. /* roomSelect: new THREE.MeshStandardMaterial({
  77134. color:"#ff44ee", metalness: 0.3, roughness:1,
  77135. side:THREE.DoubleSide,//BackSide,
  77136. opacity:1,
  77137. transparent:true,
  77138. depthTest:true,
  77139. polygonOffset : true,//是否开启多边形偏移.(开启是因为和floor重叠了会闪烁)
  77140. polygonOffsetFactor : -0.75,//多边形偏移因子
  77141. polygonOffsetUnits : -4.0,//多边形偏移单位
  77142. map: gridTex,
  77143. }), */
  77144. roomSelect: new DepthBasicMaterial({
  77145. map: gridTex,
  77146. color:"#ff44ee",
  77147. side:DoubleSide,//BackSide,
  77148. opacity:1,
  77149. transparent:true,
  77150. useDepth : true,
  77151. /* polygonOffset : true,//是否开启多边形偏移
  77152. polygonOffsetFactor : -0.75,//多边形偏移因子
  77153. polygonOffsetUnits : -4.0,//多边形偏移单位 */
  77154. clipDistance : 1, occlusionDistance:0.5, /* occlusionDistance:变为backColor距离, clipDistance:opacity到达0或者1-maxClipFactor时的距离 */
  77155. maxClipFactor:0.6, backColor:'#ff88dd'//"#cc99c2" ,
  77156. })
  77157. };
  77158. }
  77159. return faceMats[name]
  77160. };
  77161. class BuildingBox extends ctrlPolygon{//建筑实体,包括building, floor, room
  77162. constructor(prop) {
  77163. prop.dimension = '3d';
  77164. //prop.name = Potree.config.siteModel.names[prop.buildType] +
  77165. super('siteModel_'+prop.buildType, prop);
  77166. this.midMarkers = [];
  77167. this.buildChildren = [];//子实体
  77168. this.holes = []; //在这创建的hole
  77169. this.parentHoles = [];//floor从building那得到的当层holes
  77170. this.mats = {}; //材质
  77171. this.panos = this.panos || [];
  77172. this.center; //中心点
  77173. if(this.buildType=='floor'){
  77174. this.points = prop.points = this.buildParent.points;//完全等于建筑的点
  77175. this.buildParent.holes.forEach(hole=>{//从building获取holes
  77176. let floorHole = new BuildingBox({
  77177. buildType : 'hole',
  77178. buildParent:this,
  77179. originHole : hole, //整栋大楼在当层的hole
  77180. ifDraw: this.ifDraw || Potree.settings.drawEntityData
  77181. });
  77182. this.parentHoles.push(floorHole);
  77183. this.add(floorHole);
  77184. floorHole.points = hole.points;//完全等于建筑的点
  77185. });
  77186. }
  77187. if(this.buildType == 'room' || this.buildType == 'hole'){
  77188. this.restrictArea = this.buildParent; //不能超出的区域
  77189. }
  77190. if(this.ifDraw){ //只存储空间模型信息,不绘制
  77191. if(this.buildType != 'hole'){
  77192. this.box = this.createBox();
  77193. this.add(this.box);
  77194. }
  77195. {
  77196. this.lineMesh = LineDraw.createLine([],{color: color$2});
  77197. this.lineMesh.name = 'buildingLines';
  77198. this.lineMesh.visible = false;
  77199. this.add(this.lineMesh);
  77200. viewer.setObjectLayers(this.lineMesh, 'bothMapAndScene' );
  77201. }
  77202. this.addEventListener('dragChange',(e)=>{ //修改中点
  77203. this.updateTwoMidMarker(e.index);
  77204. });
  77205. }
  77206. this.initData(prop);
  77207. }
  77208. initData(prop){
  77209. if(prop.ifDraw){
  77210. super.initData(prop);
  77211. }else {
  77212. if(prop.points){
  77213. this.points = prop.points;
  77214. }
  77215. }
  77216. }
  77217. intersectPointcloudVolume(pointcloud){//和pointcloud的重叠体积
  77218. var bound = this.getBound();
  77219. let bound2 = pointcloud.bound;
  77220. if(!bound.intersectsBox(bound2)) return 0;
  77221. let {zMin , zMax} = this.getRealZ();
  77222. let min = Math.min(zMin, bound2.min.z);
  77223. let max = Math.max(zMax, bound2.max.z);
  77224. let height1 = zMax - zMin;
  77225. let height2 = bound2.max.z-bound2.min.z;
  77226. let coverHeight = height1 + height2 - (max-min);//重叠高度 <=0是没重叠
  77227. let boxPoints = pointcloud.getUnrotBoundPoint(); //获取tightBound的四个点。 如果是有旋转角度的点云,这个和pointcloud.bound的四个点是不一致的,覆盖面积小于pointcloud.bound
  77228. let areaWhole = 0;
  77229. let area1 = this.getArea();
  77230. let area2 = Math.abs(math.getArea(boxPoints));
  77231. {//计算points与点云总面积 (但是把hole也加入了面积)(并集,重叠部分只算一次)
  77232. let rings = math.getPolygonsMixedRings([this.points, boxPoints] );
  77233. rings.forEach(e=>{
  77234. areaWhole+=e.area;
  77235. });
  77236. }
  77237. let coverHoleArea = 0; //holes与数据集重叠的部分
  77238. let holes = this.holes.concat(this.parentHoles);
  77239. let holesArea = 0; //所有holes面积相加
  77240. let areaHoleWithPointcloud = 0; //hole和点云的面积并集
  77241. if(holes.length>0){//还要再扣除holes与数据集重叠的部分。其中holes为mix轮廓
  77242. let outHoles = [];//没有重合的holes的外轮廓
  77243. /* if(holes.length>=2){//合并holes。如果能在绘制时直接合并holes就好啦,这步就转移到那去,但是要删除hole好麻烦
  77244. let holes_ = holes.map(e=>e.points)
  77245. outHoles = math.getPolygonsMixedRings(holes_, true )
  77246. outHoles.forEach(e=>{
  77247. holesArea+=e.area
  77248. })
  77249. outHoles = outHoles.map(e=>e.points)
  77250. }else{
  77251. outHoles = holes.map(e=>e.points)
  77252. outHoles.forEach(e=> holesArea += Math.abs(math.getArea(e)))
  77253. } */
  77254. holesArea = this.getHolesArea();
  77255. //holes与数据集重叠的部分
  77256. {
  77257. let polygons = outHoles.concat([boxPoints]);
  77258. let rings = math.getPolygonsMixedRings(polygons);
  77259. rings.forEach(e=>{
  77260. areaHoleWithPointcloud+=e.area;
  77261. });
  77262. coverHoleArea = holesArea + area2 - areaHoleWithPointcloud;//hole和点云的交集
  77263. }
  77264. }
  77265. let coverArea = area1 + area2 - areaWhole - coverHoleArea; //重叠面积
  77266. return coverArea * coverHeight
  77267. }
  77268. addHole(points=[]){
  77269. let prop = {
  77270. buildType : 'hole',
  77271. zMin : this.zMin,
  77272. zMax : this.zMax,
  77273. points,
  77274. buildParent:this,
  77275. ifDraw: this.ifDraw || Potree.settings.drawEntityData
  77276. };
  77277. //hole的zMin zMax跟随buildParent
  77278. var hole = new BuildingBox(prop);
  77279. this.holes.push(hole);
  77280. if(this.buildType == 'building'){//为每一层添加对应的hole
  77281. this.buildChildren.forEach(floor=>{
  77282. let floorHole = new BuildingBox({
  77283. buildType : 'hole',
  77284. zMin : this.zMin,
  77285. zMax : this.zMax,
  77286. buildParent:floor,
  77287. originHole : hole, //整栋大楼在当层的hole
  77288. ifDraw: this.ifDraw || Potree.settings.drawEntityData
  77289. });
  77290. floor.parentHoles.push(floorHole);
  77291. floor.add(floorHole);
  77292. floorHole.points = hole.points;//完全等于建筑的点
  77293. });
  77294. }
  77295. this.add(hole);//直接加在这,不加meshGroup了
  77296. this.update(); //update box mesh
  77297. return hole
  77298. //hole不创建box,只有它的buildParent需要更新box。 但有线条和marker. hole不在buildChildren里,但有buildParent
  77299. }
  77300. removeHole(hole){// 这个hole不会是parentHoles里的。
  77301. hole.dispose();
  77302. if(this.buildType == 'building'){ //若是整栋大楼的hole,在每层去除它的对应hole
  77303. this.buildChildren.forEach(floor=>{
  77304. let holeAtFloor = floor.parentHoles.find(e=>e.originHole == this );
  77305. let index = floor.parentHoles.indexOf(holeAtFloor);
  77306. index > -1 && floor.parentHoles.splice(index, 1);
  77307. holeAtFloor.dispose();
  77308. });
  77309. }
  77310. let index = this.holes.indexOf(hole);
  77311. if(index>-1){
  77312. this.holes.splice(index, 1);
  77313. }
  77314. this.remove(hole);
  77315. this.update();
  77316. }
  77317. createBox(){
  77318. var geometry = new Geometry();
  77319. this.mats.boxDefault = getFaceMat(this.buildType);
  77320. this.mats.boxSelected = getFaceMat(this.buildType+'Select');
  77321. var mesh = new Mesh(geometry, this.mats.boxDefault);
  77322. mesh.name = 'buildingBox';
  77323. if(this.buildType == 'floor'){
  77324. viewer.setObjectLayers(mesh, 'siteModelMapUnvisi' ); //楼层默认在地图不显示,为了不会叠加透明度
  77325. }else {
  77326. viewer.setObjectLayers(mesh, 'bothMapAndScene' );
  77327. }
  77328. //mesh.frustumCulled = false;
  77329. return mesh
  77330. }
  77331. addMarker(o={} ){
  77332. if(this.buildType=='floor')return; //楼层不需要marker
  77333. let marker = new Sprite$1({mat:this.getMarkerMaterial('default'), renderOrder : 3, sizeInfo: markerSizeInfo$2, dontFixOrient: true, name:"building_marker"} );
  77334. viewer.setObjectLayers(marker, 'siteModeOnlyMapVisi' );
  77335. o.marker = marker;
  77336. super.addMarker(o);
  77337. if(!this.selected)viewer.updateVisible(marker,'select',false);
  77338. let addClickEvent = (e)=>{
  77339. let click = (e) => {
  77340. this.dispatchEvent({type:'clickMarker', marker } ); //由entity发送给sitemodel统一处理
  77341. };
  77342. marker.addEventListener('click', click);
  77343. marker.addEventListener('clickSelect', (e)=>{
  77344. this.setMarkerSelected(marker, e.state ? 'select' : 'unselect' );
  77345. });
  77346. marker.removeEventListener('addHoverEvent',addClickEvent);
  77347. };
  77348. marker.addEventListener('addHoverEvent',addClickEvent);//当非isNew时才添加事件
  77349. if(!this.isNew){
  77350. marker.dispatchEvent('addHoverEvent');
  77351. }
  77352. return marker
  77353. }
  77354. removeMarker(index){
  77355. super.removeMarker(index);
  77356. if(!this.isNew){
  77357. //重新添加midMarkers
  77358. this.midMarkers.forEach(e=>this.remove(e));
  77359. this.midMarkers = [];
  77360. this.addMidMarkers();
  77361. }
  77362. this.update();
  77363. if(this.points.length == 2 && this.box){//清除原先length>=3时候的
  77364. this.box.geometry = new Geometry();
  77365. }
  77366. }
  77367. addMidMarker(index, point){
  77368. if(this.buildType=='floor')return; //楼层不需要marker
  77369. let marker = new Sprite$1({mat:this.getMarkerMaterial('midPrepare'), sizeInfo: markerSizeInfo$2, dontFixOrient: true, name:"building_midMarker"} );
  77370. this.midMarkers = [...this.midMarkers.slice(0,index), marker, ...this.midMarkers.slice(index,this.midMarkers.length)];
  77371. marker.renderOrder = 3;
  77372. viewer.setObjectLayers(marker, 'siteModeOnlyMapVisi' );
  77373. { // Event Listeners
  77374. let mouseover = (e) => {
  77375. this.setMarkerSelected(e.object, 'hover', 'single');
  77376. viewer.dispatchEvent({
  77377. type : "CursorChange", action : "add", name:"markerMove"
  77378. });
  77379. };
  77380. let mouseleave = (e) => {
  77381. this.setMarkerSelected(e.object, 'unhover', 'single');
  77382. viewer.dispatchEvent({
  77383. type : "CursorChange", action : "remove", name:"markerMove"
  77384. });
  77385. };
  77386. let drag = (e) => {
  77387. let index = this.midMarkers.indexOf(marker);
  77388. let newMarker = this.addMarker({index:(index+1), point:marker.position.clone() });
  77389. this.addMidMarker(index+1, new Vector3 );
  77390. this.updateTwoMidMarker(index+1);
  77391. this.setMarkerSelected(marker, 'unhover');
  77392. viewer.inputHandler.startDragging(newMarker , {/* dragViewport:viewer.mapViewer.viewports[0], */ } ); //notPressMouse代表不是通过按下鼠标来拖拽. dragViewport指定了只能在地图上拖拽
  77393. };
  77394. marker.addEventListener('drag', drag );
  77395. //marker.addEventListener('drop', drop);
  77396. marker.addEventListener('mouseover', mouseover);
  77397. marker.addEventListener('mouseleave', mouseleave);
  77398. }
  77399. this.add(marker);
  77400. this.updateMarker(marker, point);
  77401. if(!this.selected)viewer.updateVisible(marker,'select',false);
  77402. return marker
  77403. }
  77404. addMidMarkers(){//第一次画好所有marker后,一次性为线段增加中点marker
  77405. let length = this.points.length;
  77406. this.points.forEach((point,index)=>{
  77407. let nextPoint = this.points[(index+1)%length];
  77408. let midPoint = new Vector3().addVectors(point, nextPoint).multiplyScalar(0.5);
  77409. this.addMidMarker(index, midPoint );
  77410. });
  77411. }
  77412. updateTwoMidMarker(index){//更新第index个marker两边的midMarker
  77413. if(!this.midMarkers.length)return
  77414. let length = this.points.length;
  77415. let last = this.points[(index-1+length)%length]; //它之前的marker位置
  77416. let next = this.points[(index+1)%length];//它之后的marker位置
  77417. let current = this.points[index];//当前位置
  77418. let lastMid = new Vector3().addVectors(last, current).multiplyScalar(0.5);//上一个中点
  77419. let nextMid = new Vector3().addVectors(next, current).multiplyScalar(0.5);//下一个中点
  77420. let lastMidMarker = this.midMarkers[(index-1+length)%length];
  77421. let nextMidMarker = this.midMarkers[index];
  77422. this.updateMarker(lastMidMarker, lastMid);
  77423. this.updateMarker(nextMidMarker, nextMid);
  77424. }
  77425. dispose(){//销毁geo、remove from parent
  77426. super.dispose();
  77427. this.box && this.box.geometry.dispose();
  77428. this.lineMesh && this.lineMesh.geometry.dispose();
  77429. this.holes.forEach(e=>e.dispose());
  77430. this.parentHoles.forEach(e=>e.dispose());
  77431. //this.buildChildren.forEach(e=>e.dispose())
  77432. this.dispatchEvent('dispose');
  77433. }
  77434. updateBox(){
  77435. if(!this.box)return
  77436. this.box.geometry.dispose();
  77437. var shrink = this.buildType == 'room' ? 0.11 : this.buildType == 'floor' ? 0.082 : 0.2 ;//防止mesh重叠冲突(给一个不寻常的数字) 但离远了还是会有点闪烁
  77438. if(this.points.length >= 3){
  77439. let holes = this.holes.concat(this.parentHoles);
  77440. let holesPoints = holes.filter(e=>e.points.length>2).map(e=>e.points);
  77441. this.box.geometry = MeshDraw.getExtrudeGeo(this.points, holesPoints, {
  77442. depth:this.zMax-this.zMin-shrink,
  77443. UVGenerator: new MetricUVGenerator()
  77444. });
  77445. if(this.buildType == 'building' ){
  77446. this.box.position.z = this.zMin - shrink / 2;
  77447. }else {
  77448. this.box.position.z = this.zMin + shrink / 2;
  77449. }
  77450. }
  77451. }
  77452. update(options={}){
  77453. super.update(this.buildType != 'floor' && options.ifUpdateMarkers);
  77454. let length = this.points.length;
  77455. {//确保一下一样
  77456. if(this.originHole){
  77457. this.points = this.originHole.points; //完全等于building的hole
  77458. }
  77459. if(this.buildType == 'hole'){
  77460. this.zMin = this.buildParent.zMin;
  77461. this.zMax = this.buildParent.zMax;
  77462. }
  77463. }
  77464. if(!options.dontUpdateBox){
  77465. let boxOwner;
  77466. if(this.buildType == 'hole'){
  77467. if(this.buildParent.buildType == 'building'){ //若是整栋大楼的hole,在每层都要更新下它的对应hole
  77468. this.buildParent.buildChildren.forEach(floor=>{
  77469. let holeAtFloor = floor.parentHoles.find(e=>e.originHole == this );
  77470. holeAtFloor && holeAtFloor.update(); //刚开始创建时还没创建对应的 holeAtFloor会为null
  77471. });
  77472. }
  77473. boxOwner = this.buildParent;
  77474. }else {
  77475. boxOwner = this;
  77476. }
  77477. boxOwner.updateBox();
  77478. }
  77479. {//update lines
  77480. let positions = [];
  77481. this.points.forEach((point, index)=>{
  77482. //竖线:
  77483. positions.push(point.clone().setZ(this.zMin), point.clone().setZ(this.zMax));
  77484. //横线
  77485. let nextPoint = this.points[(index+1)%length];
  77486. if(!nextPoint)return;//when length==1
  77487. positions.push(point.clone().setZ(this.zMax), nextPoint.clone().setZ(this.zMax));//上横线
  77488. positions.push(point.clone().setZ(this.zMin), nextPoint.clone().setZ(this.zMin));//下横线
  77489. });
  77490. LineDraw.moveLine(this.lineMesh,positions);
  77491. }
  77492. if(!options.dontUpdateChildren){
  77493. if(this.buildType == 'building' ){
  77494. this.buildChildren.forEach(floor=>{
  77495. floor.points = this.points;
  77496. floor.update();
  77497. });
  77498. }
  77499. {
  77500. let holes = this.holes.concat(this.parentHoles);
  77501. holes.forEach(hole=> {
  77502. hole.update({dontUpdateBox:true});//父级更新了box,hole就不需要更新box了
  77503. });
  77504. }
  77505. }
  77506. }
  77507. getHolesArea(){
  77508. let holes = this.holes.concat(this.parentHoles);
  77509. let outHoles, holesArea = 0;
  77510. if(holes.length>=2){//合并holes。如果能在绘制时直接合并holes就好啦,这步就转移到那去,但是要删除hole好麻烦
  77511. let holes_ = holes.map(e=>e.points);
  77512. outHoles = math.getPolygonsMixedRings(holes_, true );
  77513. outHoles.forEach(e=>{
  77514. holesArea+=e.area;
  77515. });
  77516. outHoles = outHoles.map(e=>e.points);
  77517. }else {
  77518. outHoles = holes.map(e=>e.points);
  77519. outHoles.forEach(e=> holesArea += Math.abs(math.getArea(e)));
  77520. }
  77521. return holesArea
  77522. }
  77523. getArea(ifRidOfHoles){//面积
  77524. //不排除hole
  77525. return Math.abs(math.getArea(this.points)) - (ifRidOfHoles ? this.getHolesArea() : 0)
  77526. }
  77527. getVolume(ifRidOfHoles){//体积
  77528. let {zMin , zMax} = this.getRealZ();
  77529. let height = zMax - zMin;
  77530. if(isNaN(height))height = 0;
  77531. return this.getArea(ifRidOfHoles) * height
  77532. }
  77533. getRealZ(){//求真实高度时用到的
  77534. let zMin , zMax;
  77535. if (this.buildType == 'building') {
  77536. //building的zMax和zMin一样的所以要算
  77537. let top = this.buildChildren[this.buildChildren.length - 1];
  77538. let btm = this.buildChildren[0];
  77539. zMin = btm ? btm.zMin : 0; //建好的建筑不加楼的话是0
  77540. zMax = top ? top.zMax : 0;
  77541. }else if(this.buildType == 'hole'){
  77542. return this.buildParent.getRealZ()
  77543. }else {
  77544. zMin = this.zMin, zMax = this.zMax;
  77545. }
  77546. return {zMin,zMax}
  77547. }
  77548. /* getDrawZ(){ //画线和box时用到的z
  77549. let zMin , zMax
  77550. if(this.buildType == 'hole'){
  77551. if(this.buildParent.buildType == 'building' && atFloor){
  77552. zMin = atFloor.zMin, zMax = atFloor.zMax
  77553. }else{
  77554. zMin = this.buildParent.zMin, zMax = this.buildParent.zMax
  77555. }
  77556. }else{
  77557. zMin = this.zMin, zMax = this.zMax
  77558. }
  77559. return {zMin, zMax}
  77560. } */
  77561. getBound(){
  77562. let bound = new Box3;
  77563. let {zMin , zMax} = this.getRealZ();
  77564. let points = this.buildType == 'floor' ? this.buildParent.points : this.points;
  77565. points.forEach(p=>{
  77566. bound.expandByPoint(p.clone().setZ(zMin));
  77567. bound.expandByPoint(p.clone().setZ(zMax));
  77568. });
  77569. return bound
  77570. }
  77571. getMarkerMaterial(type) {
  77572. if(!markerMats$2){
  77573. markerMats$2 = {
  77574. default: new MeshBasicMaterial({
  77575. transparent: !0,
  77576. color: color$2,
  77577. opacity: 0.8,
  77578. map: texLoader$6.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  77579. depthTest:false,
  77580. }),
  77581. midPrepare: new MeshBasicMaterial({ //线中心的半透明点
  77582. transparent: !0,
  77583. color: color$2,
  77584. opacity: 0.4,
  77585. map: texLoader$6.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  77586. depthTest:false,
  77587. }),
  77588. hover: new MeshBasicMaterial({
  77589. transparent: !0,
  77590. color: color$2,
  77591. opacity: 1,
  77592. map: texLoader$6.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  77593. depthTest:false,
  77594. }),
  77595. select: new MeshBasicMaterial({
  77596. transparent: !0,
  77597. color:new Color('#00C8AF'),
  77598. opacity: 1,
  77599. map: texLoader$6.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  77600. depthTest:false,
  77601. }),
  77602. };
  77603. }
  77604. return markerMats$2[type]
  77605. }
  77606. setMarkerSelected(marker, state, hoverObject){
  77607. //console.warn(marker.id , state, hoverObject)
  77608. if(state == 'select'){
  77609. marker.selected = true;
  77610. marker.material = this.getMarkerMaterial('select');
  77611. }else if(state == 'unselect'){
  77612. marker.selected = false;
  77613. marker.material = this.getMarkerMaterial('default');
  77614. }else {
  77615. if(marker.selected)return //选中时不允许修改为除了'unselect'以外的状态
  77616. if(state == 'hover'){
  77617. marker.material = this.getMarkerMaterial('hover');
  77618. }else if(state == 'unhover'){
  77619. if(marker.name.includes('mid')){
  77620. marker.material = this.getMarkerMaterial('midPrepare');
  77621. }else {
  77622. marker.material = this.getMarkerMaterial('default');
  77623. }
  77624. }
  77625. }
  77626. }
  77627. select(){
  77628. //最多再显示一层子级的线,如building不会显示room中的hole的线
  77629. //box是一直显示的,但会切换材质
  77630. /*
  77631. 选中 box 线
  77632. building 自己(底盘)选中 自己, floor不带hole
  77633. floor 自己选中 自己, room不带hole
  77634. room 自己选中 自己
  77635. */ //注:自己的就代表定包括hole,如果有parentHoles的也(building上的hole的对应)
  77636. //console.log('select '+this.name, this.selected)
  77637. if(this.selected)return
  77638. if(this.box){
  77639. this.box.material = this.mats.boxSelected;
  77640. }
  77641. if(this.buildType == 'building'|| this.buildType == 'floor'){
  77642. this.buildChildren.forEach(e=>{
  77643. e.lineMesh.visible = true;
  77644. });
  77645. if(this.buildType == 'floor'){
  77646. viewer.setObjectLayers(this.box, 'bothMapAndScene' );
  77647. viewer.setObjectLayers(this.buildParent.box, 'siteModelMapUnvisi' ); //当选中floor或room时,building在地图不可见
  77648. }
  77649. }else if(this.buildType == 'room'){
  77650. viewer.setObjectLayers(this.buildParent.box, 'bothMapAndScene' );
  77651. viewer.setObjectLayers(this.buildParent.buildParent.box, 'siteModelMapUnvisi' );
  77652. }
  77653. this.lineMesh.visible = true;
  77654. this.markers && this.markers.forEach(e=>viewer.updateVisible(e,'select',true) );
  77655. this.midMarkers && this.midMarkers.forEach(e=>e.visible = true);
  77656. let holes = this.holes.concat(this.parentHoles);
  77657. holes.forEach(e=>e.select());
  77658. this.selected = true;
  77659. this.dispatchEvent({type:'select'});
  77660. }
  77661. unselect(){
  77662. if(!this.selected)return
  77663. //console.log('unselect '+this.name )
  77664. if(this.box){
  77665. this.box.material = this.mats.boxDefault;
  77666. }
  77667. if(this.buildType == 'building' || this.buildType == 'floor'){
  77668. this.buildChildren.forEach(e=>{ //(这里要保证选中前要先取消选中,否则如选中房间后取消了楼层,房间线就隐藏了)
  77669. e.lineMesh.visible = false;
  77670. });
  77671. if(this.buildType == 'floor'){
  77672. viewer.setObjectLayers(this.box, 'siteModelMapUnvisi' );
  77673. viewer.setObjectLayers(this.buildParent.box, 'bothMapAndScene' );
  77674. }
  77675. }else if(this.buildType == 'room'){
  77676. viewer.setObjectLayers(this.buildParent.box, 'siteModelMapUnvisi' );
  77677. viewer.setObjectLayers(this.buildParent.buildParent.box, 'bothMapAndScene' );
  77678. }
  77679. this.lineMesh.visible = false;
  77680. this.markers && this.markers.forEach(e=>viewer.updateVisible(e,'select',false) );
  77681. this.midMarkers && this.midMarkers.forEach(e=>e.visible = false);
  77682. let holes = this.holes.concat(this.parentHoles);
  77683. holes.forEach(e=>e.unselect());
  77684. this.selected = false;
  77685. this.dispatchEvent({type:'unselect'});
  77686. }
  77687. ifContainsPoint(position){//看它所定义的空间是否包含某个坐标(要排除hole)
  77688. let {zMin , zMax} = this.getRealZ();
  77689. if(position.z < zMin || position.z > zMax ) return
  77690. let holes = this.holes.concat(this.parentHoles);
  77691. let holesPoints = holes.filter(e=>e!=this && e.points.length>2).map(e=>e.points);
  77692. let inShape = math.isPointInArea(this.points, holesPoints, position);
  77693. return !!inShape
  77694. }
  77695. }
  77696. class MetricUVGenerator{
  77697. constructor(){
  77698. this.a = new Vector3,
  77699. this.b = new Vector3,
  77700. this.c = new Vector3,
  77701. this.d = new Vector3;
  77702. }
  77703. generateTopUV(t, e, n, r, o) {
  77704. return [new Vector2$1(e[3 * n],e[3 * n + 1]), new Vector2$1(e[3 * r],e[3 * r + 1]), new Vector2$1(e[3 * o],e[3 * o + 1])]
  77705. }
  77706. generateSideWallUV(t, e, n, r, o, a) {
  77707. var s = e;
  77708. this.a.set(s[3 * n], s[3 * n + 1], s[3 * n + 2]),
  77709. this.b.set(s[3 * r], s[3 * r + 1], s[3 * r + 2]),
  77710. this.c.set(s[3 * o], s[3 * o + 1], s[3 * o + 2]),
  77711. this.d.set(s[3 * a], s[3 * a + 1], s[3 * a + 2]);
  77712. var c = this.a.x !== this.b.x
  77713. , l = c ? this.b : this.d
  77714. , u = this.a.distanceTo(l)
  77715. , d = l.distanceTo(this.c);
  77716. return [new Vector2$1(this.a.x,0), c ? new Vector2$1(this.a.x + u,0) : new Vector2$1(this.a.x,d), new Vector2$1(this.a.x + u,d), c ? new Vector2$1(this.a.x,d) : new Vector2$1(this.a.x + u,0)]
  77717. }
  77718. }
  77719. const minFloorHeight = 0.5;
  77720. const ifDrawDatasetBound = true; //显示一下数据集的tightBound线框
  77721. const minMarkers = 3;
  77722. const Limit = {zMin:-config$1.map.cameraHeight, zMax:config$1.map.cameraHeight,}; //不能超过camera的高度,为了对称所以也限制了最低
  77723. var SiteModel = {
  77724. bus: new EventDispatcher(),
  77725. entities:[], //所有实体
  77726. buildings:[], //所有建筑父集
  77727. meshGroup: new Object3D,
  77728. inEntity : null,
  77729. lastPos: new Vector3(Infinity,Infinity,Infinity),
  77730. init: function(){
  77731. viewer.scene.scene.add(this.meshGroup);
  77732. this.meshGroup.name = 'siteModel';
  77733. this.SplitScreen = SplitScreen4Views;
  77734. if(Potree.settings.editType == 'pano'){
  77735. return
  77736. }
  77737. this.createHeightPull();
  77738. if(Potree.settings.isTest && ifDrawDatasetBound){
  77739. viewer.addEventListener('allLoaded',()=>{
  77740. viewer.scene.pointclouds.forEach(pointcloud=>{
  77741. let boxPoints = pointcloud.getUnrotBoundPoint();
  77742. let boundingBox = new BuildingBox({
  77743. name: '数据集tightBound_'+pointcloud.dataset_id,
  77744. points: boxPoints,
  77745. buildType : 'dataset',
  77746. zMax: pointcloud.bound.max.z,
  77747. zMin: pointcloud.bound.min.z,
  77748. ifDraw:true
  77749. });
  77750. this.meshGroup.add(boundingBox);
  77751. //boundingBox.markers.forEach(e=>e.visible = false)
  77752. });
  77753. });
  77754. }
  77755. if(Potree.settings.isOfficial){
  77756. viewer.addEventListener('camera_changed', e => {
  77757. if(e.changeInfo.positionChanged){
  77758. this.updateEntityAt();
  77759. }
  77760. });
  77761. }
  77762. {
  77763. let pressDelete = (e)=>{
  77764. if(e.keyCode == KeyCodes.BACKSPACE || e.keyCode == KeyCodes.DELETE){
  77765. if(this.selectedMarker){
  77766. let entity = this.selectedMarker.parent;
  77767. let index = entity.markers.indexOf(this.selectedMarker);
  77768. entity.removeMarker(index);
  77769. if(entity.points.length<2){//删到只剩一个点时重新画(如果是hole的点,直接删除hole吧?)
  77770. this.startInsertion('resume',entity);
  77771. }
  77772. }
  77773. }
  77774. };
  77775. viewer.inputHandler.addEventListener('keydown', pressDelete);
  77776. }
  77777. },
  77778. updateEntityAt(force){
  77779. //if(!this.entities.length || this.editing) return //编辑时也要根据位置显示不同楼层的漫游点与cad
  77780. let fun = ()=>{ //延时update,防止卡顿
  77781. let currPos = viewer.mainViewport.view.position;
  77782. //if(force || !currPos.equals(this.lastPos) ){
  77783. //console.log('currPos ', currPos.toArray())
  77784. this.lastPos.copy(currPos);
  77785. let entity;
  77786. let searchPos = Potree.settings.displayMode == 'showPanos' ? viewer.images360.currentPano : currPos;
  77787. entity = this.pointInWhichEntity(searchPos, 'room');
  77788. if(force || this.inEntity != entity ){
  77789. let oldEntity = this.inEntity;
  77790. this.inEntity = entity;
  77791. //console.log('buildingChange', entity)
  77792. this.bus.dispatchEvent({type:'buildingChange',entity});
  77793. //this.updatePanosVisible(oldEntity, this.inEntity)
  77794. let lastFloor = this.currentFloor; //oldEntity ? oldEntity.buildType == 'floor' ? oldEntity : oldEntity.buildType == 'room' ? oldEntity.buildParent : null : null; //基本只会是floor或room
  77795. let currentFloor = entity ? entity.buildType == 'floor' ? entity : entity.buildType == 'room' ? entity.buildParent : null : null; //基本只会是floor或room
  77796. if(force || currentFloor != lastFloor){
  77797. //console.log('改变了floor',lastFloor,currentFloor)
  77798. this.currentFloor = currentFloor;
  77799. this.bus.dispatchEvent({type:'FloorChange',currentFloor});
  77800. }
  77801. }
  77802. force = false;
  77803. return true
  77804. //}
  77805. };
  77806. if(force)fun();
  77807. else Common.intervalTool.isWaiting('sitemodelCameraInterval', fun , 500);
  77808. },
  77809. enter:function(){
  77810. Potree.Log('sitemodel enter');
  77811. this.clear(); //确保全部清空
  77812. this.editing = true;
  77813. //this.updatePanosVisible(null, null, true)//show all
  77814. viewer.updateFpVisiDatasets();
  77815. let mapViewport = viewer.mapViewer.viewports[0];
  77816. this.SplitScreen.split({siteModel:true/* , viewports:[{name:'Top',viewport : mapViewport }] */});
  77817. viewer.viewports.forEach(e=>{
  77818. if(e.name != 'mapViewport'){
  77819. e.layersAdd('siteModelMapUnvisi');
  77820. }
  77821. if(e.name == 'right' || e.name == 'back'){
  77822. e.layersAdd('siteModeSideVisi');
  77823. }
  77824. });
  77825. viewer.images360.panos.forEach(pano=>{
  77826. viewer.setObjectLayers(pano.marker, 'siteModelMapUnvisi' );
  77827. });
  77828. mapViewport.layersAdd('siteModeOnlyMapVisi'); //只有mapViewport能看到marker
  77829. },
  77830. leave:function(){
  77831. Potree.Log('sitemodel leave');
  77832. let mapViewport = viewer.mapViewer.viewports[0];
  77833. this.SplitScreen.recover();
  77834. viewer.viewports.forEach(e=>{
  77835. if(e.name != 'mapViewport'){
  77836. e.layersRemove('siteModelMapUnvisi');
  77837. }
  77838. if(e.name == 'right' || e.name == 'back'){
  77839. e.layersRemove('siteModeSideVisi');
  77840. }
  77841. });
  77842. viewer.images360.panos.forEach(pano=>{
  77843. viewer.setObjectLayers(pano.marker, 'sceneObjects' );
  77844. });
  77845. mapViewport.layersRemove('siteModeOnlyMapVisi');
  77846. this.clear();
  77847. this.editing = false;
  77848. this.updateEntityAt(true);
  77849. viewer.updateFpVisiDatasets();
  77850. } ,
  77851. addFloor:function(parent, dirType, sid, name){//dirType:'top'|'bottom'在上方建还是下方。如果建筑中没有楼层,默认在基底建一个
  77852. let buildType = 'floor';
  77853. let zMin, zMax;
  77854. if(parent.buildChildren.length == 0){
  77855. zMin = parent.zMin;
  77856. zMax = zMin + Potree.config.siteModel.floorHeightDefault;
  77857. }else {
  77858. if(dirType == 'bottom'){
  77859. //var btm = Common.find(parent.buildChildren,null,[e=>e.zMin])
  77860. var btm = parent.buildChildren[0];
  77861. zMax = btm.zMin;
  77862. zMin = zMax - Potree.config.siteModel.floorHeightDefault;
  77863. }else {
  77864. //var top = Common.find(parent.buildChildren,null,[e=>e.zMax])
  77865. var top = parent.buildChildren[parent.buildChildren.length - 1];
  77866. zMin = top.zMax;
  77867. zMax = zMin + Potree.config.siteModel.floorHeightDefault;
  77868. }
  77869. }
  77870. let prop = {
  77871. buildType,
  77872. //name : Potree.config.siteModel.names[buildType],
  77873. zMin,
  77874. zMax,
  77875. buildParent:parent,
  77876. sid, name,
  77877. ifDraw:true
  77878. };
  77879. var floor = new BuildingBox(prop);
  77880. /* parent.buildChildren.push(floor)
  77881. this.meshGroup.add(floor);
  77882. this.entities.push(floor) */
  77883. floor.update();
  77884. this.addEntity(floor,parent);
  77885. //this.selectEntity(floor)
  77886. if(this.selected == parent){//重新选择下,为了显示新楼层线框
  77887. parent.unselect();
  77888. parent.select();
  77889. }
  77890. return floor
  77891. },
  77892. startInsertion:function(buildType, parent, sid, name, callback, cancelFun){
  77893. let zMin, zMax, entity, resume;
  77894. let mapViewport = viewer.mapViewer.viewports[0];
  77895. if(buildType == 'resume'){//继续画(使用最后一个点或者新加的点)
  77896. resume = true;
  77897. entity = parent;
  77898. buildType = parent.buildType;
  77899. //删除原先所有的点,因为它们已经添加了事件,会很麻烦:
  77900. entity.reDraw(0);
  77901. entity.isNew = true; //当作新的来画
  77902. }
  77903. if(!resume){
  77904. if(buildType == 'hole' || buildType == 'room'){
  77905. zMin = parent.zMin;
  77906. zMax = parent.zMax;
  77907. }else if(buildType == 'building'){
  77908. parent = null;
  77909. zMin = viewer.bound.boundingBox.min.z;
  77910. zMax = viewer.bound.boundingBox.min.z;
  77911. }
  77912. if(buildType == 'hole'){
  77913. entity = parent.addHole();
  77914. entity.isNew = true;
  77915. this.selectEntity(parent);
  77916. entity.select();
  77917. console.log('挖洞 ',entity.uuid);
  77918. }else {
  77919. let prop = {
  77920. buildType,
  77921. //name : Potree.config.siteModel.names[buildType],//'building',
  77922. zMin,
  77923. zMax,
  77924. buildParent:parent,
  77925. sid, name,
  77926. ifDraw:true
  77927. };
  77928. entity = new BuildingBox(prop);
  77929. entity.isNew = true;
  77930. this.selectEntity(entity);
  77931. }
  77932. this.addEntity(entity, parent);
  77933. }
  77934. let timer;
  77935. let endDragFun = (e) => {
  77936. if (e.button == MOUSE.LEFT ) {
  77937. var marker = entity.addMarker({point:entity.points[entity.points.length - 1].clone()});
  77938. //entity.editStateChange(true) //重新激活reticule状态
  77939. entity.continueDrag(marker, e);
  77940. } else if (e.button === MOUSE.RIGHT ) {
  77941. if(e.pressDistance < Potree.config.clickMaxDragDis )end(e);//非拖拽的话
  77942. else entity.continueDrag(null, e/* .drag.object */);
  77943. }
  77944. };
  77945. let finish = ()=>{//结束绘画
  77946. viewer.removeEventListener('cancel_insertions', Exit);
  77947. entity.removeEventListener('unselect', Exit);
  77948. clearTimeout(timer);
  77949. entity.editStateChange(false);
  77950. //pressExit && viewer.inputHandler.removeEventListener('keydown', pressExit);
  77951. callback && callback(entity);
  77952. };
  77953. let end = (e={}) => {//尝试结束
  77954. /* 退出的三种形式:
  77955. 1 普通:如果大于三个marker,结束且保留;否则重新画。()
  77956. 2 删除:直接结束且删除。(remove)
  77957. 3 结束:如果大于三个marker,结束且保留;否则结束且删除。 (finish)
  77958. 4 保留:无论几个marker,都保留着,结束。(remain)
  77959. */
  77960. if(e.remove){
  77961. finish();
  77962. return this.removeEntity(entity)
  77963. }
  77964. if(!e.remain && !e.finish && !e.remove && entity.markers.length<=minMarkers){//右键 当个数不够时取消
  77965. //重新开始画
  77966. entity.reDraw(1);
  77967. viewer.updateVisible(entity.markers[0],'unMove',false);
  77968. var f = ()=>{
  77969. viewer.updateVisible(entity.markers[0],'unMove',true);
  77970. entity.removeEventListener('dragChange',f);
  77971. };
  77972. entity.addEventListener('dragChange',f);
  77973. //console.log('waitcontinue')
  77974. entity.continueDrag(entity.markers[0], e);
  77975. return
  77976. }
  77977. finish();
  77978. if (e.remain || !e.remove && entity.markers.length > 3) {//保留
  77979. entity.removeMarker(entity.points.length - 1);
  77980. entity.markers.forEach(marker=>{marker.dispatchEvent('addHoverEvent'); });
  77981. if(buildType == 'room'){
  77982. this.fitPullBox();
  77983. }
  77984. entity.isNew = false;
  77985. entity.addMidMarkers();
  77986. }else {
  77987. this.removeEntity(entity); //直接删除没画好的,比较简单。这样就不用担心旧的continueDrag仍旧触发了
  77988. }
  77989. return entity
  77990. };
  77991. let Exit = (e)=>{ //强制结束
  77992. entity.removeEventListener('unselect', Exit);
  77993. if(viewer.inputHandler.drag){//还未触发drop的话
  77994. viewer.inputHandler.drag.object.dispatchEvent({
  77995. type: 'drop',
  77996. drag: viewer.inputHandler.drag,
  77997. viewer: viewer,
  77998. pressDistance:0,
  77999. button : MOUSE.RIGHT
  78000. });
  78001. viewer.inputHandler.drag = null;
  78002. }else {
  78003. end({remain:true});
  78004. }
  78005. viewer.inputHandler.drag = null;
  78006. };
  78007. viewer.dispatchEvent( 'cancel_insertions' );//取消之前的
  78008. viewer.addEventListener('cancel_insertions', Exit);
  78009. entity.addEventListener('unselect', Exit);
  78010. var marker = entity.addMarker({point:new Vector3(0, 0, 0)});
  78011. viewer.updateVisible(marker,'unMove',false);//这时候的位置是假的(0,0,0)所以先不可见
  78012. var f = ()=>{
  78013. viewer.updateVisible(marker,'unMove',true);
  78014. entity.removeEventListener('dragChange',f);
  78015. };
  78016. entity.addEventListener('dragChange',f);
  78017. marker.isDragging = true;
  78018. viewer.inputHandler.startDragging(marker , {dragViewport:mapViewport, endDragFun, notPressMouse:true} ); //notPressMouse代表不是通过按下鼠标来拖拽. dragViewport指定了只能在地图上拖拽
  78019. return entity;
  78020. },
  78021. getPreDealData(points, zMin, zMax, initial, buildType, parent){
  78022. /* if( buildType == 'building' ){
  78023. zMax = zMin //强制变得一样,作为基底。如果有必要,保存时再算真实的zMax。目前zMin没有保存所以数据是错的,会直接根据floor计算
  78024. } */
  78025. var bound = viewer.bound.boundingBox;
  78026. if(buildType == 'building' && initial){//初始数据错的,要自己建(只有一个building和floor) 原posIsLonlat
  78027. console.log('空间模型未编辑过, 初始化了一个');
  78028. points = [
  78029. new Vector3(bound.min.x, bound.min.y,0),
  78030. new Vector3(bound.max.x, bound.min.y,0),
  78031. new Vector3(bound.max.x, bound.max.y,0),
  78032. new Vector3(bound.min.x, bound.max.y,0),
  78033. ];
  78034. zMin = bound.min.z;
  78035. zMax = bound.max.z;
  78036. /* points = points.map(e=>{
  78037. return viewer.transform.lonlatToLocal.forward(e)
  78038. }) */
  78039. }else {//相对于初始数据集的模型内坐标
  78040. points = points.map(e=> this.transform(e, 'fromDataset'));
  78041. if(buildType == 'floor' && initial){
  78042. zMin = bound.min.z;
  78043. zMax = bound.max.z;
  78044. }
  78045. }
  78046. return {points, zMax, zMin }
  78047. },
  78048. resetFromData:function(entity, points=[], holes=[], zMin, zMax ){
  78049. var {points, zMax, zMin} = this.getPreDealData(points, zMin, zMax , this.autoBuild , entity.buildType, entity.buildParent );
  78050. if(entity.buildType != 'floor' )entity.points = points;
  78051. if(entity.buildType == 'room'){
  78052. entity.zMin = zMin;
  78053. entity.zMax = zMax;
  78054. }else if(entity.buildType == 'floor'){//改楼高
  78055. let height = zMax - zMin;
  78056. let zMax2 = entity.zMin + height;
  78057. SiteModel.changeZ(entity, 'zMax', zMax2);
  78058. }
  78059. {
  78060. //删除旧的holes重新添加
  78061. let holesOld = entity.holes;
  78062. holesOld.forEach(e=>{
  78063. entity.removeHole(e);
  78064. });
  78065. holes.forEach(points =>{
  78066. let ps = points.map(e=> this.transform(e, 'fromDataset'));
  78067. let hole = entity.addHole(ps);
  78068. hole.addMidMarkers();
  78069. });
  78070. }
  78071. entity.update();
  78072. return entity
  78073. }
  78074. ,
  78075. createFromData:function( buildType, parent ,sid, name, points=[], holes=[], zMin, zMax, initial,panos,flagPano){
  78076. if(buildType != 'building' && buildType != 'floor' && buildType != 'room' ) return
  78077. var {points, zMax, zMin} = this.getPreDealData(points, zMin, zMax , initial, buildType, parent );
  78078. {
  78079. let getPano = (id)=>{
  78080. return viewer.images360.panos.find(pano=>pano.id == id)
  78081. };
  78082. panos = panos ? panos.map(e=>getPano(e)) : [];
  78083. flagPano = flagPano != void 0 ? getPano(flagPano) : null ; //最中心的pano 或者 最靠近该实体的pano(当panos为空时)
  78084. if(!this.editing && buildType == 'floor' && !flagPano){//没有的话可能是自动添加的floor,直接用parent的吧
  78085. panos = parent.panos;
  78086. flagPano = parent.flagPano;
  78087. }
  78088. }
  78089. let prop = {
  78090. buildType,
  78091. points,
  78092. name,
  78093. sid,
  78094. zMin,
  78095. zMax,
  78096. buildParent:parent,
  78097. ifDraw:this.editing || Potree.settings.drawEntityData,
  78098. panos, flagPano,
  78099. autoBuild : initial
  78100. };
  78101. let entity = new BuildingBox(prop);
  78102. SiteModel.addEntity(entity, parent );
  78103. if(this.editing){
  78104. if(buildType == 'building'|| buildType == 'room'){
  78105. entity.addMidMarkers();
  78106. }
  78107. }
  78108. holes.forEach(points =>{
  78109. let ps = points.map(e=> this.transform(e, 'fromDataset'));
  78110. let hole = entity.addHole(ps);
  78111. this.editing && hole.addMidMarkers();
  78112. });
  78113. /* if(buildType == 'floor'){
  78114. this.updateBuildingZ(parent)
  78115. } */
  78116. return entity
  78117. },
  78118. transform:function(pos, type){
  78119. if(Potree.settings.editType == 'pano'){ // 模型不经转换
  78120. return new Vector3().copy(pos).setZ(0);
  78121. }
  78122. if(type == 'toDataset'){
  78123. let point = Potree.Utils.datasetPosTransform({ toDataset: true, position: pos.clone(), datasetId: Potree.settings.originDatasetId });
  78124. return new Vector2$1().copy(point)
  78125. }else {
  78126. let position = new Vector3().copy(pos).setZ(0);
  78127. return Potree.Utils.datasetPosTransform({ fromDataset: true, position, datasetId: Potree.settings.originDatasetId })
  78128. }
  78129. },
  78130. addEntity:function(entity, parent){
  78131. this.meshGroup.add(entity);
  78132. this.entities.push(entity);
  78133. if(entity.buildType == 'building'){
  78134. this.buildings.push(entity);
  78135. }else {
  78136. parent.buildChildren.push(entity);
  78137. }
  78138. if(entity.buildType == 'room'){
  78139. entity.addEventListener('marker_dropped',()=>{
  78140. this.fitPullBox();
  78141. });
  78142. }else if(entity.buildType == 'floor'){
  78143. this.updateBuildingZ(parent);
  78144. parent.dispatchEvent({type:'addFloor'});
  78145. }
  78146. {//仅能存在一个marker被选中。选中的点可以被删除
  78147. entity.addEventListener('clickMarker', (e)=>{
  78148. if(this.selectedMarker == e.marker){
  78149. this.selectedMarker.dispatchEvent({type:'clickSelect',state:false});
  78150. this.selectedMarker = null;
  78151. }else {
  78152. if(this.selectedMarker){
  78153. this.selectedMarker.dispatchEvent({type:'clickSelect',state:false});
  78154. }
  78155. this.selectedMarker = e.marker;
  78156. this.selectedMarker.dispatchEvent({type:'clickSelect',state:true});
  78157. }
  78158. });
  78159. entity.addEventListener('removeMarker', (e)=>{
  78160. if(this.selectedMarker == e.marker){
  78161. this.selectedMarker = null;
  78162. }
  78163. });
  78164. let unselect = (e)=>{//取消选中实体或删除后
  78165. if(this.selectedMarker && entity.markers.includes(this.selectedMarker)){
  78166. this.selectedMarker.dispatchEvent({type:'clickSelect',state:false});
  78167. this.selectedMarker = null;
  78168. }
  78169. };
  78170. entity.addEventListener('dispose', unselect);
  78171. entity.addEventListener('unselect', unselect);
  78172. }
  78173. //console.log('添加实体:', entity.buildType, entity.sid, entity.uuid)
  78174. },
  78175. removeEntity : function(entity){
  78176. if(!this.entities.includes(entity))return
  78177. console.log('删除实体:', entity.buildType, entity.sid);
  78178. if(this.selected == entity){
  78179. this.height_pull_box.visible = false;
  78180. this.selectEntity(null);
  78181. }
  78182. if(entity.buildType == 'building'){
  78183. var index = this.buildings.indexOf(entity);
  78184. if(index>-1){
  78185. this.buildings.splice(index,1);
  78186. }
  78187. }else {
  78188. var index = entity.buildParent.buildChildren.indexOf(entity);
  78189. if(index>-1){
  78190. entity.buildParent.buildChildren.splice(index,1);
  78191. }
  78192. }
  78193. var index = this.entities.indexOf(entity);
  78194. if(index>-1){
  78195. this.entities.splice(index,1);
  78196. }
  78197. entity.dispose();
  78198. let buildChildren = entity.buildChildren.slice();
  78199. buildChildren.forEach(e=>this.removeEntity(e));
  78200. },
  78201. updateBuildingZ:function(building){
  78202. building.buildChildren = building.buildChildren.sort((e,a)=>e.zMin-a.zMin);//从低到高排序
  78203. building.zMin = building.zMax = building.buildChildren[0].zMin; //基底高度
  78204. //building.zMax = building.buildChildren[building.buildChildren.length-1].zMax
  78205. if(this.editing) building.update({dontUpdateChildren:true});
  78206. building.dispatchEvent('updateBuildingZ');
  78207. },
  78208. selectEntity : function(entity, state=true){
  78209. if(state === false){
  78210. entity.unselect();
  78211. if(this.selected == entity)this.selected = null;
  78212. return
  78213. }
  78214. if(this.selected == entity || entity && entity.buildType == 'hole')return
  78215. //this.buildings.forEach(e=>e.unselect())
  78216. this.selected && this.selected.unselect();
  78217. this.height_pull_box.visible = false;
  78218. if(entity){
  78219. entity.select();
  78220. }
  78221. this.selected = entity;
  78222. if(entity && (entity.buildType == 'floor' || entity.buildType == 'room' )){
  78223. this.height_pull_box.visible = true;
  78224. this.fitPullBox();
  78225. }
  78226. if(entity && !entity.isNew && (entity.buildType == 'building' || entity.buildType == 'room' ) && entity.points.length<2){
  78227. this.startInsertion('resume',entity); //继续画
  78228. }
  78229. },
  78230. fitPullBox: function(){ //自适应拖拽楼层的pullMesh
  78231. if(!this.selected || this.selected.buildType!= 'floor' && this.selected.buildType!= 'room')return
  78232. let bound = new Box3();
  78233. bound.expandByObject(this.selected.box);
  78234. let center = bound.getCenter(new Vector3() );
  78235. let size = bound.getSize(new Vector3() );
  78236. this.height_pull_box.scale.copy(size);
  78237. this.height_pull_box.position.copy(center);
  78238. },
  78239. changeZ:function(entity, dirType, value){ // floor or room 修改zMin or zMax
  78240. let max, min; //limit
  78241. if(entity.buildType == 'floor'){//楼层
  78242. let index = entity.buildParent.buildChildren.indexOf(entity);
  78243. if(dirType == 'zMax'){
  78244. let upper = entity.buildParent.buildChildren[index+1];
  78245. entity.zMax = Math.min(Limit.zMax, value);
  78246. min = entity.zMin + minFloorHeight;
  78247. if(entity.zMax < min){
  78248. entity.zMax = min;
  78249. }else {
  78250. if(upper){
  78251. max = upper.zMax - minFloorHeight;
  78252. if(entity.zMax > max){
  78253. entity.zMax = max;
  78254. }
  78255. }
  78256. }
  78257. if(upper){
  78258. upper.zMin = entity.zMax;
  78259. upper.update();
  78260. upper.dispatchEvent({type:'changeHeight'});
  78261. }
  78262. }else {
  78263. let lower = entity.buildParent.buildChildren[index-1];
  78264. entity.zMin = Math.max(Limit.zMin, value);
  78265. max = entity.zMax - minFloorHeight;
  78266. if(entity.zMin > max){
  78267. entity.zMin = max;
  78268. }else {
  78269. if(lower){
  78270. min = lower.zMin + minFloorHeight;
  78271. if(entity.zMin < min){
  78272. entity.zMin = min;
  78273. }
  78274. }
  78275. }
  78276. if(lower){
  78277. lower.zMax = entity.zMin;
  78278. lower.update();
  78279. lower.dispatchEvent({type:'changeHeight'});
  78280. }
  78281. if(index == 0)this.updateBuildingZ(entity.buildParent);
  78282. }
  78283. }else if(entity.buildType == 'room'){//房间
  78284. //按照navvis的是不一定限制在当前楼层,只要高度不超过当前楼层即可。
  78285. let maxHeight = entity.buildParent.zMax - entity.buildParent.zMin;
  78286. if(dirType == 'zMax'){
  78287. min = entity.zMin + minFloorHeight;
  78288. max = entity.zMin + maxHeight;
  78289. entity.zMax = MathUtils.clamp(value, min, max);
  78290. }else {
  78291. min = entity.zMax - maxHeight;
  78292. max = entity.zMax - minFloorHeight;
  78293. entity.zMin = MathUtils.clamp(value, min, max);
  78294. }
  78295. }
  78296. entity.update();
  78297. entity.dispatchEvent({type:'changeHeight'});
  78298. //this.selected.emit('update')
  78299. this.fitPullBox();
  78300. },
  78301. createHeightPull:function(){ //拖拽楼层的bounding box
  78302. let boxGeo = new BoxBufferGeometry( 1, 1, 1/4 );
  78303. let boxMat = new MeshBasicMaterial({
  78304. color:"#F00",
  78305. opacity:0,
  78306. transparent:true,
  78307. depthTest:false,
  78308. side:2
  78309. });
  78310. let height_pull_box_up = new Mesh(boxGeo,boxMat);
  78311. let height_pull_box_down = new Mesh(boxGeo,boxMat);
  78312. height_pull_box_up.name = 'height_pull_box_up';
  78313. height_pull_box_down.name = 'height_pull_box_down';
  78314. this.height_pull_box = new Object3D();
  78315. this.height_pull_box.name = 'height_pull_box';
  78316. this.height_pull_box.add(height_pull_box_up);
  78317. this.height_pull_box.add(height_pull_box_down);
  78318. this.height_pull_box.visible = false;
  78319. this.meshGroup.add(this.height_pull_box);
  78320. height_pull_box_up.position.set(0,0,1/2/* 3/8 */);
  78321. height_pull_box_down.position.set(0,0,-1/2/* -3/8 */);
  78322. viewer.setObjectLayers(this.height_pull_box, 'siteModeSideVisi' );
  78323. let mouseover = (e)=>{
  78324. viewer.dispatchEvent({
  78325. type : "CursorChange", action : "add", name:"siteModelFloorDrag"
  78326. });
  78327. };
  78328. let mouseleave = (e)=>{
  78329. viewer.dispatchEvent({
  78330. type : "CursorChange", action : "remove", name:"siteModelFloorDrag"
  78331. });
  78332. };
  78333. let firstZ, firstIntersect;
  78334. let drag = (e)=>{
  78335. var intersectPoint = e.intersectPoint.orthoIntersect; //不要点云的intersect,只要orthocamera算出的平面intersect
  78336. if(firstIntersect != void 0){
  78337. let moveZ = intersectPoint.z - firstIntersect;
  78338. if(this.selected.buildType == 'floor'){//楼层
  78339. //限制高度不能超过上下
  78340. if(e.target == height_pull_box_up){
  78341. if(firstZ == void 0)firstZ = this.selected.zMax;
  78342. this.changeZ(this.selected, 'zMax', firstZ + moveZ);
  78343. }else {
  78344. if(firstZ == void 0)firstZ = this.selected.zMin;
  78345. this.changeZ(this.selected, 'zMin', firstZ + moveZ);
  78346. }
  78347. }else if(this.selected.buildType == 'room'){//房屋
  78348. if(e.target == height_pull_box_up){
  78349. if(firstZ == void 0)firstZ = this.selected.zMax;
  78350. this.changeZ(this.selected, 'zMax', firstZ + moveZ);
  78351. }else {
  78352. if(firstZ == void 0)firstZ = this.selected.zMin;
  78353. this.changeZ(this.selected, 'zMin', firstZ + moveZ);
  78354. }
  78355. }
  78356. }else {
  78357. firstIntersect = intersectPoint.z;
  78358. }
  78359. };
  78360. let drop = (e)=>{
  78361. firstZ = firstIntersect = null;
  78362. };
  78363. height_pull_box_up.addEventListener('mousemove',mouseover);
  78364. height_pull_box_down.addEventListener('mousemove',mouseover);
  78365. height_pull_box_up.addEventListener('mouseleave',mouseleave);
  78366. height_pull_box_down.addEventListener('mouseleave',mouseleave);
  78367. height_pull_box_up.addEventListener('drag',drag);
  78368. height_pull_box_down.addEventListener('drag',drag);
  78369. height_pull_box_up.addEventListener('drop',drop);
  78370. height_pull_box_down.addEventListener('drop',drop);
  78371. },
  78372. pointInWhichEntity(location, buildType, ifIgnoreHole){//buildType是要找的建筑类型
  78373. //location 可以是pano或者坐标
  78374. //由于房间可能在building外,所以房间要另外单独识别。
  78375. let lastResult; //最接近的上一层结果,如果没有result返回这个
  78376. let result;
  78377. let level = {
  78378. building: 0, floor: 1, room: 2
  78379. };
  78380. let traverse = (parent, buildType)=>{//返回第一个符合标准的实体
  78381. let contains;
  78382. if(location instanceof Vector3){
  78383. contains = parent.ifContainsPoint(location);
  78384. }else {//is pano
  78385. contains = parent.panos.includes(location);
  78386. }
  78387. if(contains){
  78388. if(!lastResult || level[lastResult.buildType] < level[parent.buildType] )lastResult = parent;
  78389. if(parent.buildType == buildType){
  78390. return parent
  78391. }else {
  78392. for(let i=0,len=parent.buildChildren.length; i<len; i++){
  78393. let result1 = traverse(parent.buildChildren[i]);
  78394. if(result1) return result1
  78395. }
  78396. }
  78397. }
  78398. };
  78399. //因为建筑可能重叠,所以需要先找到最接近其中心的建筑物
  78400. result = Common.sortByScore(this.buildings, [(building)=>{
  78401. return traverse(building, 'building') //在building中
  78402. }], [(building)=>{ //写法类似pointInWhichPointcloud
  78403. let boundingBox = building.getBound();
  78404. let center = boundingBox.getCenter(new Vector3());
  78405. let position = location instanceof Vector3 ? location : location.position;
  78406. let dis = position.distanceTo(center);
  78407. let size = boundingBox.getSize(new Vector3());
  78408. let length = size.length() / 2;
  78409. return length / dis
  78410. }]);
  78411. let building = result && result[0] && result[0].score > 1 && result[0].item;
  78412. if(buildType == 'building' || !building)return building
  78413. result = traverse(building, buildType);
  78414. /* if(!result && buildType == 'room'){//如果要找的是room, 且按刚才的顺序找不到的话,就单独从所有rooms中找一遍。因为room可能不在floor和building内。
  78415. let rooms = this.entities.filter(e=>e.buildType == 'room');
  78416. result = rooms.find(e=>e.ifContainsPoint(position))
  78417. }*/
  78418. //虽然房间可以画到上级之外,但是为了方便起见,假定房间绝对在楼层之内。找不到的话要调整空间模型了。
  78419. return result || lastResult
  78420. }
  78421. ,
  78422. findPanos: function(){
  78423. {
  78424. this.entities.forEach(entity=>{
  78425. //清空:
  78426. entity.panos = [];
  78427. entity.flagPano = null;
  78428. viewer.images360.panos.forEach(pano=>{
  78429. if(entity.ifContainsPoint(pano.position)){
  78430. entity.panos.push(pano);
  78431. }
  78432. });
  78433. });
  78434. }
  78435. /* viewer.images360.panos.forEach(pano=>{ //一个漫游点只对应一个实体的话
  78436. let result = this.pointInWhichEntity(pano.position, 'room');
  78437. {//get panos for every entities
  78438. let entity = result
  78439. while(entity){
  78440. entity.panos.push(pano);
  78441. entity = entity.buildParent
  78442. }
  78443. }
  78444. }) */
  78445. {//search center pano
  78446. this.entities.forEach(entity=>{
  78447. let panos = entity.panos;
  78448. if(panos.length == 0)return
  78449. let bound = entity.getBound();
  78450. let center = bound.getCenter(new Vector3);
  78451. let request = [];
  78452. let rank = [
  78453. Images360.scoreFunctions.distanceSquared({position: center})
  78454. ];
  78455. //let panos = entity.panos && entity.panos.length ? entity.panos : viewer.images360.panos //entity没有panos的话,就扩大到所有panos
  78456. let r = Common.sortByScore(panos, request, rank);
  78457. if(r && r.length){
  78458. entity.flagPano = r[0].item;
  78459. }else {
  78460. console.error('no flagPano??');
  78461. }
  78462. });
  78463. }
  78464. }
  78465. ,
  78466. findEntityForDataset:function(){//为每一个数据集寻找它所属的最小实体
  78467. /* var entities = this.entities.filter(e=>e.buildType == 'room' || e.buildType == 'floor' && e.buildChildren.length == 0)
  78468. viewer.scene.pointclouds.forEach(pointcloud=>{
  78469. let cloudVolume = pointcloud.getVolume()
  78470. let scores = []
  78471. entities.forEach(entity=>{
  78472. let volume = entity.intersectPointcloudVolume(pointcloud)
  78473. //注:默认已经findPanos过
  78474. let panos = entity.panos.filter(e=>pointcloud.panos.includes(e));
  78475. let panoCount = panos.length
  78476. let score = volume / cloudVolume + panoCount / pointcloud.panos.length
  78477. scores.push({entity, volume, panoCount, score})
  78478. })
  78479. scores.sort((a,b)=>{ return b.score-a.score })
  78480. if(scores.length == 0 || scores[0].volume/cloudVolume < 0.0001 && scores[0].volume < 3 ){//如果约等于0
  78481. pointcloud.belongToEntity = null
  78482. }else{
  78483. pointcloud.belongToEntity = scores[0].entity;
  78484. }
  78485. }) */
  78486. let getScores = (pointcloud, entities, cloudVolume)=>{
  78487. let scores = [];
  78488. entities.forEach(entity=>{
  78489. let volume = entity.intersectPointcloudVolume(pointcloud);
  78490. //注:默认已经findPanos过
  78491. let panos = entity.panos.filter(e=>pointcloud.panos.includes(e));
  78492. let panoCount = panos.length;
  78493. let score = volume / cloudVolume;
  78494. if(pointcloud.panos.length > 0){
  78495. score += panoCount / pointcloud.panos.length;
  78496. }else {
  78497. //score += 1
  78498. }
  78499. scores.push({entity, volume, panoCount, score});
  78500. });
  78501. scores.sort((a,b)=>{ return b.score-a.score });
  78502. return scores
  78503. };
  78504. viewer.scene.pointclouds.forEach(pointcloud=>{ //先判断父级,如果父集不通过就不判断子级。
  78505. let cloudVolume = pointcloud.getVolume();
  78506. let entities = this.buildings;
  78507. while(1){
  78508. let scores = getScores(pointcloud, entities, cloudVolume);
  78509. if(scores.length == 0 || scores[0].volume/cloudVolume < 0.0001 && scores[0].volume < 3 ){//如果约等于0
  78510. pointcloud.belongToEntity = null;
  78511. break;
  78512. }else {
  78513. entities = scores[0].entity.buildChildren;
  78514. if(entities.length == 0){
  78515. pointcloud.belongToEntity = scores[0].entity;
  78516. break;
  78517. }
  78518. }
  78519. }
  78520. });
  78521. /*
  78522. 旧版:
  78523. 只需要考虑 floor 和 room, 因为building的只有一个基底没高度
  78524. floor 和 room 在空间中没有完全的从属关系,因为room可以超出floor之外。所以直接混在一起来查找,但要排除有房间的楼层。
  78525. (现在改为层层递进查找,否则数据集包含entity多的,会直接挂载到体积最大的房间里,即使看起来主体点云并不在该房间)
  78526. 有的数据集虽然很高,但只有近地面的部分才是主体,这部分一般含有全部漫游点。为了防止上层的实体因体积较大而分数高,就把包含漫游点的个数也加入考虑。
  78527. 重叠体积大、且包含漫游点最多的最小实体将会拥有该点云。
  78528. 期望: 最好不挂载到最小子级,因为现在有房间都到房间里了。
  78529. */
  78530. }
  78531. ,
  78532. clear:function(){//清空
  78533. /* entities:[], //所有实体
  78534. buildings:[], //所有建筑父集
  78535. meshGroup: new THREE.Object3D, */
  78536. this.selectEntity(null);
  78537. let length = this.entities.length;
  78538. for(let i=0;i<length;i++){
  78539. this.entities[i].dispose();
  78540. }
  78541. this.entities = [];
  78542. this.buildings = [];
  78543. this.inEntity = null;
  78544. }
  78545. ,
  78546. gotoEntity(id, isNearBy, duration=1000) {
  78547. var entity = this.entities.find(e => e.sid == id);
  78548. let aimPano;
  78549. if (!entity) {
  78550. return console.error('没找到entity ')
  78551. }
  78552. if(Potree.settings.displayMode == 'showPanos'){
  78553. if (isNearBy && entity.panos.length) {
  78554. if(entity.panos.includes(viewer.images360.currentPano)) return 'posNoChange' //已在当前实体中
  78555. let position = viewer.scene.getActiveCamera().position;
  78556. let request = [];
  78557. let rank = [Images360.scoreFunctions.distanceSquared({ position })];
  78558. let r = Common.sortByScore(entity.panos, request, rank);
  78559. aimPano = r[0].item;
  78560. } else {
  78561. if (!entity.flagPano) {
  78562. return console.log('没有flagPano')
  78563. }
  78564. aimPano = entity.flagPano;
  78565. }
  78566. if(aimPano == viewer.images360.currentPano) return 'posNoChange'
  78567. viewer.images360.flyToPano(aimPano);
  78568. }else {
  78569. if(isNearBy && entity.ifContainsPoint(viewer.images360.position) ){
  78570. return 'posNoChange' //已在当前实体中
  78571. }
  78572. let boundingBox = entity.getBound();
  78573. let position = boundingBox.getCenter(new Vector3()); //中心点不一定在entity中,比如半环形建筑(所以要不要改成到漫游点呢)
  78574. if(viewer.modules.Clip && viewer.modules.Clip.editing){
  78575. viewer.modules.Clip.bus.dispatchEvent({type:'flyToPos', position});
  78576. }else {
  78577. if(math.closeTo(position, viewer.images360.position)) return 'posNoChange'
  78578. let size = boundingBox.getSize(new Vector3());
  78579. viewer.scene.view.setView({position, duration});
  78580. viewer.mapViewer.moveTo(position, size, duration);
  78581. }
  78582. }
  78583. return true
  78584. },
  78585. focusEntity(id){
  78586. var entity = this.entities.find(e => e.sid == id);
  78587. let boundingBox = entity.getBound();
  78588. //let boundSize = boundingBox.getSize(new THREE.Vector3())
  78589. let center = boundingBox.getCenter(new Vector3());
  78590. this.SplitScreen.focusOnObject(boundingBox, center);
  78591. this.gotoEntity(id, false, 0);
  78592. },
  78593. removeIlligalArchi(){//删除marker数量小于3个的建筑,当保存时
  78594. let needDelete = [];
  78595. this.entities.forEach(e=>{
  78596. if(e.points.length<3){
  78597. needDelete.push(e);
  78598. }
  78599. });
  78600. needDelete.forEach(e=>this.removeEntity(e));
  78601. },
  78602. };
  78603. // Author: Fyrestar https://mevedia.com (https://github.com/Fyrestar/THREE.InfiniteGridHelper)
  78604. class InfiniteGridHelper extends Mesh{
  78605. constructor(size1, size2, color, distance, opacity1=0.2, opacity2=1){
  78606. color = color || new Color('white');
  78607. size1 = size1 || 10;
  78608. size2 = size2 || 100;
  78609. distance = distance || 8000; //可视距离?越远越模糊
  78610. const geometry = new PlaneBufferGeometry(2, 2, 1, 1);
  78611. const material = new ShaderMaterial({
  78612. side: DoubleSide,
  78613. uniforms: {
  78614. uSize1: {
  78615. value: size1
  78616. },
  78617. uSize2: {
  78618. value: size2
  78619. },
  78620. opacity1:{//线条1的
  78621. value: opacity1
  78622. },
  78623. opacity2:{//线条2的
  78624. value: opacity2
  78625. },
  78626. uColor: {
  78627. value: color
  78628. },
  78629. uDistance: {
  78630. value: distance
  78631. }
  78632. },
  78633. transparent: true,
  78634. vertexShader: `
  78635. varying vec3 worldPosition;
  78636. uniform float uDistance;
  78637. void main() {
  78638. vec3 pos = position.xyz * uDistance;
  78639. pos.xy += cameraPosition.xy;
  78640. worldPosition = pos;
  78641. gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
  78642. }
  78643. `,
  78644. fragmentShader: `
  78645. varying vec3 worldPosition;
  78646. uniform float uSize1;
  78647. uniform float uSize2;
  78648. uniform float opacity1;
  78649. uniform float opacity2;
  78650. uniform vec3 uColor;
  78651. uniform float uDistance;
  78652. float getGrid(float size) {
  78653. vec2 r = worldPosition.xy / size;
  78654. vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);
  78655. float line = min(grid.x, grid.y);
  78656. return 1.0 - min(line, 1.0);
  78657. }
  78658. //为何侧面看不到线,因为mesh的正侧面都看不到?
  78659. void main() {
  78660. float d = 1.0 - min(distance(cameraPosition.xy, worldPosition.xy) / uDistance, 1.0);
  78661. float g1 = getGrid(uSize1);
  78662. float g2 = getGrid(uSize2);
  78663. gl_FragColor = vec4(uColor.rgb, mix(g2, g1, g1) * pow(d, 3.0));
  78664. //gl_FragColor.a = mix(0.5 * gl_FragColor.a, gl_FragColor.a, g2);
  78665. gl_FragColor.a = mix(opacity1 * gl_FragColor.a, opacity2 * gl_FragColor.a, g2);
  78666. if ( gl_FragColor.a <= 0.0 ) discard;
  78667. }
  78668. `,
  78669. extensions: {
  78670. derivatives: true
  78671. }
  78672. });
  78673. super(geometry, material);
  78674. this.frustumCulled = false;
  78675. }
  78676. };
  78677. /*
  78678. THREE.InfiniteGridHelper.prototype = {
  78679. ...THREE.Mesh.prototype,
  78680. ...THREE.Object3D.prototype,
  78681. ...THREE.EventDispatcher.prototype
  78682. };
  78683. */
  78684. const texLoader$7 = new TextureLoader();
  78685. texLoader$7.crossOrigin = "anonymous";
  78686. const viewportProps$1 = [{
  78687. left:0,
  78688. bottom:0,
  78689. width: 0.5,height:1,
  78690. name : 'top',
  78691. axis:["x","y"],
  78692. direction : new Vector3(0,0,-1), //镜头朝向
  78693. active: true,
  78694. //相机位置在z轴正向
  78695. limitBound: new Box3(new Vector3(-Infinity,-Infinity, 1),new Vector3(Infinity,Infinity,5000)) //在地面以上
  78696. },
  78697. {
  78698. left:0.5,
  78699. bottom:0,
  78700. width: 0.5,height:1,
  78701. name : 'right',
  78702. axis:["y","z"],
  78703. direction : new Vector3(1,0,0),
  78704. active: true,
  78705. //相机位置在x轴负向 右下角屏
  78706. } ];
  78707. let MergeEditor = {
  78708. bus:new EventDispatcher(),
  78709. SplitScreen : new SplitScreen(),
  78710. init(){
  78711. {
  78712. let ground = this.ground = new InfiniteGridHelper(1, 10000, new Color('#fff'), 10000, 0.2, 0.3);
  78713. viewer.scene.scene.add(ground);
  78714. //再加两条线否则在正侧边看不到
  78715. let line1 = LineDraw.createLine([new Vector3(-10000, 0, 0),new Vector3(10000, 0, 0) ], {color:'#666', dontAlwaysSeen:true});
  78716. let line2 = LineDraw.createLine([new Vector3(0, -10000, 0),new Vector3(0, 10000, 0) ], {color:'#666', dontAlwaysSeen:true});
  78717. ground.renderOrder = line1.renderOrder + 1; //要比模型低,否则模型透明时效果不对
  78718. ground.add(line1);
  78719. ground.add(line2);
  78720. }
  78721. viewer.setControls(viewer.orbitControls);
  78722. viewer.mainViewport.view.fixZWhenPan = true;
  78723. viewer.addEventListener('global_single_click',(e)=>{
  78724. if(/* viewer.inputHandler.selection[0] ||//正在平移和旋转,不允许更换 */
  78725. viewer.scene.cameraAnimations.length || //正在播放
  78726. e.drag && e.drag.notPressMouse //在加测量线
  78727. //e.clickElement && e.clickElement != e.intersect.object
  78728. ){
  78729. return
  78730. }
  78731. if(e.intersect){
  78732. let object = e.intersect.object || e.intersect.pointcloud;
  78733. let objects = this.getAllObjects();
  78734. if(objects.includes(object)){
  78735. this.selectModel(object);
  78736. }else {
  78737. this.selectModel(null);
  78738. }
  78739. }else {
  78740. this.selectModel(null);
  78741. }
  78742. });
  78743. viewer.ssaaRenderPass.enabled = false;
  78744. viewer.outlinePass.enabled = true;
  78745. },
  78746. enterSplit(){
  78747. this.SplitScreen.splitStart(viewportProps$1);
  78748. viewer.setControls(viewer.fpControls);
  78749. viewer.viewports.find(e=>e.name == 'right').alignment = {rotateSide : true};
  78750. },
  78751. leaveSplit(){
  78752. this.SplitScreen.unSplit();
  78753. viewer.setControls(viewer.orbitControls);
  78754. },
  78755. rotateSideCamera(angle){
  78756. this.SplitScreen.rotateSideCamera(viewer.viewports.find(e=>e.name == 'right'), angle);
  78757. },
  78758. //---------------------------
  78759. getAllObjects(){
  78760. return viewer.objs.children.concat(viewer.scene.pointclouds)
  78761. },
  78762. getModel(id){
  78763. let models = this.getAllObjects();
  78764. return models.find(e=>e.dataset_id == id)
  78765. },
  78766. removeModel(model){
  78767. model.traverse(e=>{
  78768. e.geometry && e.geometry.dispose();
  78769. e.material && e.material.dispose();
  78770. });
  78771. viewer.objs.remove(model);
  78772. },
  78773. selectModel(model, state=true, fitBound, by2d){
  78774. if(!model) {
  78775. model = this.selected;
  78776. state = false;
  78777. }
  78778. if(state){
  78779. if(this.selected){
  78780. if(this.selected == model) return
  78781. else this.selectModel(this.selected, false, fitBound, by2d);
  78782. }
  78783. this.selected = model;
  78784. MergeEditor.focusOn(model, 500, !!fitBound); //通过在场景里点击模型的话,不focus
  78785. viewer.outlinePass.selectedObjects = [model];
  78786. if(model.isPointcloud){
  78787. viewer.outlinePass.edgeStrength = 4;
  78788. }else {
  78789. viewer.outlinePass.edgeStrength = 100;
  78790. }
  78791. //console.log('selectModel', model)
  78792. }else {
  78793. viewer.outlinePass.selectedObjects = [];
  78794. this.selected = null;
  78795. //console.log('selectModel', null)
  78796. }
  78797. if(!by2d && model){
  78798. model.dispatchEvent({type:'changeSelect', selected : state});
  78799. }
  78800. },
  78801. /* focusOn(object, duration = 400){
  78802. let boundingBox = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
  78803. let center = boundingBox.getCenter(new THREE.Vector3)
  78804. let size = boundingBox.getSize(new THREE.Vector3)
  78805. let maxSize = size.length() //对角线长度
  78806. if(object.isPointcloud){
  78807. maxSize /= 2
  78808. }
  78809. let hfov = cameraLight.getHFOVForCamera(viewer.mainViewport.camera,true)
  78810. let minRadius = maxSize / Math.tan(hfov/2)
  78811. //viewer.mainViewport.view.lookAt(center)
  78812. viewer.mainViewport.view.setView({
  78813. position: center.clone().sub(viewer.mainViewport.view.direction.clone().multiplyScalar(minRadius)),
  78814. target: center,
  78815. duration
  78816. }) //setView can cancel bump
  78817. }, */
  78818. focusOn(objects, duration = 400, fitBound=true){
  78819. if(!(objects instanceof Array)){
  78820. objects = [objects];
  78821. }
  78822. let boundingBox = new Box3;
  78823. objects.forEach(object=>{
  78824. boundingBox.union(object.boundingBox.clone().applyMatrix4(object.matrixWorld));
  78825. });
  78826. if(fitBound){
  78827. viewer.focusOnObject({boundingBox}, 'boundingBox', duration);
  78828. }else {
  78829. viewer.focusOnObject({position: boundingBox.getCenter(new Vector3)}, 'point', duration, {dontChangePos: true});
  78830. }
  78831. },
  78832. setModelBtmHeight(model, z ){
  78833. //无论模型怎么缩放、旋转,都使最低点为z
  78834. if(z == void 0) z = model.btmHeight; //维持离地高度
  78835. else model.btmHeight = z;
  78836. model.updateMatrixWorld();
  78837. let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld);
  78838. let size = boundingBox2.getSize(new Vector3);
  78839. let center = boundingBox2.getCenter(new Vector3);
  78840. let hopeZ = z + size.z / 2;
  78841. //model.position.z = z + size.z / 2 - center.z
  78842. model.position.z += (hopeZ - center.z);
  78843. },
  78844. computeBtmHeight(model){ //位移之后重新计算btmHeight
  78845. model.updateMatrixWorld();
  78846. let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld);
  78847. let size = boundingBox2.getSize(new Vector3);
  78848. let center = boundingBox2.getCenter(new Vector3);
  78849. model.btmHeight = center.z - size.z / 2;
  78850. },
  78851. maintainBoundXY(model){ //在旋转和缩放后,立即执行这个函数,使boundCenter保持原位
  78852. model.updateMatrixWorld();
  78853. let center1 = model.boundCenter.clone();//还未更新的
  78854. this.getBoundCenter(model);//更新
  78855. let center2 = model.boundCenter.clone();
  78856. let diff = new Vector2$1().subVectors(center1,center2);
  78857. model.position.x += diff.x;
  78858. model.position.y += diff.y;
  78859. /* model.updateMatrixWorld()
  78860. this.getBoundCenter(model)//再次更新,它需要和center1相同 */
  78861. model.boundCenter = center1;
  78862. },
  78863. moveBoundCenterTo(model,pos){ //使boundCenter在所要的位置
  78864. let diff = new Vector3().subVectors(pos, model.boundCenter);
  78865. model.position.add(diff);
  78866. },
  78867. getBoundCenter(model){
  78868. model.boundCenter = model.boundingBox.getCenter(new Vector3).applyMatrix4(model.matrixWorld);
  78869. }
  78870. };
  78871. const texLoader$8 = new TextureLoader();
  78872. const circleGeo = new CircleGeometry(1.45,100);
  78873. const sphereGeo = new SphereBufferGeometry(0.018,10,10);
  78874. const magDistance_ = 1;//相机离目标位置的距离的分界线,当离得远时要缩小fov以使看到的视野固定(望远镜效果)
  78875. /* const radius_ = 0.2; //当相机离目标位置的距离>magDistance_时,希望看到的视野的半径
  78876. const maxFov = THREE.Math.radToDeg(Math.atan(radius_ / magDistance_ )) * 2//提前计算出当相机离目标位置的距离<magDistance_时的fov,均使用=magDistance_时的fov。只要保证该fov大于主相机的fov就会有放大效果
  78877. */
  78878. let w$2 = 200/1.43;
  78879. let maxPX = 1366*1024; //ipad pro. 大于这个分辨率的就直接用devicePixelRatio, 如macbook也是
  78880. const width2dPX = Math.round(window.devicePixelRatio >= 2 ? ( window.screen.width * window.screen.height >= maxPX ? window.devicePixelRatio/1.2 : window.devicePixelRatio/1.5)*w$2 : w$2); //触屏或高分辨率的可能要放大些。但在手机上不能太大
  78881. console.log('width2dPX', width2dPX);
  78882. class Magnifier extends Object3D {//放大镜or望远镜
  78883. constructor (viewer) {
  78884. super();
  78885. this.width = this.height = width2dPX/* * window.devicePixelRatio */;
  78886. this.camera = new PerspectiveCamera(50, 1, 0.01, 10000); //fov aspect near far
  78887. this.camera.up = new Vector3(0,0,1);
  78888. this.viewport = new Viewport( null, this.camera, {
  78889. left:0, bottom:0, width:1, height: 1, name:'magnifier' , cameraLayers:['magnifierContent'],
  78890. pixelRatio:1
  78891. });
  78892. this.viewport.setResolution(this.width, this.height,0,0);
  78893. {
  78894. let density;
  78895. let sizeType;
  78896. let colorType;
  78897. let opacityBefore = new Map();
  78898. this.viewport.beforeRender = ()=>{
  78899. viewer.scene.pointclouds.forEach(e=>{//因为更改pointDensity时会自动变opacity,所以这项最先获取
  78900. opacityBefore.set(e,e.temp.pointOpacity);
  78901. });
  78902. //使放大镜里的pointDensity是'magnifier' 最高质量。
  78903. density = Potree.settings.pointDensity;
  78904. Potree.settings.pointDensity = 'magnifier';
  78905. viewer.scene.pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
  78906. sizeType = e.material.pointSizeType;
  78907. e.material.pointSizeType = Potree.config.material.pointSizeType;
  78908. //材质
  78909. colorType = e.material.activeAttributeName;
  78910. e.material.activeAttributeName = 'rgba';
  78911. e.changePointOpacity(1);
  78912. });
  78913. };
  78914. this.viewport.afterRender = ()=>{
  78915. Potree.settings.pointDensity = density;
  78916. viewer.scene.pointclouds.forEach(e=>{
  78917. e.material.pointSizeType = sizeType;
  78918. e.material.activeAttributeName = colorType;
  78919. e.changePointOpacity(opacityBefore.get(e));
  78920. });
  78921. };
  78922. }
  78923. this.renderTarget = new WebGLRenderTarget(this.width,this.height, {
  78924. minFilter: LinearFilter, magFilter: LinearFilter,
  78925. format: RGBAFormat ,
  78926. /* type: THREE.FloatType,
  78927. minFilter: THREE.NearestFilter,
  78928. magFilter: THREE.NearestFilter,
  78929. */
  78930. } );
  78931. this.rtEDL = new WebGLRenderTarget(this.width, this.height, { //好像没用到? 因为这里不绘制测量线
  78932. minFilter: NearestFilter,
  78933. magFilter: NearestFilter,
  78934. format: RGBAFormat,
  78935. type: FloatType,
  78936. depthTexture: new DepthTexture(undefined, undefined, UnsignedIntType)
  78937. });
  78938. this.mesh = new Mesh(circleGeo, new MeshBasicMaterial({
  78939. side: DoubleSide ,
  78940. map: this.renderTarget.texture ,
  78941. transparent:true,
  78942. depthTest: !1,
  78943. //depthWrite: !1,
  78944. }));
  78945. this.overlayMesh = new Mesh(circleGeo, new MeshBasicMaterial({
  78946. side: DoubleSide ,
  78947. map:texLoader$8.load(Potree.resourcePath+'/textures/crosshair.png') ,
  78948. transparent:true,
  78949. depthTest: !1,
  78950. //depthWrite: !1,
  78951. }));
  78952. this.targetPoint = new Object3D;
  78953. this.targetPoint.add(new Mesh(sphereGeo, new MeshBasicMaterial({
  78954. color:"#ff0000",
  78955. transparent:true,
  78956. opacity:0.5,
  78957. })));
  78958. this.targetPoint.add(new Mesh(sphereGeo, new MeshBasicMaterial({
  78959. color:"#ff0000",
  78960. transparent:true,
  78961. opacity:0.2,
  78962. depthTest:false //被遮挡层
  78963. })));
  78964. this.targetPoint.name = 'magnifierPointTarget';
  78965. viewer.scene.scene.add(this.targetPoint);
  78966. viewer.setObjectLayers(this.targetPoint, 'magnifierContent' );
  78967. this.add(this.mesh);
  78968. this.add(this.overlayMesh);
  78969. this.position.set(-1000,-1000,-100000);//令它看不见
  78970. this.mesh.renderOrder = 10;
  78971. this.overlayMesh.renderOrder = 11;
  78972. this.aimPos;
  78973. viewer.setObjectLayers(this, 'magnifier' );
  78974. //viewer.inputHandler.addInputListener(this)
  78975. viewer.addEventListener('camera_changed',(e)=>{ // 平移、滚轮时更新
  78976. if(e.viewport == viewer.mainViewport) this.update(); //不过intersectPoint没更新
  78977. });
  78978. this.mesh.layers.set(Potree.config.renderLayers.magnifier);
  78979. this.overlayMesh.layers.set(Potree.config.renderLayers.magnifier);
  78980. //this.layers.set(Potree.config.renderLayers.magnifier);//这句在外层写没用
  78981. this.dontRender = false;
  78982. viewer.addEventListener('global_drag', (e)=>{//拖拽时不渲染。主要是右键平移时渲染延迟了,会闪烁。
  78983. this.dontRender = true;
  78984. });
  78985. viewer.addEventListener('global_drop', (e)=>{
  78986. this.dontRender = false;
  78987. });
  78988. viewer.addEventListener('global_mouseup', (e)=>{//测量时拖拽场景再mouseup
  78989. this.dontRender = false;
  78990. });
  78991. var updateVisi = (e)=>{
  78992. if(e.hoverViewport == viewer.mainViewport){
  78993. viewer.updateVisible(this,"atViewport", true);
  78994. this.update(e.intersectPoint && e.intersectPoint.location);
  78995. }else {
  78996. viewer.updateVisible(this,"atViewport", false); //小地图不显示
  78997. }
  78998. };
  78999. viewer.addEventListener('global_mousemove', updateVisi);
  79000. viewer.addEventListener('global_touchstart', updateVisi);
  79001. /* viewer.addEventListener("beginSplitView",()=>{
  79002. this.updateVisible("splitView", false)
  79003. })
  79004. viewer.addEventListener("finishSplitView",()=>{
  79005. this.updateVisible("splitView", true)
  79006. }) */
  79007. this.addEventListener("setEnable",(e)=>{
  79008. viewer.updateVisible(this, "enable", e.value); //界面开关
  79009. /* if(Potree.settings.displayMode == 'showPanos') && e.value){
  79010. Potree.settings.pointDensity = 'magnifier'
  79011. }else if() */
  79012. });
  79013. if(Potree.settings.isOfficial){
  79014. viewer.updateVisible(this, "enable", false);
  79015. }else {
  79016. viewer.updateVisible(this, "measure", false);
  79017. viewer.addEventListener("measureMovePoint",()=>{//测量开始
  79018. viewer.updateVisible(this, "measure", true);
  79019. });
  79020. viewer.addEventListener("endMeasureMove",()=>{
  79021. viewer.updateVisible(this, "measure", false);
  79022. });
  79023. }
  79024. viewer.scene.view.addEventListener('flyingDone',()=>{
  79025. if(!this.visible)return
  79026. let pickWindowSize = 100;
  79027. let intersect = viewer.inputHandler.getIntersect(viewer.mainViewport, viewer.mainViewport.camera, true, pickWindowSize );
  79028. this.update(intersect && intersect.location);
  79029. });
  79030. }
  79031. //注意:在鼠标没有移动的时候,无法获取到最新的intersect, 放大镜内的内容可能是错误的。全景模式下更奇怪,原因未知
  79032. update(aimPos){//相机靠近 navvis的做法
  79033. var dontRender = this.dontRender || !(aimPos instanceof Vector3) || Potree.settings.displayMode == 'showPanos' && viewer.images360.flying;
  79034. aimPos = aimPos instanceof Vector3 ? aimPos : this.aimPos;
  79035. if(!aimPos || !this.visible)return
  79036. var playerCamera = viewer.scene.getActiveCamera();
  79037. var playerPos = playerCamera.position;//viewer.scene.view.getPivot()
  79038. var dis = playerPos.distanceTo(aimPos);
  79039. var dirToCamera = new Vector3().subVectors(playerPos, aimPos ).normalize();
  79040. //相机位置
  79041. var finalDisToAim = dis>magDistance_ ? magDistance_ : dis / 2;
  79042. this.camera.position.copy(aimPos).add(dirToCamera.multiplyScalar(finalDisToAim));
  79043. this.camera.lookAt(aimPos);
  79044. this.camera.fov = playerCamera.fov / 2;
  79045. this.camera.updateProjectionMatrix();
  79046. //自身位置
  79047. //let pos2d = viewer.inputHandler.pointer.clone(); //跟随鼠标
  79048. let pos2d = Potree.Utils.getPos2d(aimPos, playerCamera, viewer.renderArea, viewer.mainViewport).vector; //更新目标点的实时二维位置
  79049. let margin = 0.4, maxY = 0.4;
  79050. let screenPos = pos2d.clone().setY(pos2d.y + (pos2d.y>maxY ? -margin : margin ));
  79051. let newPos = new Vector3(screenPos.x,screenPos.y,0.8).unproject(playerCamera); //z:-1朝外
  79052. let dir = newPos.clone().sub(playerPos).normalize().multiplyScalar(10);//这个数值要大于playerCamera.near
  79053. let s = dis>magDistance_ ? 1 : dis / magDistance_ ;
  79054. this.position.copy(playerPos.clone().add(dir));
  79055. this.quaternion.copy(playerCamera.quaternion);
  79056. this.targetPoint.position.copy(aimPos);
  79057. this.targetPoint.scale.set(s,s,s);
  79058. this.aimPos = aimPos;
  79059. var scale = math.getScaleForConstantSize({//
  79060. width2d : width2dPX,
  79061. camera:viewer.scene.getActiveCamera(), position: this.getWorldPosition(new Vector3()),
  79062. resolution: viewer.mainViewport.resolution2
  79063. });
  79064. this.scale.set(scale, scale, scale);
  79065. if(!dontRender){
  79066. this.waitRender = true;
  79067. }
  79068. }
  79069. /* update(aimPos){ //仅改fov的版本
  79070. aimPos = aimPos instanceof THREE.Vector3 ? aimPos : this.aimPos
  79071. if(!aimPos || !this.visible)return
  79072. //相机位置
  79073. var playerCamera = viewer.scene.getActiveCamera()
  79074. var playerPos = playerCamera.position;//viewer.scene.view.getPivot()
  79075. var dis = playerPos.distanceTo(aimPos);
  79076. if(dis<magDistance_){
  79077. this.camera.fov = maxFov
  79078. }else{
  79079. this.camera.fov = THREE.Math.radToDeg(Math.atan(radius_ / dis )) * 2 //radius_是能看到的范围半径。当dis大于magDistance_时就放大,否则维持fov为maxFov
  79080. }
  79081. this.camera.updateProjectionMatrix()
  79082. this.camera.position.copy(playerPos)
  79083. this.camera.lookAt(aimPos)
  79084. this.quaternion.copy(playerCamera.quaternion);
  79085. let pointer = viewer.inputHandler.pointer.clone();
  79086. let margin = 0.4, maxY = 0.4
  79087. let screenPos = pointer.clone().setY(pointer.y + (pointer.y>maxY ? -margin : margin ))
  79088. let newPos = new THREE.Vector3(screenPos.x,screenPos.y,0.8).unproject(playerCamera); //z:-1朝外
  79089. let dir = newPos.clone().sub(playerPos).normalize().multiplyScalar(10);//这个数值要大于playerCamera.near
  79090. this.position.copy(playerPos.clone().add(dir))
  79091. this.aimPos = aimPos
  79092. this.targetPoint.position.copy(aimPos);
  79093. var scale = math.getScaleForConstantSize({//
  79094. width2d : width2dPX,
  79095. camera:viewer.scene.getActiveCamera(), position: this.getWorldPosition(new THREE.Vector3()),
  79096. resolution: viewer.mainViewport.resolution2
  79097. })
  79098. this.scale.set(scale, scale, scale);
  79099. if(!this.dontRender){
  79100. this.waitRender = true
  79101. }
  79102. }//位置需要计算,不仅仅是点云,所以需要深度图
  79103. */
  79104. render(){
  79105. if(!this.waitRender)return
  79106. //this.visible = false;//防止放大镜里有自己
  79107. viewer.render({
  79108. target : this.renderTarget,
  79109. viewports : [this.viewport],
  79110. camera : this.camera,
  79111. magnifier : true,
  79112. rtEDL: this.rtEDL
  79113. /* width :this.renderTarget.width,
  79114. height: this.renderTarget.height, */
  79115. });
  79116. //this.visible = true;
  79117. this.waitRender = false;
  79118. }
  79119. }
  79120. let texLoader$9 = new TextureLoader();
  79121. let defaultOpacity = 0.7;
  79122. //鼠标指示小圆片
  79123. class Reticule extends Mesh{
  79124. constructor(viewer){
  79125. var defaultTex = texLoader$9.load(Potree.resourcePath+'/textures/whiteCircle.png'/* reticule-256x256.png' */);
  79126. super(new PlaneBufferGeometry(0.11,0.11,1,1),new MeshBasicMaterial({
  79127. side: DoubleSide ,
  79128. map: defaultTex,
  79129. transparent:true,
  79130. depthTest: !1,
  79131. opacity: defaultOpacity,
  79132. //depthWrite: !1,
  79133. }));
  79134. this.name = 'reticule';
  79135. this.defaultTex = defaultTex;
  79136. this.crosshairTex = texLoader$9.load(Potree.resourcePath+'/textures/reticule_cross_hair.png');
  79137. this.forbitTex = texLoader$9.load(Potree.resourcePath+'/textures/pic-forbid.png');
  79138. //this.layers.set(0/* RenderLayers.RETICULE */);
  79139. this.renderOrder = 100;
  79140. this.layers.set(Potree.config.renderLayers.marker);
  79141. this.direction = new Vector3;
  79142. this.hidden = !0;
  79143. this.mouseLastMoveTime = Date.now();
  79144. this.hoverViewport;
  79145. this.matrixMap = new Map;
  79146. this.matrixAutoUpdate = false;
  79147. this.hide(0);
  79148. //viewer.inputHandler.addInputListener(this);
  79149. viewer.addEventListener('global_mousemove',this.move.bind(this));
  79150. //viewer.addEventListener('global_click',this.move.bind(this))
  79151. viewer.addEventListener('global_mousedown',this.move.bind(this));//主要针对触屏
  79152. this.state = {};
  79153. viewer.addEventListener('measureMovePoint',()=>{
  79154. this.state.cross = true;
  79155. this.judgeTex();
  79156. });
  79157. viewer.addEventListener('endMeasureMove',()=>{
  79158. this.state.cross = false;
  79159. this.judgeTex();
  79160. });
  79161. viewer.addEventListener('reticule_forbit',(e)=>{
  79162. if(this.state.forbit != e.v){
  79163. console.log('change forbit ',e.v);
  79164. }
  79165. this.state.forbit = e.v;
  79166. this.judgeTex();
  79167. });
  79168. viewer.setObjectLayers(this, 'sceneObjects' );
  79169. }
  79170. judgeTex(){
  79171. if(this.state.forbit){
  79172. this.material.map = this.forbitTex;
  79173. }else if(this.state.cross){
  79174. this.material.map = this.crosshairTex;
  79175. }else {
  79176. this.material.map = this.defaultTex;
  79177. }
  79178. viewer.mapViewer && viewer.mapViewer.dispatchEvent({type:'content_changed'});
  79179. }
  79180. move(e){
  79181. if(e.type == "global_mousemove" && (e.isTouch || e.buttons != Buttons.NONE) && this.state != 'crosshair'){
  79182. return//按下时不更新,除非拖拽测量
  79183. }
  79184. this.mouseLastMoveTime = Date.now();
  79185. this.updatePosition(e.intersect, e.hoverViewport);
  79186. }
  79187. hide(duration = 500){
  79188. if(this.hidden)return
  79189. this.hidden = !0;
  79190. transitions.start(lerp.property(this.material , "opacity", 0), duration);
  79191. this.dispatchEvent({type:'update', visible:false});
  79192. setTimeout(()=>{
  79193. this.dispatchEvent({type:'update', visible:false});
  79194. },duration);
  79195. }
  79196. show(duration = 300){
  79197. if(!viewer.getObjVisiByReason(this, 'force'))return
  79198. //console.log("show Reticule")
  79199. this.hidden = !1;
  79200. if(this.material.opacity <= 0){
  79201. transitions.start(lerp.property(this.material, "opacity", defaultOpacity), duration);
  79202. this.dispatchEvent({type:'update', visible:true});
  79203. setTimeout(()=>{
  79204. this.dispatchEvent({type:'update', visible:false});
  79205. },duration);
  79206. }
  79207. }
  79208. //鼠标静止一段时间它就会消失
  79209. updateVisible(){
  79210. Date.now() - this.mouseLastMoveTime > 1500 && !this.hidden && this.hide();
  79211. }
  79212. updateScale(viewport){
  79213. let s, camera = viewport.camera;
  79214. if(camera.type == "OrthographicCamera"){
  79215. var sizeInfo = this.state.cross ? {width2d:500} : {minSize : 100, maxSize : 400, nearBound : 100 , farBound : 700};
  79216. s = math.getScaleForConstantSize($.extend( sizeInfo ,
  79217. {position:this.position, camera, resolution:viewport.resolution/* 2 */} ));
  79218. }else {
  79219. let n = camera.position.distanceTo(this.position);
  79220. s = 1 + .01 * n;
  79221. n < 1 && (s -= 1 - n);
  79222. }
  79223. this.scale.set(s, s, s);
  79224. }
  79225. updateAtViewports(viewport){//当多个viewports时更新。更新大小等
  79226. if(viewport.name == 'magnifier' )return
  79227. if(this.hoverViewport && this.hoverViewport.name == 'mapViewport' && viewport != this.hoverViewport){
  79228. //若是在地图上更新,在其他viewport要隐藏。因为在地图上无法得知高度。
  79229. viewer.updateVisible(this, 'hoverMap', false);
  79230. return;
  79231. }
  79232. viewer.updateVisible(this, 'hoverMap', true);
  79233. var matrix = this.matrixMap.get(viewport);
  79234. if(!matrix){
  79235. this.updateScale(viewport);
  79236. this.updateMatrix();
  79237. //this.updateMatrixWorld()
  79238. this.matrixMap.set(viewport, this.matrix.clone());
  79239. }else {
  79240. this.matrix.copy(matrix);
  79241. //this.updateMatrixWorld()
  79242. }
  79243. }
  79244. updatePosition(intersect, viewport ){ //在地图(当地图融合到viewer时)和场景里都显示且完全相同(大小可能不同)
  79245. if (viewer.getObjVisiByReason(this, 'force')) {//没有被强制隐藏,如进入某个页面后强制不显示
  79246. if (!intersect /* || !intersect.point.normal */){
  79247. return //this.hide();
  79248. }
  79249. var atMap = !intersect.location;
  79250. let location = intersect.location || intersect.orthoIntersect.clone();
  79251. let normal;
  79252. //地图上要瞬间变化 , 因为要使needRender为true很麻烦
  79253. this.show(atMap ? 0 : 300);
  79254. if(atMap){
  79255. normal = new Vector3(0,0,1);//地图无normal
  79256. location.setZ(0);//低于相机高度即可
  79257. this.direction = normal.clone();
  79258. }else {
  79259. if(intersect.point){
  79260. if(intersect.pointcloud){
  79261. normal = new Vector3().fromArray(intersect.point.normal ).applyMatrix4( intersect.pointcloud.rotateMatrix );
  79262. }else {//mesh
  79263. normal = new Vector3().copy(intersect.point.normal).applyQuaternion(intersect.object.quaternion);
  79264. }
  79265. }else {
  79266. normal = intersect.normal; //when showPanos
  79267. }
  79268. if(normal){
  79269. let ratio = /* Potree.settings.useDepthTex ? 1 : */ 0.2;
  79270. this.direction = this.direction.multiplyScalar(1-ratio);
  79271. this.direction.add(normal.clone().multiplyScalar(ratio));
  79272. }
  79273. //this.direction = normal.clone() //改为瞬间变化,否则刚hover上某个点时看起来不太对
  79274. }
  79275. this.position.copy(location);/* .add(normal.clone().multiplyScalar(.01)); */
  79276. this.updateMatrix(); //lookAt之前要保证得到matrix
  79277. this.lookAt(this.position.clone().add(this.direction));
  79278. this.hoverViewport = viewport; //记录下最近一次hover过的viewport
  79279. this.updateScale(viewport);
  79280. {//存储matrix,节省计算
  79281. this.updateMatrix();
  79282. //this.updateMatrixWorld()
  79283. this.matrixMap.clear();//重新计算
  79284. this.matrixMap.set(viewport, this.matrix.clone());
  79285. //别处会updateMatrixWorld
  79286. }
  79287. this.dispatchEvent({type:'update'});
  79288. //为什么navvis在校准数据集时每个viewport里reticule的朝向都刚好垂直于屏幕,似乎限定在了一定范围内,还是在pick时就只pick范围内的点?
  79289. }
  79290. }
  79291. //navvis在地图等地方看reticule是有厚度的
  79292. /* updateMatrixWorld(force){
  79293. console.log('updateMatrixWorld', force)
  79294. super.updateMatrixWorld(force)
  79295. } */
  79296. }
  79297. const FEET_TO_INCHES_FACTOR = 12;
  79298. const EIGHTHS_SYMBOLS = ["", "⅛", "¼", "⅜", "½", "⅝", "¾", "⅞"];//eighths 八分之……
  79299. class UnitOfMeasurement{//转化单位工具
  79300. constructor(t, e, n, i){
  79301. this.name = t,
  79302. this.symbol = e,
  79303. this.base = n,
  79304. this.factor = i;
  79305. }
  79306. toBase(t) {//换算到base
  79307. return t * this.factor
  79308. }
  79309. fromBase(t) {//换算到当前
  79310. return t / this.factor
  79311. }
  79312. }
  79313. /* var o = function t(e) {
  79314. this.gettext = e,
  79315. t.METRIC = this.gettext("metric", void 0, "measurement system"),
  79316. t.IMPERIAL = this.gettext("imperial", void 0, "measurement system")
  79317. };
  79318. e.UoMSystem = o;
  79319. let UoMSystem = {
  79320. } */
  79321. /* var MeasurementDomain = {
  79322. DISTANCE : "DISTANCE",
  79323. t.AREA = "AREA",
  79324. t.VOLUME = "VOLUME",
  79325. t.DATA = "DATA",
  79326. t
  79327. }
  79328. */
  79329. var UnitsOfMeasurement = {
  79330. MILLIMETER : ["Millimeter", "mm"],
  79331. CENTIMETER : ["Centimeter", "cm"],
  79332. METER : ["Meter", "m"],
  79333. KILOMETER : ["Kilometer", "km"],
  79334. INCH : ["Inch", "in"],
  79335. FOOT : ["Foot", "ft"],
  79336. MILE : ["Mile", "mi"],
  79337. SQUAREMETER : ["SquareMeter", "m²"],
  79338. SQUAREFOOT : ["SquareFoot", "ft²"],
  79339. CUBICMETER : ["CubicMeter", "m³"],
  79340. CUBICFOOT : ["CubicFoot", "ft³"],
  79341. BYTE : ["Byte", "B"],
  79342. KILOBYTE : ["Kilobyte", "kB"],
  79343. MEGABYTE : ["Megabyte", "MB"],
  79344. GIGABYTE : ["Gigabyte", "GB"],
  79345. TERABYTE : ["Terabyte", "TB"],
  79346. PETABYTE : ["Petabyte", "PB"],
  79347. init : function() {
  79348. var e, n, i, a, s, c, l, u, d, p, h,
  79349. f = new UnitOfMeasurement(UnitsOfMeasurement.METER[0],UnitsOfMeasurement.METER[1],void 0,1),
  79350. g = new UnitOfMeasurement(UnitsOfMeasurement.SQUAREMETER[0],UnitsOfMeasurement.SQUAREMETER[1],void 0,1),
  79351. m = new UnitOfMeasurement(UnitsOfMeasurement.CUBICMETER[0],UnitsOfMeasurement.CUBICMETER[1],void 0,1),
  79352. v = new UnitOfMeasurement(UnitsOfMeasurement.BYTE[0],UnitsOfMeasurement.BYTE[1],void 0,1);
  79353. UnitsOfMeasurement.DISTANCE = (
  79354. (e = {})['metric'] = ((n = {})[UnitsOfMeasurement.MILLIMETER[0]] = new UnitOfMeasurement(UnitsOfMeasurement.MILLIMETER[0],UnitsOfMeasurement.MILLIMETER[1],f,.001),
  79355. n[UnitsOfMeasurement.CENTIMETER[0]] = new UnitOfMeasurement(UnitsOfMeasurement.CENTIMETER[0],UnitsOfMeasurement.CENTIMETER[1],f,.01),
  79356. n[UnitsOfMeasurement.METER[0]] = f,
  79357. n[UnitsOfMeasurement.KILOMETER[0]] = new UnitOfMeasurement(UnitsOfMeasurement.KILOMETER[0],UnitsOfMeasurement.KILOMETER[1],f,1e3),
  79358. n),
  79359. e['imperial'] = ((i = {})[UnitsOfMeasurement.INCH[0]] = new UnitOfMeasurement(UnitsOfMeasurement.INCH[0],UnitsOfMeasurement.INCH[1],f,.0254),
  79360. i[UnitsOfMeasurement.FOOT[0]] = new UnitOfMeasurement(UnitsOfMeasurement.FOOT[0],UnitsOfMeasurement.FOOT[1],f,.3048),
  79361. i[UnitsOfMeasurement.MILE[0]] = new UnitOfMeasurement(UnitsOfMeasurement.MILE[0],UnitsOfMeasurement.MILE[1],f,1609.344),
  79362. i),
  79363. e);
  79364. UnitsOfMeasurement.AREA = ((a = {})['metric'] = ((s = {})[UnitsOfMeasurement.SQUAREMETER[0]] = g,
  79365. s),
  79366. a['imperial'] = ((c = {})[UnitsOfMeasurement.SQUAREFOOT[0]] = new UnitOfMeasurement(UnitsOfMeasurement.SQUAREFOOT[0],UnitsOfMeasurement.SQUAREFOOT[1],g,.092903),
  79367. c),
  79368. a);
  79369. UnitsOfMeasurement.VOLUME = ((l = {})['metric'] = ((u = {})[UnitsOfMeasurement.CUBICMETER[0]] = m,
  79370. u),
  79371. l['imperial'] = ((d = {})[UnitsOfMeasurement.CUBICFOOT[0]] = new UnitOfMeasurement(UnitsOfMeasurement.CUBICFOOT[0],UnitsOfMeasurement.CUBICFOOT[1],m,.0283168),
  79372. d),
  79373. l);
  79374. //数据大小
  79375. var y = ((p = {})[UnitsOfMeasurement.BYTE[0]] = v,
  79376. p[UnitsOfMeasurement.KILOBYTE[0]] = new UnitOfMeasurement(UnitsOfMeasurement.KILOBYTE[0],UnitsOfMeasurement.KILOBYTE[1],v,1e3),
  79377. p[UnitsOfMeasurement.MEGABYTE[0]] = new UnitOfMeasurement(UnitsOfMeasurement.MEGABYTE[0],UnitsOfMeasurement.MEGABYTE[1],v,1e6),
  79378. p[UnitsOfMeasurement.GIGABYTE[0]] = new UnitOfMeasurement(UnitsOfMeasurement.GIGABYTE[0],UnitsOfMeasurement.GIGABYTE[1],v,1e9),
  79379. p[UnitsOfMeasurement.TERABYTE[0]] = new UnitOfMeasurement(UnitsOfMeasurement.TERABYTE[0],UnitsOfMeasurement.TERABYTE[1],v,1e12),
  79380. p[UnitsOfMeasurement.PETABYTE[0]] = new UnitOfMeasurement(UnitsOfMeasurement.PETABYTE[0],UnitsOfMeasurement.PETABYTE[1],v,1e15),
  79381. p);
  79382. UnitsOfMeasurement.DATA = ((h = {})['metric'] = y,
  79383. h['imperial'] = y,
  79384. h);
  79385. }
  79386. ,
  79387. getUnitsOfMeasurementByDomain : function(e) {
  79388. return this[e.toUpperCase()]
  79389. /* switch (e.toUpperCase()) {
  79390. case a.DISTANCE:
  79391. return t.DISTANCE;
  79392. case a.AREA:
  79393. return t.AREA;
  79394. case a.VOLUME:
  79395. return t.VOLUME;
  79396. case a.DATA:
  79397. return t.DATA;
  79398. default:
  79399. console.error(e + " measurement domain is not supported.")
  79400. } */
  79401. }
  79402. ,
  79403. getUnitsOfMeasurementByDomainAndSystem : function(domain, system) {
  79404. var r = this.getUnitsOfMeasurementByDomain(domain);
  79405. if (r.hasOwnProperty(system.toLowerCase()))
  79406. return r[system.toLowerCase()];
  79407. console.error(n + " measurement system is not supported.");
  79408. }
  79409. ,
  79410. getDefaultUnitByDomainAndSystem : function(e, n) {
  79411. switch (e.toUpperCase()) {
  79412. case 'DISTANCE':
  79413. switch (n.toLowerCase()) {
  79414. case 'metric':
  79415. return this.DISTANCE['metric'][this.METER[0]];
  79416. case 'imperial':
  79417. return this.DISTANCE['imperial'][this.FOOT[0]];
  79418. default:
  79419. console.error(n + " measurement system is not supported.");
  79420. }
  79421. case 'AREA':
  79422. switch (n.toLowerCase()) {
  79423. case 'metric':
  79424. return this.AREA['metric'][this.SQUAREMETER[0]];
  79425. case 'imperial':
  79426. return this.AREA['imperial'][this.SQUAREFOOT[0]];
  79427. default:
  79428. console.error(n + " measurement system is not supported.");
  79429. }
  79430. case 'VOLUME':
  79431. switch (n.toLowerCase()) {
  79432. case 'metric':
  79433. return this.VOLUME['metric'][this.CUBICMETER[0]];
  79434. case 'imperial':
  79435. return this.VOLUME['imperial'][this.CUBICFOOT[0]];
  79436. default:
  79437. console.error(n + " measurement system is not supported.");
  79438. }
  79439. case 'DATA':
  79440. switch (n.toLowerCase()) {
  79441. case 'metric':
  79442. return this.DATA['metric'][this.BYTE[0]];
  79443. case 'imperial':
  79444. return this.DATA['imperial'][this.BYTE[0]];
  79445. default:
  79446. console.error(n + " measurement system is not supported.");
  79447. }
  79448. default:
  79449. console.error(e + " measurement domain is not supported.");
  79450. }
  79451. }
  79452. };
  79453. class UnitService{
  79454. constructor(/* e, n, i */){
  79455. //this.LanguageService = e,
  79456. //this.localStorageService = n,
  79457. //this.gettext = i,
  79458. //this.unitChanged = new r.Signal,
  79459. this.LOCAL_STORAGE_KEY = "iv_unit_key";//?
  79460. UnitsOfMeasurement.init();
  79461. this.unitSystems = ['metric', 'imperial'];//[o.UoMSystem.METRIC, o.UoMSystem.IMPERIAL],
  79462. this.defaultSystem = 'metric';//'imperial'
  79463. //var a = this.LanguageService.getBrowserLocaleString().toLowerCase();
  79464. //this.defaultSystem = t.isLocaleImperial(a) ? o.UoMSystem.IMPERIAL : o.UoMSystem.METRIC,
  79465. //this.initUnit()
  79466. }
  79467. /* initUnit() {
  79468. var t = this.localStorageService.get(this.LOCAL_STORAGE_KEY);
  79469. if (t)
  79470. for (var e = 0, n = this.unitSystems; e < n.length; e++) {
  79471. var i = n[e];
  79472. if (i === t)
  79473. return void this.setUnit(i, !0)
  79474. }
  79475. this.setUnit(this.defaultSystem, !1)
  79476. }
  79477. setUnit(t, e) {
  79478. this.currentSystem !== t && (this.currentSystem = t,
  79479. this.unitChanged.emit()),
  79480. e && this.localStorageService.set(this.LOCAL_STORAGE_KEY, t)
  79481. } */
  79482. /*isLocaleImperial(e) {
  79483. return t.IMPERIAL_LOCALES.indexOf(e.toLowerCase()) >= 0
  79484. }
  79485. ,
  79486. t.IMPERIAL_LOCALES = ["en_us"],
  79487. t.ɵfac(e) {
  79488. return new (e || t)(c.ɵɵinject(l.LanguageService),
  79489. c.ɵɵinject("localStorageService"),c.ɵɵinject("gettext"))
  79490. }
  79491. ,
  79492. t.ɵprov = c.ɵɵdefineInjectable({
  79493. token: t,
  79494. factory: t.ɵfac,
  79495. providedIn: "root"
  79496. }), */
  79497. }
  79498. class UoMService{
  79499. constructor(/* UnitService */){
  79500. this.UnitService = new UnitService();/* UnitService */
  79501. }
  79502. scopedConvert (t, n, precision = 2, r, minFactor) {
  79503. return this.convert(t, n, precision, r, minFactor)
  79504. }
  79505. convert(number, domain, precision = 2, system, minFactor, ifEighths = !1) {
  79506. if (!number) return "";
  79507. var s = this.getMostRelevantMeasurement(domain, system || this.UnitService.currentSystem, number, minFactor);
  79508. return this.getFormattedMeasurementString(s[0], s[1], precision, ifEighths)
  79509. }
  79510. convertBack(number, domain, precision = 2, fromSystem, minFactor ) { //从英制转到'metric'
  79511. if (!number) return "";
  79512. var d = UnitsOfMeasurement.getDefaultUnitByDomainAndSystem(domain,'metric');
  79513. var s = this.getMostRelevantMeasurement2(domain, fromSystem, number, minFactor);
  79514. return this.getFormattedMeasurementString(s[0], d, precision )
  79515. /* 栗子:
  79516. viewer.unitConvert.convertBack(1, 'area', 5, 'imperial')
  79517. '0.09290 m²'
  79518. viewer.unitConvert.convertBack(1, 'Distance', 2, 'imperial')
  79519. '0.03 m'
  79520. */
  79521. }
  79522. getFormattedMeasurementString(number, unit, precision, ifEighths) {
  79523. var result;
  79524. if(ifEighths && unit.name === UnitsOfMeasurement.FOOT[0]){
  79525. result = this.formatImperialDistance(number * FEET_TO_INCHES_FACTOR);
  79526. }else if(ifEighths && unit.name === UnitsOfMeasurement.INCH[0]){
  79527. result = this.formatImperialDistance(number);
  79528. }else {
  79529. result = number.toLocaleString(void 0, {
  79530. minimumFractionDigits: precision,
  79531. maximumFractionDigits: precision
  79532. }) + " " + unit.symbol;
  79533. }
  79534. return result
  79535. }
  79536. formatImperialDistance(e) {
  79537. var n = Math.round(8 * e)
  79538. , i = Math.floor(n / 8)
  79539. , r = Math.floor(i / FEET_TO_INCHES_FACTOR)
  79540. , o = i - r * FEET_TO_INCHES_FACTOR
  79541. , a = EIGHTHS_SYMBOLS[n % 8]
  79542. , s = 0 === o && "" !== a ? "" : o;
  79543. "" !== s && "" !== a && (a = " " + a);
  79544. return 0 !== r ? r + "' " + s + a + '"' : "" + s + a + '"'
  79545. }
  79546. getMostRelevantMeasurement(domain, system, number, minFactor=0) {
  79547. /* var a = r.values(UnitsOfMeasurement.getUnitsOfMeasurementByDomainAndSystem(domain, system))
  79548. , s = r.filter(a, function(t) {
  79549. return t.factor >= i
  79550. })
  79551. , c = r.reduce(s, function(t, e) {
  79552. return e.fromBase(number) < t.fromBase(number) && e.fromBase(number) >= 1 ? e : t
  79553. }); */
  79554. let a = [];
  79555. let u = UnitsOfMeasurement.getUnitsOfMeasurementByDomainAndSystem(domain, system);
  79556. for(let i in u){a.push(u[i]);}
  79557. let s = a.filter(m=>m.factor >= minFactor);
  79558. let c = s.reduce(function(prev, currentValue) {//reduce最终值是最后一次return的值 ( 没看懂这句话作用)
  79559. return currentValue.fromBase(number) < prev.fromBase(number) && currentValue.fromBase(number) >= 1 ? currentValue : prev
  79560. });
  79561. return c ? [c.fromBase(number), c] : void 0
  79562. }
  79563. getMostRelevantMeasurement2(domain, system, number, minFactor=0) {//add
  79564. let a = [];
  79565. let u = UnitsOfMeasurement.getUnitsOfMeasurementByDomainAndSystem(domain, system);
  79566. for(let i in u){a.push(u[i]);}
  79567. let s = a.filter(m=>m.factor >= minFactor);
  79568. let c = s.reduce(function(prev, currentValue) {//reduce最终值是最后一次return的值 ( 没看懂这句话作用)
  79569. return currentValue.toBase(number) < prev.toBase(number) && currentValue.toBase(number) >= 1 ? currentValue : prev
  79570. });
  79571. return c ? [c.toBase(number), c] : void 0
  79572. }
  79573. /* ɵfac(e){
  79574. return new (e || t)(c.ɵɵinject(l.UnitService))
  79575. }
  79576. ɵprov = c.ɵɵdefineInjectable({
  79577. token: t,
  79578. factory: t.ɵfac,
  79579. providedIn: "root"
  79580. }) */
  79581. }
  79582. const texLoader$a = new TextureLoader();
  79583. const arrowSpacing = 1; //间隔
  79584. const arrowSize = arrowSpacing * 0.5;
  79585. const planeGeo$3 = new PlaneBufferGeometry(1,1);
  79586. const sphereSizeInfo = {
  79587. nearBound : 2, scale:arrowSize, restricMeshScale : true,
  79588. };
  79589. //const arrowsShowingCount = 25; //场景里最多展示多少个箭头
  79590. const arrowShowMinDis = 10;
  79591. class RouteGuider extends EventDispatcher{
  79592. constructor () {
  79593. super();
  79594. this.route = [];
  79595. this.curve = [];
  79596. this.scenePoints = [];
  79597. this.sceneMeshGroup = new Object3D;
  79598. this.mapMeshGroup = new Object3D;
  79599. this.generateDeferred;
  79600. viewer.addEventListener('loadPointCloudDone',this.init.bind(this));
  79601. this.lastResult;//保存上一个的结果,以便于反向
  79602. this.datasetIds = [];//起始和终点的datasetId
  79603. }
  79604. init(){
  79605. if(this.inited) return;
  79606. let zoom;
  79607. viewer.mapViewer.addEventListener('camera_changed', e => {
  79608. if(!this.routeStart || !this.routeEnd) return
  79609. var camera = e.viewport.camera;
  79610. Common.intervalTool.isWaiting('routeCameraInterval', ()=>{ //延时update,防止卡顿
  79611. if(camera.zoom != zoom){
  79612. //console.log('updateMapArrows')
  79613. this.updateMapArrows(true);
  79614. zoom = camera.zoom;
  79615. return true
  79616. }
  79617. }, browser.isMobile()?500:200);
  79618. });
  79619. //let lastPos = new THREE.Vector3
  79620. viewer.addEventListener('camera_changed', e => {
  79621. if(!this.routeStart || !this.routeEnd || !e.changeInfo.positionChanged) return
  79622. Common.intervalTool.isWaiting('routeCameraInterval', ()=>{ //延时update,防止卡顿
  79623. //let currPos = viewer.scene.getActiveCamera().position
  79624. //if(!currPos.equals(lastPos)){
  79625. // lastPos.copy(currPos)
  79626. this.updateArrowDisplay();
  79627. return true
  79628. //}
  79629. }, 1000);
  79630. });
  79631. var polesMats = {
  79632. shadowMat: new MeshBasicMaterial({
  79633. transparent:true, depthTest:false,
  79634. map: texLoader$a.load(Potree.resourcePath+'/textures/pano_instruction_bottomMarker.png' )
  79635. }),
  79636. sphereMat : new MeshBasicMaterial({
  79637. transparent:true, depthTest:false,
  79638. map: texLoader$a.load(Potree.resourcePath+'/textures/whiteCircle.png' )
  79639. }),
  79640. hatMats:{
  79641. start: new MeshBasicMaterial({
  79642. transparent:true, depthTest:false,
  79643. map: texLoader$a.load(Potree.resourcePath+'/textures/pano_instruction_start_route.png' )
  79644. }),
  79645. end: new MeshBasicMaterial({
  79646. transparent:true, depthTest:false,
  79647. map: texLoader$a.load(Potree.resourcePath+'/textures/pano_instruction_target_reached.png' )
  79648. })
  79649. }
  79650. };
  79651. polesMats.shadowMat.map.anisotropy = 4;
  79652. this.poleStart = this.createPole(polesMats, 'start');
  79653. this.poleEnd = this.createPole(polesMats, 'end');
  79654. this.sceneMeshGroup.add(this.poleStart);
  79655. this.sceneMeshGroup.add(this.poleEnd);
  79656. let map = texLoader$a.load(Potree.resourcePath+'/textures/routePoint_panorama.png' );
  79657. map.anisotropy = 4; // 各向异性过滤 .防止倾斜模糊
  79658. this.arrow = new Mesh(planeGeo$3, new MeshBasicMaterial({
  79659. transparent:true,
  79660. depthTest:false,
  79661. map
  79662. }));
  79663. this.arrow.scale.set(arrowSize,arrowSize,arrowSize);
  79664. viewer.setObjectLayers(this.arrow, 'sceneObjects' );
  79665. /* this.testArrow = this.arrow.clone();
  79666. this.testArrow.material = this.arrow.material.clone()
  79667. this.testArrow.material.color = 'red' */
  79668. this.arrows = new Object3D;
  79669. this.sceneMeshGroup.add(this.arrows);
  79670. viewer.setObjectLayers(this.sceneMeshGroup, 'sceneObjects' );
  79671. //this.sceneMeshGroup.traverse(e=>e.renderOrder = 90)
  79672. viewer.scene.scene.add(this.sceneMeshGroup);
  79673. this.sceneMeshGroup.visible = /* this.poleStart.visibile = this.poleEnd.visibile = */ false;
  79674. //-------------map---------------------
  79675. /* this.mapMarkStart = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
  79676. transparent:true, depthTest:false,
  79677. map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_start_route.png' )
  79678. }))
  79679. this.mapMarkEnd = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
  79680. transparent:true, depthTest:false,
  79681. map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_target_reached.png' )
  79682. }))
  79683. this.mapMarkStart.renderOrder = this.mapMarkEnd.renderOrder = 2//在箭头之上 */
  79684. let map2 = texLoader$a.load(Potree.resourcePath+'/textures/routePoint_map_fsna.png' );
  79685. this.mapArrowMats = {
  79686. default: new MeshBasicMaterial({
  79687. transparent:true, depthTest:false,
  79688. map:map2,
  79689. }),
  79690. fade: new MeshBasicMaterial({
  79691. transparent:true, depthTest:false,
  79692. map:map2,
  79693. opacity:0.4
  79694. }),
  79695. };
  79696. this.mapArrow = new Mesh( planeGeo$3, this.mapArrowMats.default);
  79697. this.mapArrow.scale.set(arrowSize,arrowSize,arrowSize);
  79698. this.mapArrows = new Object3D;
  79699. this.mapArrows.name = 'mapArrows';
  79700. this.mapMeshGroup.add(this.mapArrows);
  79701. this.mapMeshGroup.name = 'mapRouteLayer';
  79702. this.mapMeshGroup.visible = false;
  79703. viewer.mapViewer.dispatchEvent({type:'add', object:this.mapMeshGroup, name:'route'});
  79704. this.mapArrow.layers.mask = this.mapArrows.layers.mask; // 修改成和map中的layer一样的
  79705. viewer.modules.SiteModel.bus.addEventListener('FloorChange',()=>{
  79706. if(this.routeStart && this.routeEnd){
  79707. this.updateOpacityAtMap();
  79708. }
  79709. });
  79710. this.inited = true;
  79711. }
  79712. updateOpacityAtMap(){//只有当前楼层的透明度为1
  79713. var currentFloor = viewer.modules.SiteModel.currentFloor;
  79714. //console.log('updateOpacityAtMap', currentFloor && currentFloor.name)
  79715. const lift = 0.3; // 因为发送请求时用的是floorPosition的高度,而它可能会到画好的floor之下,所以有误差
  79716. this.mapArrows.children.forEach((arrow,index)=>{
  79717. let pos = this.mapPoints[index].clone();
  79718. pos.z += lift;
  79719. let inSide = currentFloor && currentFloor.ifContainsPoint(pos);
  79720. arrow.material = inSide ? this.mapArrowMats.default : this.mapArrowMats.fade;
  79721. //console.log('arrow',index, arrow.material.opacity)
  79722. });
  79723. viewer.mapViewer.dispatchEvent('content_changed');
  79724. }//但是如果楼层刚好只框柱相机位置而没框住地面位置就不好了……
  79725. createPole(polesMats, name){
  79726. const height = 1.5, sphereCount = 6, shadowSize = sphereSizeInfo.scale, sphereSize = 0.04;
  79727. var group = new Object3D;
  79728. group.name = 'pole_'+name;
  79729. var shadow = new Mesh(planeGeo$3,polesMats.shadowMat);
  79730. shadow.scale.set(shadowSize,shadowSize,shadowSize);
  79731. var sliceDis = height / (sphereCount+1);
  79732. group.add(shadow);
  79733. for(let i=0;i<sphereCount;i++){
  79734. var sphere = new Sprite$1({mat: polesMats.sphereMat});
  79735. sphere.position.set(0,0,sliceDis*(i+1));
  79736. sphere.scale.set(sphereSize,sphereSize,sphereSize);
  79737. sphere.visible = false;
  79738. group.add(sphere);
  79739. }
  79740. var hatSphere = new Sprite$1({mat: polesMats.hatMats[name], sizeInfo:sphereSizeInfo});
  79741. sphere.visible = false;
  79742. hatSphere.position.set(0,0,height);
  79743. hatSphere.scale.copy(shadow.scale);
  79744. group.add(hatSphere);
  79745. return group
  79746. }
  79747. addTestArrow(){
  79748. }
  79749. addArrow(position){
  79750. var arrow = this.arrow.clone();
  79751. arrow.position.copy(position);
  79752. this.arrows.add(arrow);
  79753. }
  79754. addMapArrow(position){
  79755. var mapArrow = this.mapArrow.clone();
  79756. mapArrow.position.copy(position).setZ(0);
  79757. this.mapArrows.add(mapArrow);
  79758. }
  79759. setArrowDir(arrows,index){
  79760. let arrow = arrows[index];
  79761. var nextOne = arrows[index+1];
  79762. var nextPos = nextOne ? nextOne.position : this.endPolePos; //routeEnd
  79763. var direction = new Vector3().subVectors(arrow.position, nextPos).setZ(0);
  79764. //direction.normalize();
  79765. //console.log(direction.toArray())
  79766. var angle = Math.atan2(direction.y, direction.x ) + Math.PI/2; //Math.PI/2是因为贴图本身箭头方向不朝x
  79767. arrow.rotation.z = angle;
  79768. //console.log(angle)
  79769. }
  79770. setRouteStart(pos, dealZ , datasetId ){
  79771. if(this.routeStart && pos && this.routeStart.equals(pos)) return //可能重复设置
  79772. this.routeStart = pos && new Vector3().copy(pos);
  79773. if(dealZ && this.routeStart){
  79774. this.routeStart.setZ(this.getZAtMap());
  79775. this.bus && this.bus.emit('reposStartMarker', this.routeStart);
  79776. }
  79777. console.log('setRouteStart',this.routeStart&&this.routeStart.toArray());
  79778. this.datasetIds[0] = datasetId;
  79779. //this.setStartPole(pos)
  79780. this.generateRoute();
  79781. }
  79782. setStartPole(pos){
  79783. this.startPolePos = pos;
  79784. this.bus && this.bus.emit('reposStartMarker', pos);
  79785. }
  79786. setRouteEnd(pos, dealZ , datasetId ){
  79787. if(this.routeEnd && pos && this.routeEnd.equals(pos)) return
  79788. this.routeEnd = pos && new Vector3().copy(pos);
  79789. if(dealZ && this.routeEnd){
  79790. this.routeEnd.setZ(this.getZAtMap());
  79791. this.bus && this.bus.emit('reposEndMarker', this.routeEnd);
  79792. }
  79793. console.log('setRouteEnd',this.routeEnd&&this.routeEnd.toArray());
  79794. this.datasetIds[1] = datasetId;
  79795. //this.setEndPole(pos)
  79796. this.generateRoute();
  79797. }
  79798. getZAtMap(){
  79799. //找到position.z与当前高度最接近的漫游点
  79800. let result = Common.sortByScore(viewer.images360.panos,[],[e=> -(Math.abs(e.position.z - viewer.images360.position.z)) ]);
  79801. let pano = result && result[0] && result[0].item;
  79802. return pano ? pano.floorPosition.z : viewer.bound.boundingBox.min.z + 1
  79803. //若在平面图上画实在得不到当前楼层的,大概率是楼层画得不好,那就只能去获取当前楼层的了
  79804. //navvis的高度取的是主视图所在楼层的中心高度(可能再高些)
  79805. }
  79806. setEndPole(pos){
  79807. this.endPolePos = pos;
  79808. this.bus && this.bus.emit('reposEndMarker', pos);
  79809. }
  79810. getSourceProjectionIndex(route) {//真正的起始
  79811. var e = route.findIndex(function(t) {
  79812. return t.instruction && t.instruction.type === 'source_projection_to_navgraph'
  79813. });
  79814. return e < 0 ? 0 : e
  79815. }
  79816. getDestinationProjectionIndex(route) {//真正的终点
  79817. var e = route.findIndex(function(t) {
  79818. return t.instruction && t.instruction.type === "destination_projection_to_navgraph"
  79819. });
  79820. return e < 0 ? route.length - 1 : e
  79821. }
  79822. generateRoute(){
  79823. if(!this.routeStart || !this.routeEnd){
  79824. return
  79825. }
  79826. //array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
  79827. let create = ()=>{
  79828. this.routeLength = this.route.reduce((total, currentValue, currentIndex, arr)=>{
  79829. if(currentIndex == 0)return 0
  79830. return total + currentValue.distanceTo(arr[currentIndex-1]);
  79831. },0);
  79832. let count = Math.max(2,Math.round(this.routeLength / arrowSpacing));//点数
  79833. const curve = new CatmullRomCurve3( this.route );
  79834. curve.curveType = 'chordal';//'centripetal' 'catmullrom'这个可能会超出路径外
  79835. this.curve = curve;
  79836. const scenePoints = curve.getSpacedPoints( count );//更平均
  79837. //const scenePoints = curve.getPoints( count );
  79838. scenePoints.splice(0,1);//去掉首尾
  79839. scenePoints.pop();
  79840. this.scenePoints = scenePoints;
  79841. this.updateMapArrows();
  79842. this.displayRoute();
  79843. {//map focus on this area
  79844. const minBound = new Vector2$1(1,1);//针对垂直线,在地图上只有一个点
  79845. let bound = new Box2;
  79846. this.route.forEach(e=>{
  79847. bound.expandByPoint(e);
  79848. });
  79849. let size = bound.getSize(new Vector2$1);
  79850. let markerSize = new Vector2$1(115,40); //起始和终点的标识呈长方形
  79851. let areaSize = viewer.mapViewer.viewports[0].resolution2;
  79852. let areaArea = areaSize.x * areaSize.y;
  79853. if(areaArea> 800 * 400){//是放大的
  79854. markerSize.multiplyScalar(areaArea / (800 * 400) /* / (size.x * size.y) */);
  79855. }
  79856. let margin = size.clone().divide(viewer.mapViewer.viewports[0].resolution2).multiply(markerSize); ///边距 重点是起始和终点的标识占据较大
  79857. size.add(margin);
  79858. let center = bound.getCenter(new Vector2$1);
  79859. size.x = Math.max(size.x, minBound.x );
  79860. size.y = Math.max(size.y, minBound.y );
  79861. let duration = 1000;
  79862. viewer.mapViewer.moveTo(center, size, duration);
  79863. }
  79864. this.bus.emit('gotResult', {dis:this.routeLength});
  79865. /* this.generateDeferred && this.generateDeferred.resolve({dis:this.routeLength})
  79866. this.generateDeferred = null */
  79867. };
  79868. if(Potree.fileServer){
  79869. let dealData = (data)=>{
  79870. if(!data.data){
  79871. console.log('没有数据');
  79872. let result;
  79873. if(data && data.code == 4002){
  79874. result = data;//正被修改数据集
  79875. }else if(this.routeStart.distanceTo(this.routeEnd) < 1){
  79876. result = { code: 500, msg: '距离太短,无法规划路线' };
  79877. }else {
  79878. result = { code: 500, msg: '超出数据集范围,无法规划路线' };
  79879. }
  79880. this.clearRoute();
  79881. this.setStartPole(this.routeStart);
  79882. this.setEndPole(this.routeEnd);
  79883. this.displayRoute(); //还是要显示一下起始
  79884. this.bus && this.bus.emit('gotResult', result );
  79885. return //this.generateDeferred && this.generateDeferred.resolve()
  79886. }
  79887. data = data.data;
  79888. this.clearRoute();
  79889. let length = data.length;
  79890. if(length < 2){//可能距离太短
  79891. console.log('路径点数为'+length+',直接取起点和终点连线');
  79892. this.route = [this.routeStart, this.routeEnd];
  79893. }else {
  79894. let startIndex = this.getSourceProjectionIndex(data);
  79895. let endIndex = this.getDestinationProjectionIndex(data);
  79896. let effectiveItems = data.slice(startIndex, endIndex + 1 );//只要点云范围内的点
  79897. effectiveItems.forEach((item,i)=>{
  79898. let pos = viewer.transform.lonlatToLocal.forward(item.location.slice(0));
  79899. pos = new Vector3().fromArray(pos);//.setZ(item.z)
  79900. this.route.push(pos);
  79901. });
  79902. console.log(this.route);
  79903. }
  79904. this.setStartPole(this.route[0]);
  79905. this.setEndPole(this.route[this.route.length-1]);
  79906. create();
  79907. /*
  79908. distance: 0.17581000000000116
  79909. distance_to_previous: 0.17581000000000116
  79910. id: 567
  79911. instruction: {type: 'source_projection_to_navgraph'}
  79912. latitude: 22.366605927999238
  79913. location: (3) [113.5957510575092, 22.366605927999238, -1.12419]
  79914. longitude: 113.5957510575092
  79915. z: -1.12419
  79916. */
  79917. };
  79918. if(this.lastResult && (this.lastResult.data || this.lastResult.data.code != 4002)){//正被修改数据集的话要重新计算
  79919. let data = Common.CloneObject(this.lastResult.data) , use; //直接用上次的结果
  79920. if(this.lastResult.routeStart.equals(this.routeStart) && this.lastResult.routeEnd.equals(this.routeEnd)){//和上次请求相同
  79921. use = true;
  79922. }else if(this.lastResult.routeStart.equals(this.routeEnd) && this.lastResult.routeEnd.equals(this.routeStart)){//..反向
  79923. use = true;
  79924. if(data.data){
  79925. data.data = this.lastResult.data.data.slice(0).reverse();
  79926. }
  79927. }
  79928. if(use){
  79929. console.log('直接用上次的结果');
  79930. return setTimeout(()=>{dealData(data);}, 1)//延迟是为了等待获得 RouteGuider.generateDeferred
  79931. }
  79932. }
  79933. let start = this.routeStart.clone();
  79934. let end = this.routeEnd.clone();
  79935. let startLonlat = viewer.transform.lonlatToLocal.inverse(start);
  79936. let endLonlat = viewer.transform.lonlatToLocal.inverse(end);
  79937. var query = {
  79938. source_longitude: startLonlat.x,
  79939. source_latitude: startLonlat.y,
  79940. source_z: start.z,
  79941. destination_longitude: endLonlat.x,
  79942. destination_latitude: endLonlat.y,
  79943. destination_z: end.z
  79944. };
  79945. //let url = `/laser/route/${Potree.settings.number}/getRoute/${this.datasetIds[0]}/${this.datasetIds[1]}?`
  79946. let url = `/laser/route/${Potree.settings.number}/getRoute/${Potree.settings.originDatasetId}?`;
  79947. for(let i in query){
  79948. url+= (i + '='+ query[i] +'&');
  79949. }
  79950. Potree.fileServer.get(url).then((data)=>{
  79951. console.log(data.data);
  79952. if(!this.routeStart || !this.routeEnd)return
  79953. this.lastResult = {//保存数据
  79954. routeStart : this.routeStart.clone(),
  79955. routeEnd: this.routeEnd.clone(),
  79956. data,
  79957. };
  79958. dealData(data);
  79959. });
  79960. }else {
  79961. //创个直线
  79962. /* const sliceDis = 1
  79963. let dis = this.routeStart.distanceTo(this.routeEnd);
  79964. let count = Math.max(2,Math.round(dis / sliceDis))//点数
  79965. let realSlideDis = dis / (count-1);
  79966. let dir = new THREE.Vector3().subVectors(this.routeEnd, this.routeStart).normalize().multiplyScalar(realSlideDis);
  79967. this.route = [this.routeStart];
  79968. for(let i=0;i<count-1;i++){
  79969. let lastOne = this.route[i];
  79970. this.route.push(new THREE.Vector3().addVectors(lastOne,dir))
  79971. }
  79972. this.route.splice(0,1) //route不用包含收尾 */
  79973. this.clearRoute();
  79974. this.route = [this.routeStart, this.routeEnd];
  79975. create();
  79976. }
  79977. }
  79978. updateMapArrows(ifReset){
  79979. if(this.route.length == 0)return
  79980. var zoom = viewer.mapViewer.camera.zoom;
  79981. let count = Math.max(2,Math.round(this.routeLength * zoom / arrowSpacing / 25));//点数
  79982. if(count == this.mapPoints.length+1)return//没变
  79983. const mapPoints = this.curve.getSpacedPoints( count );
  79984. mapPoints.splice(0,1);//去掉首尾
  79985. mapPoints.pop();
  79986. this.mapPoints = mapPoints;
  79987. var scale = 25/zoom;
  79988. this.mapArrow.scale.set(scale*0.6,scale*0.6,scale*0.6);
  79989. /* this.mapMarkStart.scale.set(scale,scale,scale)
  79990. this.mapMarkEnd.scale.set(scale,scale,scale) */
  79991. if(ifReset){//因为缩放而重新排布箭头
  79992. this.clearRoute({resetMap:true});
  79993. this.displayRoute({resetMap:true});
  79994. }
  79995. this.updateOpacityAtMap();
  79996. }
  79997. updateArrowDisplay(){//根据当前位置更新显示一定范围内的箭头'
  79998. if(this.scenePoints.length == 0)return
  79999. /* var a = Common.sortByScore(this.scenePoints , null, [(point)=>{ //是否还要再requires里限制最远距离?
  80000. var playerPos = viewer.scene.getActiveCamera().position.clone().setZ(0)
  80001. var pos = point.clone().setZ(0)
  80002. return -pos.distanceTo(playerPos);
  80003. }]);
  80004. //获得展示的起始点
  80005. let start = a[0].item
  80006. let startIndex = this.scenePoints.indexOf(start)
  80007. this.arrows.children.forEach((e,i)=>{
  80008. if(i<startIndex || i>startIndex+arrowsShowingCount)e.visible = false
  80009. else e.visible = true
  80010. }) */
  80011. let cameraPos = viewer.scene.getActiveCamera().position;
  80012. this.arrows.children.forEach((e,i)=>{
  80013. if(e.position.distanceTo(cameraPos) < arrowShowMinDis) e.visible = true;
  80014. else e.visible = false;
  80015. });
  80016. }
  80017. displayRoute(o={}){
  80018. if(!o.resetMap){
  80019. this.poleStart.position.copy(this.startPolePos || this.routeStart);
  80020. this.poleEnd.position.copy(this.endPolePos || this.routeEnd);
  80021. /* this.mapMarkStart.position.copy(this.routeStart).setZ(0)
  80022. this.mapMarkEnd.position.copy(this.routeEnd).setZ(0) */
  80023. this.scenePoints.forEach(e=>this.addArrow(e));
  80024. this.arrows.children.forEach((e,i)=>this.setArrowDir(this.arrows.children,i));
  80025. }
  80026. this.sceneMeshGroup.traverse(e=>e.visible = true);
  80027. this.mapMeshGroup.visible = true;
  80028. this.mapPoints.forEach(e=>this.addMapArrow(e));
  80029. this.mapArrows.children.forEach((e,i)=>this.setArrowDir(this.mapArrows.children,i));
  80030. viewer.mapViewer.dispatchEvent({'type':'content_changed'});
  80031. this.updateArrowDisplay();
  80032. }
  80033. clearRoute(o={}){
  80034. if(!o.resetMap){
  80035. this.routeLength = 0;
  80036. this.route = [];
  80037. this.scenePoints = [];
  80038. this.mapPoints = [];
  80039. let arrows = this.arrows.children.slice(0);
  80040. arrows.forEach(e=>{
  80041. this.arrows.remove(e);
  80042. });
  80043. }
  80044. let mapArrows = this.mapArrows.children.slice(0);
  80045. mapArrows.forEach(e=>{
  80046. this.mapArrows.remove(e);
  80047. });
  80048. this.sceneMeshGroup.traverse(e=>e.visible = false); //包括sprite也要设置,防止update
  80049. this.mapMeshGroup.visible = false;
  80050. viewer.mapViewer.dispatchEvent({'type':'content_changed'});
  80051. }
  80052. clear(){//退出
  80053. console.log('导航clear');
  80054. this.routeStart = null;
  80055. this.routeEnd = null;
  80056. this.clearRoute();
  80057. }
  80058. }
  80059. //大概每十米要花一秒
  80060. /*
  80061. 存在的问题:
  80062. 路径不准确。起始点和终点偏移。
  80063. */
  80064. const vertexShader = `
  80065. attribute float randam;
  80066. attribute float sprite;
  80067. attribute float centerHeight; //add
  80068. //uniform float fireHeight; //add
  80069. uniform float time;
  80070. uniform float size;
  80071. uniform float heightOfNearPlane;
  80072. //varying float heightRatio;
  80073. varying float vSprite;
  80074. varying float vOpacity;
  80075. float PI = 3.14;
  80076. float quadraticIn( float t )
  80077. {
  80078. float tt = t * t;
  80079. return tt * tt;
  80080. //变化曲线 越来越快
  80081. }
  80082. void main() {
  80083. float progress = fract( time + ( 2.0 * randam - 1.0 ) );
  80084. float progressNeg = 1.0 - progress;
  80085. float ease = quadraticIn( progress );
  80086. float influence = sin( PI * ease );
  80087. //vec3 newPosition = position * vec3( 1.0, 1.0 , ease);
  80088. vec3 newPosition = position;
  80089. newPosition.z = (newPosition.z - centerHeight) * ease + centerHeight;
  80090. gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
  80091. gl_PointSize = ( heightOfNearPlane * size ) / gl_Position.w;
  80092. vOpacity = min( influence * 4.0, 1.0 ) * progressNeg;
  80093. vSprite = sprite;
  80094. //heightRatio = (newPosition.z - centerHeight) / fireHeight ;
  80095. }
  80096. `;
  80097. const fragmentShader = `
  80098. uniform vec3 color;
  80099. uniform sampler2D u_sampler;
  80100. varying float vSprite;
  80101. varying float vOpacity;
  80102. //varying float heightRatio;
  80103. void main()
  80104. {
  80105. vec2 texCoord = vec2(gl_PointCoord.x * 0.25 + vSprite, gl_PointCoord.y);
  80106. gl_FragColor = vec4( texture2D( u_sampler, texCoord ).xyz * color * vOpacity, 1.0 );
  80107. }
  80108. `;
  80109. // import { vertexShader, fragmentShader } from './shaders'
  80110. let ONE_SPRITE_ROW_LENGTH = 0.25; //对应着色器的0.25
  80111. let texture;
  80112. const getTexture = ()=>{
  80113. if(!texture){
  80114. texture = new TextureLoader().load( Potree.resourcePath+'/textures/fire.png');
  80115. }
  80116. return texture
  80117. };
  80118. const boxGeo = new BoxBufferGeometry(1,1,1,1);
  80119. const boxMat = new MeshBasicMaterial({wireframe:true, color:"#ffffff"});
  80120. class FireParticle extends Points{
  80121. constructor (prop) {
  80122. super();
  80123. for ( var key in prop ){
  80124. this[key] = prop[key];
  80125. }
  80126. this.strength = this.strength || 1;
  80127. this.radius = prop.radius || 1;
  80128. this.height = prop.height || 5;
  80129. this.computeParams();
  80130. this.geometry = this.createGeometry( this.radius, this.height, this.particleCount );
  80131. if(this.color == void 0) this.color = 0xff3200;
  80132. this.createMaterial( ); //小蓝火:0x00338f
  80133. //---?:
  80134. this.velocity = new Vector3();
  80135. this.acceleration = new Vector3();
  80136. this.angle = 0;
  80137. this.angleVelocity = 0;
  80138. this.angleAcceleration = 0;
  80139. this.size = 16;
  80140. this.opacity = 1;
  80141. this.age = 0;
  80142. this.alive = 0;
  80143. this.sizeTween = null;
  80144. this.colorTween = null;
  80145. this.opacityTween = null;
  80146. this.setSize({viewport:viewer.mainViewport});
  80147. this.setFov(viewer.fov);
  80148. let setSize = (e)=>{
  80149. if(e.viewport.name != "MainView")return
  80150. this.setSize(e);
  80151. };
  80152. let setFov = (e)=>{
  80153. this.setFov(e.fov);
  80154. };
  80155. viewer.addEventListener('resize',setSize);
  80156. viewer.addEventListener('fov_changed',setFov);
  80157. this.addEventListener('dispose',()=>{
  80158. viewer.removeEventListener('resize',setSize);
  80159. viewer.removeEventListener('fov_changed',setFov);
  80160. });
  80161. }
  80162. computeParams(){
  80163. let length = (this.curve ? this.curve.wholeLength : 0) + this.radius * 2; //加上首尾的半径
  80164. const minSize = 0.3, maxSize = 3, minRadiusBound = 0.3, maxRadiusBound = 10;
  80165. this.size = minSize + (maxSize - minSize) * MathUtils.smoothstep(this.radius, minRadiusBound, maxRadiusBound);
  80166. //console.log('fire material particle size:', size )
  80167. this.particleCount = Math.ceil( length * Math.sqrt(this.strength * this.height ) * this.radius / (this.size * this.size) * 25 );
  80168. //console.log('fire particleCount',this.particleCount)
  80169. }
  80170. getPointsForBound(){
  80171. return this.boundPoints; //可以用于expand实时bound的点, 不含particle的size等边距
  80172. }
  80173. getBound(points){ // points为生成点(圆心)
  80174. this.boundPoints = [];
  80175. let boundingBox = new Box3();
  80176. let margin = this.size * 0.13 + 0.3;
  80177. points.forEach(bottom=>{
  80178. let top = bottom.clone();
  80179. top.z += this.height;
  80180. boundingBox.expandByPoint(bottom);
  80181. boundingBox.expandByPoint(top);
  80182. this.boundPoints.push(bottom,top);
  80183. });
  80184. let xyExpand = this.radius+margin;
  80185. boundingBox.expandByVector(new Vector3(xyExpand,xyExpand,margin));
  80186. this.boundingBox = boundingBox;
  80187. /* if(!this.debugBox){
  80188. this.debugBox = new THREE.Mesh(boxGeo, boxMat)
  80189. this.add(this.debugBox)
  80190. }
  80191. this.debugBox.scale.copy(boundingBox.getSize(new THREE.Vector3))
  80192. this.debugBox.position.copy(boundingBox.getCenter(new THREE.Vector3)) */
  80193. }
  80194. createGeometry( radius, height, particleCount){
  80195. let geometry = new BufferGeometry();
  80196. let count , points;
  80197. if(this.positions.length>1){
  80198. const spaceDis = 0.2;//间隔距离
  80199. count = Math.ceil(this.curve.wholeLength / spaceDis) + 1;
  80200. //console.log('count', count)
  80201. points = this.curve.getSpacedPoints( count ); //得到的数量会比count多一个
  80202. count = points.length;
  80203. //得到的点不太均匀,两端容易点少。
  80204. this.getBound(points);
  80205. }else {
  80206. this.getBound(this.positions);
  80207. }
  80208. var position = new Float32Array(particleCount * 3);
  80209. var randam = new Float32Array(particleCount);
  80210. var sprite = new Float32Array(particleCount);
  80211. var centerHeight = new Float32Array(particleCount);
  80212. for (var i = 0; i < particleCount; i++) {
  80213. var center = new Vector3().copy(this.positions.length>1 ? points[Math.floor(i/particleCount * count)] : this.positions[0]);
  80214. centerHeight[i] = center.z;
  80215. if (i === 0) {
  80216. // to avoid going out of Frustum
  80217. position[i * 3 + 0] = center.x;
  80218. position[i * 3 + 1] = center.y;
  80219. position[i * 3 + 2] = center.z;
  80220. }else {
  80221. var r = Math.sqrt(Math.random()) * radius;
  80222. var angle = Math.random() * 2 * Math.PI;
  80223. position[i * 3 + 0] = center.x + Math.cos(angle) * r;
  80224. position[i * 3 + 1] = center.y + Math.sin(angle) * r;
  80225. position[i * 3 + 2] = center.z + (radius - r) / radius * height/2 + height/2; //不太明白这句为什么能达到height高度
  80226. sprite[i] = 0.25 * (Math.random() * 4 | 0);
  80227. randam[i] = Math.random();
  80228. //center在底部
  80229. }
  80230. }
  80231. geometry.setAttribute('centerHeight', new BufferAttribute(centerHeight, 1));
  80232. geometry.setAttribute('position', new BufferAttribute(position, 3));
  80233. geometry.setAttribute('randam', new BufferAttribute(randam, 1));
  80234. geometry.setAttribute('sprite', new BufferAttribute(sprite, 1));
  80235. return geometry;
  80236. }
  80237. updateGeometry(){
  80238. this.computeParams();
  80239. this.geometry.dispose();
  80240. this.geometry = this.createGeometry( this.radius, this.height, this.particleCount );
  80241. this.material.uniforms.size.value = this.size;
  80242. }
  80243. createMaterial(){
  80244. const material = new ShaderMaterial( {
  80245. uniforms:{
  80246. color: { type: "c", value: new Color(this.color) },
  80247. size: { type: "f", value: this.size},
  80248. u_sampler: { type: "t", value: getTexture() },
  80249. time: { type: "f", value: 0.0 },
  80250. heightOfNearPlane: { type: "f", value:0}, //相对far ,以确保画面缩放时点的大小也会缩放
  80251. height :{ type: "f", value:this.height} ,
  80252. },
  80253. vertexShader,
  80254. fragmentShader,
  80255. blending: AdditiveBlending, //加法融合模式 glBlendFunc(GL_ONE, GL_ONE)
  80256. depthTest: true,
  80257. depthWrite: false,
  80258. transparent: true
  80259. } );
  80260. this.material = material;
  80261. this.setPerspective(this.fov, this.screenHeight);
  80262. }
  80263. setSize(e){
  80264. let viewport = e.viewport;
  80265. this.screenHeight = viewport.resolution.y;
  80266. this.setPerspective(this.fov, this.screenHeight);
  80267. }
  80268. setFov(fov){
  80269. this.fov = fov;
  80270. this.setPerspective(this.fov, this.screenHeight);
  80271. }
  80272. setPerspective(fov, height){
  80273. //this.uniforms.heightOfNearPlane.value = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5))));
  80274. let far = Math.abs(height / (2 * Math.tan(MathUtils.degToRad(fov * 0.5))));
  80275. this.material.uniforms.heightOfNearPlane.value = far;
  80276. }
  80277. update(delta){
  80278. if(!viewer.getObjVisiByReason(this,'force')){//被手动隐藏了
  80279. return
  80280. }
  80281. if(!Potree.Utils.isInsideFrustum(this.boundingBox, viewer.scene.getActiveCamera())){
  80282. viewer.updateVisible(this,'isInsideFrustum', false ); //不在视野范围
  80283. //console.log('unvi')
  80284. return
  80285. }else {
  80286. viewer.updateVisible(this,'isInsideFrustum', true );
  80287. }
  80288. delta *= 1;//更改速度
  80289. this.material.uniforms.time.value = (this.material.uniforms.time.value + delta) % 1;
  80290. }
  80291. dispose(){
  80292. this.geometry.dispose();
  80293. this.material.dispose();
  80294. this.dispatchEvent('dispose');
  80295. }
  80296. }
  80297. class Tween {
  80298. constructor(times, values) {
  80299. this.times = times || [];
  80300. this.values = values || [];
  80301. }
  80302. lerp(t) {
  80303. if(this.times.length == 0) return
  80304. let i = 0, n = this.times.length;
  80305. while(i < n && t > this.times[i]) i++;
  80306. if(i == 0) return this.values[0]
  80307. if(i == n) return this.values[n-1]
  80308. const ratio = (t - this.times[i-1]) / (this.times[i] - this.times[i-1]);
  80309. if(this.values[0] instanceof Vector3) {
  80310. return this.values[i-1].clone().lerp(this.values[i], ratio)
  80311. } else {
  80312. return this.values[i-1] + ratio * (this.values[i] - this.values[i-1])
  80313. }
  80314. }
  80315. clone () {
  80316. return Common.CloneClassObject(this)
  80317. }
  80318. }
  80319. class Particle$1{
  80320. constructor(prop={}){
  80321. this.position = new Vector3();
  80322. this.velocity = new Vector3(); // units per second
  80323. this.angle = 0;
  80324. this.angleVelocity = 0; // degrees per second
  80325. this.angleAcceleration = 0; // degrees per second, per second
  80326. this.size = 16.0;
  80327. this.color = new Color();
  80328. this.opacity = 1.0;
  80329. this.age = 0;
  80330. this.alive = 0; // use float instead of boolean for shader purposes
  80331. this.lastChangeVage = 0; //add
  80332. this.sizeTween = prop.sizeTween || new Tween( [0, 1], [32, 128] );
  80333. this.opacityTween = prop.opacityTween || new Tween( [0.8, 2], [0.5, 0] );
  80334. this.colorTween = prop.colorTween || new Tween( [0.4, 1], [ new Vector3(0,0,0.2), new Vector3(0, 0, 0.5) ] );
  80335. }
  80336. update(dt)
  80337. {
  80338. this.position.add(this.velocity.clone().multiplyScalar(dt));
  80339. this.velocity.multiplyScalar( 1+this.acceleration*dt );
  80340. // convert from degrees to radians: 0.01745329251 = Math.PI/180
  80341. this.angle += this.angleVelocity * 0.01745329251 * dt;
  80342. this.angleVelocity += this.angleAcceleration * 0.01745329251 * dt;
  80343. this.age += dt;
  80344. // if the tween for a given attribute is nonempty,
  80345. // then use it to update the attribute's value
  80346. if ( this.sizeTween.times.length > 0 )
  80347. this.size = this.sizeTween.lerp( this.age/this.deathAge );
  80348. if ( this.colorTween.times.length > 0 )
  80349. {
  80350. var colorHSL = this.colorTween.lerp( this.age/this.deathAge );
  80351. this.color = new Color().setHSL( colorHSL.x, colorHSL.y, colorHSL.z );
  80352. }
  80353. if ( this.opacityTween.times.length > 0 )
  80354. {
  80355. this.opacity = this.opacityTween.lerp( this.age/this.deathAge);
  80356. }
  80357. }
  80358. }
  80359. const vertexShader$1 = `
  80360. attribute vec3 customColor;
  80361. attribute float customOpacity;
  80362. attribute float customSize;
  80363. attribute float customAngle;
  80364. attribute float customVisible;
  80365. uniform float heightOfNearPlane;
  80366. varying vec4 vColor;
  80367. varying float vAngle;
  80368. void main()
  80369. {
  80370. if ( customVisible > 0.5 )
  80371. vColor = vec4( customColor, customOpacity );
  80372. else
  80373. vColor = vec4(0.0, 0.0, 0.0, 0.0);
  80374. vAngle = customAngle;
  80375. vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
  80376. //gl_PointSize = customSize * ( 300.0 / length( mvPosition.xyz ) );
  80377. gl_Position = projectionMatrix * mvPosition;
  80378. gl_PointSize = ( heightOfNearPlane * customSize ) / gl_Position.w;
  80379. }
  80380. `;
  80381. const fragmentShader$1 = `
  80382. uniform sampler2D u_sampler;
  80383. varying vec4 vColor;
  80384. varying float vAngle;
  80385. void main()
  80386. {
  80387. gl_FragColor = vColor;
  80388. float c = cos(vAngle);
  80389. float s = sin(vAngle);
  80390. vec2 rotatedUV = vec2(c * (gl_PointCoord.x - 0.5) + s * (gl_PointCoord.y - 0.5) + 0.5, c * (gl_PointCoord.y - 0.5) - s * (gl_PointCoord.x - 0.5) + 0.5);
  80391. vec4 rotatedTexture = texture2D( u_sampler, rotatedUV );
  80392. gl_FragColor = gl_FragColor * rotatedTexture;
  80393. }
  80394. `;
  80395. const Type = Object.freeze({ "CUBE":1, "SPHERE":2 });
  80396. let particleTexture;
  80397. const getTexture$1 = ()=>{
  80398. if(!particleTexture){
  80399. particleTexture = new TextureLoader().load( Potree.resourcePath+'/textures/smokeparticle.png');
  80400. }
  80401. return particleTexture
  80402. };
  80403. const boxGeo$1 = new BoxBufferGeometry(1,1,1,1);
  80404. const boxMat$1 = new MeshBasicMaterial({wireframe:true, color:"#ffffff"});
  80405. const defaults =
  80406. {
  80407. positions: [],
  80408. positionStyle : "sphere",
  80409. positionBase : new Vector3( 0, 0, 0 ),
  80410. positionSpread : new Vector3( 1, 1, 0), //cube
  80411. radius : 1, // sphere
  80412. velocityStyle : 'cube',
  80413. velocityBase : new Vector3( 0, 0, 0.5), // cube 基础速度
  80414. velocitySpread : new Vector3( 1, 1, 0.3),
  80415. accelerationBase : 0.3, //基础加速度
  80416. accelerationSpread : 0.6,
  80417. //没使用
  80418. speedBase : 0.1, //sphere
  80419. speedSpread : 0.5,
  80420. angleBase : 0,
  80421. angleSpread : 360,
  80422. angleVelocityBase : 1,
  80423. angleVelocitySpread : 30,
  80424. angleAccelerationBase : 1,
  80425. angleAccelerationSpread : 5,
  80426. sizeBase : 0,
  80427. sizeSpread : 0,
  80428. sizeTween : [[0, 0.3, 1], [0.3, 1.4, 6 ]],
  80429. colorBase : new Vector3(0.0, 1.0, 0.5),
  80430. colorSpread : new Vector3(0.0, 0.0, 0.0),
  80431. colorTween : new Tween( [0.2, 1], [ new Vector3(0,0,0.4), new Vector3(0, 0, 0.1) ] ),
  80432. opacityBase : 0.1,//1.0,
  80433. opacitySpread : 0.2,
  80434. opacityTween :[ [0, 0.1, 0.9, 1], [0.1, 0.4 , 0.03, 0 ] ],
  80435. //particlesPerSecond : 20,
  80436. strength : 1,
  80437. particleDeathAge : 3, //从底下升起后能持续的时间
  80438. //emitterDeathAge : 60 // time (seconds) at which to stop creating particles.
  80439. height : 3,
  80440. };
  80441. const debugSphere = new Mesh(new SphereBufferGeometry(0.03, 5,5), new MeshBasicMaterial({color:'white',depthTest:false}));
  80442. class SmokeParticle extends Points{
  80443. constructor(prop={}) {
  80444. super();
  80445. this.blendStyle = NormalBlending; // false;
  80446. this.emitterAge = 0.0;
  80447. //this.emitterAlive = true;
  80448. prop = $.extend({}, defaults, prop);
  80449. for ( var key in prop ){
  80450. let value = prop[key];
  80451. if(value instanceof Array && value[0] instanceof Array ) this[ key ] = new Tween(...value);
  80452. else if(value instanceof Vector3 || value instanceof Color){
  80453. this[ key ] = value.clone();
  80454. }else {
  80455. this[ key ] = value;
  80456. }
  80457. }
  80458. this.defaultSizeTween = this.sizeTween.clone();
  80459. this.defaultOpacityTween = this.opacityTween.clone();
  80460. this.geometry = new BufferGeometry();
  80461. this.computeParams();
  80462. this.createMaterial();
  80463. this.createGeometry();
  80464. this.dynamic = true;
  80465. this.sortParticles = true;
  80466. this.frustumCulled = false;//似乎是禁止相机裁剪,否则会在某些角度消失。但是会不会更耗性能呢?
  80467. prop.position && this.position.copy(prop.position);
  80468. //---------------------------------------
  80469. this.setSize({viewport:viewer.mainViewport});
  80470. this.setFov(viewer.fov);
  80471. let setSize = (e)=>{
  80472. if(e.viewport.name != "MainView")return
  80473. this.setSize(e);
  80474. };
  80475. let setFov = (e)=>{
  80476. this.setFov(e.fov);
  80477. };
  80478. /* let reStart = (e)=>{
  80479. if(e.v){//重新一个个放出粒子,否则会一股脑儿全部出来,因为同时大于粒子周期了一起重新生成出现。
  80480. setTimeout(()=>{//会先update一次delta为pageUnvisile的时间才触发
  80481. //console.log('归零')
  80482. //this.reStart()
  80483. },1)
  80484. }
  80485. } */
  80486. viewer.addEventListener('resize',setSize);
  80487. viewer.addEventListener('fov_changed',setFov);
  80488. //viewer.addEventListener('pageVisible', reStart)
  80489. this.addEventListener('dispose',()=>{
  80490. viewer.removeEventListener('resize',setSize);
  80491. viewer.removeEventListener('fov_changed',setFov);
  80492. //viewer.removeEventListener('pageVisible', reStart)
  80493. });
  80494. }
  80495. computeParams(){
  80496. let length = (this.curve ? this.curve.wholeLength : 0) + this.radius * 2; //加上首尾的半径
  80497. //注意:烟最低高度一米, 0<strength<1
  80498. if(this.positionStyle == 'cube'){
  80499. this.positionSpread.set(this.radius,this.radius,0);
  80500. }
  80501. this.velocityBase.set(0,0, (this.height - 0.5 * this.accelerationBase * this.particleDeathAge * this.particleDeathAge) / this.particleDeathAge );
  80502. //let height = this.velocityBase.z * this.particleDeathAge + 0.5 * this.accelerationBase * this.particleDeathAge * this.particleDeathAge;//s = V0 * t + 0.5 * a * t*t ;
  80503. this.velocityBase.z = Math.max(0,this.velocityBase.z);
  80504. this.particleCount = Math.ceil( length * Math.sqrt(this.strength * this.height * this.radius ) );
  80505. this.particleCount = Math.max(5,this.particleCount);
  80506. {
  80507. const minSize = 1, maxSize = 2, minBound = 0.01, maxBound = 1;
  80508. let size = minSize + (maxSize - minSize) * MathUtils.smoothstep( this.strength, minBound, maxBound);
  80509. this.sizeTween.values = this.defaultSizeTween.values.map(e=> e*size);
  80510. }
  80511. {
  80512. const minSize = 1 , maxSize = 1.5, minBound = 0.01, maxBound = 1;
  80513. let opac = minSize + (maxSize - minSize) * MathUtils.smoothstep( this.strength, minBound, maxBound);
  80514. this.opacityTween.values = this.defaultOpacityTween.values.map(e=> e*opac );
  80515. }
  80516. //console.log('smoke particleCount',this.particleCount)
  80517. }
  80518. reStart(){
  80519. this.emitterAge = 0;
  80520. this.createGeometry();
  80521. }
  80522. updateGeometry(){
  80523. this.computeParams();
  80524. this.reStart();
  80525. }
  80526. createParticle(center)
  80527. {
  80528. var particle = new Particle$1({
  80529. sizeTween : this.sizeTween,
  80530. opacityTween : this.opacityTween,
  80531. colorTween : this.colorTween,
  80532. });
  80533. particle.deathAge = this.particleDeathAge;
  80534. particle.center = center;
  80535. if (this.positionStyle == 'cube')
  80536. particle.position = this.randomVector3( this.positionBase, this.positionSpread );
  80537. if (this.positionStyle == 'sphere')
  80538. {
  80539. /* var z = 2 * Math.random() - 1
  80540. var t = Math.PI * 2 * Math.random();
  80541. var r = Math.sqrt( 1 - z*z ) ;
  80542. var vec3 = new THREE.Vector3( r * Math.cos(t), r * Math.sin(t), z );
  80543. particle.position = new THREE.Vector3().addVectors( this.positionBase, vec3.multiplyScalar( this.radius ) );
  80544. */
  80545. //怎么改半径
  80546. let y = 2 * Math.random() - 1;
  80547. let t = Math.PI * 2 * Math.random();
  80548. let r = Math.sqrt( 1 - y*y ) ; //因为 r*r = 1-y*y = x*x + z*z = r*r(cos^2 + sin^2 );
  80549. let lowDownRatio = 0.2; //压低近平面
  80550. let vec3 = new Vector3( r * Math.cos(t), y, Math.abs(r * Math.sin(t) ) * lowDownRatio);
  80551. particle.position = new Vector3().addVectors( this.positionBase, vec3.multiplyScalar( this.radius ) );
  80552. }
  80553. particle.position.add(center);//add
  80554. if ( this.velocityStyle == 'cube' )
  80555. {
  80556. particle.velocity = this.randomVector3( this.velocityBase, this.velocitySpread );
  80557. }
  80558. if ( this.velocityStyle == 'sphere' )
  80559. {
  80560. //var direction = particle.position.clone()
  80561. var direction = new Vector3(0,0,1); //烟应该都是向上的
  80562. var speed = this.randomValue( this.speedBase, this.speedSpread );
  80563. particle.velocity = direction.normalize().multiplyScalar( speed );
  80564. }
  80565. particle.acceleration = this.randomValue( this.accelerationBase, this.accelerationSpread );
  80566. particle.angle = this.randomValue( this.angleBase, this.angleSpread );
  80567. particle.angleVelocity = this.randomValue( this.angleVelocityBase, this.angleVelocitySpread );
  80568. particle.angleAcceleration = this.randomValue( this.angleAccelerationBase, this.angleAccelerationSpread );
  80569. particle.size = this.randomValue( this.sizeBase, this.sizeSpread );
  80570. var color = this.randomVector3( this.colorBase, this.colorSpread );
  80571. particle.color = new Color().setHSL( color.x, color.y, color.z );
  80572. particle.opacity = this.randomValue( this.opacityBase, this.opacitySpread );
  80573. particle.age = 0;
  80574. particle.alive = 0; // particles initialize as inactive
  80575. return particle;
  80576. }
  80577. getPointsForBound(){
  80578. return this.boundPoints; //可以用于expand实时bound的点, 不含particle的size等边距
  80579. }
  80580. getBound(points){ // points为生成点(圆心)
  80581. this.boundPoints = [];
  80582. let boundingBox = new Box3();
  80583. let maxSize = this.sizeTween.values.slice().sort((a,b)=>b-a)[0];
  80584. let margin0 = maxSize * 0.11;
  80585. let margin1 = margin0 + 0.5 ;//保守估计还会飘出这么多距离吧: size + 飘动
  80586. points.forEach(bottom=>{
  80587. let top = bottom.clone();
  80588. top.z += this.height;
  80589. boundingBox.expandByPoint(bottom);
  80590. boundingBox.expandByPoint(top);
  80591. this.boundPoints.push(bottom,top);
  80592. });
  80593. let xyExpand = this.radius+margin1;
  80594. boundingBox.expandByVector(new Vector3(xyExpand,xyExpand,0));
  80595. boundingBox.min.z -= margin0;
  80596. boundingBox.max.z += margin1;
  80597. this.boundingBox = boundingBox;
  80598. /* if(!this.debugBox){
  80599. this.debugBox = new THREE.Mesh(boxGeo, boxMat)
  80600. this.add(this.debugBox)
  80601. }
  80602. this.debugBox.scale.copy(boundingBox.getSize(new THREE.Vector3))
  80603. this.debugBox.position.copy(boundingBox.getCenter(new THREE.Vector3)) */
  80604. }
  80605. createGeometry(){
  80606. this.particleArray = [];
  80607. const positions = [];
  80608. const colors = [];
  80609. const alives = [];
  80610. const opacitys = [];
  80611. const sizes = [];
  80612. const angles = [];
  80613. let count, points;
  80614. if(this.positions.length>1){
  80615. const spaceDis = 0.6;//间隔距离
  80616. count = Math.ceil(this.curve.wholeLength / spaceDis) + 1;
  80617. points = this.curve.getSpacedPoints( count );
  80618. count = points.length;
  80619. /* points.forEach(e=> {
  80620. var sphere = debugSphere.clone();
  80621. sphere.position.copy(e)
  80622. viewer.scene.scene.add(sphere)
  80623. }) */
  80624. let haventGetPoints = points.slice();
  80625. var getRanPoints = function(i){
  80626. var a = Math.random();
  80627. let choseIndex = Math.floor(haventGetPoints.length * a);
  80628. var point = haventGetPoints[choseIndex];
  80629. if(haventGetPoints.length == 1){
  80630. haventGetPoints = points.slice();
  80631. }else {
  80632. haventGetPoints.splice(choseIndex, 1);
  80633. }
  80634. return point
  80635. };
  80636. this.getBound(points);
  80637. }else {
  80638. this.getBound(this.positions);
  80639. }
  80640. for (var i = 0; i < this.particleCount; i++)
  80641. {
  80642. var center = new Vector3().copy(this.positions.length>1 ? getRanPoints(i) : this.positions[0]);
  80643. //var center = new THREE.Vector3().copy(this.positions.length>1 ? points[Math.floor(i/this.particleCount * count)] : this.positions[0])
  80644. // remove duplicate code somehow, here and in update function below.
  80645. this.particleArray[i] = this.createParticle(center);
  80646. positions[3*i] = this.particleArray[i].position.x;
  80647. positions[3*i+1] = this.particleArray[i].position.y;
  80648. positions[3*i+2] = this.particleArray[i].position.z;
  80649. colors[3*i] = this.particleArray[i].color.r;
  80650. colors[3*i+1] = this.particleArray[i].color.g;
  80651. colors[3*i+2] = this.particleArray[i].color.b;
  80652. alives[i] = this.particleArray[i].alive;
  80653. opacitys[i] = this.particleArray[i].opacity;
  80654. sizes[i] = this.particleArray[i].size;
  80655. angles[i] = this.particleArray[i].angle;
  80656. }
  80657. this.geometry.setAttribute( 'position', new BufferAttribute( new Float32Array(positions), 3 ));
  80658. this.geometry.setAttribute( 'customColor', new BufferAttribute( new Float32Array(colors), 3 ) );
  80659. this.geometry.setAttribute( 'customVisible', new BufferAttribute( new Float32Array(alives), 1 ) );
  80660. this.geometry.setAttribute( 'customOpacity', new BufferAttribute( new Float32Array(opacitys), 1 ) );
  80661. this.geometry.setAttribute( 'customSize', new BufferAttribute( new Float32Array(sizes), 1 ) );
  80662. this.geometry.setAttribute( 'customAngle', new BufferAttribute( new Float32Array(angles), 1 ) );
  80663. }
  80664. createMaterial(){
  80665. this.material = new ShaderMaterial(
  80666. {
  80667. uniforms:
  80668. {
  80669. u_sampler: { type: "t", value: getTexture$1() },
  80670. heightOfNearPlane: { type: "f", value:0} //相对far ,以确保画面缩放时点的大小也会缩放
  80671. },
  80672. vertexShader: vertexShader$1,vertexShader: vertexShader$1,
  80673. fragmentShader: fragmentShader$1,
  80674. transparent: true,
  80675. alphaTest: 0.5, // if having transparency issues, try including: alphaTest: 0.5,
  80676. blending: this.blendStyle,
  80677. depthTest: this.blendStyle != NormalBlending
  80678. });
  80679. this.setPerspective(this.fov, this.screenHeight);
  80680. }
  80681. update(dt){
  80682. if(!viewer.getObjVisiByReason(this,'force')){//被手动隐藏了
  80683. return
  80684. }
  80685. if(!Potree.Utils.isInsideFrustum(this.boundingBox, viewer.scene.getActiveCamera())){
  80686. viewer.updateVisible(this,'isInsideFrustum', false ); //不在视野范围
  80687. //console.log('unvi')
  80688. return
  80689. }else {
  80690. viewer.updateVisible(this,'isInsideFrustum', true );
  80691. }
  80692. if(dt > 1){
  80693. console.log('update dt>1', dt);
  80694. }
  80695. //dt *= 0.5;
  80696. const recycleIndices = [];
  80697. const recycleAges = [];
  80698. const positions = [];
  80699. const colors = [];
  80700. const alives = [];
  80701. const opacitys = [];
  80702. const sizes = [];
  80703. const angles = [];
  80704. for (var i = 0; i < this.particleCount; i++)
  80705. {
  80706. if ( this.particleArray[i].alive )
  80707. {
  80708. if ( this.velocityStyle == 'cube' )
  80709. { //一定几率改变下方向
  80710. let ratio = Math.random();
  80711. if(this.particleArray[i].age - this.particleArray[i].lastChangeVage > this.particleDeathAge*ratio ){
  80712. this.particleArray[i].velocity = this.randomVector3( this.velocityBase, this.velocitySpread );
  80713. this.particleArray[i].lastChangeVage = this.particleArray[i].age;
  80714. }
  80715. }else {
  80716. /* if(this.particleArray[i].age - this.particleArray[i].lastChangeVage > this.particleDeathAge*0.3 ){
  80717. if( Math.random()>0.1){//一定几率改变下方向
  80718. var speed = this.randomValue( this.speedBase, this.speedSpread );
  80719. this.particleArray[i].velocity = this.randomVector3( new THREE.Vector3, new THREE.Vector3(1,1,1) );
  80720. this.particleArray[i].velocity.normalize().multiplyScalar( speed );
  80721. }
  80722. this.particleArray[i].lastChangeVage = this.particleArray[i].age
  80723. } */
  80724. }
  80725. this.particleArray[i].update(dt);
  80726. // check if particle should expire
  80727. // could also use: death by size<0 or alpha<0.
  80728. if ( this.particleArray[i].age > this.particleDeathAge )
  80729. {
  80730. this.particleArray[i].alive = 0.0;
  80731. recycleIndices.push(i);
  80732. recycleAges.push((this.particleArray[i].age - this.particleDeathAge)%(this.particleDeathAge ));
  80733. }
  80734. // update particle properties in shader
  80735. positions[3*i] = this.particleArray[i].position.x;
  80736. positions[3*i+1] = this.particleArray[i].position.y;
  80737. positions[3*i+2] = this.particleArray[i].position.z;
  80738. colors[3*i] = this.particleArray[i].color.r;
  80739. colors[3*i+1] = this.particleArray[i].color.g;
  80740. colors[3*i+2] = this.particleArray[i].color.b;
  80741. alives[i] = this.particleArray[i].alive;
  80742. opacitys[i] = this.particleArray[i].opacity;
  80743. sizes[i] = this.particleArray[i].size;
  80744. angles[i] = this.particleArray[i].angle;
  80745. }
  80746. }
  80747. // check if particle emitter is still running
  80748. //if ( !this.emitterAlive ) return;
  80749. this.geometry.setAttribute( 'position', new BufferAttribute( new Float32Array(positions), 3 ) );
  80750. this.geometry.setAttribute( 'customColor', new BufferAttribute( new Float32Array(colors), 3 ) );
  80751. this.geometry.setAttribute( 'customVisible', new BufferAttribute( new Float32Array(alives), 1 ) );
  80752. this.geometry.setAttribute( 'customOpacity', new BufferAttribute( new Float32Array(opacitys), 1 ) );
  80753. this.geometry.setAttribute( 'customSize', new BufferAttribute( new Float32Array(sizes), 1 ) );
  80754. this.geometry.setAttribute( 'customAngle', new BufferAttribute( new Float32Array(angles), 1 ) );
  80755. this.geometry.attributes.customColor.needsUpdate = true;
  80756. this.geometry.attributes.customVisible.needsUpdate = true;
  80757. this.geometry.attributes.customOpacity.needsUpdate = true;
  80758. this.geometry.attributes.customSize.needsUpdate = true;
  80759. this.geometry.attributes.customAngle.needsUpdate = true;
  80760. // if no particles have died yet, then there are still particles to activate
  80761. if ( this.emitterAge < this.particleDeathAge ) //开始时一个个放出来
  80762. {
  80763. let particlesPerSecond = this.particleCount / this.particleDeathAge;
  80764. // determine indices of particles to activate
  80765. var startIndex = Math.round( particlesPerSecond * (this.emitterAge + 0) );
  80766. var endIndex = Math.round( particlesPerSecond * (this.emitterAge + dt) );
  80767. if ( endIndex > this.particleCount )
  80768. endIndex = this.particleCount;
  80769. for (var i = startIndex; i < endIndex; i++)
  80770. this.particleArray[i].alive = 1.0;
  80771. }
  80772. // if any particles have died while the emitter is still running, we imediately recycle them
  80773. for (var j = 0; j < recycleIndices.length; j++)
  80774. {
  80775. var i = recycleIndices[j];
  80776. this.particleArray[i] = this.createParticle(this.particleArray[i].center);
  80777. this.particleArray[i].alive = 1.0; // activate right away
  80778. this.particleArray[i].age = recycleAges[j];
  80779. positions[3*i] = this.particleArray[i].position.x;
  80780. positions[3*i+1] = this.particleArray[i].position.y;
  80781. positions[3*i+2] = this.particleArray[i].position.z;
  80782. }
  80783. this.geometry.setAttribute( 'position', new BufferAttribute( new Float32Array(positions), 3 ) );
  80784. this.geometry.attributes.position.needsUpdate = true;
  80785. // stop emitter?
  80786. this.emitterAge += dt;
  80787. //if ( this.emitterAge > this.emitterDeathAge ) this.emitterAlive = false;
  80788. }
  80789. randomValue(base, spread)
  80790. {
  80791. //return base + spread * (Math.random() - 0.5);
  80792. let p = Math.random();
  80793. return base * p + spread * (1-p)
  80794. }
  80795. randomVector3(base, spread)
  80796. {
  80797. var rand3 = new Vector3( Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5 );
  80798. return new Vector3().addVectors( base, new Vector3().multiplyVectors( spread, rand3 ) );
  80799. }
  80800. setSize(e){
  80801. let viewport = e.viewport;
  80802. this.screenHeight = viewport.resolution.y;
  80803. this.setPerspective(this.fov, this.screenHeight);
  80804. }
  80805. setFov(fov){
  80806. this.fov = fov;
  80807. this.setPerspective(this.fov, this.screenHeight);
  80808. }
  80809. setPerspective(fov, height){
  80810. //this.uniforms.heightOfNearPlane.value = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5))));
  80811. let far = Math.abs(height / (2 * Math.tan(MathUtils.degToRad(fov * 0.5))));
  80812. this.material.uniforms.heightOfNearPlane.value = far;
  80813. }
  80814. dispose(){
  80815. this.geometry.dispose();
  80816. this.material.dispose();
  80817. this.dispatchEvent('dispose');
  80818. }
  80819. }
  80820. /*
  80821. 改进:如果有必要
  80822. 根据curve中分成的点,分成多个簇,每个簇掌管该部分的可见性和particle的数量。
  80823. 在camera_changed时根据远近修改每个簇的particle的数量,当然不会大于初始创建的个数。多出的随机隐藏。
  80824. */
  80825. const vertexShader$2 = `
  80826. attribute vec3 color;
  80827. attribute float size;
  80828. attribute float angle;
  80829. attribute float opacity;
  80830. attribute float visible;
  80831. varying vec4 vColor;
  80832. varying float vAngle;
  80833. uniform float heightOfNearPlane;
  80834. void main() {
  80835. if(visible > 0.5) {
  80836. vColor = vec4(color, opacity);
  80837. } else {
  80838. vColor = vec4(0.0, 0.0, 0.0, 0.0);
  80839. }
  80840. vAngle = angle;
  80841. vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
  80842. gl_Position = projectionMatrix * mvPosition;
  80843. gl_PointSize = ( heightOfNearPlane * size ) / gl_Position.w;
  80844. }
  80845. `;
  80846. const fragmentShader$2 = `
  80847. uniform sampler2D u_sampler;
  80848. varying vec4 vColor;
  80849. varying float vAngle;
  80850. void main() {
  80851. gl_FragColor = vColor;
  80852. float u = cos(vAngle);
  80853. float v = sin(vAngle);
  80854. vec2 uv = vec2(
  80855. u * (gl_PointCoord.x - 0.5) + v * (gl_PointCoord.y - 0.5) + 0.5,
  80856. u * (gl_PointCoord.y - 0.5) - v * (gl_PointCoord.x - 0.5) + 0.5
  80857. );
  80858. vec4 texture = texture2D(u_sampler, uv);
  80859. gl_FragColor = gl_FragColor * texture;
  80860. }
  80861. `;
  80862. // import { vertexShader, fragmentShader } from './shader'
  80863. const DEG2RAD = Math.PI / 180;
  80864. class Particle$2 {
  80865. constructor() {
  80866. this.position = new Vector3();
  80867. this.velocity = new Vector3();
  80868. this.angle = 0;
  80869. this.angleVelocity = 0;
  80870. this.angleAcceleration = 0;
  80871. this.size = 16;
  80872. this.color = new Color();
  80873. this.opacity = 1;
  80874. this.rebornCount = 0;//重生次数
  80875. this.age = 0;
  80876. this.alive = 0; //注意,一开始时是未出生的
  80877. this.deadAge = 0;//已死亡时间
  80878. this.sizeTween = null;
  80879. this.colorTween = null;
  80880. this.opacityTween = null;
  80881. }
  80882. update(dt) {
  80883. //s = s0 + (v0 + at) * t 或 lastS + delta(vt)
  80884. this.position.add(this.velocity.clone().multiplyScalar(dt));
  80885. this.velocity.multiplyScalar( 1+this.acceleration*dt );
  80886. this.angle += this.angleVelocity * DEG2RAD * dt;
  80887. this.angleVelocity += this.angleAcceleration * DEG2RAD * dt;
  80888. this.age += dt;
  80889. if(this.sizeTween.times.length > 0) {
  80890. this.size = this.sizeTween.lerp(this.age/this.deathAge);
  80891. }
  80892. if(this.colorTween.times.length > 0) {
  80893. const colorHSL = this.colorTween.lerp(this.age/this.deathAge);
  80894. this.color = new Color().setHSL(colorHSL.x, colorHSL.y, colorHSL.z);
  80895. }
  80896. if(this.opacityTween.times.length > 0) {
  80897. this.opacity = this.opacityTween.lerp(this.age/this.deathAge);
  80898. }
  80899. }
  80900. }
  80901. class Util {
  80902. constructor() {}
  80903. randomValue(min, max) {
  80904. //return min + max * (Math.random() - 0.5)
  80905. let p = Math.random();
  80906. return min * p + max * (1-p)
  80907. }
  80908. randomVector3(min, max) {
  80909. const rand3 = new Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5);
  80910. return new Vector3().addVectors(min, new Vector3().multiplyVectors(max, rand3))
  80911. }
  80912. }
  80913. const util$1 = new Util();
  80914. const Shape$1 = {
  80915. CUBE: 1,
  80916. SPHERE: 2
  80917. };
  80918. let particleTexture$1;
  80919. const getTexture$2 = ()=>{
  80920. if (!particleTexture$1) {
  80921. particleTexture$1 = new TextureLoader().load(Potree.resourcePath + '/textures/explode.png');
  80922. }
  80923. return particleTexture$1
  80924. };
  80925. const sphereGeo$1 = new SphereBufferGeometry(1, 10,4);
  80926. const sphereMat = new MeshBasicMaterial({wireframe:true, color:"#ffffff"});
  80927. const defaults$1 = {
  80928. position: new Vector3(0,0,1),
  80929. positionShape: Shape$1.SPHERE,
  80930. positionRange: new Vector3(1,1,1),
  80931. //cube
  80932. radius: 1.3,
  80933. //sphere
  80934. velocityShape: Shape$1.SPHERE,
  80935. velocity: new Vector3(0,0,2),
  80936. //cube
  80937. velocityRange: new Vector3(0,0,3),
  80938. //sphere
  80939. speed: 0.4,
  80940. speedRange: 1,
  80941. size: 0.4,
  80942. sizeRange: 2,
  80943. //sizeTween: new Tween( [0, 0.05, 0.3, 0.45], [0, 1, 3, 0.1] ),
  80944. sizeTween: [[0, 0.04, 0.2, 1],[0.1, 1, 6, 8]] ,
  80945. color: new Vector3(1.0,1.0,1.0),
  80946. colorRange: new Vector3(0,0,0),
  80947. colorTween: new Tween(),
  80948. opacity: 1.0,
  80949. opacityRange: 0.0,
  80950. opacityTween: new Tween([0, 0.06, 0.3, 0.8, 1],[0, 1, 0.3, 0.05, 0]),
  80951. blendMode: AdditiveBlending,
  80952. acceleration: 0.5,
  80953. accelerationRange: 0,
  80954. angle: 0,
  80955. angleRange: 0,
  80956. angleVelocity: 0,
  80957. angleVelocityRange: 0,
  80958. angleAcceleration: 0,
  80959. angleAccelerationRange: 0,
  80960. strength:1,
  80961. //particlesPerSecond: 8,
  80962. particleDeathAge: 0.7 ,
  80963. recycleTimes : 3 , //每个粒子在一次爆炸后循环次数,循环完毕进入particleSpaceTime,等待下一次爆炸.
  80964. //爆炸时长: particleDeathAge * (recycleTimes+1)
  80965. particleSpaceTime: 3, //间隔
  80966. };
  80967. class ExplodeParticle extends Points {
  80968. constructor(params) {
  80969. super();
  80970. this.age = 0;
  80971. this.alive = true;
  80972. //this.deathAge = 60
  80973. this.loop = true;
  80974. this.blendMode = NormalBlending;
  80975. this.setParameters(params);
  80976. this.createParticles();
  80977. this.frustumCulled = false;//似乎是禁止相机裁剪,否则会在某些角度消失。但是会不会更耗性能呢?
  80978. //------------------------------------
  80979. this.setSize({viewport:viewer.mainViewport});
  80980. this.setFov(viewer.fov);
  80981. let setSize = (e)=>{
  80982. if(e.viewport.name != "MainView")return
  80983. this.setSize(e);
  80984. };
  80985. let setFov = (e)=>{
  80986. this.setFov(e.fov);
  80987. };
  80988. /* let reStart = (e)=>{
  80989. if(e.v){//重新一个个放出粒子,否则会一股脑儿全部出来,因为同时大于粒子周期了一起重新生成出现。
  80990. setTimeout(()=>{//会先update一次delta为pageUnvisile的时间才触发
  80991. //console.log('归零')
  80992. //this.reStart()
  80993. },1)
  80994. }
  80995. } */
  80996. viewer.addEventListener('resize',setSize);
  80997. viewer.addEventListener('fov_changed',setFov);
  80998. //viewer.addEventListener('pageVisible', reStart)
  80999. this.addEventListener('dispose',()=>{
  81000. viewer.removeEventListener('resize',setSize);
  81001. viewer.removeEventListener('fov_changed',setFov);
  81002. //viewer.removeEventListener('pageVisible', reStart)
  81003. });
  81004. }
  81005. computeParams(){
  81006. if(this.curve){
  81007. this.position.copy(this.curve.points[0]);
  81008. }
  81009. const minSize = 0.8, maxSize = 10, minRadiusBound = 0.2, maxRadiusBound = 20;
  81010. let size = minSize + (maxSize - minSize) * MathUtils.smoothstep(this.radius*this.strength , minRadiusBound, maxRadiusBound);
  81011. this.sizeTween.values = this.defaultSizeTween.values.map(e=> e*size);
  81012. this.particleCount = Math.ceil( this.strength * this.radius * 5 /* * this.radius * this.radius */ );
  81013. this.speed = defaults$1.speed * this.radius;
  81014. this.speedRange = defaults$1.speedRange * this.radius;
  81015. console.log(this.particleCount);
  81016. {
  81017. this.boundPoints = [];
  81018. this.boundPoints.push(this.position.clone());
  81019. let maxSize = this.sizeTween.values.slice().sort((a,b)=>b-a)[0];
  81020. let margin = maxSize * 0.35 + 0.5;
  81021. let scale = this.radius+margin;
  81022. let sphere = new Sphere(this.position, scale);//加上防止剪裁
  81023. this.boundingSphere = sphere; //虽然还是会有一些后续移动的会超出
  81024. this.boundingBox = new Box3().setFromCenterAndSize(this.position, new Vector3(scale*2,scale*2,scale*2));
  81025. /* if(!this.debugSphere){
  81026. this.debugSphere = new THREE.Mesh(sphereGeo, sphereMat)
  81027. this.add(this.debugSphere)
  81028. }
  81029. this.debugSphere.scale.set(scale,scale,scale) */
  81030. }
  81031. }
  81032. getPointsForBound(){
  81033. return this.boundPoints; //可以用于expand实时bound的点, 不含particle的size等边距
  81034. }
  81035. reStart(){
  81036. this.age = 0;
  81037. this.createParticles();
  81038. }
  81039. setParameters(params) {
  81040. params = $.extend({}, defaults$1, params);
  81041. for (var key in params) {
  81042. let value = params[key];
  81043. if (key == 'position')
  81044. this.position.copy(value);
  81045. else if (value instanceof Array && value[0]instanceof Array){
  81046. this[key] = new Tween(...value);
  81047. }else if(value instanceof Vector3 || value instanceof Color){
  81048. this[ key ] = value.clone();
  81049. }else {
  81050. this[key] = value;
  81051. }
  81052. }
  81053. this.defaultSizeTween = this.sizeTween.clone();
  81054. //Object.assign(this, params)
  81055. this.particles = [];
  81056. this.age = 0.0;
  81057. this.alive = true;
  81058. this.geometry = new BufferGeometry();
  81059. this.computeParams();
  81060. this.material = new ShaderMaterial({
  81061. uniforms: {
  81062. u_sampler: {
  81063. value: this.texture || getTexture$2()
  81064. },
  81065. heightOfNearPlane: {
  81066. type: "f",
  81067. value: 0
  81068. }//相对far ,以确保画面缩放时点的大小也会缩放
  81069. },
  81070. vertexShader: vertexShader$2,
  81071. fragmentShader: fragmentShader$2,
  81072. transparent: true,
  81073. alphaTest: 0.5,
  81074. depthTest: this.blendMode == NormalBlending,
  81075. blending: this.blendMode
  81076. });
  81077. }
  81078. createParticles() {
  81079. this.particles = [];
  81080. const count = this.particleCount;
  81081. const positionArray = new Float32Array(count * 3);
  81082. const colorArray = new Float32Array(count * 3);
  81083. const sizeArray = new Float32Array(count);
  81084. const angleArray = new Float32Array(count);
  81085. const opacityArray = new Float32Array(count);
  81086. const visibleArray = new Float32Array(count);
  81087. for (let i = 0; i < count; i++) {
  81088. const particle = this.createParticle();
  81089. /* positionArray[i * 3] = particle.position.x
  81090. positionArray[i * 3 + 1] = particle.position.y
  81091. positionArray[i * 3 + 2] = particle.position.z
  81092. colorArray[i * 3] = particle.color.r
  81093. colorArray[i * 3 + 1] = particle.color.g
  81094. colorArray[i * 3 + 2] = particle.color.b
  81095. sizeArray[i] = particle.size
  81096. angleArray[i] = particle.angel
  81097. opacityArray[i] = particle.opacity
  81098. visibleArray[i] = particle.alive */
  81099. this.particles[i] = particle;
  81100. }
  81101. this.geometry.setAttribute('position', new BufferAttribute(positionArray,3));
  81102. this.geometry.setAttribute('color', new BufferAttribute(colorArray,3));
  81103. this.geometry.setAttribute('angle', new BufferAttribute(angleArray,1));
  81104. this.geometry.setAttribute('size', new BufferAttribute(sizeArray,1));
  81105. this.geometry.setAttribute('visible', new BufferAttribute(visibleArray,1));
  81106. this.geometry.setAttribute('opacity', new BufferAttribute(opacityArray,1));
  81107. }
  81108. createParticle() {
  81109. const particle = new Particle$2();
  81110. particle.sizeTween = this.sizeTween;
  81111. particle.colorTween = this.colorTween;
  81112. particle.opacityTween = this.opacityTween;
  81113. particle.deathAge = this.particleDeathAge;
  81114. if (this.positionShape == Shape$1.CUBE) {
  81115. particle.position = util$1.randomVector3(new Vector3, this.positionRange);
  81116. }
  81117. if (this.positionShape == Shape$1.SPHERE) {
  81118. /* const z = 2 * Math.random() - 1
  81119. const t = Math.PI * 2 * Math.random()
  81120. const r = Math.sqrt(1 - z*z)
  81121. const vec3 = new THREE.Vector3(r * Math.cos(t), r * Math.sin(t), z)
  81122. particle.position = vec3.multiplyScalar(this.radius) */
  81123. const y = 2 * Math.random() - 1;
  81124. const t = Math.PI * 2 * Math.random();
  81125. const r = Math.sqrt(1 - y * y);
  81126. const vec3 = new Vector3(r * Math.cos(t),y,r * Math.sin(t));
  81127. particle.position = vec3.multiplyScalar(this.radius);
  81128. }
  81129. if (this.velocityShape == Shape$1.CUBE) {
  81130. particle.velocity = util$1.randomVector3(this.velocity, this.velocityRange);
  81131. }
  81132. if (this.velocityShape == Shape$1.SPHERE) {
  81133. const direction = new Vector3().addVectors(particle.position, new Vector3(0,0,this.radius*2));//向上升?
  81134. const speed = util$1.randomValue(this.speed, this.speedRange);
  81135. particle.velocity = direction.normalize().multiplyScalar(speed);
  81136. }
  81137. particle.acceleration = util$1.randomValue(this.acceleration, this.accelerationRange);
  81138. particle.angle = util$1.randomValue(this.angle, this.angleRange);
  81139. particle.angleVelocity = util$1.randomValue(this.angleVelocity, this.angleVelocityRange);
  81140. particle.angleAcceleration = util$1.randomValue(this.angleAcceleration, this.angleAccelerationRange);
  81141. particle.size = util$1.randomValue(this.size, this.sizeRange);
  81142. const color = util$1.randomVector3(this.color, this.colorRange);
  81143. particle.color = new Color().setHSL(color.x, color.y, color.z);
  81144. particle.opacity = util$1.randomValue(this.opacity, this.opacityRange);
  81145. return particle
  81146. }
  81147. update(dt) {
  81148. if(!viewer.getObjVisiByReason(this,'force')){//被手动隐藏了
  81149. return
  81150. }
  81151. if(this.delayStartTime>0){ // 爆炸延迟
  81152. return this.delayStartTime -= dt
  81153. }
  81154. if(!Potree.Utils.isInsideFrustum(this.boundingSphere, viewer.scene.getActiveCamera())){
  81155. viewer.updateVisible(this,'isInsideFrustum', false ); //不在视野范围
  81156. return
  81157. }else {
  81158. viewer.updateVisible(this,'isInsideFrustum', true );
  81159. }
  81160. //const timeRatio = 0.5
  81161. if(dt > 1){
  81162. console.log('update dt>1', dt);
  81163. }
  81164. //dt *= timeRatio
  81165. let particleDeathAge = this.particleDeathAge;/* * timeRatio */
  81166. let particleSpaceTime = this.particleSpaceTime; /* * timeRatio */
  81167. const recycleIndices = [];
  81168. const recycleAges = [];
  81169. const recycleRebornCount = [];
  81170. const positionArray = this.geometry.attributes.position.array;
  81171. const opacityArray = this.geometry.attributes.opacity.array;
  81172. const visibleArray = this.geometry.attributes.visible.array;
  81173. const colorArray = this.geometry.attributes.color.array;
  81174. const angleArray = this.geometry.attributes.angle.array;
  81175. const sizeArray = this.geometry.attributes.size.array;
  81176. for (let i = 0; i < this.particleCount; i++) {
  81177. const particle = this.particles[i];
  81178. if (particle.alive) {
  81179. particle.update(dt);
  81180. if (particle.age > particleDeathAge) {
  81181. particle.alive = 0.0;
  81182. if(particle.rebornCount >= this.recycleTimes){
  81183. particle.deadAge = particle.age - particleDeathAge; //已死亡时间
  81184. }else {//直接循环
  81185. recycleIndices.push(i);
  81186. recycleAges.push(/* ( */particle.age - particleDeathAge/* )%(this.particleDeathAge ) */);
  81187. recycleRebornCount.push(particle.rebornCount+1);
  81188. }
  81189. }
  81190. positionArray[i * 3] = particle.position.x;
  81191. positionArray[i * 3 + 1] = particle.position.y;
  81192. positionArray[i * 3 + 2] = particle.position.z;
  81193. colorArray[i * 3] = particle.color.r;
  81194. colorArray[i * 3 + 1] = particle.color.g;
  81195. colorArray[i * 3 + 2] = particle.color.b;
  81196. visibleArray[i] = particle.alive;
  81197. opacityArray[i] = particle.opacity;
  81198. angleArray[i] = particle.angle;
  81199. sizeArray[i] = particle.size;
  81200. }else {
  81201. if(particle.rebornCount >= this.recycleTimes){
  81202. if(particle.age > particleDeathAge) {//其他已经死亡的粒子的时间继续增加
  81203. particle.deadAge += dt;
  81204. }
  81205. }
  81206. }
  81207. if (particle.rebornCount >= this.recycleTimes && particle.age > particleDeathAge) {//已经死亡
  81208. if(particle.deadAge >= particleSpaceTime){//死亡时间超过设定的间隔时间后重启
  81209. recycleIndices.push(i);
  81210. let wholeTime = particleDeathAge * (this.recycleTimes+1) + particleSpaceTime;
  81211. recycleAges.push((particle.deadAge - particleSpaceTime)% wholeTime ); //剩余时间就是重生后的age
  81212. recycleRebornCount.push(0);
  81213. }
  81214. }
  81215. }
  81216. this.geometry.attributes.size.needsUpdate = true;
  81217. this.geometry.attributes.color.needsUpdate = true;
  81218. this.geometry.attributes.angle.needsUpdate = true;
  81219. this.geometry.attributes.visible.needsUpdate = true;
  81220. this.geometry.attributes.opacity.needsUpdate = true;
  81221. this.geometry.attributes.position.needsUpdate = true;
  81222. if (!this.alive)
  81223. return
  81224. if (this.age < particleDeathAge) {
  81225. let startIndex = Math.round(this.particleCount * (this.age + 0)/ particleDeathAge);
  81226. let endIndex = Math.round(this.particleCount * (this.age + dt)/ particleDeathAge);
  81227. if (endIndex > this.particleCount) {
  81228. endIndex = this.particleCount;
  81229. }
  81230. for (let i = startIndex; i < endIndex; i++) {
  81231. this.particles[i].alive = 1.0;
  81232. }
  81233. }
  81234. for (let j = 0; j < recycleIndices.length; j++) {
  81235. let i = recycleIndices[j];
  81236. this.particles[i] = this.createParticle();
  81237. this.particles[i].alive = 1.0; //出生
  81238. this.particles[i].age = recycleAges[j];
  81239. this.particles[i].rebornCount= recycleRebornCount[j];
  81240. /* if(this.particles[i].age < particleDeathAge){
  81241. positionArray[i * 3] = this.particles[i].position.x
  81242. positionArray[i * 3 + 1] = this.particles[i].position.y
  81243. positionArray[i * 3 + 2] = this.particles[i].position.z
  81244. visibleArray[i] = particle.alive?
  81245. } */
  81246. }
  81247. this.geometry.attributes.position.needsUpdate = true;
  81248. this.age += dt;
  81249. if (this.age > this.deathAge && !this.loop) {
  81250. this.alive = false;
  81251. }
  81252. }
  81253. setSize(e) {
  81254. let viewport = e.viewport;
  81255. this.screenHeight = viewport.resolution.y;
  81256. this.setPerspective(this.fov, this.screenHeight);
  81257. }
  81258. setFov(fov) {
  81259. this.fov = fov;
  81260. this.setPerspective(this.fov, this.screenHeight);
  81261. }
  81262. setPerspective(fov, height) {
  81263. //this.uniforms.heightOfNearPlane.value = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5))));
  81264. let far = Math.abs(height / (2 * Math.tan(MathUtils.degToRad(fov * 0.5))));
  81265. this.material.uniforms.heightOfNearPlane.value = far;
  81266. }
  81267. updateGeometry(){
  81268. this.computeParams();
  81269. this.reStart();
  81270. }
  81271. dispose(){
  81272. this.geometry.dispose();
  81273. this.material.dispose();
  81274. this.dispatchEvent('dispose');
  81275. }
  81276. }
  81277. const colors$1 = {
  81278. 'fire+smoke':0xffffff,
  81279. 'smoke': 0xffffff,
  81280. 'explode':0xffffff,
  81281. };
  81282. let depthMatPrefix = {
  81283. clipDistance : 100, occlusionDistance:60, /* 变为backColor距离 */
  81284. maxClipFactor:0.5, backColor:"#777" ,
  81285. useDepth:true, transparent: !0,
  81286. };
  81287. let lineMats$2;
  81288. let getLineMat$1 = function(type){
  81289. if(!lineMats$2){
  81290. lineMats$2 = {
  81291. 'fire+smoke':LineDraw.createFatLineMat($.extend(depthMatPrefix,{
  81292. color: colors$1['fire+smoke'],
  81293. lineWidth: 2
  81294. })),
  81295. 'smoke' :LineDraw.createFatLineMat($.extend(depthMatPrefix,{
  81296. color: colors$1['smoke'],
  81297. lineWidth: 2
  81298. })),
  81299. 'explode' :LineDraw.createFatLineMat($.extend(depthMatPrefix,{
  81300. color: colors$1['explode'],
  81301. lineWidth: 2
  81302. })),
  81303. };
  81304. }
  81305. return lineMats$2[type]
  81306. };
  81307. let handleMats;
  81308. let getHandleMat = function(type){
  81309. if(!handleMats){
  81310. let texLoader = new TextureLoader();
  81311. handleMats = {
  81312. "fire+smoke" : new DepthBasicMaterial($.extend(depthMatPrefix,{
  81313. map: texLoader.load(Potree.resourcePath+'/textures/icon-fire.png' ),
  81314. color: colors$1['fire+smoke'],
  81315. })),
  81316. "smoke" : new DepthBasicMaterial($.extend(depthMatPrefix,{
  81317. map: texLoader.load(Potree.resourcePath+'/textures/icon-smoke.png' ),
  81318. color: colors$1['smoke'],
  81319. })),
  81320. "explode" : new DepthBasicMaterial($.extend(depthMatPrefix,{
  81321. map: texLoader.load(Potree.resourcePath+'/textures/icon-explode.png' ),
  81322. color: colors$1['explode'],
  81323. })),
  81324. };
  81325. }
  81326. return handleMats[type]
  81327. };
  81328. let ParticleEditor = {
  81329. bus: new EventDispatcher$1,
  81330. particleGroup : new Object3D ,
  81331. curveGroup:new Object3D ,
  81332. init:function(){
  81333. this.particleGroup.name = 'particles';
  81334. viewer.scene.scene.add( this.particleGroup );
  81335. this.curveGroup.name = 'particles-curves';
  81336. viewer.scene.scene.add( this.curveGroup );
  81337. },
  81338. addParticle : function(prop={}){
  81339. let particle;
  81340. if(prop.type == 'fire'){
  81341. particle = new FireParticle(prop);
  81342. }else if(prop.type == 'smoke'){
  81343. particle = new SmokeParticle(prop);
  81344. }else if(prop.type == 'explode'){
  81345. particle = new ExplodeParticle(prop);
  81346. }
  81347. this.particleGroup.add(particle);
  81348. return particle
  81349. }
  81350. ,
  81351. removeParticle(particle){
  81352. //particle.dispatchEvent('delete')
  81353. particle.dispose();
  81354. this.particleGroup.remove(particle);
  81355. particle.curve.dispose();
  81356. }
  81357. ,
  81358. update(delta){
  81359. this.particleGroup.children.forEach(e=>e.update(delta));
  81360. }
  81361. ,
  81362. startInsertion(type = 'fire', prop={}){ //viewer.modules.ParticleEditor.startInsertion()
  81363. let deferred = $.Deferred();
  81364. let particles = [];
  81365. let finish = (ifDone)=>{
  81366. if(ifDone){
  81367. deferred.resolve(particles);
  81368. }
  81369. viewer.dispatchEvent({
  81370. type : "CursorChange", action : "remove", name:"addSth"
  81371. });
  81372. viewer.removeEventListener('global_click', click);
  81373. this.bus.removeEventListener('cancel_insertions',cancel);
  81374. };
  81375. let curve = new CurveCtrl([], getLineMat$1(type), colors$1[type], type+'_curve', {handleMat:getHandleMat(type)} );
  81376. this.curveGroup.add(curve);
  81377. prop.curve = curve;
  81378. prop.type = type;
  81379. //console.log('创建curve',type,curve.uuid)
  81380. let cancel = ()=>{
  81381. console.log('cancel_insertions', curve.uuid );
  81382. curve.dispose();
  81383. finish(false);
  81384. };
  81385. this.bus.dispatchEvent('cancel_insertions');//删除旧的
  81386. this.bus.addEventListener('cancel_insertions',cancel);
  81387. var click = (e)=>{
  81388. if(e.button === MOUSE.RIGHT){
  81389. if(curve.points.length>=1){ //if(type.includes('fire') || type.includes('smoke') ){
  81390. particles = this.createFromData(prop);
  81391. finish(true);
  81392. }
  81393. return
  81394. }
  81395. var I = e.intersectPoint && (e.intersectPoint.orthoIntersect || e.intersectPoint.location);
  81396. if(!I)return
  81397. curve.addPoint(I, null, true);
  81398. if(type == 'explode'){
  81399. particles = this.createFromData(prop);
  81400. finish(true);
  81401. }
  81402. return {stopContinue:true}//防止继续执行别的侦听,如flytopano
  81403. };
  81404. viewer.addEventListener('global_click', click, 10);//add importance:10
  81405. viewer.dispatchEvent({
  81406. type : "CursorChange", action : "add", name:"addSth"
  81407. });
  81408. return deferred.promise()
  81409. },
  81410. createFromData(prop){
  81411. const type = prop.type;
  81412. var particles = [];
  81413. let curve = prop.curve;
  81414. if(!curve){
  81415. curve = new CurveCtrl(prop.points, getLineMat$1(type), colors$1[type], type+'_curve', {handleMat:getHandleMat(type)} );
  81416. this.curveGroup.add(curve);
  81417. }
  81418. if(type.includes('fire') || type.includes('smoke') ){
  81419. if(type.includes('fire')){
  81420. var fire = this.addParticle({
  81421. type : 'fire',
  81422. positions : curve.points,
  81423. curve,
  81424. radius : prop.radius,
  81425. height: prop.height,
  81426. strength : prop.strength,
  81427. });
  81428. particles.push(fire);
  81429. }
  81430. if(type.includes('smoke')){
  81431. var smoke = this.addParticle({
  81432. type : 'smoke',
  81433. positions : curve.points,
  81434. curve,
  81435. positionStyle : 'sphere' ,
  81436. strength : prop.smokeStrength,
  81437. radius: prop.smokeRadius,
  81438. height: prop.smokeHeight,
  81439. });
  81440. particles.push(smoke);
  81441. }
  81442. }else if(type == 'explode'){
  81443. var explode = this.addParticle({
  81444. type : 'explode',
  81445. position : curve.points[0],
  81446. strength: prop.strength,
  81447. radius : prop.radius,
  81448. particleSpaceTime: prop.particleSpaceTime,
  81449. curve,
  81450. delayStartTime:prop.delayStartTime,
  81451. });
  81452. particles.push(explode);
  81453. }
  81454. var geoNeedsUpdate;
  81455. curve.addEventListener('dragCurvePoint',()=>{
  81456. geoNeedsUpdate = true;
  81457. Common.intervalTool.isWaiting('particlePointChange', ()=>{ //延时update,防止卡顿
  81458. if(geoNeedsUpdate){
  81459. particles.forEach(e=>e.updateGeometry());
  81460. geoNeedsUpdate = false;
  81461. curve.dispatchEvent('sendUpdatePoints');
  81462. return true
  81463. }
  81464. }, 400);
  81465. });
  81466. return particles
  81467. }
  81468. };
  81469. let CamAniEditor = {
  81470. createAnimation(data){
  81471. let animation = new CameraAnimation(viewer);
  81472. if(data) {
  81473. animation.name = data.name;
  81474. animation.duration = data.duration;
  81475. animation.useDurSlice = data.useDurSlice;
  81476. for(const cpdata of data.points){
  81477. /* const position = Potree.Utils.datasetPosTransform({ fromDataset: true, position: cpdata.position, datasetId: Potree.settings.originDatasetId })
  81478. const target = Potree.Utils.datasetPosTransform({ fromDataset: true, position: cpdata.target, datasetId: Potree.settings.originDatasetId })
  81479. */
  81480. const position = new Vector3().copy(cpdata.position);
  81481. const target = new Vector3().copy(cpdata.target);
  81482. const duration = cpdata.time;
  81483. const cp = animation.createControlPoint(null, {position, target, duration});
  81484. }
  81485. }
  81486. animation.changeCallback();
  81487. viewer.scene.addCameraAnimation(animation);
  81488. return animation
  81489. },
  81490. removeAnimation(animation){
  81491. animation.dispatchEvent('dispose');
  81492. viewer.scene.removeCameraAnimation(animation);
  81493. }
  81494. };
  81495. let images360, Alignment$1, SiteModel$1;
  81496. const texLoader$b = new TextureLoader();
  81497. texLoader$b.crossOrigin = "anonymous";
  81498. const lineMats$3 = {};
  81499. const circleMats = {};
  81500. const renderOrders = {
  81501. circleSelected:3,
  81502. circle:2,
  81503. line:1,
  81504. };
  81505. const pointColor = {
  81506. /* selected:"#c80",
  81507. default:'#1ac' */
  81508. selected:"#c60",
  81509. default:'#17c'
  81510. };
  81511. const opacitys = {
  81512. default:1.3,
  81513. selected: 2.0
  81514. };
  81515. const cameraProps = [
  81516. {
  81517. name : 'top',
  81518. axis:["x","y"],
  81519. direction : new Vector3(0,0,-1), //镜头朝向
  81520. openCount:0,
  81521. },
  81522. {
  81523. name : 'right',
  81524. axis:["y","z"],
  81525. direction : new Vector3(1,0,0),
  81526. openCount:0,
  81527. }
  81528. ];
  81529. class PanoEditor extends EventDispatcher{
  81530. constructor(){
  81531. super();
  81532. this.panoGroup = [], //分组
  81533. this.viewports = {},
  81534. this.panoLink = {},
  81535. this.panoMeshs = new Object3D,
  81536. this.lineMeshes = new Object3D;
  81537. this.views = {};
  81538. this.cameras = {};
  81539. this.orthoCamera = new OrthographicCamera(-100, 100, 100, 100, 0.01, 10000);
  81540. this.selectedPano;
  81541. this.selectedGroup;
  81542. this.operation;
  81543. this.visiblePanos = [];
  81544. }
  81545. init(){
  81546. {//init lineMats
  81547. lineMats$3.default = LineDraw.createFatLineMat({
  81548. color: '#eeeeee',
  81549. lineWidth: 2,
  81550. depthTest:false
  81551. });
  81552. lineMats$3.hovered = LineDraw.createFatLineMat({
  81553. color: '#00c8af',
  81554. lineWidth: 2,
  81555. depthTest:false
  81556. });
  81557. lineMats$3.selected = LineDraw.createFatLineMat({
  81558. color: '#00c8af',
  81559. lineWidth: 3,
  81560. depthTest:false
  81561. });
  81562. }
  81563. this.initViews();
  81564. viewer.addEventListener('allLoaded',()=>{
  81565. images360 = viewer.images360;
  81566. Alignment$1 = viewer.modules.Alignment;
  81567. SiteModel$1 = viewer.modules.SiteModel;
  81568. this.panoMeshs.name = 'panoMeshs';
  81569. viewer.scene.scene.add(this.panoMeshs);
  81570. this.lineMeshes.name = 'lineMeshes';
  81571. viewer.scene.scene.add(this.lineMeshes);
  81572. this.initPanoLink();
  81573. this.addPanoMesh();
  81574. viewer.scene.pointclouds.forEach(e=>{
  81575. e.material.color = pointColor.default;
  81576. });
  81577. this.switchView('top');
  81578. SiteModel$1.bus.addEventListener('initDataDone',()=>{
  81579. this.gotoFloor(SiteModel$1.entities.find(e=>e.buildType == 'floor')); //任意一层
  81580. });
  81581. Alignment$1.bus.addEventListener('switchHandle', this.updateCursor.bind(this));
  81582. viewer.addEventListener('global_click',(e)=>{
  81583. if(e.button === MOUSE.RIGHT){//取消旋转和平移
  81584. console.log('right click',e);
  81585. this.setLinkOperateState('addLink',false);
  81586. this.setLinkOperateState('removeLink',false);
  81587. }else if(this.clickToZoomInEnabled){
  81588. this.zoomIn(e.intersectPoint.orthoIntersect, e.pointer);
  81589. this.setZoomInState(false);
  81590. }
  81591. });
  81592. {//旋转时的辅助线
  81593. this.rotGuideLine = LineDraw.createLine([], {color:'#aaffee'});
  81594. this.rotGuideLine.visible = false;
  81595. this.rotGuideLine.name = 'rotGuideLine';
  81596. this.rotGuideLine.renderOrder = renderOrders.line;
  81597. viewer.scene.scene.add(this.rotGuideLine);
  81598. let startPoint;
  81599. Alignment$1.bus.addEventListener('rotateStart', (e)=>{
  81600. startPoint = e.startPoint;
  81601. });
  81602. Alignment$1.bus.addEventListener('rotate', (e)=>{
  81603. LineDraw.updateLine(this.rotGuideLine, [startPoint, e.endPoint] );
  81604. this.rotGuideLine.visible = true;
  81605. });
  81606. viewer.fpControls.addEventListener("end",(e)=>{
  81607. startPoint = null;
  81608. this.rotGuideLine.visible = false;
  81609. });
  81610. }
  81611. {//连接时的辅助线
  81612. this.linkGuideLine = LineDraw.createLine([], {color:'#aaa', deshed:true, dashSize:0.1,gapSize:0.1,});
  81613. this.linkGuideLine.visible = false;
  81614. this.linkGuideLine.name = 'linkGuideLine';
  81615. viewer.scene.scene.add(this.linkGuideLine);
  81616. this.linkGuideLine.renderOrder = renderOrders.line;
  81617. let update = (e)=>{
  81618. if(this.operation != 'addLink' || this.activeViewName != 'top' || !this.selectedPano){
  81619. return this.linkGuideLine.visible = false
  81620. }
  81621. LineDraw.updateLine(this.linkGuideLine, [this.selectedPano.position, e.intersectPoint.orthoIntersect.clone().setZ(this.selectedPano.position.z)] );
  81622. this.linkGuideLine.visible = true;
  81623. };
  81624. viewer.addEventListener('global_mousemove', (e)=>{
  81625. update(e);
  81626. });
  81627. this.addEventListener('updateLinkGuideLine', update);
  81628. //为何打开调试时移动很卡
  81629. }
  81630. });
  81631. }
  81632. //////////////////////////////////
  81633. initViews(){
  81634. this.splitScreenTool = new SplitScreen;
  81635. this.targetPlane = viewer.mainViewport.targetPlane = new Plane();
  81636. this.shiftTarget = viewer.mainViewport.shiftTarget = new Vector3; //project在targetPlane上的位置
  81637. for(let i=0;i<2;i++){
  81638. let prop = cameraProps[i];
  81639. let view = new View();
  81640. this.views[prop.name] = view;
  81641. this.cameras[prop.name] = this.orthoCamera;
  81642. view.direction = prop.direction;
  81643. }
  81644. this.views.mainView = viewer.mainViewport.view;
  81645. this.cameras.mainView = viewer.mainViewport.camera;
  81646. }
  81647. switchView(name){//替换view和camera到mainViewport
  81648. let view = this.views[name];
  81649. let camera = this.cameras[name];
  81650. let prop = cameraProps.find(e=>e.name == name);
  81651. let {boundSize, center} = viewer.bound;
  81652. this.lastViewName = this.activeViewName;
  81653. this.activeViewName = name;
  81654. let lastView = this.views[this.lastViewName];
  81655. let lastCamera = this.cameras[this.lastViewName];
  81656. viewer.mainViewport.view = view;
  81657. viewer.mainViewport.camera = camera;
  81658. if(lastCamera)lastView.zoom = lastCamera.zoom;
  81659. this.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), center );
  81660. this.targetPlane.projectPoint(view.position, this.shiftTarget ); //target转换到过模型中心的平面,以保证镜头一定在模型外
  81661. view.position.copy(this.splitScreenTool.getPosOutOfModel(viewer.mainViewport));
  81662. if(view.zoom)camera.zoom = view.zoom;//恢复上次的zoom
  81663. viewer.updateScreenSize({forceUpdateSize:true});//更新camera aspect left等
  81664. this.updateCursor();
  81665. if(name == 'mainView'){
  81666. viewer.mainViewport.alignment = null;
  81667. viewer.scene.pointclouds.forEach(e=>{
  81668. e.material.activeAttributeName = 'rgba';
  81669. e.material.useFilterByNormal = false;
  81670. e.changePointOpacity(1,true);
  81671. });
  81672. viewer.updateVisible(viewer.reticule, 'force', true);
  81673. if(lastView){
  81674. view.copy(lastView);
  81675. //view.position.
  81676. let direction = view.direction;
  81677. let panos = images360.panos.filter(e=>e.circle.visible);
  81678. let nearestPano = Common.sortByScore(panos , [], [(pano)=>{
  81679. let vec = new Vector3().subVectors(pano.position, view.position);
  81680. return -vec.dot(direction);
  81681. }], true);
  81682. console.log('最近',nearestPano );
  81683. if(nearestPano && nearestPano[0] ){ //尽量不变画面范围,使pano点保持原位,转换到mainView
  81684. let halfHeight = lastCamera.top/lastCamera.zoom;
  81685. let dis = halfHeight / Math.tan( MathUtils.degToRad(camera.fov/2));
  81686. view.position.add(direction.clone().multiplyScalar(-nearestPano[0].score - dis));
  81687. //console.log('getCloser', -nearestPano[0].score - dis)
  81688. this.lastDisToPano = dis; //记录一下
  81689. }
  81690. }
  81691. viewer.fpControls.lockKey = false;
  81692. }else {
  81693. if(prop.openCount == 0){//只需执行一次
  81694. this.viewportFitBound(name, boundSize, center);
  81695. }
  81696. prop.openCount ++;
  81697. viewer.scene.pointclouds.forEach(e=>{
  81698. e.material.activeAttributeName = 'color';
  81699. e.material.useFilterByNormal = true; //defines : use_filter_by_normal attenuated_opacity
  81700. if(this.selectedPano && this.selectedClouds.includes(e) /* this.selectedPano.pointcloud == e */){
  81701. e.changePointOpacity(opacitys.selected,true);
  81702. }else {
  81703. e.changePointOpacity(opacitys.default,true);
  81704. }
  81705. });
  81706. viewer.updateVisible(viewer.reticule, 'force', false);
  81707. if(name == 'top') viewer.mainViewport.alignment = {rotate:true,translate:true};
  81708. if(name == 'right'){
  81709. viewer.mainViewport.alignment = {translate:true, rotateSide:true};
  81710. }
  81711. viewer.fpControls.lockKey = true;
  81712. }
  81713. this.setZoomInState(false); //取消放大模式
  81714. }
  81715. //new THREE.Plane().setFromNormalAndCoplanarPoint( normal, this.points[0] )
  81716. viewportFitBound(/* name, boundSize_, target */){ //使一个viewport聚焦在某个范围
  81717. /* let viewport = viewer.mainViewport
  81718. let {boundSize, center} = viewer.bound
  81719. var prop = cameraProps.find(v => name == v.name )
  81720. let expand = 10;
  81721. targetPlane.setFromNormalAndCoplanarPoint( prop.direction.clone(), center )
  81722. let shiftTarget = targetPlane.projectPoint(target, new THREE.Vector3() ) //target转换到过模型中心的平面,以保证镜头一定在模型外
  81723. this.setCameraPose(shiftTarget, prop.direction)
  81724. if(name == 'top'){
  81725. let axis = prop.axis
  81726. var width = Math.max(boundSize_[axis[0]], boundSize_[axis[1]] * viewport.camera.aspect)//视口宽度(米)
  81727. }else{//因为侧面可能旋转
  81728. let vec1 = new THREE.Vector3(boundSize_.x, 0,0);
  81729. let vec2 = new THREE.Vector3(0,boundSize_.y,0);
  81730. let v1 = vec1.projectOnPlane( prop.direction.clone() )
  81731. let v2 = vec2.projectOnPlane( prop.direction.clone() )
  81732. var width = Math.max(v1.length()+v2.length(), boundSize_.z * viewport.camera.aspect)//视口宽度(米)
  81733. }
  81734. var margin = 50 //px
  81735. viewport.camera.zoom = (viewport.resolution.x - margin) / width
  81736. viewport.camera.updateProjectionMatrix() */
  81737. if(viewer.mainViewport.resolution.x == 0 || viewer.mainViewport.resolution.y == 0){
  81738. return setTimeout(()=>{
  81739. this.viewportFitBound(/* name, boundSize_, target */);
  81740. },10)
  81741. }
  81742. this.gotoFloor(this.currentFloor, true, 0, null, true);
  81743. }
  81744. rotateSideCamera(angle){//侧视图绕模型中心水平旋转
  81745. this.splitScreenTool.rotateSideCamera(viewer.mainViewport, angle);
  81746. }
  81747. /* rotateSideCamera(angle){//侧视图绕模型中心水平旋转
  81748. var prop = cameraProps.find(v => v.name == 'right' )
  81749. let {boundSize, center} = viewer.bound
  81750. //找到平移向量
  81751. targetPlane.setFromNormalAndCoplanarPoint(viewer.mainViewport.view.direction , center )
  81752. targetPlane.projectPoint(viewer.mainViewport.view.position, this.shiftTarget ) //target转换到过模型中心的平面,以保证镜头一定在模型外
  81753. let vec = new THREE.Vector3().subVectors(center, this.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转
  81754. //旋转
  81755. var rotMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle)
  81756. //prop.direction.applyMatrix4(rotMatrix)
  81757. viewer.mainViewport.view.direction = viewer.mainViewport.view.direction.applyMatrix4(rotMatrix)
  81758. vec.applyMatrix4(rotMatrix)
  81759. this.shiftTarget.subVectors(center,vec) //新的
  81760. viewer.mainViewport.view.position = this.splitScreenTool.getPosOutOfModel(viewer.mainViewport) // this.getPosOutOfModel()
  81761. } */
  81762. /* getPosOutOfModel(){//已知shiftTarget和currentDir后
  81763. let {boundSize, center} = viewer.bound
  81764. let expand = 10;
  81765. let view = viewer.mainViewport.view
  81766. let radius = boundSize.length() / 2
  81767. let position = this.shiftTarget.clone().sub(view.direction.clone().multiplyScalar(radius + expand))
  81768. return position
  81769. } */
  81770. zoomIn(intersectPoint, pointer){
  81771. let camera = viewer.mainViewport.camera;
  81772. let endZoom = 700;
  81773. //this.moveFit(intersectPoint, {endZoom:viewer.mainViewport.camera.zoom < aimZoom ? aimZoom : null} , 300)
  81774. let startZoom = camera.zoom;
  81775. if(startZoom >= endZoom){return}
  81776. viewer.mainViewport.view.zoomOrthoCamera(camera, endZoom, pointer, 300);
  81777. }
  81778. /* getRadius(){
  81779. let {boundSize, center} = viewer.bound
  81780. let expand = 10;
  81781. let radius = boundSize.length() / 2
  81782. return radius + expand
  81783. } */
  81784. moveFit(pos, info, duration){
  81785. var margin = {x:200, y:230};
  81786. this.splitScreenTool.viewportFitBound(viewer.mainViewport, info.bound, pos, duration, margin );
  81787. /* targetPlane.projectPoint(pos, this.shiftTarget) //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  81788. info.endPosition = this.getPosOutOfModel()
  81789. info
  81790. let view = viewer.mainViewport.view
  81791. view.moveOrthoCamera(viewer.mainViewport, info , duration ) */
  81792. }
  81793. setZoomInState(state, informinformBy2d){//是否点击后可放大
  81794. if(state && this.activeViewName == 'mainView')return console.log('3D不可放大')
  81795. this.clickToZoomInEnabled = !!state;
  81796. if(state){
  81797. viewer.dispatchEvent({type : "CursorChange", action : "add", name:"zoomInCloud"} );
  81798. }else {
  81799. viewer.dispatchEvent({type : "CursorChange", action : "remove", name:"zoomInCloud" });
  81800. }
  81801. if(!state && !informinformBy2d){
  81802. this.dispatchEvent({type:'operationCancel', operation: 'zoomIn'});
  81803. }
  81804. }
  81805. gotoFloor(floor, force, duration = 600, informBy2d, fitBound){// 选择不同楼层, 切换点位显示。 'all'为全部显示
  81806. floor = floor || 'all';
  81807. if(this.currentFloor == floor && !force)return
  81808. //let pointclouds = viewer.findPointcloudsAtFloor(floor)
  81809. let panos = floor == 'all' ? viewer.images360.panos : floor.panos;
  81810. viewer.images360.panos.forEach(pano=>{
  81811. let v = panos.includes(pano);
  81812. this.switchPanoVisible(pano,v);
  81813. });
  81814. this.updateLinesVisible();
  81815. //切换楼层时清空选择状态
  81816. if(this.selectedPano && floor != 'all' && !floor.panos.includes(this.selectedPano)){
  81817. this.selectedPano.circle.dispatchEvent('click');
  81818. }
  81819. if(this.selectedLine){
  81820. this.selectedLine.dispatchEvent('click');
  81821. }
  81822. let bound, center;
  81823. if(floor == 'all'){
  81824. bound = viewer.images360.bound.bounding;
  81825. center = viewer.images360.bound.center;
  81826. }else {
  81827. bound = this.getPanosBound(floor);
  81828. center = bound.getCenter(new Vector3());
  81829. if(floor.panos.length == 0)console.log(floor.name, 'floor无漫游点' );
  81830. }
  81831. if(this.activeViewName != 'mainView' ){
  81832. fitBound && this.moveFit(center, {bound}, duration);
  81833. }else if(this.activeViewName == 'mainView'){
  81834. if(floor != 'all'){ //切换一下位置,因为原处点云会消失
  81835. viewer.scene.view.setView({position:center, duration });
  81836. }
  81837. }
  81838. this.currentFloor = floor;
  81839. if(!informBy2d){
  81840. this.dispatchEvent({type:'changeFloor', floor});
  81841. }
  81842. }
  81843. getPanosBound(floor){
  81844. if(!floor.panosBound){
  81845. if(floor.panos.length == 0){
  81846. floor.panosBound = viewer.images360.bound.bounding.clone();
  81847. }else {
  81848. /* floor.panosBound = new THREE.Box3
  81849. floor.panos.forEach(pano=>{
  81850. floor.panosBound.expandByPoint(pano.position)
  81851. })
  81852. let center = floor.panosBound.getCenter(new THREE.Vector3)
  81853. let minBound = (new THREE.Box3()).setFromCenterAndSize(center, new THREE.Vector3(5,5,5))
  81854. floor.panosBound.union(minBound) */
  81855. let minSize = new Vector3(5,5,5);
  81856. let bound = math.getBoundByPoints(floor.panos.map(e=>e.position), minSize);
  81857. floor.panosBound = bound.bounding;
  81858. }
  81859. }
  81860. return floor.panosBound
  81861. }
  81862. switchPanoVisible(pano, v, informBy2d){
  81863. pano.circle.visible = v;
  81864. viewer.updateVisible(pano, 'panoEditor', v);
  81865. viewer.updateVisible(pano.pointcloud, 'panoEditor', v);
  81866. if(v){
  81867. this.visiblePanos.includes(pano) || this.visiblePanos.push(pano);
  81868. }else {
  81869. let index = this.visiblePanos.indexOf(pano);
  81870. index>-1 && this.visiblePanos.splice(index,1);
  81871. }
  81872. if(informBy2d){
  81873. this.updateLinesVisible();
  81874. }
  81875. informBy2d || this.dispatchEvent({type:"switchPanoVisible", pano, v});
  81876. }
  81877. updateLinesVisible(){
  81878. this.lineMeshes.children.forEach(line=>{
  81879. let names = line.name.split('-');
  81880. var pano0 = images360.getPano(names[0]);
  81881. var pano1 = images360.getPano(names[1]);
  81882. line.visible = this.visiblePanos.includes(pano0) || this.visiblePanos.includes(pano1);
  81883. });
  81884. }
  81885. updateCursor(){
  81886. let cursor;
  81887. if(this.activeViewName == 'mainView' || !this.selectedPano){
  81888. cursor = null;
  81889. }else {
  81890. cursor = Alignment$1.handleState;
  81891. }
  81892. if(cursor == 'rotate'){
  81893. viewer.dispatchEvent({
  81894. type : "CursorChange", action : "add", name:"rotatePointcloud"
  81895. });
  81896. viewer.dispatchEvent({
  81897. type : "CursorChange", action : "remove", name:"movePointcloud"
  81898. });
  81899. }else if(cursor == 'translate'){
  81900. viewer.dispatchEvent({
  81901. type : "CursorChange", action : "add", name:"movePointcloud"
  81902. });
  81903. viewer.dispatchEvent({
  81904. type : "CursorChange", action : "remove", name:"rotatePointcloud"
  81905. });
  81906. }else {
  81907. viewer.dispatchEvent({
  81908. type : "CursorChange", action : "remove", name:"movePointcloud"
  81909. });
  81910. viewer.dispatchEvent({
  81911. type : "CursorChange", action : "remove", name:"rotatePointcloud"
  81912. });
  81913. }
  81914. //this.cursorState = cursor
  81915. }
  81916. setLinkOperateState(name, state, informinformBy2d){
  81917. if(state && name == this.operation || !state && name != this.operation)return
  81918. let old = this.operation;
  81919. this.operation = state ? name : null;
  81920. if(this.operation == 'removeLink'){
  81921. if(this.selectedLine){
  81922. this.selectedLine.dispatchEvent('click');//删除
  81923. }
  81924. if(this.selectedPano){
  81925. this.selectedPano.circle.dispatchEvent('click');//删除
  81926. }
  81927. }
  81928. if(this.operation != 'addLink'){
  81929. this.linkGuideLine.visible = false;
  81930. }
  81931. if(!state && !informinformBy2d){
  81932. this.dispatchEvent({type: "operationCancel", operation: old});
  81933. }
  81934. if(this.operation == 'addLink'){
  81935. viewer.dispatchEvent({type : "CursorChange", action : "add", name:"connectPano"} );
  81936. }else {
  81937. viewer.dispatchEvent({type : "CursorChange", action : "remove", name:"connectPano"} );
  81938. }
  81939. if(this.operation == 'removeLink'){
  81940. viewer.dispatchEvent({type : "CursorChange", action : "add", name:"disconnectPano"} );
  81941. }else {
  81942. viewer.dispatchEvent({type : "CursorChange", action : "remove", name:"disconnectPano"} );
  81943. }
  81944. }
  81945. /////////////////////////////////
  81946. initPanoLink(){
  81947. images360.panos.forEach((pano)=>{
  81948. this.panoLink[pano.id] = {};
  81949. });
  81950. images360.panos.forEach((pano)=>{
  81951. pano.visibles.forEach(index=>{//visibles中存的是下标!
  81952. this.linkChange(pano, images360.getPano(index,'index'), 'add');
  81953. });
  81954. });
  81955. console.log('panoLink',this.panoLink);
  81956. }
  81957. groupChange(pano0, pano1, type){//修改group (type == 'remove'时,pano1可以为空)
  81958. if(type == 'add'){
  81959. Common.pushToGroupAuto([pano0, pano1], this.panoGroup );
  81960. }else {
  81961. let atGroup = this.panoGroup.find(e=>e.includes(pano0) && (e.includes(pano1) || !pano1));//所在组
  81962. if(!atGroup){
  81963. if(pano1){
  81964. console.log('这两个pano原本就不在一个组', pano0.id, pano1.id);
  81965. }else {
  81966. console.log('pano0不在任何组', pano0);
  81967. }
  81968. return
  81969. }
  81970. //断开连接时,因为组内没有其他成员的连接信息,所以需要清除整组,并将剩余的一个个重新连接
  81971. this.panoGroup.splice(this.panoGroup.indexOf(atGroup),1); //删除
  81972. atGroup.forEach(pano=>{//然后再重新生成这两个和组的关系,各自分组
  81973. if(pano == pano0 || pano == pano1)return
  81974. for(let id in this.panoLink[pano.id]){
  81975. if(this.panoLink[pano.id][id]){
  81976. let pano_ = images360.getPano(id);
  81977. Common.pushToGroupAuto([pano, pano_], this.panoGroup );
  81978. }
  81979. }
  81980. });
  81981. }
  81982. }
  81983. linkChange(pano0, pano1, type){//修改link (type == 'remove'时,pano1可以为空)
  81984. let temp = [];
  81985. if(type == 'add'){
  81986. if(!pano1)return console.error('不支持add时pano1为空')
  81987. this.panoLink[pano0.id][pano1.id] = this.panoLink[pano0.id][pano1.id] || {};
  81988. this.panoLink[pano1.id][pano0.id] = this.panoLink[pano1.id][pano0.id] || {};
  81989. }else {
  81990. if(!pano1){
  81991. for(let id in this.panoLink[pano0.id]){
  81992. if(this.panoLink[pano0.id][id]){
  81993. this.panoLink[id][pano0.id] = false;
  81994. temp.push(id);
  81995. }
  81996. }
  81997. this.panoLink[pano0.id] = {}; //全部断连
  81998. }else {
  81999. this.panoLink[pano0.id][pano1.id] = false;
  82000. this.panoLink[pano1.id][pano0.id] = false;
  82001. }
  82002. }
  82003. if(!pano1){ //全部断连
  82004. temp.forEach(id=>{
  82005. this.lineChange(pano0, images360.getPano(id) , type);
  82006. });
  82007. }else {
  82008. this.lineChange(pano0, pano1, type);
  82009. }
  82010. this.groupChange(pano0, pano1, type);
  82011. //this.updateSelectGroup()
  82012. this.selectPano(this.selectedPano, false,true); //更新选中点云显示
  82013. }
  82014. lineChange(pano0, pano1, type){//修改line
  82015. if(type == 'add'){
  82016. if(this.panoLink[pano0.id][pano1.id].line) return
  82017. let line = LineDraw.createFatLine([pano0.position, pano1.position], {material:lineMats$3.default});
  82018. line.name = `${pano0.id}-${pano1.id}`;
  82019. line.renderOrder = renderOrders.line;
  82020. this.lineMeshes.add(line);
  82021. this.panoLink[pano0.id][pano1.id].line = this.panoLink[pano1.id][pano0.id].line = line;
  82022. line.addEventListener('mouseover', ()=>{
  82023. if(this.activeViewName == 'mainView')return
  82024. if(this.selectedLine != line)line.material = lineMats$3.hovered;
  82025. viewer.dispatchEvent({
  82026. type : "CursorChange", action : "add", name:"hoverLine"
  82027. });
  82028. });
  82029. line.addEventListener('mouseleave', ()=>{
  82030. //if(this.activeViewName == 'mainView')return
  82031. if(this.selectedLine != line)line.material = lineMats$3.default;
  82032. viewer.dispatchEvent({
  82033. type : "CursorChange", action : "remove", name:"hoverLine"
  82034. });
  82035. });
  82036. line.addEventListener('click', (e)=>{
  82037. if(this.activeViewName == 'mainView')return
  82038. if(this.operation == 'removeLink'){
  82039. if(this.selectedLine == line) this.selectLine(null);
  82040. return this.linkChange(pano0, pano1, 'remove')
  82041. }
  82042. this.selectLine(line);
  82043. });
  82044. }else {
  82045. let line = this.lineMeshes.children.find(e=>e.name == `${pano0.id}-${pano1.id}` || e.name == `${pano1.id}-${pano0.id}` );
  82046. if(line){
  82047. this.lineMeshes.remove(line);
  82048. line.geometry.dispose();
  82049. }
  82050. }
  82051. }
  82052. selectLine(line){
  82053. if(this.selectedLine == line)return
  82054. if(this.selectedLine){
  82055. this.selectedLine.material = lineMats$3.default;
  82056. }
  82057. if(line){
  82058. line.material = lineMats$3.selected;
  82059. }
  82060. this.selectedLine = line;
  82061. }
  82062. addPanoMesh(){
  82063. let map = texLoader$b.load(Potree.resourcePath+'/textures/correct_n.png' );
  82064. circleMats.default = new MeshBasicMaterial({
  82065. map,
  82066. color: 0xffffff,
  82067. transparent: true,
  82068. depthTest: false,
  82069. depthWrite: false,
  82070. });
  82071. circleMats.hovered = new MeshBasicMaterial({
  82072. map,
  82073. color: 0xffff00,
  82074. transparent: true,
  82075. depthTest: false,
  82076. depthWrite: false,
  82077. });
  82078. circleMats.selected = new MeshBasicMaterial({
  82079. map: texLoader$b.load(Potree.resourcePath+'/textures/correct_s.png' ) ,
  82080. color: 0xffffff,
  82081. transparent: true,
  82082. depthTest: false,
  82083. depthWrite: false,
  82084. });
  82085. let setPos = (circle)=>{
  82086. circle.position.copy(circle.pano.position);
  82087. for(let id in this.panoLink[circle.pano.id]){
  82088. let linkInfo = this.panoLink[circle.pano.id][id];
  82089. if(linkInfo){
  82090. LineDraw.updateLine(linkInfo.line, [circle.pano.position, images360.getPano(id).position] );
  82091. }
  82092. }
  82093. circle.update(); //update sprite Matrix
  82094. };
  82095. images360.panos.forEach(pano=>{
  82096. var circle = new Sprite$1({mat: circleMats.default, sizeInfo:{
  82097. minSize : 50 , maxSize : 120, nearBound : 2, farBound : 10,
  82098. },
  82099. renderOrder : renderOrders.circle
  82100. }); //new THREE.Sprite(circleMats.default)
  82101. circle.name = 'panoCircle';
  82102. circle.sid = pano.id;
  82103. circle.pano = pano;
  82104. pano.circle = circle;
  82105. this.panoMeshs.add(circle);
  82106. setPos(circle);
  82107. pano.addEventListener('rePos', setPos.bind(this,circle));
  82108. let drag = ()=>{
  82109. if(this.activeViewName == 'mainView')return
  82110. this.selectPano(circle.pano); //为了方便拖拽点云,拖动circle就直接选中
  82111. viewer.inputHandler.drag.object = null; //取消拖拽状态,否则不触发点云拖动
  82112. };
  82113. circle.addEventListener('drag', drag);
  82114. /* circle.addEventListener('drop', ()=>{
  82115. }) */
  82116. circle.addEventListener('mouseover', ()=>{
  82117. this.hoverPano(pano,true);
  82118. });
  82119. circle.addEventListener('mouseleave', ()=>{
  82120. this.hoverPano(pano,false);
  82121. });
  82122. circle.addEventListener('click', ()=>{
  82123. //if(this.activeViewName == 'mainView')return
  82124. if(this.operation == 'removeLink'){
  82125. this.linkChange(pano, null, 'remove'); //删除所有连接
  82126. }
  82127. if(this.selectedPano == circle.pano) return this.selectPano(null)
  82128. if(this.operation == 'addLink' && this.selectedPano){
  82129. this.linkChange(this.selectedPano, circle.pano, 'add');
  82130. //this.setLinkOperateState('addLink',false)
  82131. return
  82132. }
  82133. //if(this.operation == 'removeLink' && this.selectedPano){ //和选择中心点冲突
  82134. // this.linkChange(this.selectedPano, circle.pano, 'remove')
  82135. // //this.setLinkOperateState('removeLink',false)
  82136. // return
  82137. // }
  82138. this.selectPano(circle.pano);
  82139. });
  82140. });
  82141. }
  82142. hoverPano(pano, state){
  82143. if(pano && state){ //在hover一个pano之前,一定会先取消已经hover的pano, 最多存在一个hovered的pano
  82144. if(this.hoveredPano == pano)return
  82145. if(this.hoveredPano){
  82146. this.hoverPano(this.hoveredPano,false);
  82147. }
  82148. this.hoveredPano = pano;
  82149. pano.hovered = true;
  82150. if(/* this.activeViewName == 'mainView' || */Alignment$1.handleState && this.selectedPano && this.selectedPano == pano)return
  82151. if(this.operation != 'addLink' || !this.selectedPano || this.selectedPano == pano){ // this.selectedPano == pano?
  82152. viewer.dispatchEvent({
  82153. type : "CursorChange", action : "add", name:"hoverPano"
  82154. });
  82155. }
  82156. if(this.selectedPano != pano) pano.circle.material = circleMats.hovered;
  82157. }else if(pano && !state){//unhover
  82158. if(this.hoveredPano != pano)return
  82159. pano.hovered = false;
  82160. viewer.dispatchEvent({
  82161. type : "CursorChange", action : "remove", name:"hoverPano"
  82162. });
  82163. if(this.selectedPano != pano) pano.circle.material = circleMats.default;
  82164. this.hoveredPano = null;
  82165. }else {//unhover any
  82166. if(this.hoveredPano){
  82167. this.hoverPano(this.hoveredPano, false);
  82168. }
  82169. }
  82170. }
  82171. selectPano(pano, informinformBy2d, force){
  82172. if(this.selectedPano == pano && !force)return
  82173. let lastSeletedPano = this.selectedPano;
  82174. if(this.selectedPano){
  82175. this.selectedPano.circle.material = circleMats.default;
  82176. this.selectedPano.circle.renderOrder = renderOrders.circle;
  82177. if(this.activeViewName != 'mainView'){
  82178. this.selectedClouds.forEach(e=>{
  82179. e.changePointOpacity(opacitys.default,true);
  82180. e.material.color = pointColor.default;
  82181. });
  82182. //this.selectedPano.pointcloud.changePointOpacity(opacitys.default,true)
  82183. //this.selectedPano.pointcloud.material.color = Potree.config.material.pointColor
  82184. }
  82185. }
  82186. this.selectedPano = pano || null;
  82187. this.updateSelectGroup();
  82188. if(pano){
  82189. this.selectedPano.circle.material = circleMats.selected;
  82190. this.selectedPano.circle.renderOrder = renderOrders.circleSelected; //侧视图能显示在最前
  82191. //this.selectedPano.pointcloud.material.color = '#ff0000'
  82192. //this.selectedPano.pointcloud.changePointOpacity(opacitys.selected,true)
  82193. this.selectedClouds.forEach(e=>{
  82194. e.changePointOpacity(opacitys.selected,true);
  82195. e.material.color = pointColor.selected;
  82196. });
  82197. {//自动切换楼层
  82198. let atFloor = SiteModel$1.entities.find(e=>e.buildType == 'floor' && e.panos.includes(pano));
  82199. if(!atFloor){
  82200. atFloor = 'all';
  82201. }else {
  82202. }
  82203. this.gotoFloor(atFloor, false, 600 );
  82204. }
  82205. }
  82206. this.updateCursor();
  82207. if(informinformBy2d){
  82208. if(this.selectedPano){
  82209. if(this.activeViewName == 'mainView'){ //平移,focus选中的pano
  82210. let distance = this.lastDisToPano || 5;
  82211. if(lastSeletedPano){
  82212. distance = viewer.mainViewport.camera.position.distanceTo(lastSeletedPano.position);
  82213. }
  82214. viewer.focusOnObject({ position:this.selectedPano.position}, 'point', null, {distance });
  82215. }else {
  82216. this.moveFit(this.selectedPano.position, {}, 500);
  82217. }
  82218. }
  82219. }else {
  82220. this.dispatchEvent({type:'panoSelect', pano });
  82221. }
  82222. }
  82223. updateSelectGroup(){//更新选中的组
  82224. this.selectedGroup = this.panoGroup.find(e=>e.includes(this.selectedPano));
  82225. this.selectedClouds = this.selectedPano ? (this.selectedGroup || [this.selectedPano]).map(e=>e.pointcloud) : [];
  82226. }
  82227. checkIfCanSave(){//如果未全部相连,不能保存
  82228. for(let datasetId in Potree.settings.datasetsPanos ) {
  82229. if(!this.checkIfAllLinked({datasetId})){
  82230. console.log('没有全部连通,不能保存。其中一个:', datasetId);
  82231. return
  82232. }
  82233. }
  82234. return true
  82235. }
  82236. checkIfAllLinked(o){//某个(or组所在的)数据集是否全部连通
  82237. let datasetId, group;
  82238. if(o.group){
  82239. group = o.group;
  82240. let pano = o.group[0];
  82241. if(!pano)return //会有没有漫游点的点云来编辑吗
  82242. datasetId = pano.pointcloud.dataset_id;
  82243. }else if(o.datasetId){
  82244. datasetId = o.datasetId;
  82245. group = this.panoGroup.find(panos=>panos[0].pointcloud.dataset_id == datasetId );
  82246. if(!group)return //要找的数据集的pano全部都孤立了
  82247. }
  82248. let panos = Potree.settings.datasetsPanos[datasetId].panos;
  82249. return panos.length == group.length
  82250. }
  82251. exportSavingData(){//输出漫游点新的坐标和朝向、以及连接信息
  82252. let sweepLocations = {};
  82253. for(let datasetId in Potree.settings.datasetsPanos ) {
  82254. let {panos} = Potree.settings.datasetsPanos[datasetId];
  82255. let data = panos.map(pano=>{
  82256. let visibles = [];
  82257. for(let id in this.panoLink[pano.id]){
  82258. if(this.panoLink[pano.id][id]){
  82259. visibles.push(viewer.images360.getPano(id).index);
  82260. }
  82261. }
  82262. return Object.assign({}, pano.panosData, {
  82263. uuid: pano.uuid,
  82264. pose:{
  82265. translation: dealData(pano.position.clone().negate()),
  82266. rotation: dealData(new Quaternion().setFromRotationMatrix(pano.panoMatrix) ),
  82267. },
  82268. visibles,
  82269. //subgroup: 0,group: 1, "id_view":..
  82270. })
  82271. });
  82272. sweepLocations[datasetId] = {sweepLocations:data};
  82273. }
  82274. /* this.lineMeshes.children.forEach(e=>{//从line中搜集连接信息,而不从linkInfo,这样visibles不会重复一次
  82275. let names = e.name.split('-') //是不是该转成数字
  82276. var pano0 = names[0]
  82277. var pano1 = names[1]
  82278. sweepLocations.find(s=>s.uuid == pano0).visibles.push(pano1)
  82279. }) */
  82280. function dealData(value){
  82281. let v = math.toPrecision(value, 6);
  82282. if(v instanceof Quaternion){
  82283. return {x:v.x, y:v.y, z:v.z, w:v.w}
  82284. }else if(v instanceof Vector3){
  82285. return {x:v.x, y:v.y, z:v.z}
  82286. }
  82287. }
  82288. console.log(sweepLocations);
  82289. return sweepLocations
  82290. }
  82291. }
  82292. /*
  82293. 不同数据集之间不能连线
  82294. 不同楼层可能也不能
  82295. 如果楼层在不同建筑物怎么办? 楼层切换按钮只能在一个建筑内切换。
  82296. 全部相连时不能移动和旋转
  82297. 如果未全部相连,不能保存
  82298. */
  82299. var PanoEditor$1 = new PanoEditor();
  82300. var OBJLoader = ( function () {
  82301. // o object_name | g group_name
  82302. var object_pattern = /^[og]\s*(.+)?/;
  82303. // mtllib file_reference
  82304. var material_library_pattern = /^mtllib /;
  82305. // usemtl material_name
  82306. var material_use_pattern = /^usemtl /;
  82307. // usemap map_name
  82308. var map_use_pattern = /^usemap /;
  82309. var vA = new Vector3();
  82310. var vB = new Vector3();
  82311. var vC = new Vector3();
  82312. var ab = new Vector3();
  82313. var cb = new Vector3();
  82314. function ParserState() {
  82315. var state = {
  82316. objects: [],
  82317. object: {},
  82318. vertices: [],
  82319. normals: [],
  82320. colors: [],
  82321. uvs: [],
  82322. materials: {},
  82323. materialLibraries: [],
  82324. startObject: function ( name, fromDeclaration ) {
  82325. // If the current object (initial from reset) is not from a g/o declaration in the parsed
  82326. // file. We need to use it for the first parsed g/o to keep things in sync.
  82327. if ( this.object && this.object.fromDeclaration === false ) {
  82328. this.object.name = name;
  82329. this.object.fromDeclaration = ( fromDeclaration !== false );
  82330. return;
  82331. }
  82332. var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
  82333. if ( this.object && typeof this.object._finalize === 'function' ) {
  82334. this.object._finalize( true );
  82335. }
  82336. this.object = {
  82337. name: name || '',
  82338. fromDeclaration: ( fromDeclaration !== false ),
  82339. geometry: {
  82340. vertices: [],
  82341. normals: [],
  82342. colors: [],
  82343. uvs: [],
  82344. hasUVIndices: false
  82345. },
  82346. materials: [],
  82347. smooth: true,
  82348. startMaterial: function ( name, libraries ) {
  82349. var previous = this._finalize( false );
  82350. // New usemtl declaration overwrites an inherited material, except if faces were declared
  82351. // after the material, then it must be preserved for proper MultiMaterial continuation.
  82352. if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
  82353. this.materials.splice( previous.index, 1 );
  82354. }
  82355. var material = {
  82356. index: this.materials.length,
  82357. name: name || '',
  82358. mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
  82359. smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
  82360. groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
  82361. groupEnd: - 1,
  82362. groupCount: - 1,
  82363. inherited: false,
  82364. clone: function ( index ) {
  82365. var cloned = {
  82366. index: ( typeof index === 'number' ? index : this.index ),
  82367. name: this.name,
  82368. mtllib: this.mtllib,
  82369. smooth: this.smooth,
  82370. groupStart: 0,
  82371. groupEnd: - 1,
  82372. groupCount: - 1,
  82373. inherited: false
  82374. };
  82375. cloned.clone = this.clone.bind( cloned );
  82376. return cloned;
  82377. }
  82378. };
  82379. this.materials.push( material );
  82380. return material;
  82381. },
  82382. currentMaterial: function () {
  82383. if ( this.materials.length > 0 ) {
  82384. return this.materials[ this.materials.length - 1 ];
  82385. }
  82386. return undefined;
  82387. },
  82388. _finalize: function ( end ) {
  82389. var lastMultiMaterial = this.currentMaterial();
  82390. if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
  82391. lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
  82392. lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
  82393. lastMultiMaterial.inherited = false;
  82394. }
  82395. // Ignore objects tail materials if no face declarations followed them before a new o/g started.
  82396. if ( end && this.materials.length > 1 ) {
  82397. for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
  82398. if ( this.materials[ mi ].groupCount <= 0 ) {
  82399. this.materials.splice( mi, 1 );
  82400. }
  82401. }
  82402. }
  82403. // Guarantee at least one empty material, this makes the creation later more straight forward.
  82404. if ( end && this.materials.length === 0 ) {
  82405. this.materials.push( {
  82406. name: '',
  82407. smooth: this.smooth
  82408. } );
  82409. }
  82410. return lastMultiMaterial;
  82411. }
  82412. };
  82413. // Inherit previous objects material.
  82414. // Spec tells us that a declared material must be set to all objects until a new material is declared.
  82415. // If a usemtl declaration is encountered while this new object is being parsed, it will
  82416. // overwrite the inherited material. Exception being that there was already face declarations
  82417. // to the inherited material, then it will be preserved for proper MultiMaterial continuation.
  82418. if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
  82419. var declared = previousMaterial.clone( 0 );
  82420. declared.inherited = true;
  82421. this.object.materials.push( declared );
  82422. }
  82423. this.objects.push( this.object );
  82424. },
  82425. finalize: function () {
  82426. if ( this.object && typeof this.object._finalize === 'function' ) {
  82427. this.object._finalize( true );
  82428. }
  82429. },
  82430. parseVertexIndex: function ( value, len ) {
  82431. var index = parseInt( value, 10 );
  82432. return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
  82433. },
  82434. parseNormalIndex: function ( value, len ) {
  82435. var index = parseInt( value, 10 );
  82436. return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
  82437. },
  82438. parseUVIndex: function ( value, len ) {
  82439. var index = parseInt( value, 10 );
  82440. return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
  82441. },
  82442. addVertex: function ( a, b, c ) {
  82443. var src = this.vertices;
  82444. var dst = this.object.geometry.vertices;
  82445. dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
  82446. dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
  82447. dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
  82448. },
  82449. addVertexPoint: function ( a ) {
  82450. var src = this.vertices;
  82451. var dst = this.object.geometry.vertices;
  82452. dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
  82453. },
  82454. addVertexLine: function ( a ) {
  82455. var src = this.vertices;
  82456. var dst = this.object.geometry.vertices;
  82457. dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
  82458. },
  82459. addNormal: function ( a, b, c ) {
  82460. var src = this.normals;
  82461. var dst = this.object.geometry.normals;
  82462. dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
  82463. dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
  82464. dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
  82465. },
  82466. addFaceNormal: function ( a, b, c ) {
  82467. var src = this.vertices;
  82468. var dst = this.object.geometry.normals;
  82469. vA.fromArray( src, a );
  82470. vB.fromArray( src, b );
  82471. vC.fromArray( src, c );
  82472. cb.subVectors( vC, vB );
  82473. ab.subVectors( vA, vB );
  82474. cb.cross( ab );
  82475. cb.normalize();
  82476. dst.push( cb.x, cb.y, cb.z );
  82477. dst.push( cb.x, cb.y, cb.z );
  82478. dst.push( cb.x, cb.y, cb.z );
  82479. },
  82480. addColor: function ( a, b, c ) {
  82481. var src = this.colors;
  82482. var dst = this.object.geometry.colors;
  82483. if ( src[ a ] !== undefined ) dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
  82484. if ( src[ b ] !== undefined ) dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
  82485. if ( src[ c ] !== undefined ) dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
  82486. },
  82487. addUV: function ( a, b, c ) {
  82488. var src = this.uvs;
  82489. var dst = this.object.geometry.uvs;
  82490. dst.push( src[ a + 0 ], src[ a + 1 ] );
  82491. dst.push( src[ b + 0 ], src[ b + 1 ] );
  82492. dst.push( src[ c + 0 ], src[ c + 1 ] );
  82493. },
  82494. addDefaultUV: function () {
  82495. var dst = this.object.geometry.uvs;
  82496. dst.push( 0, 0 );
  82497. dst.push( 0, 0 );
  82498. dst.push( 0, 0 );
  82499. },
  82500. addUVLine: function ( a ) {
  82501. var src = this.uvs;
  82502. var dst = this.object.geometry.uvs;
  82503. dst.push( src[ a + 0 ], src[ a + 1 ] );
  82504. },
  82505. addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
  82506. var vLen = this.vertices.length;
  82507. var ia = this.parseVertexIndex( a, vLen );
  82508. var ib = this.parseVertexIndex( b, vLen );
  82509. var ic = this.parseVertexIndex( c, vLen );
  82510. this.addVertex( ia, ib, ic );
  82511. this.addColor( ia, ib, ic );
  82512. // normals
  82513. if ( na !== undefined && na !== '' ) {
  82514. var nLen = this.normals.length;
  82515. ia = this.parseNormalIndex( na, nLen );
  82516. ib = this.parseNormalIndex( nb, nLen );
  82517. ic = this.parseNormalIndex( nc, nLen );
  82518. this.addNormal( ia, ib, ic );
  82519. } else {
  82520. this.addFaceNormal( ia, ib, ic );
  82521. }
  82522. // uvs
  82523. if ( ua !== undefined && ua !== '' ) {
  82524. var uvLen = this.uvs.length;
  82525. ia = this.parseUVIndex( ua, uvLen );
  82526. ib = this.parseUVIndex( ub, uvLen );
  82527. ic = this.parseUVIndex( uc, uvLen );
  82528. this.addUV( ia, ib, ic );
  82529. this.object.geometry.hasUVIndices = true;
  82530. } else {
  82531. // add placeholder values (for inconsistent face definitions)
  82532. this.addDefaultUV();
  82533. }
  82534. },
  82535. addPointGeometry: function ( vertices ) {
  82536. this.object.geometry.type = 'Points';
  82537. var vLen = this.vertices.length;
  82538. for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
  82539. var index = this.parseVertexIndex( vertices[ vi ], vLen );
  82540. this.addVertexPoint( index );
  82541. this.addColor( index );
  82542. }
  82543. },
  82544. addLineGeometry: function ( vertices, uvs ) {
  82545. this.object.geometry.type = 'Line';
  82546. var vLen = this.vertices.length;
  82547. var uvLen = this.uvs.length;
  82548. for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
  82549. this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
  82550. }
  82551. for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
  82552. this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
  82553. }
  82554. }
  82555. };
  82556. state.startObject( '', false );
  82557. return state;
  82558. }
  82559. //
  82560. function OBJLoader( manager ) {
  82561. Loader.call( this, manager );
  82562. this.materials = null;
  82563. }
  82564. OBJLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  82565. constructor: OBJLoader,
  82566. load: function ( url, onLoad, onProgress, onError ) {
  82567. var scope = this;
  82568. var loader = new FileLoader( this.manager );
  82569. loader.setPath( this.path );
  82570. loader.setRequestHeader( this.requestHeader );
  82571. loader.setWithCredentials( this.withCredentials );
  82572. loader.load( url, function ( text , total ) {// xzw add total
  82573. try {
  82574. onLoad( scope.parse( text ) , total );
  82575. } catch ( e ) {
  82576. if ( onError ) {
  82577. onError( e );
  82578. } else {
  82579. console.error( e );
  82580. }
  82581. scope.manager.itemError( url );
  82582. }
  82583. }, onProgress, onError );
  82584. },
  82585. setMaterials: function ( materials ) {
  82586. this.materials = materials;
  82587. return this;
  82588. },
  82589. parse: function ( text ) {
  82590. var state = new ParserState();
  82591. if ( text.indexOf( '\r\n' ) !== - 1 ) {
  82592. // This is faster than String.split with regex that splits on both
  82593. text = text.replace( /\r\n/g, '\n' );
  82594. }
  82595. if ( text.indexOf( '\\\n' ) !== - 1 ) {
  82596. // join lines separated by a line continuation character (\)
  82597. text = text.replace( /\\\n/g, '' );
  82598. }
  82599. var lines = text.split( '\n' );
  82600. var line = '', lineFirstChar = '';
  82601. var lineLength = 0;
  82602. var result = [];
  82603. // Faster to just trim left side of the line. Use if available.
  82604. var trimLeft = ( typeof ''.trimLeft === 'function' );
  82605. for ( var i = 0, l = lines.length; i < l; i ++ ) {
  82606. line = lines[ i ];
  82607. line = trimLeft ? line.trimLeft() : line.trim();
  82608. lineLength = line.length;
  82609. if ( lineLength === 0 ) continue;
  82610. lineFirstChar = line.charAt( 0 );
  82611. // @todo invoke passed in handler if any
  82612. if ( lineFirstChar === '#' ) continue;
  82613. if ( lineFirstChar === 'v' ) {
  82614. var data = line.split( /\s+/ );
  82615. switch ( data[ 0 ] ) {
  82616. case 'v':
  82617. state.vertices.push(
  82618. parseFloat( data[ 1 ] ),
  82619. parseFloat( data[ 2 ] ),
  82620. parseFloat( data[ 3 ] )
  82621. );
  82622. if ( data.length >= 7 ) {
  82623. state.colors.push(
  82624. parseFloat( data[ 4 ] ),
  82625. parseFloat( data[ 5 ] ),
  82626. parseFloat( data[ 6 ] )
  82627. );
  82628. } else {
  82629. // if no colors are defined, add placeholders so color and vertex indices match
  82630. state.colors.push( undefined, undefined, undefined );
  82631. }
  82632. break;
  82633. case 'vn':
  82634. state.normals.push(
  82635. parseFloat( data[ 1 ] ),
  82636. parseFloat( data[ 2 ] ),
  82637. parseFloat( data[ 3 ] )
  82638. );
  82639. break;
  82640. case 'vt':
  82641. state.uvs.push(
  82642. parseFloat( data[ 1 ] ),
  82643. parseFloat( data[ 2 ] )
  82644. );
  82645. break;
  82646. }
  82647. } else if ( lineFirstChar === 'f' ) {
  82648. var lineData = line.substr( 1 ).trim();
  82649. var vertexData = lineData.split( /\s+/ );
  82650. var faceVertices = [];
  82651. // Parse the face vertex data into an easy to work with format
  82652. for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
  82653. var vertex = vertexData[ j ];
  82654. if ( vertex.length > 0 ) {
  82655. var vertexParts = vertex.split( '/' );
  82656. faceVertices.push( vertexParts );
  82657. }
  82658. }
  82659. // Draw an edge between the first vertex and all subsequent vertices to form an n-gon
  82660. var v1 = faceVertices[ 0 ];
  82661. for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
  82662. var v2 = faceVertices[ j ];
  82663. var v3 = faceVertices[ j + 1 ];
  82664. state.addFace(
  82665. v1[ 0 ], v2[ 0 ], v3[ 0 ],
  82666. v1[ 1 ], v2[ 1 ], v3[ 1 ],
  82667. v1[ 2 ], v2[ 2 ], v3[ 2 ]
  82668. );
  82669. }
  82670. } else if ( lineFirstChar === 'l' ) {
  82671. var lineParts = line.substring( 1 ).trim().split( ' ' );
  82672. var lineVertices = [], lineUVs = [];
  82673. if ( line.indexOf( '/' ) === - 1 ) {
  82674. lineVertices = lineParts;
  82675. } else {
  82676. for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
  82677. var parts = lineParts[ li ].split( '/' );
  82678. if ( parts[ 0 ] !== '' ) lineVertices.push( parts[ 0 ] );
  82679. if ( parts[ 1 ] !== '' ) lineUVs.push( parts[ 1 ] );
  82680. }
  82681. }
  82682. state.addLineGeometry( lineVertices, lineUVs );
  82683. } else if ( lineFirstChar === 'p' ) {
  82684. var lineData = line.substr( 1 ).trim();
  82685. var pointData = lineData.split( ' ' );
  82686. state.addPointGeometry( pointData );
  82687. } else if ( ( result = object_pattern.exec( line ) ) !== null ) {
  82688. // o object_name
  82689. // or
  82690. // g group_name
  82691. // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
  82692. // var name = result[ 0 ].substr( 1 ).trim();
  82693. var name = ( ' ' + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
  82694. state.startObject( name );
  82695. } else if ( material_use_pattern.test( line ) ) {
  82696. // material
  82697. state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
  82698. } else if ( material_library_pattern.test( line ) ) {
  82699. // mtl file
  82700. state.materialLibraries.push( line.substring( 7 ).trim() );
  82701. } else if ( map_use_pattern.test( line ) ) {
  82702. // the line is parsed but ignored since the loader assumes textures are defined MTL files
  82703. // (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
  82704. console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
  82705. } else if ( lineFirstChar === 's' ) {
  82706. result = line.split( ' ' );
  82707. // smooth shading
  82708. // @todo Handle files that have varying smooth values for a set of faces inside one geometry,
  82709. // but does not define a usemtl for each face set.
  82710. // This should be detected and a dummy material created (later MultiMaterial and geometry groups).
  82711. // This requires some care to not create extra material on each smooth value for "normal" obj files.
  82712. // where explicit usemtl defines geometry groups.
  82713. // Example asset: examples/models/obj/cerberus/Cerberus.obj
  82714. /*
  82715. * http://paulbourke.net/dataformats/obj/
  82716. * or
  82717. * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
  82718. *
  82719. * From chapter "Grouping" Syntax explanation "s group_number":
  82720. * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
  82721. * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
  82722. * surfaces, smoothing groups are either turned on or off; there is no difference between values greater
  82723. * than 0."
  82724. */
  82725. if ( result.length > 1 ) {
  82726. var value = result[ 1 ].trim().toLowerCase();
  82727. state.object.smooth = ( value !== '0' && value !== 'off' );
  82728. } else {
  82729. // ZBrush can produce "s" lines #11707
  82730. state.object.smooth = true;
  82731. }
  82732. var material = state.object.currentMaterial();
  82733. if ( material ) material.smooth = state.object.smooth;
  82734. } else {
  82735. // Handle null terminated files without exception
  82736. if ( line === '\0' ) continue;
  82737. console.warn( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
  82738. }
  82739. }
  82740. state.finalize();
  82741. var container = new Group();
  82742. container.materialLibraries = [].concat( state.materialLibraries );
  82743. var hasPrimitives = ! ( state.objects.length === 1 && state.objects[ 0 ].geometry.vertices.length === 0 );
  82744. if ( hasPrimitives === true ) {
  82745. for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
  82746. var object = state.objects[ i ];
  82747. var geometry = object.geometry;
  82748. var materials = object.materials;
  82749. var isLine = ( geometry.type === 'Line' );
  82750. var isPoints = ( geometry.type === 'Points' );
  82751. var hasVertexColors = false;
  82752. // Skip o/g line declarations that did not follow with any faces
  82753. if ( geometry.vertices.length === 0 ) continue;
  82754. var buffergeometry = new BufferGeometry();
  82755. buffergeometry.setAttribute( 'position', new Float32BufferAttribute( geometry.vertices, 3 ) );
  82756. if ( geometry.normals.length > 0 ) {
  82757. buffergeometry.setAttribute( 'normal', new Float32BufferAttribute( geometry.normals, 3 ) );
  82758. }
  82759. if ( geometry.colors.length > 0 ) {
  82760. hasVertexColors = true;
  82761. buffergeometry.setAttribute( 'color', new Float32BufferAttribute( geometry.colors, 3 ) );
  82762. }
  82763. if ( geometry.hasUVIndices === true ) {
  82764. buffergeometry.setAttribute( 'uv', new Float32BufferAttribute( geometry.uvs, 2 ) );
  82765. }
  82766. // Create materials
  82767. var createdMaterials = [];
  82768. for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
  82769. var sourceMaterial = materials[ mi ];
  82770. var materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_' + hasVertexColors;
  82771. var material = state.materials[ materialHash ];
  82772. if ( this.materials !== null ) {
  82773. material = this.materials.create( sourceMaterial.name );
  82774. // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
  82775. if ( isLine && material && ! ( material instanceof LineBasicMaterial ) ) {
  82776. var materialLine = new LineBasicMaterial();
  82777. Material.prototype.copy.call( materialLine, material );
  82778. materialLine.color.copy( material.color );
  82779. material = materialLine;
  82780. } else if ( isPoints && material && ! ( material instanceof PointsMaterial ) ) {
  82781. var materialPoints = new PointsMaterial( { size: 10, sizeAttenuation: false } );
  82782. Material.prototype.copy.call( materialPoints, material );
  82783. materialPoints.color.copy( material.color );
  82784. materialPoints.map = material.map;
  82785. material = materialPoints;
  82786. }
  82787. }
  82788. if ( material === undefined ) {
  82789. if ( isLine ) {
  82790. material = new LineBasicMaterial();
  82791. } else if ( isPoints ) {
  82792. material = new PointsMaterial( { size: 1, sizeAttenuation: false } );
  82793. } else {
  82794. material = new MeshPhongMaterial();
  82795. }
  82796. material.name = sourceMaterial.name;
  82797. material.flatShading = sourceMaterial.smooth ? false : true;
  82798. material.vertexColors = hasVertexColors;
  82799. state.materials[ materialHash ] = material;
  82800. }
  82801. createdMaterials.push( material );
  82802. }
  82803. // Create mesh
  82804. var mesh;
  82805. if ( createdMaterials.length > 1 ) {
  82806. for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
  82807. var sourceMaterial = materials[ mi ];
  82808. buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
  82809. }
  82810. if ( isLine ) {
  82811. mesh = new LineSegments( buffergeometry, createdMaterials );
  82812. } else if ( isPoints ) {
  82813. mesh = new Points( buffergeometry, createdMaterials );
  82814. } else {
  82815. mesh = new Mesh( buffergeometry, createdMaterials );
  82816. }
  82817. } else {
  82818. if ( isLine ) {
  82819. mesh = new LineSegments( buffergeometry, createdMaterials[ 0 ] );
  82820. } else if ( isPoints ) {
  82821. mesh = new Points( buffergeometry, createdMaterials[ 0 ] );
  82822. } else {
  82823. mesh = new Mesh( buffergeometry, createdMaterials[ 0 ] );
  82824. }
  82825. }
  82826. mesh.name = object.name;
  82827. container.add( mesh );
  82828. }
  82829. } else {
  82830. // if there is only the default parser state object with no geometry data, interpret data as point cloud
  82831. if ( state.vertices.length > 0 ) {
  82832. var material = new PointsMaterial( { size: 1, sizeAttenuation: false } );
  82833. var buffergeometry = new BufferGeometry();
  82834. buffergeometry.setAttribute( 'position', new Float32BufferAttribute( state.vertices, 3 ) );
  82835. if ( state.colors.length > 0 && state.colors[ 0 ] !== undefined ) {
  82836. buffergeometry.setAttribute( 'color', new Float32BufferAttribute( state.colors, 3 ) );
  82837. material.vertexColors = true;
  82838. }
  82839. var points = new Points( buffergeometry, material );
  82840. container.add( points );
  82841. }
  82842. }
  82843. return container;
  82844. }
  82845. } );
  82846. return OBJLoader;
  82847. } )();
  82848. /**
  82849. * Loads a Wavefront .mtl file specifying materials
  82850. */
  82851. var MTLLoader = function ( manager ) {
  82852. Loader.call( this, manager );
  82853. };
  82854. MTLLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
  82855. constructor: MTLLoader,
  82856. /**
  82857. * Loads and parses a MTL asset from a URL.
  82858. *
  82859. * @param {String} url - URL to the MTL file.
  82860. * @param {Function} [onLoad] - Callback invoked with the loaded object.
  82861. * @param {Function} [onProgress] - Callback for download progress.
  82862. * @param {Function} [onError] - Callback for download errors.
  82863. *
  82864. * @see setPath setResourcePath
  82865. *
  82866. * @note In order for relative texture references to resolve correctly
  82867. * you must call setResourcePath() explicitly prior to load.
  82868. */
  82869. load: function ( url, onLoad, onProgress, onError ) {
  82870. var scope = this;
  82871. var path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
  82872. var loader = new FileLoader( this.manager );
  82873. loader.setPath( this.path );
  82874. loader.setRequestHeader( this.requestHeader );
  82875. loader.setWithCredentials( this.withCredentials );
  82876. loader.load( url, function ( text ) {
  82877. try {
  82878. onLoad( scope.parse( text, path ) );
  82879. } catch ( e ) {
  82880. if ( onError ) {
  82881. onError( e );
  82882. } else {
  82883. console.error( e );
  82884. }
  82885. scope.manager.itemError( url );
  82886. }
  82887. }, onProgress, onError );
  82888. },
  82889. setMaterialOptions: function ( value ) {
  82890. this.materialOptions = value;
  82891. return this;
  82892. },
  82893. /**
  82894. * Parses a MTL file.
  82895. *
  82896. * @param {String} text - Content of MTL file
  82897. * @return {MTLLoader.MaterialCreator}
  82898. *
  82899. * @see setPath setResourcePath
  82900. *
  82901. * @note In order for relative texture references to resolve correctly
  82902. * you must call setResourcePath() explicitly prior to parse.
  82903. */
  82904. parse: function ( text, path ) {
  82905. var lines = text.split( '\n' );
  82906. var info = {};
  82907. var delimiter_pattern = /\s+/;
  82908. var materialsInfo = {};
  82909. for ( var i = 0; i < lines.length; i ++ ) {
  82910. var line = lines[ i ];
  82911. line = line.trim();
  82912. if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
  82913. // Blank line or comment ignore
  82914. continue;
  82915. }
  82916. var pos = line.indexOf( ' ' );
  82917. var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
  82918. key = key.toLowerCase();
  82919. var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : '';
  82920. value = value.trim();
  82921. if ( key === 'newmtl' ) {
  82922. // New material
  82923. info = { name: value };
  82924. materialsInfo[ value ] = info;
  82925. } else {
  82926. if ( key === 'ka' || key === 'kd' || key === 'ks' || key === 'ke' ) {
  82927. var ss = value.split( delimiter_pattern, 3 );
  82928. info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
  82929. } else {
  82930. info[ key ] = value;
  82931. }
  82932. }
  82933. }
  82934. var materialCreator = new MTLLoader.MaterialCreator( this.resourcePath || path, this.materialOptions );
  82935. materialCreator.setCrossOrigin( this.crossOrigin );
  82936. materialCreator.setManager( this.manager );
  82937. materialCreator.setMaterials( materialsInfo );
  82938. return materialCreator;
  82939. }
  82940. } );
  82941. /**
  82942. * Create a new MTLLoader.MaterialCreator
  82943. * @param baseUrl - Url relative to which textures are loaded
  82944. * @param options - Set of options on how to construct the materials
  82945. * side: Which side to apply the material
  82946. * FrontSide (default), THREE.BackSide, THREE.DoubleSide
  82947. * wrap: What type of wrapping to apply for textures
  82948. * RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
  82949. * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
  82950. * Default: false, assumed to be already normalized
  82951. * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
  82952. * Default: false
  82953. * @constructor
  82954. */
  82955. MTLLoader.MaterialCreator = function ( baseUrl, options ) {
  82956. this.baseUrl = baseUrl || '';
  82957. this.options = options;
  82958. this.materialsInfo = {};
  82959. this.materials = {};
  82960. this.materialsArray = [];
  82961. this.nameLookup = {};
  82962. this.side = ( this.options && this.options.side ) ? this.options.side : FrontSide;
  82963. this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : RepeatWrapping;
  82964. };
  82965. MTLLoader.MaterialCreator.prototype = {
  82966. constructor: MTLLoader.MaterialCreator,
  82967. crossOrigin: 'anonymous',
  82968. setCrossOrigin: function ( value ) {
  82969. this.crossOrigin = value;
  82970. return this;
  82971. },
  82972. setManager: function ( value ) {
  82973. this.manager = value;
  82974. },
  82975. setMaterials: function ( materialsInfo ) {
  82976. this.materialsInfo = this.convert( materialsInfo );
  82977. this.materials = {};
  82978. this.materialsArray = [];
  82979. this.nameLookup = {};
  82980. },
  82981. convert: function ( materialsInfo ) {
  82982. if ( ! this.options ) return materialsInfo;
  82983. var converted = {};
  82984. for ( var mn in materialsInfo ) {
  82985. // Convert materials info into normalized form based on options
  82986. var mat = materialsInfo[ mn ];
  82987. var covmat = {};
  82988. converted[ mn ] = covmat;
  82989. for ( var prop in mat ) {
  82990. var save = true;
  82991. var value = mat[ prop ];
  82992. var lprop = prop.toLowerCase();
  82993. switch ( lprop ) {
  82994. case 'kd':
  82995. case 'ka':
  82996. case 'ks':
  82997. // Diffuse color (color under white light) using RGB values
  82998. if ( this.options && this.options.normalizeRGB ) {
  82999. value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
  83000. }
  83001. if ( this.options && this.options.ignoreZeroRGBs ) {
  83002. if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) {
  83003. // ignore
  83004. save = false;
  83005. }
  83006. }
  83007. break;
  83008. default:
  83009. break;
  83010. }
  83011. if ( save ) {
  83012. covmat[ lprop ] = value;
  83013. }
  83014. }
  83015. }
  83016. return converted;
  83017. },
  83018. preload: function () {
  83019. for ( var mn in this.materialsInfo ) {
  83020. this.create( mn );
  83021. }
  83022. },
  83023. getIndex: function ( materialName ) {
  83024. return this.nameLookup[ materialName ];
  83025. },
  83026. getAsArray: function () {
  83027. var index = 0;
  83028. for ( var mn in this.materialsInfo ) {
  83029. this.materialsArray[ index ] = this.create( mn );
  83030. this.nameLookup[ mn ] = index;
  83031. index ++;
  83032. }
  83033. return this.materialsArray;
  83034. },
  83035. create: function ( materialName ) {
  83036. if ( this.materials[ materialName ] === undefined ) {
  83037. this.createMaterial_( materialName );
  83038. }
  83039. return this.materials[ materialName ];
  83040. },
  83041. createMaterial_: function ( materialName ) {
  83042. // Create material
  83043. var scope = this;
  83044. var mat = this.materialsInfo[ materialName ];
  83045. var params = {
  83046. name: materialName,
  83047. side: this.side
  83048. };
  83049. function resolveURL( baseUrl, url ) {
  83050. if ( typeof url !== 'string' || url === '' )
  83051. return '';
  83052. // Absolute URL
  83053. if ( /^https?:\/\//i.test( url ) ) return url;
  83054. return baseUrl + url;
  83055. }
  83056. function setMapForType( mapType, value ) {
  83057. if ( params[ mapType ] ) return; // Keep the first encountered texture
  83058. var texParams = scope.getTextureParams( value, params );
  83059. var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) );
  83060. map.repeat.copy( texParams.scale );
  83061. map.offset.copy( texParams.offset );
  83062. map.wrapS = scope.wrap;
  83063. map.wrapT = scope.wrap;
  83064. params[ mapType ] = map;
  83065. }
  83066. for ( var prop in mat ) {
  83067. var value = mat[ prop ];
  83068. var n;
  83069. if ( value === '' ) continue;
  83070. switch ( prop.toLowerCase() ) {
  83071. // Ns is material specular exponent
  83072. case 'kd':
  83073. // Diffuse color (color under white light) using RGB values
  83074. params.color = new Color().fromArray( value );
  83075. break;
  83076. case 'ks':
  83077. // Specular color (color when light is reflected from shiny surface) using RGB values
  83078. //params.specular = new Color().fromArray( value );
  83079. //console.log('specular',value)
  83080. break;
  83081. case 'ke':
  83082. // Emissive using RGB values
  83083. params.emissive = new Color().fromArray( value );
  83084. break;
  83085. case 'map_kd':
  83086. // Diffuse texture map
  83087. setMapForType( 'map', value );
  83088. break;
  83089. case 'map_ks':
  83090. // Specular map
  83091. setMapForType( 'specularMap', value );
  83092. break;
  83093. case 'map_ke':
  83094. // Emissive map
  83095. setMapForType( 'emissiveMap', value );
  83096. break;
  83097. case 'norm':
  83098. setMapForType( 'normalMap', value );
  83099. break;
  83100. case 'map_bump':
  83101. case 'bump':
  83102. // Bump texture map
  83103. setMapForType( 'bumpMap', value );
  83104. break;
  83105. case 'map_d':
  83106. // Alpha map
  83107. setMapForType( 'alphaMap', value );
  83108. params.transparent = true;
  83109. break;
  83110. case 'ns':
  83111. // The specular exponent (defines the focus of the specular highlight)
  83112. // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
  83113. //params.shininess = parseFloat( value );
  83114. //console.log('shininess',value)
  83115. break;
  83116. case 'd':
  83117. n = parseFloat( value );
  83118. if ( n < 1 ) {
  83119. params.opacity = n;
  83120. params.transparent = true;
  83121. }
  83122. break;
  83123. case 'tr':
  83124. n = parseFloat( value );
  83125. if ( this.options && this.options.invertTrProperty ) n = 1 - n;
  83126. if ( n > 0 ) {
  83127. params.opacity = 1 - n;
  83128. params.transparent = true;
  83129. }
  83130. break;
  83131. default:
  83132. break;
  83133. }
  83134. }
  83135. this.materials[ materialName ] = new MeshStandardMaterial( params );//MeshPhongMaterial( params );
  83136. return this.materials[ materialName ];
  83137. },
  83138. getTextureParams: function ( value, matParams ) {
  83139. var texParams = {
  83140. scale: new Vector2$1( 1, 1 ),
  83141. offset: new Vector2$1( 0, 0 )
  83142. };
  83143. var items = value.split( /\s+/ );
  83144. var pos;
  83145. pos = items.indexOf( '-bm' );
  83146. if ( pos >= 0 ) {
  83147. matParams.bumpScale = parseFloat( items[ pos + 1 ] );
  83148. items.splice( pos, 2 );
  83149. }
  83150. pos = items.indexOf( '-s' );
  83151. if ( pos >= 0 ) {
  83152. texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
  83153. items.splice( pos, 4 ); // we expect 3 parameters here!
  83154. }
  83155. pos = items.indexOf( '-o' );
  83156. if ( pos >= 0 ) {
  83157. texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
  83158. items.splice( pos, 4 ); // we expect 3 parameters here!
  83159. }
  83160. texParams.url = items.join( ' ' ).trim();
  83161. return texParams;
  83162. },
  83163. loadTexture: function ( url, mapping, onLoad, onProgress, onError ) {
  83164. var texture;
  83165. var manager = ( this.manager !== undefined ) ? this.manager : DefaultLoadingManager;
  83166. var loader = manager.getHandler( url );
  83167. if ( loader === null ) {
  83168. loader = new TextureLoader( manager );
  83169. }
  83170. if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );
  83171. texture = loader.load( url, onLoad, onProgress, onError );
  83172. if ( mapping !== undefined ) texture.mapping = mapping;
  83173. return texture;
  83174. }
  83175. };
  83176. /**
  83177. * @author alteredq / http://alteredqualia.com/
  83178. */
  83179. let Pass = function () {
  83180. // if set to true, the pass is processed by the composer
  83181. this.enabled = true;
  83182. // if set to true, the pass indicates to swap read and write buffer after rendering
  83183. this.needsSwap = true;
  83184. // if set to true, the pass clears its buffer before rendering
  83185. this.clear = false;
  83186. // if set to true, the result of the pass is rendered to screen
  83187. this.renderToScreen = false;
  83188. };
  83189. Object.assign( Pass.prototype, {
  83190. setSize: function ( width, height ) {},
  83191. render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
  83192. console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
  83193. }
  83194. } );
  83195. let ShaderPass = function ( shader, textureID ) {
  83196. Pass.call( this );
  83197. this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
  83198. if ( shader instanceof ShaderMaterial ) {
  83199. this.uniforms = shader.uniforms;
  83200. this.material = shader;
  83201. } else if ( shader ) {
  83202. this.uniforms = UniformsUtils.clone( shader.uniforms );
  83203. this.material = new ShaderMaterial( {
  83204. defines: Object.assign( {}, shader.defines ),
  83205. uniforms: this.uniforms,
  83206. vertexShader: shader.vertexShader,
  83207. fragmentShader: shader.fragmentShader,
  83208. transparent:true,//add
  83209. } );
  83210. }
  83211. this.camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
  83212. this.scene = new Scene();
  83213. this.quad = new Mesh( new PlaneBufferGeometry( 2, 2 ), null );
  83214. this.quad.frustumCulled = false; // Avoid getting clipped
  83215. this.scene.add( this.quad );
  83216. };
  83217. ShaderPass.prototype = Object.assign( Object.create( Pass.prototype ), {
  83218. constructor: ShaderPass,
  83219. render: function(scene,camera, renderer, writeBuffer, readBuffer, delta, maskActive ) {
  83220. let oldTarget = renderer.getRenderTarget();
  83221. /* if(this.readTarget){ //add
  83222. readBuffer = oldTarget
  83223. } */
  83224. if ( this.uniforms[ this.textureID ] ) {
  83225. this.uniforms[ this.textureID ].value = readBuffer.texture;
  83226. }
  83227. this.quad.material = this.material;
  83228. if ( this.renderToScreen ) {
  83229. renderer.render( this.scene, this.camera );
  83230. } else {
  83231. renderer.setRenderTarget(writeBuffer);
  83232. if(this.clear) renderer.clear();
  83233. renderer.render( this.scene, this.camera );
  83234. renderer.setRenderTarget(oldTarget);
  83235. }
  83236. }
  83237. } );
  83238. /**
  83239. * @author alteredq / http://alteredqualia.com/
  83240. *
  83241. * Full-screen textured quad shader
  83242. */
  83243. let CopyShader = {
  83244. uniforms: {
  83245. "tDiffuse": { value: null },
  83246. "opacity": { value: 1.0 }
  83247. },
  83248. vertexShader: [
  83249. "varying vec2 vUv;",
  83250. "void main() {",
  83251. "vUv = uv;",
  83252. "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
  83253. "}"
  83254. ].join( "\n" ),
  83255. fragmentShader: [
  83256. "uniform float opacity;",
  83257. "uniform sampler2D tDiffuse;",
  83258. "varying vec2 vUv;",
  83259. "void main() {",
  83260. "vec4 texel = texture2D( tDiffuse, vUv );", //如果开启premultipliedAlpha用这个,否则用注释的
  83261. "gl_FragColor = opacity * texel;",
  83262. //"gl_FragColor = texture2D( tDiffuse, vUv );",
  83263. //"gl_FragColor.a *= opacity;",
  83264. "}"
  83265. ].join( "\n" )
  83266. };
  83267. /**
  83268. *
  83269. * Supersample Anti-Aliasing Render Pass
  83270. *
  83271. * @author bhouston / http://clara.io/
  83272. *
  83273. * This manual approach to SSAA re-renders the scene ones for each sample with camera jitter and accumulates the results.
  83274. *
  83275. * References: https://en.wikipedia.org/wiki/Supersampling
  83276. *
  83277. */
  83278. //较为原始的一种抗锯齿 (超级采样抗锯齿)
  83279. let SSAARenderPass = function ( clearColor, clearAlpha ) {
  83280. Pass.call( this );
  83281. //this.scene //= scene;
  83282. //this.camera = camera;
  83283. this.sampleLevel = 4; // specified as n, where the number of samples is 2^n, so sampleLevel = 4, is 2^4 samples, 16.
  83284. this.unbiased = true;
  83285. // as we need to clear the buffer in this pass, clearColor must be set to something, defaults to black.
  83286. this.clearColor = ( clearColor !== undefined ) ? clearColor : 0x000000;
  83287. this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
  83288. this.renderUniforms = {
  83289. bgTex : {value:null},
  83290. outlineTex : {value:null},
  83291. opacity : {value:1},
  83292. };
  83293. this.renderMat = new ShaderMaterial({
  83294. uniforms: this.renderUniforms,
  83295. vertexShader: CopyShader.vertexShader,
  83296. /* fragmentShader: CopyShader.fragmentShader, */
  83297. fragmentShader: `
  83298. uniform sampler2D bgTex;
  83299. uniform sampler2D outlineTex;
  83300. uniform float opacity;
  83301. varying vec2 vUv;
  83302. void main() {
  83303. vec4 color1 = texture2D( bgTex, vUv );
  83304. vec4 color2 = texture2D( outlineTex, vUv );
  83305. gl_FragColor = opacity * mix(color1, color2, color2.a) ;
  83306. }
  83307. `,
  83308. premultipliedAlpha: true,
  83309. blending: AdditiveBlending,
  83310. depthTest: false,
  83311. depthWrite: false,
  83312. transparent: true
  83313. });
  83314. this.renderMat2 = new ShaderMaterial({
  83315. uniforms: UniformsUtils.clone(CopyShader.uniforms) ,
  83316. vertexShader: CopyShader.vertexShader,
  83317. fragmentShader:`uniform float opacity;
  83318. uniform sampler2D tDiffuse;
  83319. varying vec2 vUv;
  83320. void main() {
  83321. vec4 texel = texture2D( tDiffuse, vUv );
  83322. if(texel.r == 0.0 && texel.g == 0.0 && texel.b == 0.0){
  83323. discard;
  83324. }else{
  83325. gl_FragColor = opacity * texel;
  83326. }
  83327. }
  83328. ` ,
  83329. depthTest: false,
  83330. depthWrite: false,
  83331. transparent: true
  83332. });
  83333. ////////////////////
  83334. /* this.renderMat.blendSrc = THREE.OneFactor //即将写入缓冲区的颜色。
  83335. this.renderMat.blendDst = THREE.OneFactor //缓冲区已经存在的颜色
  83336. this.renderMat.blendEquation = THREE.AddEquation;
  83337. this.renderMat.blendEquationAlpha = THREE.AddEquation;
  83338. this.renderMat.blendDstAlpha = THREE.SrcAlphaFactor
  83339. this.renderMat.blendSrcAlpha = THREE.SrcAlphaFactor */
  83340. this.camera2 = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
  83341. this.scene2 = new Scene();
  83342. this.quad2 = new Mesh( new PlaneBufferGeometry( 2, 2 ), this.renderMat/* this.copyMaterial */ );
  83343. this.quad2.frustumCulled = false; // Avoid getting clipped
  83344. this.scene2.add( this.quad2 );
  83345. this.copyPass = new ShaderPass( CopyShader );
  83346. this.copyPass.renderToScreen = true;
  83347. };
  83348. SSAARenderPass.prototype = Object.assign( Object.create( Pass.prototype ), {
  83349. constructor: SSAARenderPass,
  83350. dispose: function () {
  83351. if ( this.sampleRenderTarget ) {
  83352. this.sampleRenderTarget.dispose();
  83353. this.sampleRenderTarget = null;
  83354. }
  83355. },
  83356. setSize: function ( width, height ) {
  83357. if ( this.sampleRenderTarget ) this.sampleRenderTarget.setSize( width, height );
  83358. this.childPass && this.childPass.setSize(width, height);
  83359. },
  83360. addPass: function (pass){
  83361. this.childPass = pass;
  83362. },
  83363. render: function (scene, camera, viewports, renderer, writeBuffer, readBuffer, maskActive, renderFun ) {
  83364. if(this.useCopy ){
  83365. scene = this.copyPass.scene; camera = this.copyPass.camera;
  83366. }
  83367. if ( ! this.sampleRenderTarget ) {
  83368. this.sampleRenderTarget = new WebGLRenderTarget( readBuffer.width, readBuffer.height, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat } );
  83369. this.sampleRenderTarget.texture.name = "SSAARenderPass.sample";
  83370. }
  83371. var jitterOffsets = SSAARenderPass.JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ];
  83372. var autoClear = renderer.autoClear;
  83373. renderer.autoClear = false;
  83374. var oldClearColor = renderer.getClearColor(new Color).getHex();
  83375. var oldClearAlpha = renderer.getClearAlpha();
  83376. renderer.setClearColor( this.clearColor, this.clearAlpha );
  83377. var baseSampleWeight = 1.0 / jitterOffsets.length;
  83378. var roundingRange = 1 / 32;
  83379. //this.copyUniforms[ "tDiffuse" ].value = this.sampleRenderTarget.texture;
  83380. let oldTarget = renderer.getRenderTarget();
  83381. if(oldTarget){
  83382. if(oldTarget.scissorTest){
  83383. var width = oldTarget.scissor.w, height = oldTarget.scissor.z;
  83384. }else {
  83385. var width = oldTarget.width, height = oldTarget.height;
  83386. }
  83387. }else {
  83388. var width = readBuffer.width, height = readBuffer.height;
  83389. }
  83390. // render the scene multiple times, each slightly jitter offset from the last and accumulate the results.
  83391. let opa = 0;
  83392. for ( var i = 0; i < jitterOffsets.length; i ++ ) {
  83393. var jitterOffset = jitterOffsets[ i ];
  83394. if ( camera.setViewOffset ) {
  83395. camera.setViewOffset( width, height,
  83396. jitterOffset[ 0 ] * 0.0625 , jitterOffset[ 1 ] * 0.0625 , // 0.0625 = 1 / 16
  83397. width, height );
  83398. }
  83399. var sampleWeight = baseSampleWeight;
  83400. if ( this.unbiased ) {//更柔和
  83401. var uniformCenteredDistribution = ( - 0.5 + ( i + 0.5 ) / jitterOffsets.length );
  83402. sampleWeight += roundingRange * uniformCenteredDistribution;
  83403. }
  83404. renderer.setRenderTarget(this.sampleRenderTarget);
  83405. renderer.clear();
  83406. if(this.useCopy){
  83407. this.copyPass.render(scene,camera, renderer, writeBuffer, readBuffer );
  83408. }else {
  83409. if(renderFun){
  83410. renderFun({target : this.sampleRenderTarget});
  83411. }else {
  83412. renderer.render( scene, camera );
  83413. }
  83414. }
  83415. renderer.setRenderTarget(oldTarget);
  83416. //---------------------
  83417. //获取outline tex
  83418. let hasOutline = this.childPass && this.childPass.render(scene, camera, renderer, writeBuffer, readBuffer, null, renderFun );
  83419. //合成到该材质
  83420. this.renderUniforms[ "bgTex" ].value = this.sampleRenderTarget.texture;
  83421. this.renderUniforms[ "outlineTex" ].value = hasOutline ? readBuffer.texture : null;
  83422. this.renderUniforms[ "opacity" ].value = sampleWeight;
  83423. /* console.log('sampleWeight', sampleWeight)
  83424. opa += sampleWeight */
  83425. if(!this.renderToScreen){
  83426. renderer.setRenderTarget(writeBuffer);
  83427. }
  83428. if(i === 0 ){
  83429. renderer.setClearColor( 0x000000, 0 ); //叠加前颜色必须0
  83430. renderer.clear();
  83431. }
  83432. renderer.render( this.scene2, this.camera2); // , this.renderToScreen ? null : writeBuffer, ( i === 0 )
  83433. if(!this.renderToScreen){
  83434. renderer.setRenderTarget(oldTarget);
  83435. }
  83436. //if(i==2)break;
  83437. }
  83438. //console.log('sum:',opa)
  83439. if ( camera.clearViewOffset )camera.clearViewOffset();
  83440. //renderer.setRenderTarget(readBuffer)
  83441. //renderer.setClearColor( 0x000000, 0 );
  83442. //renderer.clear()
  83443. /* this.quad2.material = this.renderMat2
  83444. this.renderMat2.uniforms.tDiffuse.value = writeBuffer.texture;
  83445. renderer.render( this.scene2, this.camera2);
  83446. this.quad2.material = this.renderMat */
  83447. //renderer.setRenderTarget(oldTarget)
  83448. renderer.autoClear = autoClear;
  83449. renderer.setClearColor( oldClearColor, oldClearAlpha );
  83450. /* 试了好几次,测量线的透明度还是还原不了。 clearAlpha十分影响结果。
  83451. 因为绘制测量线需要背景透明。 或许可以先全部绘制完后,再 copyshader中 抗锯齿?
  83452. 另外会有黑边。
  83453. */
  83454. }
  83455. } );
  83456. // These jitter vectors are specified in integers because it is easier.
  83457. // I am assuming a [-8,8) integer grid, but it needs to be mapped onto [-0.5,0.5)
  83458. // before being used, thus these integers need to be scaled by 1/16.
  83459. //
  83460. // Sample patterns reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
  83461. SSAARenderPass.JitterVectors = [
  83462. [
  83463. [ 0, 0 ]
  83464. ],
  83465. [
  83466. [ 4, 4 ], [ - 4, - 4 ]
  83467. ],
  83468. [
  83469. [ - 2, - 6 ], [ 6, - 2 ], [ - 6, 2 ], [ 2, 6 ]
  83470. ],
  83471. [
  83472. [ 1, - 3 ], [ - 1, 3 ], [ 5, 1 ], [ - 3, - 5 ],
  83473. [ - 5, 5 ], [ - 7, - 1 ], [ 3, 7 ], [ 7, - 7 ]
  83474. ],
  83475. [
  83476. [ 1, 1 ], [ - 1, - 3 ], [ - 3, 2 ], [ 4, - 1 ],
  83477. [ - 5, - 2 ], [ 2, 5 ], [ 5, 3 ], [ 3, - 5 ],
  83478. [ - 2, 6 ], [ 0, - 7 ], [ - 4, - 6 ], [ - 6, 4 ],
  83479. [ - 8, 0 ], [ 7, - 4 ], [ 6, 7 ], [ - 7, - 8 ]
  83480. ],
  83481. [
  83482. [ - 4, - 7 ], [ - 7, - 5 ], [ - 3, - 5 ], [ - 5, - 4 ],
  83483. [ - 1, - 4 ], [ - 2, - 2 ], [ - 6, - 1 ], [ - 4, 0 ],
  83484. [ - 7, 1 ], [ - 1, 2 ], [ - 6, 3 ], [ - 3, 3 ],
  83485. [ - 7, 6 ], [ - 3, 6 ], [ - 5, 7 ], [ - 1, 7 ],
  83486. [ 5, - 7 ], [ 1, - 6 ], [ 6, - 5 ], [ 4, - 4 ],
  83487. [ 2, - 3 ], [ 7, - 2 ], [ 1, - 1 ], [ 4, - 1 ],
  83488. [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ],
  83489. [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ]
  83490. ]
  83491. ];
  83492. class MaskPass extends Pass {
  83493. constructor( scene, camera ) {
  83494. super();
  83495. this.scene = scene;
  83496. this.camera = camera;
  83497. this.clear = true;
  83498. this.needsSwap = false;
  83499. this.inverse = false;
  83500. }
  83501. render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
  83502. const context = renderer.getContext();
  83503. const state = renderer.state;
  83504. // don't update color or depth
  83505. state.buffers.color.setMask( false );
  83506. state.buffers.depth.setMask( false );
  83507. // lock buffers
  83508. state.buffers.color.setLocked( true );
  83509. state.buffers.depth.setLocked( true );
  83510. // set up stencil
  83511. let writeValue, clearValue;
  83512. if ( this.inverse ) {
  83513. writeValue = 0;
  83514. clearValue = 1;
  83515. } else {
  83516. writeValue = 1;
  83517. clearValue = 0;
  83518. }
  83519. state.buffers.stencil.setTest( true );
  83520. state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
  83521. state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
  83522. state.buffers.stencil.setClear( clearValue );
  83523. state.buffers.stencil.setLocked( true );
  83524. // draw into the stencil buffer
  83525. renderer.setRenderTarget( readBuffer );
  83526. if ( this.clear ) renderer.clear();
  83527. renderer.render( this.scene, this.camera );
  83528. renderer.setRenderTarget( writeBuffer );
  83529. if ( this.clear ) renderer.clear();
  83530. renderer.render( this.scene, this.camera );
  83531. // unlock color and depth buffer for subsequent rendering
  83532. state.buffers.color.setLocked( false );
  83533. state.buffers.depth.setLocked( false );
  83534. // only render where stencil is set to 1
  83535. state.buffers.stencil.setLocked( false );
  83536. state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
  83537. state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
  83538. state.buffers.stencil.setLocked( true );
  83539. }
  83540. }
  83541. class ClearMaskPass extends Pass {
  83542. constructor() {
  83543. super();
  83544. this.needsSwap = false;
  83545. }
  83546. render( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
  83547. renderer.state.buffers.stencil.setLocked( false );
  83548. renderer.state.buffers.stencil.setTest( false );
  83549. }
  83550. }
  83551. /**
  83552. * @author alteredq / http://alteredqualia.com/
  83553. */
  83554. var EffectComposer = function ( renderer, renderTarget ) {
  83555. this.renderer = renderer;
  83556. if ( renderTarget === undefined ) {
  83557. var parameters = {
  83558. minFilter: LinearFilter,
  83559. magFilter: LinearFilter,
  83560. format: RGBAFormat,
  83561. stencilBuffer: false,
  83562. };
  83563. var size = renderer.getDrawingBufferSize();
  83564. renderTarget = new WebGLRenderTarget( size.width, size.height , parameters );
  83565. renderTarget.texture.name = 'EffectComposer.rt1';
  83566. }
  83567. this.renderTarget1 = renderTarget;
  83568. this.renderTarget2 = renderTarget.clone();
  83569. this.renderTarget2.texture.name = 'EffectComposer.rt2';
  83570. this.writeBuffer = this.renderTarget1;
  83571. this.readBuffer = this.renderTarget2;
  83572. this.passes = [];
  83573. // dependencies
  83574. /* if ( THREE.CopyShader === undefined ) {
  83575. console.error( 'THREE.EffectComposer relies on THREE.CopyShader' );
  83576. }
  83577. if ( THREE.ShaderPass === undefined ) {
  83578. console.error( 'THREE.EffectComposer relies on THREE.ShaderPass' );
  83579. } */
  83580. this.copyPass = new ShaderPass( CopyShader );
  83581. };
  83582. Object.assign( EffectComposer.prototype, {
  83583. swapBuffers: function () {
  83584. var tmp = this.readBuffer;
  83585. this.readBuffer = this.writeBuffer;
  83586. this.writeBuffer = tmp;
  83587. },
  83588. addPass: function ( pass ) {
  83589. this.passes.push( pass );
  83590. var size = this.renderer.getDrawingBufferSize();
  83591. pass.setSize( size.width, size.height );
  83592. },
  83593. removePass: function(pass){ //add
  83594. let index = this.passes.indexOf(pass);
  83595. index > -1 && this.passes.splice(index,1);
  83596. },
  83597. insertPass: function ( pass, index ) {
  83598. this.passes.splice( index, 0, pass );
  83599. },
  83600. render: function ( scene, camera, viewports, renderFun ) {
  83601. var maskActive = false;
  83602. let passes = this.passes.filter(e=>e.enabled);
  83603. var pass, i, il = passes.length;
  83604. if(this.readTarget){ //add 使用当前renderTarget中的像素
  83605. this.copyPass.render(scene, this.renderer, this.readBuffer, this.renderer.getRenderTarget() );
  83606. }
  83607. for ( i = 0; i < il; i ++ ) {
  83608. pass = passes[ i ];
  83609. //if(i == il-1)pass.renderToScreen = true//
  83610. pass.render( scene, camera, viewports, this.renderer, this.writeBuffer, this.readBuffer, maskActive, renderFun );
  83611. if ( pass.needsSwap ) {
  83612. if ( maskActive ) {
  83613. var context = this.renderer.context;
  83614. context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
  83615. this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer );// delta
  83616. context.stencilFunc( context.EQUAL, 1, 0xffffffff );
  83617. }
  83618. this.swapBuffers();
  83619. }
  83620. if ( MaskPass !== undefined ) {
  83621. if ( pass instanceof MaskPass ) {
  83622. maskActive = true;
  83623. } else if ( pass instanceof ClearMaskPass ) {
  83624. maskActive = false;
  83625. }
  83626. }
  83627. }
  83628. //add
  83629. if(!pass.renderToScreen){ //最后一个如果没有绘制到屏幕or target上
  83630. this.copyPass.renderToScreen = true;
  83631. this.copyPass.render(null,null, this.renderer, this.writeBuffer, this.readBuffer);
  83632. }
  83633. },
  83634. reset: function ( renderTarget ) {
  83635. if ( renderTarget === undefined ) {
  83636. var size = this.renderer.getDrawingBufferSize();
  83637. renderTarget = this.renderTarget1.clone();
  83638. renderTarget.setSize( size.width, size.height );
  83639. }
  83640. this.renderTarget1.dispose();
  83641. this.renderTarget2.dispose();
  83642. this.renderTarget1 = renderTarget;
  83643. this.renderTarget2 = renderTarget.clone();
  83644. this.writeBuffer = this.renderTarget1;
  83645. this.readBuffer = this.renderTarget2;
  83646. },
  83647. setSize: function ( width, height, scaleRatio ) {
  83648. scaleRatio = scaleRatio || 1;
  83649. this.renderTarget1.setSize( width * scaleRatio , height * scaleRatio );
  83650. this.renderTarget2.setSize( width * scaleRatio, height * scaleRatio );
  83651. for ( var i = 0; i < this.passes.length; i ++ ) {
  83652. this.passes[ i ].setSize( width * scaleRatio, height * scaleRatio );
  83653. }
  83654. }
  83655. } );
  83656. /**
  83657. * @author alteredq / http://alteredqualia.com/
  83658. */
  83659. class RenderPass extends Pass {
  83660. constructor( overrideMaterial, clearColor, clearAlpha ) {
  83661. super();
  83662. /* this.scene = scene;
  83663. this.camera = camera; */
  83664. this.overrideMaterial = overrideMaterial;
  83665. this.clearColor = clearColor;
  83666. this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
  83667. this.clear = true;
  83668. this.clearDepth = false;
  83669. this.needsSwap = false;
  83670. this._oldClearColor = new Color();
  83671. }
  83672. render(scene, camera, renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
  83673. const oldAutoClear = renderer.autoClear;
  83674. renderer.autoClear = false;
  83675. let oldClearAlpha, oldOverrideMaterial;
  83676. if ( this.overrideMaterial !== undefined ) {
  83677. oldOverrideMaterial = this.scene.overrideMaterial;
  83678. scene.overrideMaterial = this.overrideMaterial;
  83679. }
  83680. if ( this.clearColor ) {
  83681. renderer.getClearColor( this._oldClearColor );
  83682. oldClearAlpha = renderer.getClearAlpha();
  83683. renderer.setClearColor( this.clearColor, this.clearAlpha );
  83684. }
  83685. if ( this.clearDepth ) {
  83686. renderer.clearDepth();
  83687. }
  83688. let oldTarget = renderer.getRenderTarget();
  83689. if(!this.renderToScreen)renderer.setRenderTarget( readBuffer );
  83690. // TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
  83691. if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
  83692. renderer.render( scene, camera );
  83693. if(!this.renderToScreen)renderer.setRenderTarget( oldTarget );
  83694. if ( this.clearColor ) {
  83695. renderer.setClearColor( this._oldClearColor, oldClearAlpha );
  83696. }
  83697. if ( this.overrideMaterial !== undefined ) {
  83698. scene.overrideMaterial = oldOverrideMaterial;
  83699. }
  83700. renderer.autoClear = oldAutoClear;
  83701. }
  83702. }
  83703. /**
  83704. * NVIDIA FXAA by Timothy Lottes
  83705. * https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
  83706. * - WebGL port by @supereggbert
  83707. * http://www.glge.org/demos/fxaa/
  83708. * Further improved by Daniel Sturk
  83709. */
  83710. const FXAAShader = {
  83711. uniforms: {
  83712. 'tDiffuse': { value: null },
  83713. 'resolution': { value: new Vector2$1( 1 / 1024, 1 / 512 ) }
  83714. },
  83715. vertexShader: /* glsl */`
  83716. varying vec2 vUv;
  83717. void main() {
  83718. vUv = uv;
  83719. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  83720. }`,
  83721. fragmentShader: `
  83722. precision highp float;
  83723. uniform sampler2D tDiffuse;
  83724. uniform vec2 resolution;
  83725. varying vec2 vUv;
  83726. // FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com)
  83727. //----------------------------------------------------------------------------------
  83728. // File: es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag
  83729. // SDK Version: v3.00
  83730. // Email: gameworks@nvidia.com
  83731. // Site: http://developer.nvidia.com/
  83732. //
  83733. // Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
  83734. //
  83735. // Redistribution and use in source and binary forms, with or without
  83736. // modification, are permitted provided that the following conditions
  83737. // are met:
  83738. // * Redistributions of source code must retain the above copyright
  83739. // notice, this list of conditions and the following disclaimer.
  83740. // * Redistributions in binary form must reproduce the above copyright
  83741. // notice, this list of conditions and the following disclaimer in the
  83742. // documentation and/or other materials provided with the distribution.
  83743. // * Neither the name of NVIDIA CORPORATION nor the names of its
  83744. // contributors may be used to endorse or promote products derived
  83745. // from this software without specific prior written permission.
  83746. //
  83747. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
  83748. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  83749. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  83750. // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  83751. // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  83752. // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  83753. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  83754. // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  83755. // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  83756. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  83757. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  83758. //
  83759. //----------------------------------------------------------------------------------
  83760. #ifndef FXAA_DISCARD
  83761. //
  83762. // Only valid for PC OpenGL currently.
  83763. // Probably will not work when FXAA_GREEN_AS_LUMA = 1.
  83764. //
  83765. // 1 = Use discard on pixels which don't need AA.
  83766. // For APIs which enable concurrent TEX+ROP from same surface.
  83767. // 0 = Return unchanged color on pixels which don't need AA.
  83768. //
  83769. #define FXAA_DISCARD 0
  83770. #endif
  83771. /*--------------------------------------------------------------------------*/
  83772. #define FxaaTexTop(t, p) texture2D(t, p, -100.0)
  83773. #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
  83774. /*--------------------------------------------------------------------------*/
  83775. #define NUM_SAMPLES 5
  83776. // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha
  83777. float contrast( vec4 a, vec4 b ) {
  83778. vec4 diff = abs( a - b );
  83779. return max( max( max( diff.r, diff.g ), diff.b ), diff.a );
  83780. }
  83781. /*============================================================================
  83782. FXAA3 QUALITY - PC
  83783. ============================================================================*/
  83784. /*--------------------------------------------------------------------------*/
  83785. vec4 FxaaPixelShader(
  83786. vec2 posM,
  83787. sampler2D tex,
  83788. vec2 fxaaQualityRcpFrame,
  83789. float fxaaQualityEdgeThreshold,
  83790. float fxaaQualityinvEdgeThreshold
  83791. ) {
  83792. vec4 rgbaM = FxaaTexTop(tex, posM);
  83793. vec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);
  83794. vec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);
  83795. vec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);
  83796. vec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);
  83797. // . S .
  83798. // W M E
  83799. // . N .
  83800. bool earlyExit = max( max( max(
  83801. contrast( rgbaM, rgbaN ),
  83802. contrast( rgbaM, rgbaS ) ),
  83803. contrast( rgbaM, rgbaE ) ),
  83804. contrast( rgbaM, rgbaW ) )
  83805. < fxaaQualityEdgeThreshold;
  83806. // . 0 .
  83807. // 0 0 0
  83808. // . 0 .
  83809. #if (FXAA_DISCARD == 1)
  83810. if(earlyExit) FxaaDiscard;
  83811. #else
  83812. if(earlyExit) return rgbaM;
  83813. #endif
  83814. float contrastN = contrast( rgbaM, rgbaN );
  83815. float contrastS = contrast( rgbaM, rgbaS );
  83816. float contrastE = contrast( rgbaM, rgbaE );
  83817. float contrastW = contrast( rgbaM, rgbaW );
  83818. float relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );
  83819. relativeVContrast *= fxaaQualityinvEdgeThreshold;
  83820. bool horzSpan = relativeVContrast > 0.;
  83821. // . 1 .
  83822. // 0 0 0
  83823. // . 1 .
  83824. // 45 deg edge detection and corners of objects, aka V/H contrast is too similar
  83825. if( abs( relativeVContrast ) < .3 ) {
  83826. // locate the edge
  83827. vec2 dirToEdge;
  83828. dirToEdge.x = contrastE > contrastW ? 1. : -1.;
  83829. dirToEdge.y = contrastS > contrastN ? 1. : -1.;
  83830. // . 2 . . 1 .
  83831. // 1 0 2 ~= 0 0 1
  83832. // . 1 . . 0 .
  83833. // tap 2 pixels and see which ones are "outside" the edge, to
  83834. // determine if the edge is vertical or horizontal
  83835. vec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);
  83836. float matchAlongH = contrast( rgbaM, rgbaAlongH );
  83837. // . 1 .
  83838. // 0 0 1
  83839. // . 0 H
  83840. vec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);
  83841. float matchAlongV = contrast( rgbaM, rgbaAlongV );
  83842. // V 1 .
  83843. // 0 0 1
  83844. // . 0 .
  83845. relativeVContrast = matchAlongV - matchAlongH;
  83846. relativeVContrast *= fxaaQualityinvEdgeThreshold;
  83847. if( abs( relativeVContrast ) < .3 ) { // 45 deg edge
  83848. // 1 1 .
  83849. // 0 0 1
  83850. // . 0 1
  83851. // do a simple blur
  83852. return mix(
  83853. rgbaM,
  83854. (rgbaN + rgbaS + rgbaE + rgbaW) * .25,
  83855. .4
  83856. );
  83857. }
  83858. horzSpan = relativeVContrast > 0.;
  83859. }
  83860. if(!horzSpan) rgbaN = rgbaW;
  83861. if(!horzSpan) rgbaS = rgbaE;
  83862. // . 0 . 1
  83863. // 1 0 1 -> 0
  83864. // . 0 . 1
  83865. bool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );
  83866. if(!pairN) rgbaN = rgbaS;
  83867. vec2 offNP;
  83868. offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
  83869. offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
  83870. bool doneN = false;
  83871. bool doneP = false;
  83872. float nDist = 0.;
  83873. float pDist = 0.;
  83874. vec2 posN = posM;
  83875. vec2 posP = posM;
  83876. int iterationsUsed = 0;
  83877. int iterationsUsedN = 0;
  83878. int iterationsUsedP = 0;
  83879. for( int i = 0; i < NUM_SAMPLES; i++ ) {
  83880. iterationsUsed = i;
  83881. float increment = float(i + 1);
  83882. if(!doneN) {
  83883. nDist += increment;
  83884. posN = posM + offNP * nDist;
  83885. vec4 rgbaEndN = FxaaTexTop(tex, posN.xy);
  83886. doneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );
  83887. iterationsUsedN = i;
  83888. }
  83889. if(!doneP) {
  83890. pDist += increment;
  83891. posP = posM - offNP * pDist;
  83892. vec4 rgbaEndP = FxaaTexTop(tex, posP.xy);
  83893. doneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );
  83894. iterationsUsedP = i;
  83895. }
  83896. if(doneN || doneP) break;
  83897. }
  83898. if ( !doneP && !doneN ) return rgbaM; // failed to find end of edge
  83899. float dist = min(
  83900. doneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,
  83901. doneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.
  83902. );
  83903. // hacky way of reduces blurriness of mostly diagonal edges
  83904. // but reduces AA quality
  83905. dist = pow(dist, .5);
  83906. dist = 1. - dist;
  83907. return mix(
  83908. rgbaM,
  83909. rgbaN,
  83910. dist * .5
  83911. );
  83912. }
  83913. void main() {
  83914. const float edgeDetectionQuality = .05 ; //越高,越保留细节;越低,越平滑 但模糊
  83915. const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
  83916. gl_FragColor = FxaaPixelShader(
  83917. vUv,
  83918. tDiffuse,
  83919. resolution,
  83920. edgeDetectionQuality, // [0,1] contrast needed, otherwise early discard
  83921. invEdgeDetectionQuality
  83922. );
  83923. }
  83924. `
  83925. };
  83926. /**
  83927. * @author spidersharma / http://eduperiment.com/
  83928. */
  83929. let OutlinePass = function ( selectedObjects ) {
  83930. /* scene = scene;
  83931. camera = camera; */
  83932. this.selectedObjects = selectedObjects !== undefined ? selectedObjects : [];
  83933. this.visibleEdgeColor = new Color( 1, 1, 1 );
  83934. this.hiddenEdgeColor = new Color( 0.1, 0.04, 0.02 );
  83935. this.edgeGlow = 0.0;
  83936. this.usePatternTexture = false;
  83937. //this.edgeThickness = 1.0;
  83938. this.edgeStrength = 50;
  83939. this.downSampleRatio = 1;//2; // 抗锯齿 值越低renderTarget size越大,抗锯齿越强,线条可越细(或许可以把模糊化去掉?)
  83940. this.pulsePeriod = 0;
  83941. Pass.call( this );
  83942. this.resolution = new Vector2$1( 256, 256 );
  83943. var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
  83944. var resx = Math.round( this.resolution.x / this.downSampleRatio );
  83945. var resy = Math.round( this.resolution.y / this.downSampleRatio );
  83946. //this.maskBufferMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff } );
  83947. //this.maskBufferMaterial.side = THREE.DoubleSide;
  83948. this.renderTargetMaskBuffer = new WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
  83949. this.renderTargetMaskBuffer.texture.name = "OutlinePass.mask";
  83950. this.renderTargetMaskBuffer.texture.generateMipmaps = false;
  83951. this.depthMaterial = new MeshDepthMaterial();
  83952. this.depthMaterial.side = DoubleSide;
  83953. this.depthMaterial.depthPacking = RGBADepthPacking;
  83954. this.depthMaterial.blending = NoBlending;
  83955. this.prepareMaskMaterial = this.getPrepareMaskMaterial();
  83956. this.prepareMaskMaterial.side = DoubleSide;
  83957. //this.replaceDepthToViewZ( viewer.mainViewport.camera /* camera */ );
  83958. this.renderTargetDepthBuffer = new WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
  83959. this.renderTargetDepthBuffer.texture.name = "OutlinePass.depth";
  83960. this.renderTargetDepthBuffer.texture.generateMipmaps = false;
  83961. /* this.renderTargetMaskDownSampleBuffer = new THREE.WebGLRenderTarget( resx, resy, pars );
  83962. this.renderTargetMaskDownSampleBuffer.texture.name = "OutlinePass.depthDownSample";
  83963. this.renderTargetMaskDownSampleBuffer.texture.generateMipmaps = false;
  83964. this.renderTargetBlurBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars );
  83965. this.renderTargetBlurBuffer1.texture.name = "OutlinePass.blur1";
  83966. this.renderTargetBlurBuffer1.texture.generateMipmaps = false;
  83967. this.renderTargetBlurBuffer2 = new THREE.WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), pars );
  83968. this.renderTargetBlurBuffer2.texture.name = "OutlinePass.blur2";
  83969. this.renderTargetBlurBuffer2.texture.generateMipmaps = false; */
  83970. this.edgeDetectionMaterial = this.getEdgeDetectionMaterial(this.edgeStrength);
  83971. this.renderTargetEdgeBuffer1 = new WebGLRenderTarget( resx, resy, pars );
  83972. this.renderTargetEdgeBuffer1.texture.name = "OutlinePass.edge1";
  83973. this.renderTargetEdgeBuffer1.texture.generateMipmaps = false;
  83974. /* this.renderTargetEdgeBuffer2 = new THREE.WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), pars );
  83975. this.renderTargetEdgeBuffer2.texture.name = "OutlinePass.edge2";
  83976. this.renderTargetEdgeBuffer2.texture.generateMipmaps = false;
  83977. var MAX_EDGE_THICKNESS = 4;
  83978. var MAX_EDGE_GLOW = 4;
  83979. this.separableBlurMaterial1 = this.getSeperableBlurMaterial( MAX_EDGE_THICKNESS );
  83980. this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
  83981. this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = 1;
  83982. this.separableBlurMaterial2 = this.getSeperableBlurMaterial( MAX_EDGE_GLOW );
  83983. this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2( Math.round( resx / 2 ), Math.round( resy / 2 ) );
  83984. this.separableBlurMaterial2.uniforms[ "kernelRadius" ].value = MAX_EDGE_GLOW;
  83985. */
  83986. // Overlay material
  83987. this.overlayMaterial = this.getOverlayMaterial();
  83988. // copy material
  83989. this.copyUniforms = UniformsUtils.clone( CopyShader.uniforms );
  83990. this.copyUniforms[ "opacity" ].value = 1.0;
  83991. this.materialCopy = new ShaderMaterial( {
  83992. uniforms: this.copyUniforms,
  83993. vertexShader: CopyShader.vertexShader,
  83994. fragmentShader: CopyShader.fragmentShader,
  83995. blending: NoBlending,
  83996. depthTest: false,
  83997. depthWrite: false,
  83998. transparent: true
  83999. } );
  84000. this.enabled = true;
  84001. this.needsSwap = false;
  84002. this.oldClearColor = new Color();
  84003. this.oldClearAlpha = 1;
  84004. this.camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
  84005. this.scene = new Scene();
  84006. this.quad = new Mesh( new PlaneBufferGeometry( 2, 2 ), null );
  84007. this.quad.frustumCulled = false; // Avoid getting clipped
  84008. this.scene.add( this.quad );
  84009. /* this.tempPulseColor1 = new THREE.Color();
  84010. this.tempPulseColor2 = new THREE.Color(); */
  84011. this.textureMatrix = new Matrix4();
  84012. };
  84013. OutlinePass.prototype = Object.assign( Object.create( Pass.prototype ), {
  84014. constructor: OutlinePass,
  84015. dispose: function () {
  84016. this.renderTargetMaskBuffer.dispose();
  84017. this.renderTargetEdgeBuffer1.dispose();
  84018. this.renderTargetDepthBuffer.dispose();
  84019. },
  84020. replaceDepthToViewZ( camera ) {
  84021. var type = camera.isPerspectiveCamera ? 'perspective' : 'orthographic';
  84022. if(type == this.lastCameraType )return
  84023. this.lastCameraType = type;
  84024. this.prepareMaskMaterial.fragmentShader = this.prepareMaskMaterial.fragmentShader.replace( /DEPTH_TO_VIEW_Z/g, type + 'DepthToViewZ' );
  84025. this.prepareMaskMaterial.needsUpdate = true;
  84026. },
  84027. setSize: function ( width, height ) {
  84028. this.renderTargetEdgeBuffer1.setSize( width, height );
  84029. this.renderTargetMaskBuffer.setSize( width, height );
  84030. this.resolution.set(width,height);
  84031. },
  84032. changeVisibilityOfSelectedObjects: function ( bVisible ) {
  84033. function gatherSelectedMeshesCallBack( object ) {
  84034. /* if ( object.isMesh ) { */
  84035. if ( object.isPointcloud || object.isMesh || object.isLine || object.isSprite ) {
  84036. /* if ( bVisible ) {
  84037. object.visible = object.userData.oldVisible;
  84038. delete object.userData.oldVisible;
  84039. } else {
  84040. object.userData.oldVisible = object.visible;
  84041. object.visible = bVisible;
  84042. } */
  84043. viewer.updateVisible(object, 'overlinePass', bVisible);
  84044. }
  84045. }
  84046. for ( var i = 0; i < this.selectedObjects.length; i ++ ) {
  84047. var selectedObject = this.selectedObjects[ i ];
  84048. selectedObject.traverse( gatherSelectedMeshesCallBack );
  84049. }
  84050. },
  84051. changeVisibilityOfNonSelectedObjects: function ( bVisible , scenes) {
  84052. var selectedMeshes = [];
  84053. function gatherSelectedMeshesCallBack( object ) {
  84054. //if ( object.isMesh ) selectedMeshes.push( object );
  84055. if ( object.isPointcloud || object.isMesh || object.isLine || object.isSprite ) {
  84056. selectedMeshes.push( object );
  84057. }
  84058. }
  84059. for ( var i = 0; i < this.selectedObjects.length; i ++ ) {
  84060. var selectedObject = this.selectedObjects[ i ];
  84061. selectedObject.traverse( gatherSelectedMeshesCallBack );
  84062. }
  84063. function VisibilityChangeCallBack( object ) {
  84064. if ( object.isPointcloud || object.isMesh || object.isLine || object.isSprite ) {
  84065. var bFound = false;
  84066. for ( var i = 0; i < selectedMeshes.length; i ++ ) {
  84067. var selectedObjectId = selectedMeshes[ i ].id;
  84068. if ( selectedObjectId === object.id ) {
  84069. bFound = true;
  84070. break;
  84071. }
  84072. }
  84073. if ( ! bFound ) {
  84074. /* var visibility = object.visible;
  84075. if(object == viewer.reticule){
  84076. console.log(visibility)
  84077. }
  84078. if ( ! bVisible || object.bVisible ) object.visible = bVisible;
  84079. object.bVisible = visibility; */
  84080. viewer.updateVisible(object, 'overlinePass', bVisible);
  84081. //要确保其他所有mesh也都是通过updateVisible来设置visible=false的,否则会在这变为true
  84082. }
  84083. }
  84084. }
  84085. scenes.forEach(scene=>scene.traverse( VisibilityChangeCallBack ));
  84086. },
  84087. updateTextureMatrix: function (camera) {
  84088. this.textureMatrix.set( 0.5, 0.0, 0.0, 0.5,
  84089. 0.0, 0.5, 0.0, 0.5,
  84090. 0.0, 0.0, 0.5, 0.5,
  84091. 0.0, 0.0, 0.0, 1.0 );
  84092. this.textureMatrix.multiply( camera.projectionMatrix );
  84093. this.textureMatrix.multiply( camera.matrixWorldInverse );
  84094. },
  84095. render: function (scenes, camera, viewports, renderer, writeBuffer, readBuffer, maskActive, renderFun ) {
  84096. if(!(scenes instanceof Array))scenes = [scenes];
  84097. if ( this.selectedObjects.length > 0 ) {
  84098. let render2 = (target)=>{
  84099. if(renderFun){
  84100. renderFun({target , dontRenderRtEDL:true});
  84101. }else {
  84102. renderer.setRenderTarget(target);
  84103. renderer.clear();
  84104. scenes.forEach(scene=>renderer.render( scene, camera));
  84105. }
  84106. };
  84107. viewports.forEach(e=> e.beforeRender = ()=>{
  84108. this.replaceDepthToViewZ( e.camera );
  84109. });
  84110. this.oldClearColor.copy( renderer.getClearColor(new Color) );
  84111. this.oldClearAlpha = renderer.getClearAlpha();
  84112. let oldAutoClear = renderer.autoClear;
  84113. let oldTarget = renderer.getRenderTarget();
  84114. renderer.autoClear = false;
  84115. if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
  84116. renderer.setClearColor( 0xffffff, 1 );
  84117. // Make selected objects invisible
  84118. this.changeVisibilityOfSelectedObjects( false );
  84119. scenes.forEach(scene=>{
  84120. scene.currentBackground = scene.background;
  84121. scene.background = null;
  84122. // 1. Draw Non Selected objects in the depth buffer
  84123. scene.overrideMaterial = this.depthMaterial;
  84124. });
  84125. render2(this.renderTargetDepthBuffer);
  84126. //renderer.setRenderTarget(this.renderTargetDepthBuffer)
  84127. //renderer.clear()
  84128. //renderer.render( scene, camera/* , this.renderTargetDepthBuffer, true */);
  84129. // Make selected objects visible
  84130. this.changeVisibilityOfSelectedObjects( true );
  84131. viewports.forEach(e=> e.beforeRender = ()=>{
  84132. // Update Texture Matrix for Depth compare
  84133. this.updateTextureMatrix(e.camera);
  84134. this.prepareMaskMaterial.uniforms[ "cameraNearFar" ].value = new Vector2$1( e.camera.near, e.camera.far );
  84135. });
  84136. // Make non selected objects invisible, and draw only the selected objects, by comparing the depth buffer of non selected objects
  84137. this.changeVisibilityOfNonSelectedObjects( false , scenes);
  84138. scenes.forEach(scene=>{
  84139. scene.overrideMaterial = this.prepareMaskMaterial;
  84140. });
  84141. this.prepareMaskMaterial.uniforms[ "depthTexture" ].value = this.renderTargetDepthBuffer.texture;
  84142. this.prepareMaskMaterial.uniforms[ "textureMatrix" ].value = this.textureMatrix;
  84143. //renderer.setRenderTarget(this.renderTargetMaskBuffer)
  84144. //renderer.clear()
  84145. //renderer.render( scene, camera/* , this.renderTargetMaskBuffer, true */ );
  84146. render2(this.renderTargetMaskBuffer);
  84147. viewports.forEach((e)=>{e.beforeRender = null;});
  84148. this.changeVisibilityOfNonSelectedObjects( true , scenes);
  84149. scenes.forEach(scene=>{
  84150. scene.overrideMaterial = null;
  84151. scene.background = scene.currentBackground;
  84152. });
  84153. // 3. Apply Edge Detection Pass
  84154. this.quad.material = this.edgeDetectionMaterial;
  84155. this.edgeDetectionMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskBuffer.texture;//this.renderTargetMaskDownSampleBuffer.texture;
  84156. this.edgeDetectionMaterial.uniforms[ "texSize" ].value = new Vector2$1(this.resolution.x, this.resolution.y );//new THREE.Vector2( this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height );
  84157. //this.edgeDetectionMaterial.uniforms[ "texSize" ].value = new THREE.Vector2(this.renderTargetMaskBuffer.width, this.renderTargetMaskBuffer.height)//new THREE.Vector2( this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height );
  84158. this.edgeDetectionMaterial.uniforms[ "thickness" ].value = this.edgeStrength;
  84159. this.edgeDetectionMaterial.uniforms[ "visibleEdgeColor" ].value = this.visibleEdgeColor;//this.tempPulseColor1;
  84160. this.edgeDetectionMaterial.uniforms[ "hiddenEdgeColor" ].value = this.hiddenEdgeColor; //this.tempPulseColor2;
  84161. let buffer = readBuffer;
  84162. if ( this.renderToScreen ) {
  84163. this.quad.material.transparent = true;
  84164. buffer = null;
  84165. renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
  84166. render2();
  84167. //绘制到全屏
  84168. let renderSize = renderer.getSize(new Vector2$1()); //是client大小
  84169. renderer.setViewport(0, 0, renderSize.x, renderSize.y); //规定视口,影响图形变换(画布的使用范围)
  84170. renderer.setScissorTest( false );
  84171. }else {
  84172. renderer.setClearColor( 0x000000, 0 );
  84173. renderer.clear();
  84174. }
  84175. renderer.setRenderTarget(buffer/* this.renderTargetEdgeBuffer1 */);
  84176. renderer.render( this.scene, this.camera/* , this.renderTargetEdgeBuffer1, true */);
  84177. //这次删掉
  84178. /* // Blend it additively over the input texture
  84179. this.quad.material = this.overlayMaterial;
  84180. //this.overlayMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskBuffer.texture;
  84181. this.overlayMaterial.uniforms[ "edgeTexture1" ].value = this.renderTargetEdgeBuffer1.texture;
  84182. //this.overlayMaterial.uniforms[ "edgeTexture2" ].value = this.renderTargetEdgeBuffer2.texture;
  84183. //this.overlayMaterial.uniforms[ "patternTexture" ].value = this.patternTexture;
  84184. this.overlayMaterial.uniforms[ "edgeStrength" ].value = this.edgeStrength;
  84185. //this.overlayMaterial.uniforms[ "edgeGlow" ].value = this.edgeGlow;
  84186. //this.overlayMaterial.uniforms[ "usePatternTexture" ].value = this.usePatternTexture;
  84187. if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
  84188. //renderer.render( this.scene, camera, readBuffer, false );
  84189. //改:清空readBuffer, 仅绘制出outline的部分
  84190. renderer.setClearColor( 0x000000, 0 );
  84191. renderer.setRenderTarget(readBuffer)
  84192. renderer.clear()
  84193. renderer.render( this.scene, this.camera );
  84194. */
  84195. renderer.setRenderTarget(oldTarget);
  84196. renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
  84197. renderer.autoClear = oldAutoClear;
  84198. return true
  84199. }
  84200. /* if ( this.renderToScreen ) {
  84201. this.quad.material = this.materialCopy;
  84202. this.copyUniforms[ "tDiffuse" ].value = readBuffer.texture;
  84203. renderer.render( this.scene , this.camera );
  84204. } */
  84205. },
  84206. getPrepareMaskMaterial: function () {
  84207. return new ShaderMaterial( {
  84208. uniforms: {
  84209. "depthTexture": { value: null },
  84210. "cameraNearFar": { value: new Vector2$1( 0.5, 0.5 ) },
  84211. "textureMatrix": { value: new Matrix4() }
  84212. },
  84213. vertexShader: [
  84214. 'varying vec4 projTexCoord;',
  84215. 'varying vec4 vPosition;',
  84216. 'uniform mat4 textureMatrix;',
  84217. 'void main() {',
  84218. ' vPosition = modelViewMatrix * vec4( position, 1.0 );',
  84219. ' vec4 worldPosition = modelMatrix * vec4( position, 1.0 );',
  84220. ' projTexCoord = textureMatrix * worldPosition;',
  84221. ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
  84222. '}'
  84223. ].join( '\n' ),
  84224. fragmentShader: [
  84225. '#include <packing>',
  84226. 'varying vec4 vPosition;',
  84227. 'varying vec4 projTexCoord;',
  84228. 'uniform sampler2D depthTexture;',
  84229. 'uniform vec2 cameraNearFar;',
  84230. 'void main() {',
  84231. ' float depth = unpackRGBAToDepth(texture2DProj( depthTexture, projTexCoord ));',
  84232. ' float viewZ = - DEPTH_TO_VIEW_Z( depth, cameraNearFar.x, cameraNearFar.y );',
  84233. ' float depthTest = (-vPosition.z > viewZ) ? 1.0 : 0.0;',
  84234. ' gl_FragColor = vec4(0.0, depthTest, 1.0, 1.0);',
  84235. '}'
  84236. ].join( '\n' )
  84237. } );
  84238. },
  84239. getEdgeDetectionMaterial: function (thickness) {
  84240. return new ShaderMaterial( {
  84241. uniforms: {
  84242. "thickness": { value: thickness },
  84243. "maskTexture": { value: null },
  84244. "texSize": { value: new Vector2$1( 10, 10 ) },
  84245. "visibleEdgeColor": { value: new Vector3( 1.0, 1.0, 1.0 ) },
  84246. "hiddenEdgeColor": { value: new Vector3( 1.0, 1.0, 1.0 ) },
  84247. },
  84248. vertexShader:
  84249. "varying vec2 vUv;\n\
  84250. void main() {\n\
  84251. vUv = uv;\n\
  84252. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
  84253. }",
  84254. /* fragmentShader:
  84255. "varying vec2 vUv;\
  84256. uniform sampler2D maskTexture;\
  84257. uniform vec2 texSize;\
  84258. uniform vec3 visibleEdgeColor;\
  84259. uniform vec3 hiddenEdgeColor;\
  84260. \
  84261. void main() {\n\
  84262. vec2 invSize = 1.0 / texSize;\
  84263. vec4 uvOffset = vec4(1.0, 0.0, 0.0, 1.0) * vec4(invSize, invSize);\
  84264. vec4 c1 = texture2D( maskTexture, vUv + uvOffset.xy);\
  84265. vec4 c2 = texture2D( maskTexture, vUv - uvOffset.xy);\
  84266. vec4 c3 = texture2D( maskTexture, vUv + uvOffset.yw);\
  84267. vec4 c4 = texture2D( maskTexture, vUv - uvOffset.yw);\
  84268. float diff1 = (c1.r - c2.r)*0.5;\
  84269. float diff2 = (c3.r - c4.r)*0.5;\
  84270. float d = length( vec2(diff1, diff2) );\
  84271. float a1 = min(c1.g, c2.g);\
  84272. float a2 = min(c3.g, c4.g);\
  84273. float visibilityFactor = min(a1, a2);\
  84274. vec3 edgeColor = 1.0 - visibilityFactor > 0.001 ? visibleEdgeColor : hiddenEdgeColor;\
  84275. gl_FragColor = vec4(edgeColor, 1.0) * vec4(d);\
  84276. }" */
  84277. fragmentShader:
  84278. "varying vec2 vUv;\
  84279. uniform sampler2D maskTexture;\
  84280. uniform float thickness;\
  84281. uniform vec2 texSize;\
  84282. uniform vec3 visibleEdgeColor;\
  84283. uniform vec3 hiddenEdgeColor;\
  84284. \
  84285. void main() {\n\
  84286. vec2 invSize = 1.0 / texSize;\
  84287. vec4 uvOffset = vec4(1.0, 0.0, 0.0, 1.0) * vec4(invSize, invSize);\
  84288. vec4 c1 = texture2D( maskTexture, vUv + uvOffset.xy);\
  84289. vec4 c2 = texture2D( maskTexture, vUv - uvOffset.xy);\
  84290. vec4 c3 = texture2D( maskTexture, vUv + uvOffset.yw);\
  84291. vec4 c4 = texture2D( maskTexture, vUv - uvOffset.yw);\
  84292. float diff1 = (c1.r - c2.r)*0.5;\
  84293. float diff2 = (c3.r - c4.r)*0.5;\
  84294. float d = length( vec2(diff1, diff2) ) * thickness;\
  84295. float a1 = min(c1.g, c2.g);\
  84296. float a2 = min(c3.g, c4.g);\
  84297. float visibilityFactor = min(a1, a2);\
  84298. vec3 edgeColor = 1.0 - visibilityFactor > 0.001 ? visibleEdgeColor : hiddenEdgeColor;\
  84299. gl_FragColor = vec4(edgeColor, 1.0) * vec4(d);\
  84300. }"
  84301. } );
  84302. },
  84303. getSeperableBlurMaterial: function ( maxRadius ) {
  84304. return new ShaderMaterial( {
  84305. defines: {
  84306. "MAX_RADIUS": maxRadius,
  84307. },
  84308. uniforms: {
  84309. "colorTexture": { value: null },
  84310. "texSize": { value: new Vector2$1( 0.5, 0.5 ) },
  84311. "direction": { value: new Vector2$1( 0.5, 0.5 ) },
  84312. "kernelRadius": { value: 1.0 }
  84313. },
  84314. vertexShader:
  84315. "varying vec2 vUv;\n\
  84316. void main() {\n\
  84317. vUv = uv;\n\
  84318. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
  84319. }",
  84320. fragmentShader:
  84321. "#include <common>\
  84322. varying vec2 vUv;\
  84323. uniform sampler2D colorTexture;\
  84324. uniform vec2 texSize;\
  84325. uniform vec2 direction;\
  84326. uniform float kernelRadius;\
  84327. \
  84328. float gaussianPdf(in float x, in float sigma) {\
  84329. return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\
  84330. }\
  84331. void main() {\
  84332. vec2 invSize = 1.0 / texSize;\
  84333. float weightSum = gaussianPdf(0.0, kernelRadius);\
  84334. vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
  84335. vec2 delta = direction * invSize * kernelRadius/float(MAX_RADIUS);\
  84336. vec2 uvOffset = delta;\
  84337. for( int i = 1; i <= MAX_RADIUS; i ++ ) {\
  84338. float w = gaussianPdf(uvOffset.x, kernelRadius);\
  84339. vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
  84340. vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
  84341. diffuseSum += ((sample1 + sample2) * w);\
  84342. weightSum += (2.0 * w);\
  84343. uvOffset += delta;\
  84344. }\
  84345. gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\
  84346. }"
  84347. } );
  84348. },
  84349. getOverlayMaterial: function () {
  84350. return new ShaderMaterial( {
  84351. uniforms: {
  84352. "maskTexture": { value: null },
  84353. "edgeTexture1": { value: null },
  84354. "edgeTexture2": { value: null },
  84355. "patternTexture": { value: null },
  84356. "edgeStrength": { value: 1.0 },
  84357. "edgeGlow": { value: 1.0 },
  84358. "usePatternTexture": { value: 0.0 }
  84359. },
  84360. vertexShader:
  84361. "varying vec2 vUv;\n\
  84362. void main() {\n\
  84363. vUv = uv;\n\
  84364. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
  84365. }",
  84366. /* fragmentShader:
  84367. "varying vec2 vUv;\
  84368. uniform sampler2D maskTexture;\
  84369. uniform sampler2D edgeTexture1;\
  84370. uniform sampler2D edgeTexture2;\
  84371. uniform sampler2D patternTexture;\
  84372. uniform float edgeStrength;\
  84373. uniform float edgeGlow;\
  84374. uniform bool usePatternTexture;\
  84375. \
  84376. void main() {\
  84377. vec4 edgeValue1 = texture2D(edgeTexture1, vUv);\
  84378. vec4 edgeValue2 = texture2D(edgeTexture2, vUv);\
  84379. vec4 maskColor = texture2D(maskTexture, vUv);\
  84380. vec4 patternColor = texture2D(patternTexture, 6.0 * vUv);\
  84381. float visibilityFactor = 1.0 - maskColor.g > 0.0 ? 1.0 : 0.5;\
  84382. vec4 edgeValue = edgeValue1 + edgeValue2 * edgeGlow;\
  84383. vec4 finalColor = edgeStrength * maskColor.r * edgeValue;\ // 删除 * maskColor.r 也就是去掉遮罩,使模型部分也有outline
  84384. if(usePatternTexture)\
  84385. finalColor += + visibilityFactor * (1.0 - maskColor.r) * (1.0 - patternColor.r);\
  84386. gl_FragColor = finalColor;\
  84387. }", */
  84388. fragmentShader:
  84389. `varying vec2 vUv;
  84390. uniform sampler2D edgeTexture1;
  84391. uniform float edgeStrength;
  84392. void main() {
  84393. gl_FragColor = edgeStrength * texture2D(edgeTexture1, vUv);
  84394. }`,
  84395. blending: AdditiveBlending,
  84396. depthTest: false,
  84397. depthWrite: false,
  84398. transparent: true
  84399. } );
  84400. }
  84401. } );
  84402. OutlinePass.BlurDirectionX = new Vector2$1( 1.0, 0.0 );
  84403. OutlinePass.BlurDirectionY = new Vector2$1( 0.0, 1.0 );
  84404. /**
  84405. * https://github.com/google/model-viewer/blob/master/packages/model-viewer/src/three-components/EnvironmentScene.ts
  84406. */
  84407. class RoomEnvironment extends Scene {
  84408. constructor() {
  84409. super();
  84410. const geometry = new BoxGeometry();
  84411. //geometry.deleteAttribute( 'uv' );//????????????
  84412. const roomMaterial = new MeshStandardMaterial( { side: BackSide } );
  84413. const boxMaterial = new MeshStandardMaterial();
  84414. const mainLight = new PointLight( 0xffffff, 5.0, 28, 2 );
  84415. mainLight.position.set( 0.418, 16.199, 0.300 );
  84416. this.add( mainLight );
  84417. const room = new Mesh( geometry, roomMaterial );
  84418. room.position.set( - 0.757, 13.219, 0.717 );
  84419. room.scale.set( 31.713, 28.305, 28.591 );
  84420. this.add( room );
  84421. const box1 = new Mesh( geometry, boxMaterial );
  84422. box1.position.set( - 10.906, 2.009, 1.846 );
  84423. box1.rotation.set( 0, - 0.195, 0 );
  84424. box1.scale.set( 2.328, 7.905, 4.651 );
  84425. this.add( box1 );
  84426. const box2 = new Mesh( geometry, boxMaterial );
  84427. box2.position.set( - 5.607, - 0.754, - 0.758 );
  84428. box2.rotation.set( 0, 0.994, 0 );
  84429. box2.scale.set( 1.970, 1.534, 3.955 );
  84430. this.add( box2 );
  84431. const box3 = new Mesh( geometry, boxMaterial );
  84432. box3.position.set( 6.167, 0.857, 7.803 );
  84433. box3.rotation.set( 0, 0.561, 0 );
  84434. box3.scale.set( 3.927, 6.285, 3.687 );
  84435. this.add( box3 );
  84436. const box4 = new Mesh( geometry, boxMaterial );
  84437. box4.position.set( - 2.017, 0.018, 6.124 );
  84438. box4.rotation.set( 0, 0.333, 0 );
  84439. box4.scale.set( 2.002, 4.566, 2.064 );
  84440. this.add( box4 );
  84441. const box5 = new Mesh( geometry, boxMaterial );
  84442. box5.position.set( 2.291, - 0.756, - 2.621 );
  84443. box5.rotation.set( 0, - 0.286, 0 );
  84444. box5.scale.set( 1.546, 1.552, 1.496 );
  84445. this.add( box5 );
  84446. const box6 = new Mesh( geometry, boxMaterial );
  84447. box6.position.set( - 2.193, - 0.369, - 5.547 );
  84448. box6.rotation.set( 0, 0.516, 0 );
  84449. box6.scale.set( 3.875, 3.487, 2.986 );
  84450. this.add( box6 );
  84451. // -x right
  84452. const light1 = new Mesh( geometry, createAreaLightMaterial( 50 ) );
  84453. light1.position.set( - 16.116, 14.37, 8.208 );
  84454. light1.scale.set( 0.1, 2.428, 2.739 );
  84455. this.add( light1 );
  84456. // -x left
  84457. const light2 = new Mesh( geometry, createAreaLightMaterial( 50 ) );
  84458. light2.position.set( - 16.109, 18.021, - 8.207 );
  84459. light2.scale.set( 0.1, 2.425, 2.751 );
  84460. this.add( light2 );
  84461. // +x
  84462. const light3 = new Mesh( geometry, createAreaLightMaterial( 17 ) );
  84463. light3.position.set( 14.904, 12.198, - 1.832 );
  84464. light3.scale.set( 0.15, 4.265, 6.331 );
  84465. this.add( light3 );
  84466. // +z
  84467. const light4 = new Mesh( geometry, createAreaLightMaterial( 43 ) );
  84468. light4.position.set( - 0.462, 8.89, 14.520 );
  84469. light4.scale.set( 4.38, 5.441, 0.088 );
  84470. this.add( light4 );
  84471. // -z
  84472. const light5 = new Mesh( geometry, createAreaLightMaterial( 20 ) );
  84473. light5.position.set( 3.235, 11.486, - 12.541 );
  84474. light5.scale.set( 2.5, 2.0, 0.1 );
  84475. this.add( light5 );
  84476. // +y
  84477. const light6 = new Mesh( geometry, createAreaLightMaterial( 100 ) );
  84478. light6.position.set( 0.0, 20.0, 0.0 );
  84479. light6.scale.set( 1.0, 0.1, 1.0 );
  84480. this.add( light6 );
  84481. }
  84482. }
  84483. function createAreaLightMaterial( intensity ) {
  84484. const material = new MeshBasicMaterial();
  84485. material.color.setScalar( intensity );
  84486. return material;
  84487. }
  84488. const manager = new LoadingManager();
  84489. let loaders = {};
  84490. let mapArea;
  84491. let blockedByIntersectHistory = new Map();
  84492. class Viewer extends ViewerBase{
  84493. constructor(domElement, mapArea_, args = {}){
  84494. super(domElement, $.extend(args,{name:'mainViewer'}));
  84495. window.viewer = this;
  84496. if(Potree.settings.editType == "pano" || Potree.settings.editType == "merge"){
  84497. this.modules = {
  84498. Alignment,
  84499. SiteModel
  84500. };
  84501. Potree.settings.useDepthTex = false;
  84502. if(Potree.settings.editType == "pano" ){
  84503. this.modules.PanoEditor = PanoEditor$1;
  84504. }else if(Potree.settings.editType == "merge"){
  84505. this.modules.MergeEditor = MergeEditor;
  84506. this.modules.CamAniEditor = CamAniEditor;
  84507. }
  84508. }else {
  84509. this.modules = {
  84510. Clip,
  84511. Alignment,
  84512. SiteModel,
  84513. RouteGuider : new RouteGuider,
  84514. ParticleEditor,
  84515. CamAniEditor,
  84516. };
  84517. }
  84518. console.log('create viewer');
  84519. this.navigateMode = 'free'; // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点,
  84520. this.isEdit = true;
  84521. this.waitQueue = [];
  84522. this.unitConvert = new UoMService();
  84523. mapArea = mapArea_;
  84524. this.visible = true;
  84525. this.fpVisiDatasets = [];
  84526. this.atDatasets = [];
  84527. this.objs = new Object3D;
  84528. //this.lastPos = new THREE.Vector3(Infinity,Infinity,Infinity)
  84529. //-------------
  84530. var supportExtFragDepth = !!Features.EXT_DEPTH.isSupported() ;//iphoneX居然不支持
  84531. //这意味着边缘增强和测量线遮挡失效
  84532. if(!supportExtFragDepth)console.error('ExtFragDepth unsupported! 边缘增强和测量线遮挡失效');
  84533. this.guiLoaded = false;
  84534. this.guiLoadTasks = [];
  84535. this.onVrListeners = [];
  84536. this.messages = [];
  84537. this.elMessages = $(`
  84538. <div id="message_listing"
  84539. style="position: absolute; z-index: 1000; left: 10px; bottom: 10px">
  84540. </div>`);
  84541. $(domElement).append(this.elMessages);
  84542. this.paused;
  84543. document.addEventListener('visibilitychange',(e)=>{
  84544. //console.log('visibilitychange', !document.hidden )
  84545. this.dispatchEvent({type:'pageVisible', v:!document.hidden} );
  84546. });
  84547. try{
  84548. if(!Potree.settings.isOfficial)
  84549. { // generate missing dom hierarchy
  84550. if ($(domElement).find('#potree_map').length === 0) {
  84551. let potreeMap = $(`
  84552. <div id="potree_map" class="mapBox" style="position: absolute; left: 50px; top: 50px; width: 400px; height: 400px; display: none">
  84553. <div id="potree_map_header" style="position: absolute; width: 100%; height: 25px; top: 0px; background-color: rgba(0,0,0,0.5); z-index: 1000; border-top-left-radius: 3px; border-top-right-radius: 3px;">
  84554. </div>
  84555. <div id="potree_map_content" class="map" style="position: absolute; z-index: 100; top: 25px; width: 100%; height: calc(100% - 25px); border: 2px solid rgba(0,0,0,0.5); box-sizing: border-box;"></div>
  84556. </div>
  84557. `);
  84558. $(domElement).append(potreeMap);
  84559. }
  84560. if ($(domElement).find('#potree_description').length === 0) {
  84561. let potreeDescription = $(`<div id="potree_description" class="potree_info_text"></div>`);
  84562. $(domElement).append(potreeDescription);
  84563. }
  84564. if ($(domElement).find('#potree_annotations').length === 0) {
  84565. let potreeAnnotationContainer = $(`
  84566. <div id="potree_annotation_container"
  84567. style="position: absolute; z-index: 100000; width: 100%; height: 100%; pointer-events: none;"></div>`);
  84568. $(domElement).append(potreeAnnotationContainer);
  84569. }
  84570. if ($(domElement).find('#potree_quick_buttons').length === 0) {
  84571. let potreeMap = $(`
  84572. <div id="potree_quick_buttons" class="quick_buttons_container" style="">
  84573. </div>
  84574. `);
  84575. $(domElement).append(potreeMap);
  84576. }
  84577. //add
  84578. {
  84579. if(!mapArea && Potree.settings.editType != 'merge'){
  84580. $(domElement).append($("<div id='potree_labels'></div>"));
  84581. mapArea = $("<div id='mapGaode'></div>");
  84582. $(domElement).append(mapArea);
  84583. mapArea = mapArea[0];
  84584. }
  84585. }
  84586. /* let domRoot = this.renderer.domElement.parentElement;
  84587. let elAttach = $("<input type='button' value='test'></input>");
  84588. elAttach.css({
  84589. position : "absolute",
  84590. right : '10%',
  84591. bottom: '20px',
  84592. zIndex: "10000",
  84593. fontSize:'1em', color:"black",
  84594. background:'rgba(255,255,255,0.8)',
  84595. })
  84596. let state = false
  84597. elAttach.on("click", () => {
  84598. window.buttonFunction && window.buttonFunction()
  84599. });
  84600. domRoot.appendChild(elAttach[0]); */
  84601. }
  84602. this.pointCloudLoadedCallback = args.onPointCloudLoaded || function () {};
  84603. // if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
  84604. // defaultSettings.navigation = "Orbit";
  84605. // }
  84606. this.server = null;
  84607. this.fov = 60;
  84608. this.isFlipYZ = false;
  84609. this.useDEMCollisions = false;
  84610. this.generateDEM = false;
  84611. this.minNodeSize = 30;
  84612. this.edlStrength = 1.0;
  84613. this.edlRadius = 1.4;
  84614. this.edlOpacity = 1.0;
  84615. this.useEDL = false;
  84616. this.description = "";
  84617. this.classifications = ClassificationScheme.DEFAULT;
  84618. this.moveSpeed = 10;
  84619. this.lengthUnit = LengthUnits.METER;
  84620. this.lengthUnitDisplay = LengthUnits.METER;
  84621. this.showBoundingBox = false;
  84622. this.showAnnotations = true;
  84623. this.freeze = false;
  84624. this.clipTask = ClipTask.HIGHLIGHT;
  84625. this.clipMethod = ClipMethod.INSIDE_ANY;
  84626. this.elevationGradientRepeat = ElevationGradientRepeat.CLAMP;
  84627. this.filterReturnNumberRange = [0, 7];
  84628. this.filterNumberOfReturnsRange = [0, 7];
  84629. this.filterGPSTimeRange = [-Infinity, Infinity];
  84630. this.filterPointSourceIDRange = [0, 65535];
  84631. this.potreeRenderer = null;
  84632. this.edlRenderer = null;
  84633. this.pRenderer = null;
  84634. this.scene = null;
  84635. this.sceneVR = null;
  84636. this.overlay = null;
  84637. this.overlayCamera = null;
  84638. this.inputHandler = null;
  84639. this.controls = null;
  84640. this.clippingTool = null;
  84641. this.transformationTool = null;
  84642. this.navigationCube = null;
  84643. this.compass = null;
  84644. this.skybox = null;
  84645. this.clock = new Clock();
  84646. this.background = null;
  84647. if(args.noDragAndDrop){
  84648. }else {
  84649. this.initDragAndDrop();
  84650. }
  84651. if(typeof Stats !== "undefined"){
  84652. this.stats = new Stats();
  84653. this.stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
  84654. document.body.appendChild( this.stats.dom );
  84655. }
  84656. {
  84657. let canvas = this.renderer.domElement;
  84658. canvas.addEventListener("webglcontextlost", (e) => {
  84659. console.log(e);
  84660. this.postMessage("WebGL context lost. \u2639");
  84661. let gl = this.renderer.getContext();
  84662. let error = gl.getError();
  84663. console.log(error);
  84664. this.dispatchEvent({type:'webglError', msg:'webglcontextlost'});
  84665. }, false);
  84666. }
  84667. {
  84668. this.overlay = new Scene();
  84669. this.overlayCamera = new OrthographicCamera(
  84670. 0, 1,
  84671. 1, 0,
  84672. -1000, 1000
  84673. );
  84674. }
  84675. this.pRenderer = new Renderer(this.renderer);
  84676. {
  84677. let near = 2.5;
  84678. let far = 10.0;
  84679. let fov = 90;
  84680. this.shadowTestCam = new PerspectiveCamera(90, 1, near, far);
  84681. this.shadowTestCam.position.set(3.50, -2.80, 8.561);
  84682. this.shadowTestCam.lookAt(new Vector3(0, 0, 4.87));
  84683. }
  84684. let scene = new Scene$1(this.renderer);
  84685. { // create VR scene
  84686. this.sceneVR = new Scene();
  84687. // let texture = new THREE.TextureLoader().load(`${Potree.resourcePath}/images/vr_controller_help.jpg`);
  84688. // let plane = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
  84689. // let infoMaterial = new THREE.MeshBasicMaterial({map: texture});
  84690. // let infoNode = new THREE.Mesh(plane, infoMaterial);
  84691. // infoNode.position.set(-0.5, 1, 0);
  84692. // infoNode.scale.set(0.4, 0.3, 1);
  84693. // infoNode.lookAt(0, 1, 0)
  84694. // this.sceneVR.add(infoNode);
  84695. // window.infoNode = infoNode;
  84696. }
  84697. this.setScene(scene);
  84698. //add: for 截图时抗锯齿
  84699. {
  84700. this.composer = new EffectComposer( this.renderer );
  84701. this.ssaaRenderPass = new SSAARenderPass(0x000000, 0);
  84702. this.composer.addPass( this.ssaaRenderPass );
  84703. //this.ssaaRenderPass.useCopy = true
  84704. //this.ssaaRenderPass.renderToScreen = true;
  84705. //this.ssaaRenderPass.needsSwap = false
  84706. //见 https://threejs.org/examples/?q=AA#webgl_postprocessing_fxaa 效果和SSAA差不多,都对透明不太友好。
  84707. /* const renderPass = new RenderPass();
  84708. renderPass.clearColor = new THREE.Color( 0, 0, 0 );
  84709. renderPass.clearAlpha = 0;
  84710. this.composer.addPass( renderPass );
  84711. this.fxaaPass = new ShaderPass( FXAAShader );
  84712. this.composer.addPass( this.fxaaPass );
  84713. this.fxaaPass.setSize = function(width, height){
  84714. this.material.uniforms[ 'resolution' ].value.x = 1 / ( width );
  84715. this.material.uniforms[ 'resolution' ].value.y = 1 / ( height );
  84716. }
  84717. this.fxaaPass.renderToScreen = true; */
  84718. /* this.fxaaPass = new ShaderPass( FXAAShader );
  84719. //this.fxaaPass.readTarget = true //add
  84720. this.composer.addPass( this.fxaaPass );
  84721. this.composer.readTarget = true
  84722. this.fxaaPass.setSize = function(width, height){
  84723. this.material.uniforms[ 'resolution' ].value.x = 1 / ( width );
  84724. this.material.uniforms[ 'resolution' ].value.y = 1 / ( height );
  84725. }
  84726. this.fxaaPass.renderToScreen = true; */
  84727. //for 融合页面
  84728. /* let outlinePass = this.outlinePass = new OutlinePass( );
  84729. //composer.addPass( outlinePass );
  84730. outlinePass.edgeStrength = 10
  84731. outlinePass.edgeGlow = 0
  84732. outlinePass.visibleEdgeColor = new THREE.Color("#09a1b3")
  84733. outlinePass.hiddenEdgeColor = new THREE.Color("#09a1b3")
  84734. this.ssaaRenderPass.addPass(outlinePass)
  84735. */
  84736. let outlinePass = this.outlinePass = new OutlinePass( );
  84737. outlinePass.renderToScreen = true; //这样更流畅,不用ssaa了,缺点是outline有锯齿
  84738. outlinePass.enabled = false;
  84739. this.composer.addPass( outlinePass );
  84740. outlinePass.edgeStrength = 10;
  84741. outlinePass.edgeGlow = 0;
  84742. outlinePass.visibleEdgeColor = new Color("#09a1b3");
  84743. outlinePass.hiddenEdgeColor = new Color("#09a1b3");
  84744. }
  84745. {
  84746. this.mainViewport = new Viewport( this.scene.view, this.scene.cameraP, {
  84747. left:0, bottom:0, width:1, height: 1, name:'MainView'
  84748. });
  84749. this.viewports = [this.mainViewport];
  84750. this.compass = new Compass(this);
  84751. this.magnifier = new Magnifier(this);
  84752. this.reticule = new Reticule(this);
  84753. this.scene.scene.add(this.magnifier);
  84754. this.scene.scene.add(this.reticule);
  84755. if(Potree.settings.editType != "pano" && Potree.settings.editType != 'merge'){
  84756. this.mapViewer = new MapViewer(mapArea/* $('#mapGaode')[0] */);
  84757. }
  84758. this.inputHandler = new InputHandler(this, this.scene.scene);
  84759. //this.inputHandler.setScene(this.scene);
  84760. //this.inputHandler.addInputListener(this);//add
  84761. this.clippingTool = new ClippingTool(this);
  84762. this.transformationTool = new TransformationTool(this);
  84763. this.navigationCube = new NavigationCube(this);
  84764. this.navigationCube.visible = false;
  84765. this.createControls();
  84766. this.clippingTool.setScene(this.scene);
  84767. let onPointcloudAdded = (e) => {
  84768. if (this.scene.pointclouds.length === 1) {
  84769. let speed = e.pointcloud.boundingBox.getSize(new Vector3()).length();
  84770. speed = speed / 2000;
  84771. this.setMoveSpeed(speed);
  84772. }
  84773. };
  84774. let onVolumeRemoved = (e) => {
  84775. this.inputHandler.deselect(e.volume);
  84776. };
  84777. this.addEventListener('scene_changed', (e) => {
  84778. this.inputHandler.setScene(e.scene);
  84779. this.clippingTool.setScene(this.scene);
  84780. if(!e.scene.hasEventListener("pointcloud_added", onPointcloudAdded)){
  84781. e.scene.addEventListener("pointcloud_added", onPointcloudAdded);
  84782. }
  84783. if(!e.scene.hasEventListener("volume_removed", onPointcloudAdded)){
  84784. e.scene.addEventListener("volume_removed", onVolumeRemoved);
  84785. }
  84786. });
  84787. this.scene.addEventListener("volume_removed", onVolumeRemoved);
  84788. this.scene.addEventListener('pointcloud_added', onPointcloudAdded);
  84789. }
  84790. { // set defaults
  84791. this.setFOV(60);
  84792. this.setEDLEnabled(false);
  84793. this.setEDLRadius(1.4);
  84794. this.setEDLStrength(0.4);
  84795. this.setEDLOpacity(1.0);
  84796. this.setClipTask(ClipTask.HIGHLIGHT);
  84797. this.setClipMethod(ClipMethod.INSIDE_ANY);
  84798. this.setPointBudget(1*1000*1000);
  84799. this.setShowBoundingBox(false);
  84800. this.setFreeze(false);
  84801. this.setControls(this.fpControls/* orbitControls */);
  84802. this.setBackground( new Color(Potree.config.background),1 /* 'gradient' */ );
  84803. this.scaleFactor = 1;
  84804. this.loadSettingsFromURL();
  84805. }
  84806. // start rendering!
  84807. //if(args.useDefaultRenderLoop === undefined || args.useDefaultRenderLoop === true){
  84808. //requestAnimationFrame(this.loop.bind(this));
  84809. //}
  84810. this.renderer.setAnimationLoop(this.loop.bind(this));
  84811. this.loadGUI = this.loadGUI.bind(this);
  84812. this.annotationTool = new AnnotationTool(this);
  84813. this.measuringTool = new MeasuringTool(this);
  84814. this.profileTool = new ProfileTool(this);
  84815. this.volumeTool = new VolumeTool(this);
  84816. //-----------
  84817. CursorDeal.init(this, this.mapViewer ? [this, this.mapViewer] : [this]);//ADD
  84818. if(Potree.settings.editType == "pano"){
  84819. this.modules.PanoEditor.init();
  84820. }else if(Potree.settings.editType == "merge"){
  84821. this.modules.MergeEditor.init();
  84822. }else {
  84823. this.modules.SiteModel.init();
  84824. this.modules.ParticleEditor.init();
  84825. }
  84826. this.modules.Alignment.init();
  84827. this.images360 = new Images360(this);
  84828. this.scene.scene.add(this.objs);
  84829. loaders = {
  84830. objLoader : new OBJLoader( manager ),
  84831. mtlLoader : new MTLLoader( manager ),
  84832. glbLoader : new GLTFLoader(undefined, this.renderer, Potree.settings.libsUrl )
  84833. };
  84834. //add test
  84835. const environment = new RoomEnvironment();
  84836. const pmremGenerator = new PMREMGenerator( this.renderer );
  84837. this.scene.scene.environment = pmremGenerator.fromScene( environment ).texture;
  84838. //-----------
  84839. }catch(e){
  84840. this.onCrash(e);
  84841. }
  84842. //-----------------------add----------------------------------------------------
  84843. /* {
  84844. let ratio
  84845. this.addEventListener('resize',(e)=>{
  84846. if(ratio != e.deviceRatio){ //因为devicePixelRatio会影响到点云大小,所以改变时计算下点云大小
  84847. viewer.scene.pointclouds.forEach(p => {
  84848. p.changePointSize()
  84849. })
  84850. }
  84851. ratio = e.deviceRatio
  84852. })
  84853. } */
  84854. {
  84855. let pointDensity = '';
  84856. Object.defineProperty(Potree.settings , "pointDensity",{
  84857. get: function() {
  84858. return pointDensity
  84859. },
  84860. set: (density)=>{
  84861. if(density && density != pointDensity){
  84862. let pointBudget;
  84863. var config = Potree.config.pointDensity[density];
  84864. if(this.magnifier.visible){//放大镜打开时不要切换pointBudget,否则点云会闪烁。这时使用最高密度。
  84865. pointBudget = Potree.config.pointDensity['magnifier'].pointBudget;
  84866. }else {
  84867. pointBudget = config.pointBudget;
  84868. }
  84869. viewer.setPointBudget(pointBudget );
  84870. //Potree.maxPointLevel = config.maxLevel
  84871. pointDensity = density;
  84872. this.setPointLevels();
  84873. }
  84874. }
  84875. });
  84876. let UserPointDensity = '';
  84877. Object.defineProperty(Potree.settings , "UserPointDensity",{
  84878. get: function() {
  84879. return UserPointDensity
  84880. },
  84881. set: (density)=>{
  84882. if(UserPointDensity != density){
  84883. if(Potree.settings.displayMode == 'showPointCloud' && this.viewports.length != 4){//漫游模式和四屏时都有自己的pointDensity
  84884. Potree.settings.pointDensity = density;
  84885. }
  84886. UserPointDensity = density;
  84887. }
  84888. }
  84889. });
  84890. }
  84891. {
  84892. let cameraFar = Potree.settings.cameraFar;
  84893. Object.defineProperty(Potree.settings , "cameraFar",{
  84894. get: function() {
  84895. return cameraFar
  84896. },
  84897. set: (far)=>{
  84898. if(far != cameraFar){
  84899. if(Potree.settings.displayMode != 'showPanos'){
  84900. this.mainViewport.camera.far = far;
  84901. this.mainViewport.camera.updateProjectionMatrix();
  84902. }
  84903. cameraFar = far;
  84904. }
  84905. }
  84906. });
  84907. }
  84908. this.addEventListener('allLoaded', ()=>{
  84909. setTimeout(this.testPointcloudsMaxLevel.bind(this), 2000); //延迟一丢丢,等画面出现
  84910. });
  84911. if(Potree.settings.editType != 'pano' && Potree.settings.editType != 'merge'){
  84912. this.addEventListener('switchFloorplanSelect',(e)=>{//进入平面图设置后 切换选中的数据集
  84913. this.selectedFloorplan = e.pointcloud; //绝对显示
  84914. this.updateFpVisiDatasets();
  84915. let pointclouds;
  84916. if(e.pointcloud){
  84917. pointclouds = [e.pointcloud];
  84918. }else if(this.fpVisiDatasets.length){
  84919. pointclouds = this.fpVisiDatasets;
  84920. }
  84921. pointclouds && this.mapViewer.fitToDatasets(pointclouds);
  84922. });
  84923. this.modules.SiteModel.bus.addEventListener('FloorChange',()=>{
  84924. this.updateFpVisiDatasets();
  84925. });
  84926. this.mapViewer.mapLayer.addEventListener('floorplanLoaded',()=>{
  84927. this.updateCadVisibles(this.fpVisiDatasets, true); //加载完成后重新更新下
  84928. });
  84929. /* this.modules.Clip.bus.addEventListener('updateSelectedDatasets',()=>{
  84930. this.updateFpVisiDatasets()
  84931. }) */
  84932. }
  84933. {
  84934. //更新所在数据集
  84935. this.addEventListener('camera_changed', e => {
  84936. if(e.changeInfo.positionChanged){
  84937. blockedByIntersectHistory.clear(); //清空
  84938. this.updateDatasetAt();
  84939. }
  84940. });
  84941. }
  84942. }
  84943. ifPointBlockedByIntersect(pos3d, object){//点是否被遮挡
  84944. let ifShelter;
  84945. let shelter = blockedByIntersectHistory.get(object || pos3d);
  84946. if(shelter){
  84947. ifShelter = shelter.ifShelter;
  84948. }else {
  84949. ifShelter = viewer.inputHandler.ifBlockedByIntersect(pos3d, 0.3, true);//由于热点都是使用点云得到的位置,所以判断遮挡时也用点云
  84950. blockedByIntersectHistory.set(object || pos3d, {ifShelter});
  84951. }
  84952. return ifShelter
  84953. }
  84954. updateDatasetAt(force){//更新所在数据集
  84955. let fun = ()=>{
  84956. let currPos = viewer.mainViewport.view.position;
  84957. //if(force || !currPos.equals(this.lastPos)){
  84958. //this.lastPos.copy(currPos)
  84959. var at = this.scene.pointclouds.filter(e=>e.ifContainsPoint(currPos));
  84960. if(Common.getDifferenceSet(at, this.atDatasets).length){
  84961. //console.log('atDatasets', at)
  84962. this.atDatasets = at;
  84963. if(Potree.settings.editType != 'pano' && Potree.settings.editType != 'merge')this.updateFpVisiDatasets();
  84964. this.dispatchEvent({type:'pointcloudAtChange',pointclouds:at});
  84965. }
  84966. force = false;
  84967. return true
  84968. //}
  84969. };
  84970. if(force)fun();
  84971. else Common.intervalTool.isWaiting('atWhichDataset', fun , 500);
  84972. }
  84973. updatePanosVisibles(currentFloor){//显示当前楼层的所有panos
  84974. viewer.images360.panos.forEach(pano=>{
  84975. let visible = currentFloor && currentFloor.panos.includes(pano);
  84976. viewer.updateVisible(pano, 'buildingChange', visible, 2);
  84977. });
  84978. }
  84979. updateFpVisiDatasets(){
  84980. let Clip = this.modules.Clip;
  84981. let SiteModel = this.modules.SiteModel;
  84982. let Alignment = this.modules.Alignment;
  84983. var currentFloor = SiteModel.currentFloor;
  84984. /* if(Clip.editing){//下载页面已经改为和普通时一样,根据位置判断
  84985. this.updateCadVisibles(Clip.selectedDatasets)
  84986. }else */if(this.selectedFloorplan){//平面图设置中
  84987. let pointclouds = [this.selectedFloorplan];
  84988. this.updateCadVisibles(pointclouds);
  84989. }else if(SiteModel.editing || Alignment.editing){//只显示勾选的,也就是显示的点云的
  84990. let pointclouds = this.scene.pointclouds.filter(p => this.getObjVisiByReason(p,'datasetSelection') );
  84991. this.updateCadVisibles(pointclouds);
  84992. this.updatePanosVisibles(currentFloor/* , pointclouds */);
  84993. }else {
  84994. let pointclouds = currentFloor ? this.findPointcloudsAtFloor(currentFloor) : [];
  84995. if(pointclouds.length == 0){//如果当前不在任何楼层或楼层中无数据集,就用当前所在数据集
  84996. pointclouds = this.atDatasets;
  84997. }
  84998. this.updateCadVisibles(pointclouds);
  84999. this.updatePanosVisibles(currentFloor/* , pointclouds */);
  85000. }
  85001. }
  85002. findPointcloudsAtFloor(entity){//找当前楼层需要显示哪些数据集。
  85003. //数据集的belongToEntity 在这个entity内(否则会出现点击数据集飞过去平面图却不显示)。or 如果数据集有漫游点的话,需要包含>20%的漫游点。 (防止重叠体积很大但其实一个漫游点都不包含)
  85004. //重叠体积>50% 或 包含>50%的漫游点
  85005. const ratio1 = 0.2, ratio2 = 0.5, ratio3 = 0.95;
  85006. var lowScores = [];
  85007. var pointclouds = viewer.scene.pointclouds.filter(e=>{
  85008. let score = 0;
  85009. if(e.belongToEntity && (e.belongToEntity == entity || e.belongToEntity.buildParent == entity)){//条件1 若该数据集挂载到该楼层 或 该数据集挂载到的房间属于该楼层(这样能显示该层所有房间)
  85010. return true
  85011. }
  85012. if(e.panos.length){//条件2
  85013. var insidePanos = e.panos.filter(a=>entity.ifContainsPoint(a.position));
  85014. let panoCountRatio = insidePanos.length / e.panos.length;
  85015. if(panoCountRatio > ratio2)return true
  85016. if(panoCountRatio < ratio1){
  85017. score += panoCountRatio;//return false
  85018. }
  85019. }
  85020. //条件3
  85021. let volume = entity.intersectPointcloudVolume(e);
  85022. let volumeRatio = volume / entity.getVolume(true); //注:hole加入计算
  85023. if(volumeRatio > ratio3){ //ratio3要高一些,因为点云bounding可能很大,包含很多无点云的空间。即使整个数据集包含entity都不一定看起来在数据集中。(千万要防止两层楼都显示了)
  85024. return true
  85025. }else {
  85026. score += volumeRatio;
  85027. }
  85028. lowScores.push({score, pointcloud:e});
  85029. });
  85030. if(pointclouds.length == 0){//从低分项挑一个出来。
  85031. lowScores.sort((a,b)=>{return a.score - b.score});
  85032. if(lowScores[0].score > 0.4){
  85033. pointclouds = [lowScores[0].pointcloud];
  85034. }
  85035. }
  85036. return pointclouds
  85037. }
  85038. updateCadVisibles(visiClouds, force){
  85039. let oldVisi = this.fpVisiDatasets;
  85040. var visiClouds = this.fpVisiDatasets = visiClouds;
  85041. if(!force){
  85042. var difference = Common.getDifferenceSet(oldVisi , visiClouds);
  85043. if(difference.length == 0)return
  85044. }
  85045. //console.log('visiClouds',visiClouds.map(e=>e.name))
  85046. viewer.scene.pointclouds.forEach(pointcloud=>{
  85047. var floorplan = viewer.mapViewer.mapLayer.getFloorplan(pointcloud.dataset_id);
  85048. var visi = visiClouds.includes(pointcloud);
  85049. if(floorplan){
  85050. viewer.updateVisible(floorplan.objectGroup, 'buildingChange', visi);
  85051. }/* else if(!visi){
  85052. let changeVisi = (e)=>{
  85053. viewer.updateVisible(e.floorplan.objectGroup, 'buildingChange', this.fpVisiDatasets.includes(pointcloud))
  85054. viewer.mapViewer.mapLayer.removeEventListener('floorplanLoaded', changeVisi)
  85055. console.log('updateCadVisibles加载后更改显示',e)
  85056. }
  85057. viewer.mapViewer.mapLayer.addEventListener('floorplanLoaded', changeVisi)
  85058. } */
  85059. //已经添加了全局的 floorplanLoaded后会updateCadVisibles,这段就删了
  85060. });
  85061. viewer.mapViewer.mapLayer.needUpdate = true; //可能需要更新加载的level程度
  85062. viewer.mapViewer.needRender = true; //若上句不触发加载也要立即重新绘制
  85063. }
  85064. //促使点云加载出最高级别
  85065. testPointcloudsMaxLevel(){ //所有点云都无需testMaxNodeLevel 就停止
  85066. let camera_changed, count = 0;
  85067. let test = ()=>{
  85068. camera_changed = true;
  85069. Common.intervalTool.isWaiting('testPointcloudsMaxLevel', ()=>{
  85070. if(!camera_changed && count>20 )return //只有当camera_changed后才继续循环, 除了最开始几次需要连续加载下
  85071. camera_changed = false;
  85072. count ++;
  85073. //console.log('testPointcloudsMaxLevel中')
  85074. var success = true;
  85075. viewer.scene.pointclouds.forEach(e=>{
  85076. var wait = e.testMaxNodeLevel();
  85077. if(wait){
  85078. success = false;
  85079. }
  85080. });
  85081. if(!success)return true //没有全部加载完,继续循环
  85082. else {
  85083. this.removeEventListener('camera_changed',test);
  85084. console.log('testPointcloudsMaxLevel结束');
  85085. }
  85086. }, count<10 ? 150 : 500);
  85087. };
  85088. this.addEventListener('camera_changed',test);
  85089. test();
  85090. /* 检验:
  85091. viewer.scene.pointclouds.sort((a,b)=>a.nodeMaxLevelPredict.min - b.nodeMaxLevelPredict.min).forEach(e=>console.log(e.nodeMaxLevel, e.nodeMaxLevelPredict.min))
  85092. */
  85093. }
  85094. setPointLevels(){
  85095. this.scene.pointclouds.forEach(e=>{
  85096. e.setPointLevel();
  85097. });
  85098. }
  85099. onCrash(error){
  85100. $(this.renderArea).empty();
  85101. if ($(this.renderArea).find('#potree_failpage').length === 0) {
  85102. let elFailPage = $(`
  85103. <div id="#potree_failpage" class="potree_failpage">
  85104. <h1>Potree Encountered An Error </h1>
  85105. <p>
  85106. This may happen if your browser or graphics card is not supported.
  85107. <br>
  85108. We recommend to use
  85109. <a href="https://www.google.com/chrome/browser" target="_blank" style="color:initial">Chrome</a>
  85110. or
  85111. <a href="https://www.mozilla.org/" target="_blank">Firefox</a>.
  85112. </p>
  85113. <p>
  85114. Please also visit <a href="http://webglreport.com/" target="_blank">webglreport.com</a> and
  85115. check whether your system supports WebGL.
  85116. </p>
  85117. <p>
  85118. If you are already using one of the recommended browsers and WebGL is enabled,
  85119. consider filing an issue report at <a href="https://github.com/potree/potree/issues" target="_blank">github</a>,<br>
  85120. including your operating system, graphics card, browser and browser version, as well as the
  85121. error message below.<br>
  85122. Please do not report errors on unsupported browsers.
  85123. </p>
  85124. <pre id="potree_error_console" style="width: 100%; height: 100%"></pre>
  85125. </div>`);
  85126. let elErrorMessage = elFailPage.find('#potree_error_console');
  85127. elErrorMessage.html(error.stack);
  85128. $(this.renderArea).append(elFailPage);
  85129. }
  85130. throw error;
  85131. }
  85132. // ------------------------------------------------------------------------------------
  85133. // Viewer API
  85134. // ------------------------------------------------------------------------------------
  85135. setScene (scene) {
  85136. if (scene === this.scene) {
  85137. return;
  85138. }
  85139. let oldScene = this.scene;
  85140. this.scene = scene;
  85141. this.dispatchEvent({
  85142. type: 'scene_changed',
  85143. oldScene: oldScene,
  85144. scene: scene
  85145. });
  85146. { // Annotations
  85147. $('.annotation').detach();
  85148. // for(let annotation of this.scene.annotations){
  85149. // this.renderArea.appendChild(annotation.domElement[0]);
  85150. // }
  85151. this.scene.annotations.traverse(annotation => {
  85152. this.renderArea.appendChild(annotation.domElement[0]);
  85153. });
  85154. if (!this.onAnnotationAdded) {
  85155. this.onAnnotationAdded = e => {
  85156. // console.log("annotation added: " + e.annotation.title);
  85157. e.annotation.traverse(node => {
  85158. $("#potree_annotation_container").append(node.domElement);
  85159. //this.renderArea.appendChild(node.domElement[0]);
  85160. node.scene = this.scene;
  85161. });
  85162. };
  85163. }
  85164. if (oldScene) {
  85165. oldScene.annotations.removeEventListener('annotation_added', this.onAnnotationAdded);
  85166. }
  85167. this.scene.annotations.addEventListener('annotation_added', this.onAnnotationAdded);
  85168. }
  85169. };
  85170. setControls(controls/* , setSpeed */){
  85171. if (controls !== this.controls) {
  85172. if (this.controls) {
  85173. this.controls.setEnable(false);
  85174. //this.inputHandler.removeInputListener(this.controls);
  85175. this.controls.moveSpeed = this.moveSpeed; //记录 (因为orbit的radius很大,转为firstPerson时要缩小)
  85176. }
  85177. this.controls = controls;
  85178. controls.moveSpeed && this.setMoveSpeed(controls.moveSpeed); //add
  85179. this.controls.setEnable(true);
  85180. //this.inputHandler.addInputListener(this.controls);
  85181. }
  85182. }
  85183. getControls () {
  85184. if(this.renderer.xr.isPresenting){
  85185. return this.vrControls;
  85186. }else {
  85187. return this.controls;
  85188. }
  85189. }
  85190. getMinNodeSize () {
  85191. return this.minNodeSize;
  85192. };
  85193. setMinNodeSize (value) {
  85194. if (this.minNodeSize !== value) {
  85195. this.minNodeSize = value;
  85196. this.dispatchEvent({'type': 'minnodesize_changed', 'viewer': this});
  85197. }
  85198. };
  85199. getBackground () {
  85200. return this.background;
  85201. }
  85202. setBackground(bg){
  85203. if (this.background === bg) {
  85204. return;
  85205. }
  85206. if(bg === "skybox"){
  85207. this.skybox = Utils.loadSkybox(new URL(Potree.resourcePath + '/textures/skybox2/').href);
  85208. }
  85209. this.background = bg;
  85210. this.backgroundOpacity = 1;//add
  85211. this.dispatchEvent({'type': 'background_changed', 'viewer': this});
  85212. }
  85213. setDescription (value) {
  85214. this.description = value;
  85215. $('#potree_description').html(value);
  85216. //$('#potree_description').text(value);
  85217. }
  85218. getDescription(){
  85219. return this.description;
  85220. }
  85221. setShowBoundingBox (value) {
  85222. if (this.showBoundingBox !== value) {
  85223. this.showBoundingBox = value;
  85224. this.dispatchEvent({'type': 'show_boundingbox_changed', 'viewer': this});
  85225. }
  85226. };
  85227. getShowBoundingBox () {
  85228. return this.showBoundingBox;
  85229. };
  85230. setMoveSpeed (value) {
  85231. if (this.getMoveSpeed() !== value) {
  85232. this.mainViewport.setMoveSpeed(value);
  85233. this.dispatchEvent({'type': 'move_speed_changed', 'viewer': this, 'speed': value});
  85234. }
  85235. };
  85236. getMoveSpeed () {
  85237. return this.mainViewport.moveSpeed;
  85238. };
  85239. setWeightClassification (w) {
  85240. for (let i = 0; i < this.scene.pointclouds.length; i++) {
  85241. this.scene.pointclouds[i].material.weightClassification = w;
  85242. this.dispatchEvent({'type': 'attribute_weights_changed' + i, 'viewer': this});
  85243. }
  85244. };
  85245. setFreeze (value) {
  85246. value = Boolean(value);
  85247. if (this.freeze !== value) {
  85248. this.freeze = value;
  85249. this.dispatchEvent({'type': 'freeze_changed', 'viewer': this});
  85250. }
  85251. };
  85252. getFreeze () {
  85253. return this.freeze;
  85254. };
  85255. getClipTask(){
  85256. return this.clipTask;
  85257. }
  85258. getClipMethod(){
  85259. return this.clipMethod;
  85260. }
  85261. setClipTask(value){
  85262. if(this.clipTask !== value){
  85263. this.clipTask = value;
  85264. this.dispatchEvent({
  85265. type: "cliptask_changed",
  85266. viewer: this});
  85267. }
  85268. }
  85269. setClipMethod(value){
  85270. if(this.clipMethod !== value){
  85271. this.clipMethod = value;
  85272. this.dispatchEvent({
  85273. type: "clipmethod_changed",
  85274. viewer: this});
  85275. }
  85276. }
  85277. setElevationGradientRepeat(value){
  85278. if(this.elevationGradientRepeat !== value){
  85279. this.elevationGradientRepeat = value;
  85280. this.dispatchEvent({
  85281. type: "elevation_gradient_repeat_changed",
  85282. viewer: this});
  85283. }
  85284. }
  85285. setPointBudget (value) {
  85286. if (Potree.pointBudget !== value) {
  85287. Potree.pointBudget = parseInt(value);
  85288. this.dispatchEvent({'type': 'point_budget_changed', 'viewer': this});
  85289. }
  85290. };
  85291. getPointBudget () {
  85292. return Potree.pointBudget;
  85293. };
  85294. setShowAnnotations (value) {
  85295. if (this.showAnnotations !== value) {
  85296. this.showAnnotations = value;
  85297. this.dispatchEvent({'type': 'show_annotations_changed', 'viewer': this});
  85298. }
  85299. }
  85300. getShowAnnotations () {
  85301. return this.showAnnotations;
  85302. }
  85303. setDEMCollisionsEnabled(value){
  85304. if(this.useDEMCollisions !== value){
  85305. this.useDEMCollisions = value;
  85306. this.dispatchEvent({'type': 'use_demcollisions_changed', 'viewer': this});
  85307. };
  85308. };
  85309. getDEMCollisionsEnabled () {
  85310. return this.useDEMCollisions;
  85311. };
  85312. setEDLEnabled (value) {
  85313. value = Boolean(value) && Features.SHADER_EDL.isSupported();
  85314. if (this.useEDL !== value) {
  85315. this.useEDL = value;
  85316. this.dispatchEvent({'type': 'use_edl_changed', 'viewer': this});
  85317. }
  85318. };
  85319. getEDLEnabled () {
  85320. return this.useEDL;
  85321. };
  85322. setEDLRadius (value) {
  85323. if (this.edlRadius !== value) {
  85324. this.edlRadius = value;
  85325. this.dispatchEvent({'type': 'edl_radius_changed', 'viewer': this});
  85326. }
  85327. };
  85328. getEDLRadius () {
  85329. return this.edlRadius;
  85330. };
  85331. setEDLStrength (value) {
  85332. if (this.edlStrength !== value) {
  85333. this.edlStrength = value;
  85334. this.dispatchEvent({'type': 'edl_strength_changed', 'viewer': this});
  85335. }
  85336. };
  85337. getEDLStrength () {
  85338. return this.edlStrength;
  85339. };
  85340. setEDLOpacity (value) {
  85341. if (this.edlOpacity !== value) {
  85342. this.edlOpacity = value;
  85343. this.dispatchEvent({'type': 'edl_opacity_changed', 'viewer': this});
  85344. }
  85345. };
  85346. getEDLOpacity () {
  85347. return this.edlOpacity;
  85348. };
  85349. setFOV (value) {
  85350. if (this.fov !== value) {
  85351. let oldFov = this.fov;
  85352. this.fov = value;
  85353. this.scene.cameraP.fov = this.fov;
  85354. this.scene.cameraP.updateProjectionMatrix();
  85355. this.dispatchEvent({'type': 'fov_changed', 'viewer': this, oldFov, fov:this.fov});
  85356. }
  85357. };
  85358. getFOV () {
  85359. return this.fov;
  85360. };
  85361. disableAnnotations () {
  85362. this.scene.annotations.traverse(annotation => {
  85363. annotation.domElement.css('pointer-events', 'none');
  85364. // return annotation.visible;
  85365. });
  85366. };
  85367. enableAnnotations () {
  85368. this.scene.annotations.traverse(annotation => {
  85369. annotation.domElement.css('pointer-events', 'auto');
  85370. // return annotation.visible;
  85371. });
  85372. }
  85373. setClassifications(classifications){
  85374. this.classifications = classifications;
  85375. this.dispatchEvent({'type': 'classifications_changed', 'viewer': this});
  85376. }
  85377. setClassificationVisibility (key, value) {
  85378. if (!this.classifications[key]) {
  85379. this.classifications[key] = {visible: value, name: 'no name'};
  85380. this.dispatchEvent({'type': 'classification_visibility_changed', 'viewer': this});
  85381. } else if (this.classifications[key].visible !== value) {
  85382. this.classifications[key].visible = value;
  85383. this.dispatchEvent({'type': 'classification_visibility_changed', 'viewer': this});
  85384. }
  85385. }
  85386. toggleAllClassificationsVisibility(){
  85387. let numVisible = 0;
  85388. let numItems = 0;
  85389. for(const key of Object.keys(this.classifications)){
  85390. if(this.classifications[key].visible){
  85391. numVisible++;
  85392. }
  85393. numItems++;
  85394. }
  85395. let visible = true;
  85396. if(numVisible === numItems){
  85397. visible = false;
  85398. }
  85399. let somethingChanged = false;
  85400. for(const key of Object.keys(this.classifications)){
  85401. if(this.classifications[key].visible !== visible){
  85402. this.classifications[key].visible = visible;
  85403. somethingChanged = true;
  85404. }
  85405. }
  85406. if(somethingChanged){
  85407. this.dispatchEvent({'type': 'classification_visibility_changed', 'viewer': this});
  85408. }
  85409. }
  85410. setFilterReturnNumberRange(from, to){
  85411. this.filterReturnNumberRange = [from, to];
  85412. this.dispatchEvent({'type': 'filter_return_number_range_changed', 'viewer': this});
  85413. }
  85414. setFilterNumberOfReturnsRange(from, to){
  85415. this.filterNumberOfReturnsRange = [from, to];
  85416. this.dispatchEvent({'type': 'filter_number_of_returns_range_changed', 'viewer': this});
  85417. }
  85418. setFilterGPSTimeRange(from, to){
  85419. this.filterGPSTimeRange = [from, to];
  85420. this.dispatchEvent({'type': 'filter_gps_time_range_changed', 'viewer': this});
  85421. }
  85422. setFilterPointSourceIDRange(from, to){
  85423. this.filterPointSourceIDRange = [from, to];
  85424. this.dispatchEvent({'type': 'filter_point_source_id_range_changed', 'viewer': this});
  85425. }
  85426. setLengthUnit (value) {
  85427. switch (value) {
  85428. case 'm':
  85429. this.lengthUnit = LengthUnits.METER;
  85430. this.lengthUnitDisplay = LengthUnits.METER;
  85431. break;
  85432. case 'ft':
  85433. this.lengthUnit = LengthUnits.FEET;
  85434. this.lengthUnitDisplay = LengthUnits.FEET;
  85435. break;
  85436. case 'in':
  85437. this.lengthUnit = LengthUnits.INCH;
  85438. this.lengthUnitDisplay = LengthUnits.INCH;
  85439. break;
  85440. }
  85441. this.dispatchEvent({ 'type': 'length_unit_changed', 'viewer': this, value: value});
  85442. };
  85443. setLengthUnitAndDisplayUnit(lengthUnitValue, lengthUnitDisplayValue) {
  85444. switch (lengthUnitValue) {
  85445. case 'm':
  85446. this.lengthUnit = LengthUnits.METER;
  85447. break;
  85448. case 'ft':
  85449. this.lengthUnit = LengthUnits.FEET;
  85450. break;
  85451. case 'in':
  85452. this.lengthUnit = LengthUnits.INCH;
  85453. break;
  85454. }
  85455. switch (lengthUnitDisplayValue) {
  85456. case 'm':
  85457. this.lengthUnitDisplay = LengthUnits.METER;
  85458. break;
  85459. case 'ft':
  85460. this.lengthUnitDisplay = LengthUnits.FEET;
  85461. break;
  85462. case 'in':
  85463. this.lengthUnitDisplay = LengthUnits.INCH;
  85464. break;
  85465. }
  85466. this.dispatchEvent({ 'type': 'length_unit_changed', 'viewer': this, value: lengthUnitValue });
  85467. };
  85468. zoomTo(node, factor, animationDuration = 0){
  85469. let view = this.scene.view;
  85470. let camera = this.scene.cameraP.clone();
  85471. camera.rotation.copy(this.scene.cameraP.rotation);
  85472. camera.rotation.order = "ZXY";
  85473. camera.rotation.x = Math.PI / 2 + view.pitch;
  85474. camera.rotation.z = view.yaw;
  85475. camera.updateMatrix();
  85476. camera.updateMatrixWorld();
  85477. camera.zoomTo(node, factor);
  85478. let bs;
  85479. if (node.boundingSphere) {
  85480. bs = node.boundingSphere;
  85481. } else if (node.geometry && node.geometry.boundingSphere) {
  85482. bs = node.geometry.boundingSphere;
  85483. } else {
  85484. bs = node.boundingBox.getBoundingSphere(new Sphere());
  85485. }
  85486. bs = bs.clone().applyMatrix4(node.matrixWorld);
  85487. let startPosition = view.position.clone();
  85488. let endPosition = camera.position.clone();
  85489. let startTarget = view.getPivot();
  85490. let endTarget = bs.center;
  85491. let startRadius = view.radius;
  85492. let endRadius = endPosition.distanceTo(endTarget);
  85493. let easing = TWEEN.Easing.Quartic.Out;
  85494. { // animate camera position
  85495. let pos = startPosition.clone();
  85496. let tween = new TWEEN.Tween(pos).to(endPosition, animationDuration);
  85497. tween.easing(easing);
  85498. tween.onUpdate(() => {
  85499. view.position.copy(pos);
  85500. });
  85501. tween.start();
  85502. }
  85503. { // animate camera target
  85504. let target = startTarget.clone();
  85505. let tween = new TWEEN.Tween(target).to(endTarget, animationDuration);
  85506. tween.easing(easing);
  85507. tween.onUpdate(() => {
  85508. view.lookAt(target);
  85509. });
  85510. tween.onComplete(() => {
  85511. view.lookAt(target);
  85512. this.dispatchEvent({type: 'focusing_finished', target: this});
  85513. });
  85514. this.dispatchEvent({type: 'focusing_started', target: this});
  85515. tween.start();
  85516. }
  85517. };
  85518. moveToGpsTimeVicinity(time){
  85519. const result = Potree.Utils.findClosestGpsTime(time, viewer);
  85520. const box = result.node.pointcloud.deepestNodeAt(result.position).getBoundingBox();
  85521. const diameter = box.min.distanceTo(box.max);
  85522. const camera = this.scene.getActiveCamera();
  85523. const offset = camera.getWorldDirection(new Vector3()).multiplyScalar(diameter);
  85524. const newCamPos = result.position.clone().sub(offset);
  85525. this.scene.view.position.copy(newCamPos);
  85526. this.scene.view.lookAt(result.position);
  85527. }
  85528. showAbout () {
  85529. $(function () {
  85530. $('#about-panel').dialog();
  85531. });
  85532. };
  85533. getGpsTimeExtent(){
  85534. const range = [Infinity, -Infinity];
  85535. for(const pointcloud of this.scene.pointclouds){
  85536. const attributes = pointcloud.pcoGeometry.pointAttributes.attributes;
  85537. const aGpsTime = attributes.find(a => a.name === "gps-time");
  85538. if(aGpsTime){
  85539. range[0] = Math.min(range[0], aGpsTime.range[0]);
  85540. range[1] = Math.max(range[1], aGpsTime.range[1]);
  85541. }
  85542. }
  85543. return range;
  85544. }
  85545. fitToScreen (factor = 1, animationDuration = 0) {
  85546. let box = this.getBoundingBox(this.scene.pointclouds);
  85547. let node = new Object3D();
  85548. node.boundingBox = box;
  85549. this.zoomTo(node, factor, animationDuration);
  85550. this.controls.stop();
  85551. };
  85552. toggleNavigationCube() {
  85553. this.navigationCube.visible = !this.navigationCube.visible;
  85554. }
  85555. /* setView(pos, view) {
  85556. if(!pos) return;
  85557. switch(pos) {
  85558. case "F":
  85559. this.setFrontView(view);
  85560. break;
  85561. case "B":
  85562. this.setBackView(view);
  85563. break;
  85564. case "L":
  85565. this.setLeftView(view);
  85566. break;
  85567. case "R":
  85568. this.setRightView(view);
  85569. break;
  85570. case "U":
  85571. this.setTopView(view);
  85572. break;
  85573. case "D":
  85574. this.setBottomView(view);
  85575. break;
  85576. }
  85577. } */
  85578. setTopView(view){
  85579. view = view || this.scene.view;
  85580. view.setCubeView("top");
  85581. this.fitToScreen();
  85582. };
  85583. setBottomView(){
  85584. this.scene.view.yaw = -Math.PI;
  85585. this.scene.view.pitch = Math.PI / 2;
  85586. this.fitToScreen();
  85587. };
  85588. setFrontView(view){
  85589. view = view || this.scene.view;
  85590. view.yaw = 0;
  85591. view.pitch = 0;
  85592. this.fitToScreen();
  85593. };
  85594. setBackView(view){
  85595. view = view || this.scene.view;
  85596. view.yaw = Math.PI;
  85597. view.pitch = 0;
  85598. this.fitToScreen();
  85599. };
  85600. setLeftView(){
  85601. this.scene.view.yaw = -Math.PI / 2;
  85602. this.scene.view.pitch = 0;
  85603. this.fitToScreen();
  85604. };
  85605. setRightView () {
  85606. this.scene.view.yaw = Math.PI / 2;
  85607. this.scene.view.pitch = 0;
  85608. this.fitToScreen();
  85609. };
  85610. flipYZ () {
  85611. this.isFlipYZ = !this.isFlipYZ;
  85612. // TODO flipyz
  85613. console.log('TODO');
  85614. }
  85615. setCameraMode(mode){
  85616. this.scene.cameraMode = mode;
  85617. for(let pointcloud of this.scene.pointclouds) {
  85618. pointcloud.material.useOrthographicCamera = mode == CameraMode.ORTHOGRAPHIC;
  85619. }
  85620. }
  85621. getProjection(){
  85622. const pointcloud = this.scene.pointclouds[0];
  85623. if(pointcloud){
  85624. return pointcloud.projection;
  85625. }else {
  85626. return null;
  85627. }
  85628. }
  85629. async loadProject(url,done){
  85630. const response = await fetch(url);
  85631. if(response.ok){
  85632. const text = await response.text();
  85633. const json = lib.parse(text);
  85634. // const json = JSON.parse(text);
  85635. if(json.type === "Potree"){
  85636. Potree.loadProject(viewer, json, done);
  85637. }
  85638. }else {
  85639. console.warn("未能加载:"+url );
  85640. }
  85641. }
  85642. saveProject(){
  85643. return Potree.saveProject(this);
  85644. }
  85645. loadSettingsFromURL(){
  85646. if(Utils.getParameterByName("pointSize")){
  85647. this.setPointSize(parseFloat(Utils.getParameterByName("pointSize")));
  85648. }
  85649. if(Utils.getParameterByName("FOV")){
  85650. this.setFOV(parseFloat(Utils.getParameterByName("FOV")));
  85651. }
  85652. if(Utils.getParameterByName("opacity")){
  85653. this.setOpacity(parseFloat(Utils.getParameterByName("opacity")));
  85654. }
  85655. if(Utils.getParameterByName("edlEnabled")){
  85656. let enabled = Utils.getParameterByName("edlEnabled") === "true";
  85657. this.setEDLEnabled(enabled);
  85658. }
  85659. if (Utils.getParameterByName('edlRadius')) {
  85660. this.setEDLRadius(parseFloat(Utils.getParameterByName('edlRadius')));
  85661. }
  85662. if (Utils.getParameterByName('edlStrength')) {
  85663. this.setEDLStrength(parseFloat(Utils.getParameterByName('edlStrength')));
  85664. }
  85665. if (Utils.getParameterByName('pointBudget')) {
  85666. this.setPointBudget(parseFloat(Utils.getParameterByName('pointBudget')));
  85667. }
  85668. if (Utils.getParameterByName('showBoundingBox')) {
  85669. let enabled = Utils.getParameterByName('showBoundingBox') === 'true';
  85670. if (enabled) {
  85671. this.setShowBoundingBox(true);
  85672. } else {
  85673. this.setShowBoundingBox(false);
  85674. }
  85675. }
  85676. if (Utils.getParameterByName('material')) {
  85677. let material = Utils.getParameterByName('material');
  85678. this.setMaterial(material);
  85679. }
  85680. if (Utils.getParameterByName('pointSizing')) {
  85681. let sizing = Utils.getParameterByName('pointSizing');
  85682. this.setPointSizing(sizing);
  85683. }
  85684. if (Utils.getParameterByName('quality')) {
  85685. let quality = Utils.getParameterByName('quality');
  85686. this.setQuality(quality);
  85687. }
  85688. if (Utils.getParameterByName('position')) {
  85689. let value = Utils.getParameterByName('position');
  85690. value = value.replace('[', '').replace(']', '');
  85691. let tokens = value.split(';');
  85692. let x = parseFloat(tokens[0]);
  85693. let y = parseFloat(tokens[1]);
  85694. let z = parseFloat(tokens[2]);
  85695. this.scene.view.position.set(x, y, z);
  85696. }
  85697. if (Utils.getParameterByName('target')) {
  85698. let value = Utils.getParameterByName('target');
  85699. value = value.replace('[', '').replace(']', '');
  85700. let tokens = value.split(';');
  85701. let x = parseFloat(tokens[0]);
  85702. let y = parseFloat(tokens[1]);
  85703. let z = parseFloat(tokens[2]);
  85704. this.scene.view.lookAt(new Vector3(x, y, z));
  85705. }
  85706. if (Utils.getParameterByName('background')) {
  85707. let value = Utils.getParameterByName('background');
  85708. this.setBackground(value);
  85709. }
  85710. // if(Utils.getParameterByName("elevationRange")){
  85711. // let value = Utils.getParameterByName("elevationRange");
  85712. // value = value.replace("[", "").replace("]", "");
  85713. // let tokens = value.split(";");
  85714. // let x = parseFloat(tokens[0]);
  85715. // let y = parseFloat(tokens[1]);
  85716. //
  85717. // this.setElevationRange(x, y);
  85718. // //this.scene.view.target.set(x, y, z);
  85719. // }
  85720. };
  85721. // ------------------------------------------------------------------------------------
  85722. // Viewer Internals
  85723. // ------------------------------------------------------------------------------------
  85724. createControls () {
  85725. { // create FIRST PERSON CONTROLS
  85726. this.fpControls = new FirstPersonControls(this, this.mainViewport);
  85727. this.fpControls.enabled = false;
  85728. this.fpControls.addEventListener('start', this.disableAnnotations.bind(this));
  85729. this.fpControls.addEventListener('end', this.enableAnnotations.bind(this));
  85730. /* this.addEventListener("loadPointCloudDone", ()=>{
  85731. let boundPlane = new THREE.Box3()
  85732. boundPlane.expandByPoint(this.bound.boundingBox.min.clone())//最低高度为bound的最低
  85733. boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z))//最高高度为bound的中心高度
  85734. FirstPersonControls.boundPlane = boundPlane
  85735. FirstPersonControls.standardSpeed = THREE.Math.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 , 0.02,0.5); //在这个boundPlane中的速度
  85736. }) */
  85737. }
  85738. // { // create GEO CONTROLS
  85739. // this.geoControls = new GeoControls(this.scene.camera, this.renderer.domElement);
  85740. // this.geoControls.enabled = false;
  85741. // this.geoControls.addEventListener("start", this.disableAnnotations.bind(this));
  85742. // this.geoControls.addEventListener("end", this.enableAnnotations.bind(this));
  85743. // this.geoControls.addEventListener("move_speed_changed", (event) => {
  85744. // this.setMoveSpeed(this.geoControls.moveSpeed);
  85745. // });
  85746. // }
  85747. { // create ORBIT CONTROLS
  85748. this.orbitControls = new OrbitControls(this);
  85749. this.orbitControls.enabled = false;
  85750. this.orbitControls.addEventListener('start', this.disableAnnotations.bind(this));
  85751. this.orbitControls.addEventListener('end', this.enableAnnotations.bind(this));
  85752. }
  85753. { // create EARTH CONTROLS
  85754. this.earthControls = new EarthControls(this);
  85755. this.earthControls.enabled = false;
  85756. this.earthControls.addEventListener('start', this.disableAnnotations.bind(this));
  85757. this.earthControls.addEventListener('end', this.enableAnnotations.bind(this));
  85758. }
  85759. { // create DEVICE ORIENTATION CONTROLS
  85760. this.deviceControls = new DeviceOrientationControls(this);
  85761. this.deviceControls.enabled = false;
  85762. this.deviceControls.addEventListener('start', this.disableAnnotations.bind(this));
  85763. this.deviceControls.addEventListener('end', this.enableAnnotations.bind(this));
  85764. }
  85765. /* { // create VR CONTROLS
  85766. this.vrControls = new VRControls(this);
  85767. this.vrControls.enabled = false;
  85768. this.vrControls.addEventListener('start', this.disableAnnotations.bind(this));
  85769. this.vrControls.addEventListener('end', this.enableAnnotations.bind(this));
  85770. } */
  85771. };
  85772. toggleSidebar () {
  85773. let renderArea = $('#potree_render_area');
  85774. let isVisible = renderArea.css('left') !== '0px';
  85775. if (isVisible) {
  85776. renderArea.css('left', '0px');
  85777. } else {
  85778. renderArea.css('left', '300px');
  85779. }
  85780. };
  85781. toggleMap () {
  85782. // let map = $('#potree_map');
  85783. // map.toggle(100);
  85784. if (this.mapView) {
  85785. this.mapView.toggle();
  85786. }
  85787. };
  85788. onGUILoaded(callback){
  85789. if(this.guiLoaded){
  85790. callback();
  85791. }else {
  85792. this.guiLoadTasks.push(callback);
  85793. }
  85794. }
  85795. promiseGuiLoaded(){
  85796. return new Promise( resolve => {
  85797. if(this.guiLoaded){
  85798. resolve();
  85799. }else {
  85800. this.guiLoadTasks.push(resolve);
  85801. }
  85802. });
  85803. }
  85804. loadGUI(callback){
  85805. if(callback){
  85806. this.onGUILoaded(callback);
  85807. }
  85808. let viewer = this;
  85809. let sidebarContainer = $('#potree_sidebar_container');
  85810. sidebarContainer.load(new URL(Potree.scriptPath + '/' + (Potree.settings.sidebar || 'sidebar.html')).href, () => {
  85811. sidebarContainer.css('width', '300px');
  85812. sidebarContainer.css('height', '100%');
  85813. let imgMenuToggle = document.createElement('img');
  85814. imgMenuToggle.src = new URL(Potree.resourcePath + '/icons/menu_button.svg').href;
  85815. imgMenuToggle.onclick = this.toggleSidebar;
  85816. imgMenuToggle.classList.add('potree_menu_toggle');
  85817. let imgMapToggle = document.createElement('img');
  85818. imgMapToggle.src = new URL(Potree.resourcePath + '/icons/map_icon.png').href;
  85819. imgMapToggle.style.display = 'none';
  85820. imgMapToggle.onclick = e => { this.toggleMap(); };
  85821. imgMapToggle.id = 'potree_map_toggle';
  85822. let elButtons = $("#potree_quick_buttons").get(0);
  85823. elButtons.append(imgMenuToggle);
  85824. elButtons.append(imgMapToggle);
  85825. /*
  85826. VRButton.createButton(this.renderer).then(vrButton => {
  85827. if(vrButton == null){
  85828. console.log("VR not supported or active.");
  85829. return;
  85830. }
  85831. this.renderer.xr.enabled = true;
  85832. let element = vrButton.element;
  85833. element.style.position = "";
  85834. element.style.bottom = "";
  85835. element.style.left = "";
  85836. element.style.margin = "4px";
  85837. element.style.fontSize = "100%";
  85838. element.style.width = "2.5em";
  85839. element.style.height = "2.5em";
  85840. element.style.padding = "0";
  85841. element.style.textShadow = "black 2px 2px 2px";
  85842. element.style.display = "block";
  85843. elButtons.append(element);
  85844. vrButton.onStart(() => {
  85845. this.dispatchEvent({type: "vr_start"});
  85846. });
  85847. vrButton.onEnd(() => {
  85848. this.dispatchEvent({type: "vr_end"});
  85849. });
  85850. });
  85851. this.mapView = new MapView(this);
  85852. this.mapView.init(); */
  85853. i18n.init({
  85854. lng: 'en',
  85855. resGetPath: Potree.resourcePath + '/lang/__lng__/__ns__.json',
  85856. preload: ['en', 'fr', 'de', 'jp', 'se', 'es', 'zh'],
  85857. getAsync: true,
  85858. debug: false
  85859. }, function (t) {
  85860. // Start translation once everything is loaded
  85861. $('body').i18n();
  85862. });
  85863. $(() => {
  85864. //initSidebar(this);
  85865. let sidebar = new Sidebar(this);
  85866. sidebar.init();
  85867. this.sidebar = sidebar;
  85868. //if (callback) {
  85869. // $(callback);
  85870. //}
  85871. let elProfile = $('<div>').load(new URL(Potree.scriptPath + '/profile.html').href, () => {
  85872. $(document.body).append(elProfile.children());
  85873. this.profileWindow = new ProfileWindow(this);
  85874. this.profileWindowController = new ProfileWindowController(this);
  85875. $('#profile_window').draggable({
  85876. handle: $('#profile_titlebar'),
  85877. containment: $(document.body)
  85878. });
  85879. $('#profile_window').resizable({
  85880. containment: $(document.body),
  85881. handles: 'n, e, s, w'
  85882. });
  85883. $(() => {
  85884. this.guiLoaded = true;
  85885. for(let task of this.guiLoadTasks){
  85886. task();
  85887. }
  85888. });
  85889. });
  85890. });
  85891. });
  85892. return this.promiseGuiLoaded();
  85893. }
  85894. setLanguage (lang) {
  85895. i18n.setLng(lang);
  85896. $('body').i18n();
  85897. }
  85898. setServer (server) {
  85899. this.server = server;
  85900. }
  85901. initDragAndDrop(){
  85902. function allowDrag(e) {
  85903. e.dataTransfer.dropEffect = 'copy';
  85904. e.preventDefault();
  85905. }
  85906. let dropHandler = async (event) => {
  85907. console.log(event);
  85908. event.preventDefault();
  85909. for(const item of event.dataTransfer.items){
  85910. console.log(item);
  85911. if(item.kind !== "file"){
  85912. continue;
  85913. }
  85914. const file = item.getAsFile();
  85915. const isJson = file.name.toLowerCase().endsWith(".json");
  85916. const isGeoPackage = file.name.toLowerCase().endsWith(".gpkg");
  85917. if(isJson){
  85918. try{
  85919. const text = await file.text();
  85920. const json = JSON.parse(text);
  85921. if(json.type === "Potree"){
  85922. Potree.loadProject(viewer, json);
  85923. }
  85924. }catch(e){
  85925. console.error("failed to parse the dropped file as JSON");
  85926. console.error(e);
  85927. }
  85928. }else if(isGeoPackage){
  85929. const hasPointcloud = viewer.scene.pointclouds.length > 0;
  85930. if(!hasPointcloud){
  85931. let msg = "At least one point cloud is needed that specifies the ";
  85932. msg += "coordinate reference system before loading vector data.";
  85933. console.error(msg);
  85934. }else {
  85935. proj4.defs("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
  85936. proj4.defs("pointcloud", this.getProjection());
  85937. let transform = proj4("WGS84", "pointcloud");
  85938. const buffer = await file.arrayBuffer();
  85939. const params = {
  85940. transform: transform,
  85941. source: file.name,
  85942. };
  85943. const geo = await Potree.GeoPackageLoader.loadBuffer(buffer, params);
  85944. viewer.scene.addGeopackage(geo);
  85945. }
  85946. }
  85947. }
  85948. };
  85949. $("body")[0].addEventListener("dragenter", allowDrag);
  85950. $("body")[0].addEventListener("dragover", allowDrag);
  85951. $("body")[0].addEventListener("drop", dropHandler);
  85952. }
  85953. updateAnnotations () {
  85954. if(!this.visibleAnnotations){
  85955. this.visibleAnnotations = new Set();
  85956. }
  85957. this.scene.annotations.updateBounds();
  85958. this.scene.cameraP.updateMatrixWorld();
  85959. this.scene.cameraO.updateMatrixWorld();
  85960. let distances = [];
  85961. let renderAreaSize = this.renderer.getSize(new Vector2$1());
  85962. let viewer = this;
  85963. let visibleNow = [];
  85964. this.scene.annotations.traverse(annotation => {
  85965. if (annotation === this.scene.annotations) {
  85966. return true;
  85967. }
  85968. if (!annotation.visible) {
  85969. return false;
  85970. }
  85971. annotation.scene = this.scene;
  85972. let element = annotation.domElement;
  85973. let position = annotation.position.clone();
  85974. position.add(annotation.offset);
  85975. if (!position) {
  85976. position = annotation.boundingBox.getCenter(new Vector3());
  85977. }
  85978. let distance = viewer.scene.cameraP.position.distanceTo(position);
  85979. let radius = annotation.boundingBox.getBoundingSphere(new Sphere()).radius;
  85980. let screenPos = new Vector3();
  85981. let screenSize = 0;
  85982. {
  85983. // SCREEN POS
  85984. screenPos.copy(position).project(this.scene.getActiveCamera());
  85985. screenPos.x = renderAreaSize.x * (screenPos.x + 1) / 2;
  85986. screenPos.y = renderAreaSize.y * (1 - (screenPos.y + 1) / 2);
  85987. // SCREEN SIZE
  85988. if(viewer.scene.cameraMode == CameraMode.PERSPECTIVE) {
  85989. let fov = Math.PI * viewer.scene.cameraP.fov / 180;
  85990. let slope = Math.tan(fov / 2.0);
  85991. let projFactor = 0.5 * renderAreaSize.y / (slope * distance);
  85992. screenSize = radius * projFactor;
  85993. } else {
  85994. screenSize = Utils.projectedRadiusOrtho(radius, viewer.scene.cameraO.projectionMatrix, renderAreaSize.x, renderAreaSize.y);
  85995. }
  85996. }
  85997. element.css("left", screenPos.x + "px");
  85998. element.css("top", screenPos.y + "px");
  85999. //element.css("display", "block");
  86000. let zIndex = 10000000 - distance * (10000000 / this.scene.cameraP.far);
  86001. if(annotation.descriptionVisible){
  86002. zIndex += 10000000;
  86003. }
  86004. element.css("z-index", parseInt(zIndex));
  86005. if(annotation.children.length > 0){
  86006. let expand = screenSize > annotation.collapseThreshold || annotation.boundingBox.containsPoint(this.scene.getActiveCamera().position);
  86007. annotation.expand = expand;
  86008. if (!expand) {
  86009. //annotation.display = (screenPos.z >= -1 && screenPos.z <= 1);
  86010. let inFrustum = (screenPos.z >= -1 && screenPos.z <= 1);
  86011. if(inFrustum){
  86012. visibleNow.push(annotation);
  86013. }
  86014. }
  86015. return expand;
  86016. } else {
  86017. //annotation.display = (screenPos.z >= -1 && screenPos.z <= 1);
  86018. let inFrustum = (screenPos.z >= -1 && screenPos.z <= 1);
  86019. if(inFrustum){
  86020. visibleNow.push(annotation);
  86021. }
  86022. }
  86023. });
  86024. let notVisibleAnymore = new Set(this.visibleAnnotations);
  86025. for(let annotation of visibleNow){
  86026. annotation.display = true;
  86027. notVisibleAnymore.delete(annotation);
  86028. }
  86029. this.visibleAnnotations = visibleNow;
  86030. for(let annotation of notVisibleAnymore){
  86031. annotation.display = false;
  86032. }
  86033. }
  86034. updateMaterialDefaults(pointcloud){
  86035. // PROBLEM STATEMENT:
  86036. // * [min, max] of intensity, source id, etc. are computed as point clouds are loaded
  86037. // * the point cloud material won't know the range it should use until some data is loaded
  86038. // * users can modify the range at runtime, but sensible default ranges should be
  86039. // applied even if no GUI is present
  86040. // * display ranges shouldn't suddenly change even if the actual range changes over time.
  86041. // e.g. the root node has intensity range [1, 478]. One of the descendants increases range to
  86042. // [0, 2047]. We should not automatically change to the new range because that would result
  86043. // in sudden and drastic changes of brightness. We should adjust the min/max of the sidebar slider.
  86044. const material = pointcloud.material;
  86045. const attIntensity = pointcloud.getAttribute("intensity");
  86046. if(attIntensity != null && material.intensityRange[0] === Infinity){
  86047. material.intensityRange = [...attIntensity.range];
  86048. }
  86049. // const attIntensity = pointcloud.getAttribute("intensity");
  86050. // if(attIntensity && material.intensityRange[0] === Infinity){
  86051. // material.intensityRange = [...attIntensity.range];
  86052. // }
  86053. // let attributes = pointcloud.getAttributes();
  86054. // for(let attribute of attributes.attributes){
  86055. // if(attribute.range){
  86056. // let range = [...attribute.range];
  86057. // material.computedRange.set(attribute.name, range);
  86058. // //material.setRange(attribute.name, range);
  86059. // }
  86060. // }
  86061. }
  86062. update(delta, timestamp){
  86063. if(Potree.measureTimings) performance.mark("update-start");
  86064. this.dispatchEvent({
  86065. type: 'update_start',
  86066. delta: delta,
  86067. timestamp: timestamp});
  86068. this.updateScreenSize(); //判断是否改变canvas大小
  86069. const scene = this.scene;
  86070. const camera = scene.getActiveCamera();
  86071. const visiblePointClouds = this.scene.pointclouds.filter(pc => pc.visible);
  86072. Potree.pointLoadLimit = Potree.pointBudget * 2;
  86073. const lTarget = camera.position.clone().add(camera.getWorldDirection(new Vector3()).multiplyScalar(1000));
  86074. this.scene.directionalLight.position.copy(camera.position);
  86075. this.scene.directionalLight.lookAt(lTarget);
  86076. for (let pointcloud of visiblePointClouds) {
  86077. pointcloud.showBoundingBox = this.showBoundingBox;
  86078. pointcloud.generateDEM = this.generateDEM;
  86079. pointcloud.minimumNodePixelSize = this.minNodeSize;
  86080. let material = pointcloud.material;
  86081. material.uniforms.uFilterReturnNumberRange.value = this.filterReturnNumberRange;
  86082. material.uniforms.uFilterNumberOfReturnsRange.value = this.filterNumberOfReturnsRange;
  86083. material.uniforms.uFilterGPSTimeClipRange.value = this.filterGPSTimeRange;
  86084. material.uniforms.uFilterPointSourceIDClipRange.value = this.filterPointSourceIDRange;
  86085. material.classification = this.classifications;
  86086. material.recomputeClassification();
  86087. this.updateMaterialDefaults(pointcloud);
  86088. }
  86089. {
  86090. if(this.showBoundingBox){
  86091. let bbRoot = this.scene.scene.getObjectByName("potree_bounding_box_root");
  86092. if(!bbRoot){
  86093. let node = new Object3D();
  86094. node.name = "potree_bounding_box_root";
  86095. this.scene.scene.add(node);
  86096. bbRoot = node;
  86097. }
  86098. let visibleBoxes = [];
  86099. for(let pointcloud of this.scene.pointclouds){
  86100. for(let node of pointcloud.visibleNodes.filter(vn => vn.boundingBoxNode !== undefined)){
  86101. let box = node.boundingBoxNode;
  86102. visibleBoxes.push(box);
  86103. }
  86104. }
  86105. bbRoot.children = visibleBoxes;
  86106. }
  86107. }
  86108. if (!this.freeze) {
  86109. /*let cameraGroup = []
  86110. let size = this.renderer.getSize(new THREE.Vector2())
  86111. if(this.viewports){
  86112. this.viewports.forEach(viewport=>{
  86113. if(!viewport.active)return
  86114. cameraGroup.push({camera:viewport.camera, areaSize:new THREE.Vector2(Math.floor(size.x * viewport.width), Math.floor(size.y * viewport.height))})
  86115. })
  86116. }else{
  86117. cameraGroup.push({camera, areaSize:size})
  86118. }
  86119. let result = Potree.updatePointClouds(scene.pointclouds, cameraGroup );
  86120. */
  86121. // DEBUG - ONLY DISPLAY NODES THAT INTERSECT MOUSE
  86122. //if(false){
  86123. // let renderer = viewer.renderer;
  86124. // let mouse = viewer.inputHandler.mouse;
  86125. // let nmouse = {
  86126. // x: (mouse.x / renderer.domElement.clientWidth) * 2 - 1,
  86127. // y: -(mouse.y / renderer.domElement.clientHeight) * 2 + 1
  86128. // };
  86129. // let pickParams = {};
  86130. // //if(params.pickClipped){
  86131. // // pickParams.pickClipped = params.pickClipped;
  86132. // //}
  86133. // pickParams.x = mouse.x;
  86134. // pickParams.y = renderer.domElement.clientHeight - mouse.y;
  86135. // let raycaster = new THREE.Raycaster();
  86136. // raycaster.setFromCamera(nmouse, camera);
  86137. // let ray = raycaster.ray;
  86138. // for(let pointcloud of scene.pointclouds){
  86139. // let nodes = pointcloud.nodesOnRay(pointcloud.visibleNodes, ray);
  86140. // pointcloud.visibleNodes = nodes;
  86141. // }
  86142. //}
  86143. // const tStart = performance.now();
  86144. // const worldPos = new THREE.Vector3();
  86145. // const camPos = viewer.scene.getActiveCamera().getWorldPosition(new THREE.Vector3());
  86146. // let lowestDistance = Infinity;
  86147. // let numNodes = 0;
  86148. // viewer.scene.scene.traverse(node => {
  86149. // node.getWorldPosition(worldPos);
  86150. // const distance = worldPos.distanceTo(camPos);
  86151. // lowestDistance = Math.min(lowestDistance, distance);
  86152. // numNodes++;
  86153. // if(Number.isNaN(distance)){
  86154. // console.error(":(");
  86155. // }
  86156. // });
  86157. // const duration = (performance.now() - tStart).toFixed(2);
  86158. // Potree.debug.computeNearDuration = duration;
  86159. // Potree.debug.numNodes = numNodes;
  86160. //console.log(lowestDistance.toString(2), duration);
  86161. //搬走
  86162. /* const tStart = performance.now();
  86163. const campos = camera.position;
  86164. let closestImage = Infinity;
  86165. for(const images of this.scene.orientedImages){
  86166. for(const image of images.images){
  86167. const distance = image.mesh.position.distanceTo(campos);
  86168. closestImage = Math.min(closestImage, distance);
  86169. }
  86170. }
  86171. const tEnd = performance.now();
  86172. if(result.lowestSpacing !== Infinity){
  86173. let near = result.lowestSpacing * 10.0;
  86174. let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
  86175. far = Math.max(far * 1.5, 10000);
  86176. near = Math.min(100.0, Math.max(0.01, near));
  86177. near = Math.min(near, closestImage);
  86178. far = Math.max(far, near + 10000);
  86179. if(near === Infinity){
  86180. near = 0.1;
  86181. }
  86182. camera.near = near;
  86183. camera.far = far;
  86184. }else{
  86185. // don't change near and far in this case
  86186. }
  86187. if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
  86188. camera.near = -camera.far;
  86189. }*/
  86190. }
  86191. this.scene.cameraP.fov = this.fov;
  86192. let controls = this.getControls();
  86193. if (controls === this.deviceControls) {
  86194. this.controls.setScene(scene);
  86195. this.controls.update(delta);
  86196. this.scene.cameraP.position.copy(scene.view.position);
  86197. this.scene.cameraO.position.copy(scene.view.position);
  86198. } else if (controls !== null) {
  86199. controls.setScene(scene);
  86200. controls.update(delta);
  86201. //更新camera
  86202. this.viewports.forEach(viewport=>{
  86203. if(!viewport.active)return
  86204. viewport.view.applyToCamera(viewport.camera);
  86205. });
  86206. }
  86207. /* this.viewports.forEach(e=>{//判断camera画面是否改变
  86208. if(e.cameraChanged()){
  86209. this.dispatchEvent({
  86210. type: "camera_changed",
  86211. camera: e.camera,
  86212. viewport : e
  86213. })
  86214. }
  86215. }) */
  86216. this.cameraChanged();//判断camera画面是否改变
  86217. /* {//判断camera画面是否改变
  86218. if(this._previousCamera === undefined){
  86219. this._previousCamera = this.scene.getActiveCamera().clone();
  86220. this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
  86221. }
  86222. if(!this._previousCamera.matrixWorld.equals(camera.matrixWorld) ||
  86223. !this._previousCamera.projectionMatrix.equals(camera.projectionMatrix)
  86224. ){
  86225. this.dispatchEvent({
  86226. type: "camera_changed",
  86227. previous: this._previousCamera,
  86228. camera: camera
  86229. });
  86230. }
  86231. this._previousCamera = this.scene.getActiveCamera().clone();
  86232. this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
  86233. } */
  86234. { // update clip boxes
  86235. let boxes = [];
  86236. // volumes with clipping enabled
  86237. //boxes.push(...this.scene.volumes.filter(v => (v.clip)));
  86238. boxes.push(...this.scene.volumes.filter(v => (v.clip && v instanceof BoxVolume)));
  86239. // profile segments
  86240. for(let profile of this.scene.profiles){
  86241. boxes.push(...profile.boxes);
  86242. }
  86243. // Needed for .getInverse(), pre-empt a determinant of 0, see #815 / #816
  86244. let degenerate = (box) => box.matrixWorld.determinant() !== 0;
  86245. let clipBoxes = boxes.filter(degenerate).map( box => {
  86246. box.updateMatrixWorld();
  86247. let boxInverse = box.matrixWorld.clone().invert();
  86248. let boxPosition = box.getWorldPosition(new Vector3());
  86249. return {box: box, inverse: boxInverse, position: boxPosition};
  86250. });
  86251. let clipPolygons = this.scene.polygonClipVolumes.filter(vol => vol.initialized);
  86252. // set clip volumes in material
  86253. for(let pointcloud of visiblePointClouds){
  86254. pointcloud.material.setClipBoxes(clipBoxes);
  86255. pointcloud.material.setClipPolygons(clipPolygons, this.clippingTool.maxPolygonVertices);
  86256. pointcloud.material.clipTask = this.clipTask;
  86257. pointcloud.material.clipMethod = this.clipMethod;
  86258. }
  86259. }
  86260. {
  86261. for(let pointcloud of visiblePointClouds){
  86262. pointcloud.material.elevationGradientRepeat = this.elevationGradientRepeat;
  86263. }
  86264. }
  86265. { // update navigation cube
  86266. this.navigationCube.update(camera.rotation);
  86267. }
  86268. this.updateAnnotations();
  86269. if(this.mapView){
  86270. this.mapView.update(delta);
  86271. if(this.mapView.sceneProjection){
  86272. $( "#potree_map_toggle" ).css("display", "block");
  86273. }
  86274. }
  86275. TWEEN.update(timestamp);
  86276. transitions.update(delta);
  86277. this.transformationTool.update();
  86278. if(Potree.settings.editType != 'pano' && Potree.settings.editType != 'merge'){
  86279. this.modules.ParticleEditor.update(delta);
  86280. this.mapViewer.update(delta);
  86281. }
  86282. this.dispatchEvent({
  86283. type: 'update',
  86284. delta: delta,
  86285. timestamp: timestamp});
  86286. if(Potree.measureTimings) {
  86287. performance.mark("update-end");
  86288. performance.measure("update", "update-start", "update-end");
  86289. }
  86290. //add ------
  86291. this.reticule.updateVisible();
  86292. }
  86293. updateViewPointcloud(camera, areaSize, isViewport){
  86294. let result = Potree.updatePointClouds(this.scene.pointclouds, camera, areaSize );
  86295. //if(isViewport)return
  86296. const tStart = performance.now();
  86297. const campos = camera.position;
  86298. let closestImage = Infinity;
  86299. for(const images of this.scene.orientedImages){
  86300. for(const image of images.images){
  86301. const distance = image.mesh.position.distanceTo(campos);
  86302. closestImage = Math.min(closestImage, distance);
  86303. }
  86304. }
  86305. const tEnd = performance.now();
  86306. //改:不根据点云修改视野near far
  86307. var near = camera.near, far = camera.far;
  86308. if(!camera.limitFar && result.lowestSpacing !== Infinity){
  86309. //let near = result.lowestSpacing * 10.0;
  86310. let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
  86311. far = Math.max(far * 1.5, 10000);
  86312. //near = Math.min(100.0, Math.max(0.01, near));
  86313. //near = Math.min(near, closestImage);
  86314. far = Math.max(far, near + 10000);
  86315. /* if(near === Infinity){
  86316. near = 0.1;
  86317. } */
  86318. //camera.near = near; //为了其他物体的显示,不修改near
  86319. camera.far = far;
  86320. }
  86321. /* if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {//???
  86322. camera.near = -camera.far;
  86323. } */
  86324. if(/* near != camera.near || */far != camera.far){
  86325. camera.updateProjectionMatrix();
  86326. }
  86327. //注:pointcloud.visibleNodes会随着near far自动更新
  86328. }
  86329. getPRenderer(){
  86330. if(this.useHQ){
  86331. if (!this.hqRenderer) {
  86332. this.hqRenderer = new HQSplatRenderer(this);
  86333. }
  86334. this.hqRenderer.useEDL = this.useEDL;
  86335. return this.hqRenderer;
  86336. }else {
  86337. /* if (this.useEDL && Features.SHADER_EDL.isSupported()) {
  86338. if (!this.edlRenderer) {
  86339. this.edlRenderer = new EDLRenderer(this);
  86340. }
  86341. return this.edlRenderer;
  86342. } else {
  86343. if (!this.potreeRenderer) {
  86344. this.potreeRenderer = new PotreeRenderer(this);
  86345. }
  86346. return this.potreeRenderer;
  86347. } */
  86348. if (!this.edlRenderer) {
  86349. this.edlRenderer = new EDLRenderer(this);
  86350. }
  86351. return this.edlRenderer;
  86352. }
  86353. }
  86354. renderVR(){
  86355. let renderer = this.renderer;
  86356. renderer.setClearColor(0x550000, 0);
  86357. renderer.clear();
  86358. let xr = renderer.xr;
  86359. let dbg = new PerspectiveCamera();
  86360. let xrCameras = xr.getCamera(dbg);
  86361. if(xrCameras.cameras.length !== 2){
  86362. return;
  86363. }
  86364. let makeCam = this.vrControls.getCamera.bind(this.vrControls);
  86365. { // clear framebuffer
  86366. if(viewer.background === "skybox"){
  86367. renderer.setClearColor(0xff0000, 1);
  86368. }else if(viewer.background === "gradient"){
  86369. renderer.setClearColor(0x112233, 1);
  86370. }else if(viewer.background === "black"){
  86371. renderer.setClearColor(0x000000, 1);
  86372. }else if(viewer.background === "white"){
  86373. renderer.setClearColor(0xFFFFFF, 1);
  86374. }else {
  86375. renderer.setClearColor(0x000000, 0);
  86376. }
  86377. renderer.clear();
  86378. }
  86379. // render background
  86380. if(this.background === "skybox"){
  86381. let {skybox} = this;
  86382. let cam = makeCam();
  86383. skybox.camera.rotation.copy(cam.rotation);
  86384. skybox.camera.fov = cam.fov;
  86385. skybox.camera.aspect = cam.aspect;
  86386. // let dbg = new THREE.Object3D();
  86387. let dbg = skybox.parent;
  86388. // dbg.up.set(0, 0, 1);
  86389. dbg.rotation.x = Math.PI / 2;
  86390. // skybox.camera.parent = dbg;
  86391. // dbg.children.push(skybox.camera);
  86392. dbg.updateMatrix();
  86393. dbg.updateMatrixWorld();
  86394. skybox.camera.updateMatrix();
  86395. skybox.camera.updateMatrixWorld();
  86396. skybox.camera.updateProjectionMatrix();
  86397. renderer.render(skybox.scene, skybox.camera);
  86398. // renderer.render(skybox.scene, cam);
  86399. }else if(this.background === "gradient"){
  86400. // renderer.render(this.scene.sceneBG, this.scene.cameraBG);
  86401. }
  86402. this.renderer.xr.getSession().updateRenderState({
  86403. depthNear: 0.1,
  86404. depthFar: 10000
  86405. });
  86406. let cam = null;
  86407. let view = null;
  86408. { // render world scene
  86409. cam = makeCam();
  86410. cam.position.z -= 0.8 * cam.scale.x;
  86411. cam.parent = null;
  86412. // cam.near = 0.05;
  86413. cam.near = viewer.scene.getActiveCamera().near;
  86414. cam.far = viewer.scene.getActiveCamera().far;
  86415. cam.updateMatrix();
  86416. cam.updateMatrixWorld();
  86417. this.scene.scene.updateMatrix();
  86418. this.scene.scene.updateMatrixWorld();
  86419. this.scene.scene.matrixAutoUpdate = false;
  86420. let camWorld = cam.matrixWorld.clone();
  86421. view = camWorld.clone().invert();
  86422. this.scene.scene.matrix.copy(view);
  86423. this.scene.scene.matrixWorld.copy(view);
  86424. cam.matrix.identity();
  86425. cam.matrixWorld.identity();
  86426. cam.matrixWorldInverse.identity();
  86427. renderer.render(this.scene.scene, cam);
  86428. this.scene.scene.matrixWorld.identity();
  86429. }
  86430. for(let pointcloud of this.scene.pointclouds){
  86431. let viewport = xrCameras.cameras[0].viewport;
  86432. pointcloud.material.useEDL = false;
  86433. pointcloud.screenHeight = viewport.height;
  86434. pointcloud.screenWidth = viewport.width;
  86435. // automatically switch to paraboloids because they cause far less flickering in VR,
  86436. // when point sizes are larger than around 2 pixels
  86437. // if(Features.SHADER_INTERPOLATION.isSupported()){
  86438. // pointcloud.material.shape = Potree.PointShape.PARABOLOID;
  86439. // }
  86440. }
  86441. // render point clouds
  86442. for(let xrCamera of xrCameras.cameras){
  86443. let v = xrCamera.viewport;
  86444. renderer.setViewport(v.x, v.y, v.width, v.height);
  86445. // xrCamera.fov = 90;
  86446. { // estimate VR fov
  86447. let proj = xrCamera.projectionMatrix;
  86448. let inv = proj.clone().invert();
  86449. let p1 = new Vector4(0, 1, -1, 1).applyMatrix4(inv);
  86450. let rad = p1.y;
  86451. let fov = 180 * (rad / Math.PI);
  86452. xrCamera.fov = fov;
  86453. }
  86454. for(let pointcloud of this.scene.pointclouds){
  86455. const {material} = pointcloud;
  86456. material.useEDL = false;
  86457. }
  86458. let vrWorld = view.clone().invert();
  86459. vrWorld.multiply(xrCamera.matrixWorld);
  86460. let vrView = vrWorld.clone().invert();
  86461. this.pRenderer.render(this.scene.scenePointCloud, xrCamera, null, {
  86462. viewOverride: vrView,
  86463. });
  86464. }
  86465. { // render VR scene
  86466. let cam = makeCam();
  86467. cam.parent = null;
  86468. renderer.render(this.sceneVR, cam);
  86469. }
  86470. renderer.resetState();
  86471. }
  86472. clear(params={}){
  86473. let background = params.background || this.background;
  86474. let backgroundOpacity = params.backgroundOpacity == void 0 ? this.backgroundOpacity : params.backgroundOpacity;//如果想完全透明,只需要backgroundOpacity为0
  86475. let renderer = this.renderer;
  86476. //let gl = renderer.getContext()
  86477. if(background instanceof Color){ //add
  86478. renderer.setClearColor(background, backgroundOpacity);
  86479. }else if(background === "skybox"){
  86480. renderer.setClearColor(0x000000, 0);
  86481. } else if (background === 'gradient') {
  86482. renderer.setClearColor(0x000000, 0);
  86483. } else if (background === 'black') {
  86484. renderer.setClearColor(0x000000, 1);
  86485. } else if (background === 'white') {
  86486. renderer.setClearColor(0xFFFFFF, 1);
  86487. } else {
  86488. renderer.setClearColor(background, backgroundOpacity);
  86489. }
  86490. params.target || renderer.clear();
  86491. }
  86492. renderDefault(params_={}){
  86493. if(!this.visible || this.paused )return
  86494. /* if(this.outlinePass.selectedObjects.length){
  86495. this.clear()
  86496. this.composer.render(this.scene.scene, this.mainViewport.camera );
  86497. return;
  86498. } */
  86499. let pRenderer = this.getPRenderer();
  86500. let viewports = params_.viewports || this.viewports;
  86501. let renderSize;
  86502. if(params_.target){
  86503. renderSize = new Vector2$1(params_.target.width, params_.target.height); //是画布大小
  86504. //可能需要viewer.setSize
  86505. }else {
  86506. renderSize = this.renderer.getSize(new Vector2$1()); //是client大小
  86507. }
  86508. let needSResize = viewports.filter(e=>e.active).length > 1 || params_.resize;
  86509. viewports.forEach(view=>{
  86510. let params = $.extend({},params_);
  86511. params.viewport = view;
  86512. //if(!params.target){
  86513. params.camera = params.camera || view.camera;
  86514. params.extraEnableLayers = view.extraEnableLayers;
  86515. params.cameraLayers = view.cameraLayers;
  86516. //}
  86517. if(!view.active)return
  86518. var left,bottom,width,height;
  86519. {
  86520. left = Math.ceil(renderSize.x * view.left);
  86521. bottom = Math.ceil(renderSize.y * view.bottom);
  86522. if(params_.target){//有target时最好viewport是专门建出来的
  86523. width = Math.ceil(renderSize.x * view.width); //target的大小可能和viewport不同,比如截图,这时会更改viewport大小
  86524. height = Math.ceil(renderSize.y * view.height);
  86525. }else {
  86526. width = view.resolution.x; // 用的是client的width和height
  86527. height = view.resolution.y;
  86528. }
  86529. if(width == 0 || height == 0)return
  86530. let scissorTest = view.width<1 || view.height<1;
  86531. if(params_.target){
  86532. params_.target.viewport.set(left, bottom, width, height);
  86533. scissorTest && params_.target.scissor.set(left, bottom, width, height);
  86534. params_.target.scissorTest = scissorTest;
  86535. }else {
  86536. this.renderer.setViewport(left, bottom, width, height); //规定视口,影响图形变换(画布的使用范围)
  86537. scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
  86538. this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
  86539. }
  86540. }
  86541. if(needSResize){
  86542. this.emitResizeMsg( { viewport:view} );
  86543. }
  86544. //needSResize && this.emitResizeMsg({resolution: params_.target ? new THREE.Vector2(width,height) : view.resolution2, left:view.left, bottom:view.bottom })//resize everything such as lines targets
  86545. viewer.dispatchEvent({type: "render.begin", viewer: viewer, viewport:view, params });
  86546. if(view.render){
  86547. view.render($.extend({}, params, {
  86548. renderer:this.renderer, clear:this.clear.bind(this), resize:null,
  86549. renderOverlay: this.renderOverlay.bind(this), force:!view.noPointcloud //如果要渲染点云,必须也一直渲染地图,否则地图会被覆盖(点云目前未能获取是否改变,也可能有其他动态物体,所以还是一直渲染的好)
  86550. }));
  86551. }
  86552. if(!view.noPointcloud ){
  86553. //if(!params.target){
  86554. //params.width = width; params.height = height;
  86555. //}
  86556. if(view.render){
  86557. params.noBG = true;
  86558. }
  86559. view.beforeRender && view.beforeRender();
  86560. this.updateViewPointcloud(params.camera, view.resolution2, true);
  86561. params.background = view.background;
  86562. params.backgroundColor = view.backgroundColor;
  86563. params.backgroundOpacity = view.backgroundOpacity;
  86564. view.render || this.clear(params);
  86565. pRenderer.clearTargets(params);
  86566. pRenderer.render(params);
  86567. }
  86568. view.render || this.renderOverlay(params);
  86569. view.afterRender && view.afterRender();
  86570. this.dispatchEvent({type: "render.end", viewer: this, viewport:view });
  86571. });
  86572. /* if(params_.screenshot){ //抗锯齿
  86573. params_.target.viewport.set(0, 0, params_.target.width, params_.target.height);
  86574. //scissorTest && params_.target.scissor.set(left, bottom, width, height);
  86575. params_.target.scissorTest = false
  86576. this.renderer.setRenderTarget(params_.target)
  86577. this.composer.render();
  86578. this.renderer.setRenderTarget(params_.target) //本想再画一层标签,但是viewport总是出错
  86579. } */
  86580. this.renderer.setRenderTarget(null);
  86581. }
  86582. renderOverlay(params){
  86583. let camera = params.camera ? params.camera : this.scene.getActiveCamera();
  86584. this.reticule.updateAtViewports(params.viewport);
  86585. //为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖
  86586. let cameraLayers;
  86587. if(params.cameraLayers) cameraLayers = params.cameraLayers;
  86588. else {
  86589. if(params.isMap)cameraLayers = ['bothMapAndScene'];
  86590. else cameraLayers = ['sceneObjects', 'bothMapAndScene' ];
  86591. }
  86592. if(cameraLayers.length){
  86593. this.setCameraLayers(camera, cameraLayers, params.extraEnableLayers); //透明贴图层 skybox 、reticule marker 不能遮住测量线
  86594. /* if(this.outlinePass.selectedObjects.some(e=>e.isModel).length){
  86595. this.composer.render(this.scene.scene, camera);
  86596. }else{ */
  86597. this.renderer.render(this.scene.scene, camera);
  86598. //}
  86599. }
  86600. this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
  86601. //清除深度 !!!!
  86602. this.renderer.clearDepth();
  86603. //this.transformationTool.update();
  86604. if(!params.magnifier){
  86605. //测量线
  86606. this.dispatchEvent({type: "render.pass.perspective_overlay", camera, screenshot:params.screenshot});
  86607. if(!params.screenshot && !params.isMap){
  86608. this.setCameraLayers(camera, ['magnifier']); //magnifier 遮住测量线
  86609. this.renderer.render(this.scene.scene, camera);
  86610. }
  86611. }
  86612. if(!params.isMap) {
  86613. this.setCameraLayers(camera, ['volume','transformationTool']);
  86614. this.renderer.render(this.clippingTool.sceneVolume, camera);
  86615. this.renderer.render(this.transformationTool.scene, camera);
  86616. }
  86617. }
  86618. /* renderDefault(){//测试 ios15.4.1
  86619. //let pRenderer = this.getPRenderer();
  86620. //this.clear()
  86621. this.renderer.autoClear = false
  86622. this.renderer.setRenderTarget(null)
  86623. let camera = this.scene.getActiveCamera();
  86624. this.setCameraLayers(camera, [ 'sceneObjects', 'marker' , 'reticule' ,'skybox' ])
  86625. this.renderer.render(this.scene.scene, camera);
  86626. // pRenderer.clearTargets( );
  86627. //pRenderer.render( );
  86628. } */
  86629. setLimitFar(state){//切换是否limitFar
  86630. viewer.mainViewport.camera.limitFar = !!state;
  86631. if(state){
  86632. viewer.mainViewport.camera.near = 0.1;
  86633. viewer.mainViewport.camera.far = Potree.settings.displayMode == 'showPanos' ? viewer.farWhenShowPano : Potree.settings.cameraFar;
  86634. viewer.mainViewport.camera.updateProjectionMatrix();
  86635. }
  86636. }
  86637. setCameraLayers(camera, enableLayers, extraEnableLayers=[]){//add
  86638. camera.layers.disableAll();
  86639. enableLayers.concat(extraEnableLayers).forEach(e=>{
  86640. let layer = Potree.config.renderLayers[e];
  86641. if(layer == void 0){
  86642. console.error('setCameraLayer没找到layer!');
  86643. return
  86644. }
  86645. camera.layers.enable(layer);
  86646. });
  86647. }
  86648. setObjectLayers(object, layerName){//add
  86649. let layer = Potree.config.renderLayers[layerName];
  86650. if(layer == void 0){
  86651. console.error('setCameraLayer没找到layer!');
  86652. return
  86653. }
  86654. object.traverse(e=>{
  86655. e.layers.set(layer);
  86656. });
  86657. }
  86658. /* updateVisible(object, reason, ifShow, force){//当所有加入的条件都不为false时才显示. reason='force'一般是强制、临时的
  86659. if(!object.unvisibleReasons) object.unvisibleReasons = []; //如果length>0代表不可见
  86660. if(!object.forceVisibleReasons) object.forceVisibleReasons = []; //只要有一项代表一定可见,优先级比unvisibleReasons高
  86661. if(ifShow){
  86662. if(force){
  86663. object.forceVisibleReasons.includes(reason) || object.forceVisibleReasons.push(reason)
  86664. object.visible = true;
  86665. object.dispatchEvent({
  86666. type: 'isVisible',
  86667. visible:true,
  86668. reason
  86669. })
  86670. }
  86671. var index = object.unvisibleReasons.indexOf(reason)
  86672. if(index > -1){
  86673. object.unvisibleReasons.splice(index, 1);
  86674. if(object.unvisibleReasons.length == 0){
  86675. object.visible = true;
  86676. //mapChange()
  86677. object.dispatchEvent({
  86678. type: 'isVisible',
  86679. visible:true,
  86680. reason
  86681. })
  86682. }
  86683. }
  86684. }else{
  86685. var index = object.forceVisibleReasons.indexOf(reason)
  86686. if(index > -1){//如果是forceVisibleReasons里的,就只是单纯取消之前设置的一定可见
  86687. object.forceVisibleReasons.splice(index, 1);
  86688. }else{
  86689. if(!object.unvisibleReasons.includes(reason)) object.unvisibleReasons.push(reason)
  86690. }
  86691. if(object.forceVisibleReasons.length) return
  86692. var visiBefore = object.visible
  86693. if(object.unvisibleReasons.length && visiBefore){
  86694. object.visible = false
  86695. //mapChange()
  86696. object.dispatchEvent({
  86697. type: 'isVisible',
  86698. visible:false,
  86699. reason,
  86700. })
  86701. }else if(object.unvisibleReasons.length ==0 && !visiBefore){
  86702. object.visible = true;
  86703. //mapChange()
  86704. object.dispatchEvent({
  86705. type: 'isVisible',
  86706. visible:true,
  86707. reason
  86708. })
  86709. }
  86710. }
  86711. } */
  86712. updateVisible(object, reason, ifShow, level=0, type){//当所有加入的条件都不为false时才显示. reason='force'一般是强制、临时的
  86713. if(!object.unvisibleReasons) object.unvisibleReasons = []; //如果length>0代表不可见
  86714. if(!object.visibleReasons) object.visibleReasons = []; //在同级时,优先可见
  86715. var update = function(){
  86716. //先按从高到低的level排列
  86717. object.unvisibleReasons = object.unvisibleReasons.sort((a,b)=>b.level-a.level);
  86718. object.visibleReasons = object.visibleReasons.sort((a,b)=>b.level-a.level);
  86719. var maxVisiLevel = object.visibleReasons[0] ? object.visibleReasons[0].level : -1;
  86720. var maxunVisiLevel = object.unvisibleReasons[0] ? object.unvisibleReasons[0].level : -1;
  86721. var shouldVisi = maxVisiLevel >= maxunVisiLevel;
  86722. var visiBefore = object.visible;
  86723. if(visiBefore != shouldVisi){
  86724. object.visible = shouldVisi;
  86725. object.dispatchEvent({
  86726. type: 'isVisible',
  86727. visible: shouldVisi,
  86728. reason,
  86729. });
  86730. }
  86731. };
  86732. if(ifShow){
  86733. var index = object.unvisibleReasons.findIndex(e=>e.reason == reason);
  86734. if(index > -1){
  86735. type = 'cancel';
  86736. object.unvisibleReasons.splice(index, 1);
  86737. }
  86738. if(type == 'add' ){
  86739. if(!object.visibleReasons.some(e=>e.reason == reason)){
  86740. object.visibleReasons.push({reason,level});
  86741. }
  86742. }
  86743. }else {
  86744. var index = object.visibleReasons.findIndex(e=>e.reason == reason);
  86745. if(index > -1){
  86746. type = 'cancel';
  86747. object.visibleReasons.splice(index, 1);
  86748. }
  86749. if(type != 'cancel' ){
  86750. if(!object.unvisibleReasons.some(e=>e.reason == reason)){
  86751. object.unvisibleReasons.push({reason,level});
  86752. }
  86753. }
  86754. }
  86755. update();
  86756. }
  86757. getObjVisiByReason(object,reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
  86758. if(object.visible)return true
  86759. else {
  86760. return !object.unvisibleReasons || !object.unvisibleReasons.some(e=>e.reason == reason)
  86761. }
  86762. }
  86763. /* 大规模WebGL应用引发浏览器崩溃的几种情况及解决办法
  86764. https://blog.csdn.net/weixin_30378311/article/details/94846947 */
  86765. render(params){//add params
  86766. if(Potree.measureTimings) performance.mark("render-start");
  86767. if(this.outlinePass.selectedObjects.length){
  86768. this.composer.render(this.inputHandler.interactiveScenes.concat(this.scene.scene).concat(viewer.scene.scenePointCloud), null, this.viewports, this.renderDefault.bind(this));
  86769. }else {
  86770. this.renderDefault(params);
  86771. }
  86772. if(Potree.measureTimings){
  86773. performance.mark("render-end");
  86774. performance.measure("render", "render-start", "render-end");
  86775. }
  86776. }
  86777. startScreenshot(info={}, width=800, height=400, compressRatio){//add
  86778. let deferred = info.deferred || $.Deferred();
  86779. let viewerMaster = info.map ? this.mapViewer : this; //截图主体
  86780. let useMap = info.type == 'measure' || info.map;
  86781. if(this.images360.flying){//如果在飞,飞完再截图
  86782. info.deferred = deferred;
  86783. let f = ()=>{
  86784. this.startScreenshot(info, width, height, compressRatio);
  86785. this.images360.removeEventListener('cameraMoveDone', f);
  86786. };
  86787. this.images360.addEventListener('cameraMoveDone', f); //once
  86788. return deferred.promise()
  86789. }
  86790. var sid = Date.now();
  86791. //抗锯齿待加 1 post处理 2截图大张再抗锯齿缩小
  86792. console.log('startScreenshot: '+sid);
  86793. let updateCamera = ()=>{
  86794. this.viewports.forEach(e=>{
  86795. e.view.applyToCamera(e.camera); //因为fly时只更新了view所以要强制更新下camera
  86796. this.dispatchEvent({ //update map and sprite
  86797. type: "camera_changed",
  86798. camera: e.camera,
  86799. viewport : e,
  86800. changeInfo:{positionChanged:true,changed:true}
  86801. });
  86802. });
  86803. };
  86804. let screenshot = ()=>{
  86805. useMap && (viewer.mapViewer.needRender = true);
  86806. let { dataUrl } = viewerMaster.makeScreenshot( new Vector2$1(width,height), null, compressRatio );
  86807. if(!Potree.settings.isOfficial){
  86808. Common.downloadFile(dataUrl, 'screenshot.jpg');
  86809. }
  86810. var finish = ()=>{
  86811. oldStates.viewports.forEach(old=>{//恢复相机
  86812. var viewport = viewports.find(v=>v.name == old.name);
  86813. viewport.left = old.left;
  86814. viewport.width = old.width;
  86815. viewport.view.copy(old.view);
  86816. viewport.view.applyToCamera(viewport.camera);
  86817. });
  86818. viewer.updateScreenSize({forceUpdateSize:true});//更新像素
  86819. /* oldStates.viewports.forEach(old=>{//恢复相机
  86820. var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
  86821. this.dispatchEvent({ //update map
  86822. type: "camera_changed",
  86823. camera: viewport.camera,
  86824. viewport : viewport
  86825. })
  86826. }) */
  86827. updateCamera();
  86828. deferred.resolve(dataUrl);
  86829. console.log('screenshot done: '+sid);
  86830. };
  86831. {//恢复:
  86832. if(info.type == 'measure'){
  86833. this.scene.measurements.forEach(e=>this.updateVisible(e, 'screenshot',true));
  86834. info.measurement.setSelected(false, 'screenshot');
  86835. }
  86836. this.images360.panos.forEach(pano=>{
  86837. viewer.updateVisible(pano, 'screenshot', true);
  86838. });
  86839. viewer.updateVisible(this.reticule, 'screenshot', true);
  86840. if(useMap){
  86841. viewer.updateVisible(this.mapViewer.cursor, 'screenshot', true);
  86842. if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){
  86843. if(info.type == 'measure'){
  86844. this.mapViewer.attachToMainViewer(false );
  86845. }
  86846. }
  86847. mapViewport.camera.zoom = oldStates.mapZoom;
  86848. mapViewport.camera.updateProjectionMatrix();
  86849. }
  86850. if(Potree.settings.displayMode == 'showPanos') {
  86851. viewer.images360.flyToPano({pano:oldStates.pano, duration:0, callback:()=>{
  86852. finish();
  86853. }});
  86854. }else {
  86855. finish();
  86856. }
  86857. }
  86858. };// screenshot end
  86859. let mapViewport;
  86860. let mainViewport = this.mainViewport;
  86861. let viewports = [mainViewport];
  86862. let oldStates = {
  86863. viewports : [mainViewport.clone()],
  86864. pano: Potree.settings.displayMode == 'showPanos' ? viewer.images360.currentPano : null,
  86865. };
  86866. if(useMap){
  86867. mapViewport = this.mapViewer.viewports[0];
  86868. viewports.push(mapViewport);
  86869. oldStates.viewports.push(mapViewport.clone());
  86870. oldStates.attachedToViewer = this.mapViewer.attachedToViewer;
  86871. oldStates.mapZoom = mapViewport.camera.zoom;
  86872. viewer.updateVisible(this.mapViewer.cursor, 'screenshot', false);//令mapCursor不可见
  86873. }
  86874. if(info.hideMarkers){
  86875. this.images360.panos.forEach(pano=>{//令漫游点不可见
  86876. viewer.updateVisible(pano, 'screenshot', false);
  86877. });
  86878. }
  86879. viewer.updateVisible(this.reticule, 'screenshot', false);//令reticule不可见
  86880. if(info.type == 'measure'){//要截图双屏
  86881. this.scene.measurements.forEach(e=>this.updateVisible(e,'screenshot',e == info.measurement) );
  86882. info.measurement.setSelected(true, 'screenshot');
  86883. //因为分屏后位置才最终确定,才能确定是否显示出floorplan所以先分屏
  86884. if(Potree.settings.floorplanEnable){
  86885. this.mapViewer.attachToMainViewer(true, 'measure', 0.5 );
  86886. }
  86887. viewer.updateScreenSize({forceUpdateSize:true, width, height}); //更新viewports相机透视 使focusOnObject在此窗口大小下
  86888. let begin = ()=>{
  86889. useMap = this.mapViewer.attachedToViewer;
  86890. updateCamera();
  86891. let waitTime = Potree.settings.displayMode == 'showPointCloud' ? 500 : 0; //等点云加载 网速差的话还是加载稀疏 是否要用最高质量点云
  86892. if(useMap){
  86893. let waitMap = ()=>{
  86894. //console.log('waitMap: '+sid)
  86895. this.mapViewer.waitLoadDone(screenshot.bind(this));//等待地图所有加载完
  86896. };
  86897. setTimeout(waitMap.bind(this), waitTime);
  86898. }else {
  86899. setTimeout(screenshot.bind(this), waitTime);
  86900. }
  86901. };
  86902. let {promise}= this.focusOnObject(info.measurement, 'measure', 0, {basePanoSize:1024} );//注意:不同角度截图 得到三维的会不一样,因为focusOnObject是根据方向的
  86903. promise.done(()=>{
  86904. //console.log('promise.done')
  86905. //根据当前位置更新floorplan显示
  86906. //console.log('view Pos ', this.mainViewport.view.position.toArray())
  86907. this.updateDatasetAt(true);
  86908. this.modules.SiteModel.updateEntityAt(true);
  86909. //this.updateFpVisiDatasets()
  86910. //console.log('currentFloor', this.modules.SiteModel.currentFloor, 'currentDataset', this.atDatasets )
  86911. let floorplanShowed = this.mapViewer.mapLayer.maps.some(e => e.name.includes('floorplan') && e.objectGroup.visible);
  86912. if(!floorplanShowed && this.mapViewer.attachedToViewer){
  86913. this.mapViewer.attachToMainViewer(false); //取消分屏
  86914. viewer.updateScreenSize({forceUpdateSize:true, width, height}); //更新viewports相机透视
  86915. let {promise} = this.focusOnObject(info.measurement, 'measure', 0, {basePanoSize:1024} );//因画面比例更改,重新focus
  86916. promise.done(()=>{
  86917. begin();
  86918. });
  86919. }else {
  86920. begin();
  86921. }
  86922. });
  86923. }else {
  86924. screenshot();
  86925. }
  86926. /*
  86927. 测量线的截图因为要调用分屏的,会改变画面
  86928. 但是普通截图的话,不会改变画面
  86929. */
  86930. return deferred.promise()
  86931. }
  86932. focusOnObject(object, type, duration, o={} ) {
  86933. //飞向热点、测量线等 。
  86934. console.log('focusOnObject: '+object.name, type);
  86935. let deferred = o.deferred || $.Deferred();
  86936. let target = new Vector3, //相机focus的位置
  86937. position = new Vector3, //相机最终位置
  86938. dis; //相机距离目标
  86939. duration = duration == void 0 ? 1000 : duration;
  86940. let camera = viewer.scene.getActiveCamera();
  86941. let cameraPos = camera.position.clone();
  86942. let getPosWithFullBound = (points, boundingBox, target, cameraPos )=>{//使boundingBox差不多占满屏幕时的相机到target的距离
  86943. // points 和 boundingBox 至少有一个
  86944. var cameraTemp = camera.clone();
  86945. cameraTemp.position.copy(cameraPos);
  86946. cameraTemp.lookAt(target);
  86947. cameraTemp.updateMatrix();
  86948. cameraTemp.updateMatrixWorld();
  86949. //对镜头的bound
  86950. var inv = cameraTemp.matrixWorldInverse;
  86951. var bound = new Box3();
  86952. if(points){//使用points得到的bound更小 //如果points和boundingbox的差别较大,尤其使target和points中心不一致,那么points不一定会刚好在boundingbox内
  86953. points.forEach(e=>{
  86954. var p = e.clone().applyMatrix4(inv);
  86955. bound.expandByPoint(p);
  86956. });
  86957. }else {
  86958. bound = boundingBox.applyMatrix4(inv);
  86959. }
  86960. let boundSize = bound.getSize(new Vector3);
  86961. if(!this.boundBox){//调试
  86962. this.boundBox = new Mesh(new BoxGeometry(1,1,1,1));
  86963. this.boundBox.material.wireframe = true;
  86964. this.boundBox.up.set(0,0,1);
  86965. viewer.updateVisible(this.boundBox, 'hidden', false);//打开以检查box
  86966. this.setObjectLayers(this.boundBox,'sceneObjects');
  86967. this.scene.scene.add(this.boundBox);
  86968. }
  86969. this.boundBox.position.copy(target);
  86970. this.boundBox.scale.copy(boundSize);
  86971. this.boundBox.lookAt(cameraPos);
  86972. {
  86973. let scale = 1.1; //稍微放大一些,不然会靠到屏幕边缘
  86974. boundSize.x *= scale;
  86975. boundSize.y *= scale;
  86976. }
  86977. let aspect = boundSize.x / boundSize.y;
  86978. if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
  86979. dis = boundSize.y/2/ Math.tan(MathUtils.degToRad(camera.fov / 2)) + boundSize.z/2;
  86980. }else {
  86981. let hfov = cameraLight.getHFOVForCamera(camera, true);
  86982. dis = boundSize.x/2 / Math.tan(hfov / 2) + boundSize.z/2;
  86983. }
  86984. dis = Math.max(0.1,dis);
  86985. //三个顶点以上的由于measure的中心不等于bound的中心,所以点会超出bound外。 且由于视椎近大远小,即使是两个点的,bound居中后线看上去仍旧不居中.
  86986. //获得相机最佳位置
  86987. let dir = new Vector3().subVectors(cameraPos, target).normalize();
  86988. position.copy(target).add(dir.multiplyScalar(dis));
  86989. return position
  86990. };
  86991. if(this.images360.flying){
  86992. let f = ()=>{
  86993. this.focusOnObject(object, type, duration, $.extend(o,{deferred}));
  86994. this.images360.removeEventListener('cameraMoveDone',f);
  86995. };
  86996. this.images360.addEventListener('cameraMoveDone',f);
  86997. return {promise: deferred.promise() }
  86998. }
  86999. if (type == 'measure') {
  87000. target.copy(object.getCenter());
  87001. //试试改变位置,直视测量线。能避免倾斜角度造成的非常不居中、以及看不到面的情况
  87002. if(object.facePlane/* && window.focusMeasureFaceToIt */){
  87003. let normal;
  87004. if(object.facePlane){
  87005. normal = object.facePlane.normal.clone();
  87006. }
  87007. let angle = this.scene.view.direction.angleTo(normal);
  87008. let minDiff = MathUtils.degToRad(60);
  87009. //console.log('angle',angle)
  87010. if(angle>minDiff && angle<Math.PI-minDiff){//当几乎正对时就不执行
  87011. if(angle<Math.PI/2){ //在背面
  87012. normal.negate();
  87013. }
  87014. let dir = new Vector3().subVectors(camera.position, target).normalize();
  87015. let newDir = new Vector3().addVectors(dir,normal);//两个角度的中间
  87016. cameraPos.copy(target.clone().add(newDir));
  87017. }
  87018. }else if(object.points.length == 2){ //线段
  87019. let lineDir = new Vector3().subVectors(object.points[0],object.points[1]).normalize();
  87020. let angle = this.scene.view.direction.angleTo(lineDir);
  87021. let maxDiff = Math.PI*0.25;// 45度
  87022. if(angle<maxDiff || angle>Math.PI-maxDiff){//当几乎正对时就不执行
  87023. if(angle>Math.PI/2){ //令dir和lineDir成钝角
  87024. lineDir.negate();
  87025. }
  87026. let dir = new Vector3().subVectors(camera.position, target).normalize();
  87027. let mid = new Vector3().addVectors(lineDir, dir).normalize(); //中间法向量(如果刚好dir和lineDir反向,那得到的为零向量,就不移动了,但一般不会酱紫吧)
  87028. let newDir = new Vector3().addVectors(dir, mid);
  87029. cameraPos.copy(target.clone().add(newDir));
  87030. }
  87031. }else {
  87032. console.error('measure 没有facePlane points点数还不为2?');
  87033. }
  87034. position = getPosWithFullBound(object.points, null, target, cameraPos );
  87035. if(this.mapViewer/* .attachedToViewer */){
  87036. //console.log('mapFocusOn: '+target.toArray())
  87037. const minBound = new Vector2$1(4,4);//针对垂直线,在地图上只有一个点
  87038. //原始的bound
  87039. let boundOri = new Box3();
  87040. object.points.forEach(e=>{
  87041. boundOri.expandByPoint(e);
  87042. });
  87043. let boundSizeOri = boundOri.getSize(new Vector3);
  87044. let boundSizeMap = boundSizeOri.clone().multiplyScalar(2);
  87045. boundSizeMap.x = Math.max(minBound.x, boundSizeMap.x );
  87046. boundSizeMap.y = Math.max(minBound.y, boundSizeMap.y );
  87047. this.mapViewer.moveTo(target.clone(), boundSizeMap, duration);
  87048. }
  87049. if(Potree.settings.displayMode == 'showPointCloud'){ //点云
  87050. let minDis = 0.3;
  87051. if(o.checkIntersect){
  87052. let checkIntersect = ( )=>{
  87053. let intersect = this.inputHandler.ifBlockedByIntersect(position, null , true, target);// 不一定准确
  87054. if(intersect){
  87055. let blockCount = 0, unblockCount = 0, visi;
  87056. for(let i=0;i<object.points.length;i++){ //如果顶点超过一半不可见,就要更改位置
  87057. let p = object.points[i];
  87058. let blocked = this.inputHandler.ifBlockedByIntersect(p, 0.3 , true, position, 4);
  87059. if(blocked){
  87060. blockCount ++;
  87061. if(blockCount / object.points.length >= 0.5){
  87062. visi = false;
  87063. break
  87064. }
  87065. }else {
  87066. unblockCount ++;
  87067. if(unblockCount / object.points.length > 0.5){
  87068. visi = true;
  87069. break
  87070. }
  87071. }
  87072. }
  87073. if(visi == void 0){
  87074. visi = unblockCount / object.points.length > 0.5;
  87075. }
  87076. let shrink = ()=>{
  87077. let dir = new Vector3().subVectors(position, target).normalize().multiplyScalar(intersect.distance);
  87078. position.copy(target).add(dir);
  87079. console.log('checkIntersect newPos', position.clone() );
  87080. };
  87081. if(!visi){//更改位置距离target如果小于最小距离,需要反向。 否则直接缩短距离。
  87082. if(intersect.distance < minDis ){
  87083. console.log('检测到intersect 反向', intersect.distance );
  87084. let position1 = position.clone();
  87085. let dir = new Vector3().subVectors(position, target);
  87086. position.copy(target).sub(dir);
  87087. let intersect2 = this.inputHandler.ifBlockedByIntersect(position, null , true, target);// 不一定准确
  87088. if(intersect2){
  87089. if(intersect2.distance < intersect.distance ){
  87090. position.copy(position1);//恢复
  87091. }
  87092. shrink();
  87093. }
  87094. }else {
  87095. shrink();
  87096. }
  87097. }
  87098. }
  87099. };
  87100. checkIntersect();
  87101. }
  87102. }else if(Potree.settings.displayMode == 'showPanos'){//全景 (比较难校准)
  87103. let pano = viewer.images360.fitPanoTowardPoint({
  87104. /*point : target, //不使用目标点来判断是因为缺少measure角度的信息。比如虽然可以靠近线的中心,但是线朝向屏幕,那几乎就是一个点了。
  87105. //bestDistance : dis * 0.5, //乘以小数是为了尽量靠近
  87106. boundSphere: boundOri.getBoundingSphere(new THREE.Sphere), */
  87107. target,
  87108. point : position,
  87109. bestDistance : 0 ,
  87110. checkIntersect: o.checkIntersect
  87111. });
  87112. if(pano){
  87113. viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize});//dontMoveMap不要移动map,否则flytopano会自动在map中focus到漫游点的位置,而非测量线了
  87114. }
  87115. if(viewer.images360.currentPano == pano){
  87116. let dis1 = viewer.images360.currentPano.position.distanceTo(target);
  87117. let dis2 = position.distanceTo(target);
  87118. console.log('dis1 / dis2',dis1 / dis2, 'dis1-dis2', dis1-dis2);
  87119. return {mag: (dis1 / dis2 > 1.5 && dis1-dis2>10)? 'tooFar' : 'posNoChange', promise : deferred.promise() }
  87120. }else {
  87121. return {promise : deferred.promise()}
  87122. }
  87123. //出现过到达位置后测量线标签闪烁的情况
  87124. }
  87125. } else if (type == 'tag' || type == 'point') {
  87126. //dimension = 1
  87127. target.copy(object.position);
  87128. let bestDistance = o.distance || 3;
  87129. if(!o.dontMoveMap && this.mapViewer){
  87130. //console.log('mapFocusOn: '+target.toArray())
  87131. this.mapViewer.moveTo(target.clone(), null, duration);
  87132. }
  87133. if(Potree.settings.displayMode == 'showPointCloud'){
  87134. if(o.dontChangePos){
  87135. position.copy(cameraPos);
  87136. }else {
  87137. dis = bestDistance;
  87138. let dir = o.direction ? o.direction.clone().negate() : this.mainViewport.view.direction.negate();//new THREE.Vector3().subVectors(camera.position, target).normalize()
  87139. position.copy(target).add(dir.multiplyScalar(dis));
  87140. }
  87141. /* if(o.checkIntersect){//识别被点云遮住的话
  87142. let ifShelter
  87143. while(1){
  87144. ifShelter = this.inputHandler.ifBlockedByIntersect(target, o.checkMargin, true, position)
  87145. if(ifShelter){
  87146. if(dis > 0.5){
  87147. dis --
  87148. dir.dot(ifShelter.normal)>0 ? dir.copy(ifShelter.normal).negate() : dir.copy(ifShelter.normal);
  87149. position.copy(target).add(dir.multiplyScalar(dis))
  87150. }
  87151. }
  87152. }
  87153. } */
  87154. }else if(Potree.settings.displayMode == 'showPanos'){
  87155. let pano = viewer.images360.fitPanoTowardPoint({
  87156. point : target,
  87157. bestDistance //越近越好,但不要太近,bestDistance左右差不多
  87158. });
  87159. pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize });
  87160. return {promise:deferred.promise() }
  87161. }
  87162. }else if(object.boundingBox && type == 'boundingBox'){//使屏幕刚好看全boundingBox
  87163. target = object.boundingBox.getCenter(new Vector3);
  87164. position = getPosWithFullBound(object.points, object.boundingBox, target, cameraPos );
  87165. if(Potree.settings.displayMode == 'showPanos'){//全景 (比较难校准)
  87166. let pano = viewer.images360.fitPanoTowardPoint({
  87167. point : position,
  87168. bestDistance : 0 ,
  87169. });
  87170. pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize});//dontMoveMap不要移动map,否则flytopano会自动在map中focus到漫游点的位置,而非测量线了
  87171. if(!pano){
  87172. console.error('no pano');
  87173. }
  87174. return {promise:deferred.promise() }
  87175. //出现过到达位置后测量线标签闪烁的情况
  87176. }
  87177. }
  87178. /*} else if(dimension == 2){//线
  87179. }else if(dimension == 3){//面
  87180. }else{//立体
  87181. } */
  87182. viewer.scene.view.setView({position, target, duration, callback:()=>{
  87183. //console.log('focusOnObjectSuccess: '+object.name, type)
  87184. deferred.resolve();
  87185. }
  87186. });
  87187. return {promise:deferred.promise()}
  87188. }
  87189. flyToDataset(o={}){
  87190. var pointcloud;
  87191. if(o instanceof Object3D) pointcloud = o;
  87192. else if(o.pointcloud) pointcloud = o.pointcloud;
  87193. else pointcloud = this.scene.pointclouds.find(p => p.dataset_id == o.id);
  87194. let duration = o.duration == void 0 ? 1000 : o.duration;
  87195. var center = pointcloud.bound.getCenter(new Vector3);
  87196. let position;
  87197. let getPano = ()=>{//获取离中心最近的pano
  87198. let request = [];
  87199. let rank = [
  87200. Images360.scoreFunctions.distanceSquared({position: center})
  87201. ];
  87202. let r = Common.sortByScore(pointcloud.panos, request, rank);
  87203. if(r && r.length){
  87204. return r[0].item
  87205. }
  87206. };
  87207. if(Potree.settings.displayMode == 'showPanos'){
  87208. let pano = getPano();
  87209. if(pano){
  87210. if(pano == this.images360.currentPano) return 'posNoChange'
  87211. this.images360.flyToPano({
  87212. pano
  87213. });
  87214. }else return false
  87215. }else {
  87216. let target;
  87217. position = center;
  87218. if(pointcloud.panosBound){
  87219. let panosCenter = pointcloud.panosBound.center; //pano集中的地方,也就是真正有点云的地方
  87220. position = panosCenter.clone();
  87221. /* let ratio = 0.2
  87222. position.z = center.z * ratio + panosCenter.z * (1-ratio) //因为panos一般比较低,为了不让相机朝下时看不到点云,加一丢丢中心高度
  87223. */
  87224. let pano = getPano();
  87225. if(pano){
  87226. target = pano.position; //针对像隧道一样的场景, 中心点还是panosCenter都在没有点云的地方,所以还是看向其中一个漫游点好。
  87227. position.z = target.z; //水平, 避免朝上或朝下
  87228. }
  87229. }
  87230. if(this.modules.Clip.editing){
  87231. position.z = center.z; //剪裁时在中心高度,因为以点云为重点
  87232. this.modules.Clip.bus.dispatchEvent({type:'flyToPos', position });
  87233. }else {
  87234. if(math.closeTo(position, this.images360.position)) return 'posNoChange'
  87235. viewer.scene.view.setView({position, target, duration });
  87236. o.dontMoveMap || viewer.mapViewer.moveTo(position.clone(), null , duration);
  87237. }
  87238. }
  87239. return true
  87240. }
  87241. resolveTimings(timestamp){
  87242. if(Potree.measureTimings){
  87243. if(!this.toggle){
  87244. this.toggle = timestamp;
  87245. }
  87246. let duration = timestamp - this.toggle;
  87247. if(duration > 1000.0){
  87248. let measures = performance.getEntriesByType("measure");
  87249. let names = new Set();
  87250. for(let measure of measures){
  87251. names.add(measure.name);
  87252. }
  87253. let groups = new Map();
  87254. for(let name of names){
  87255. groups.set(name, {
  87256. measures: [],
  87257. sum: 0,
  87258. n: 0,
  87259. min: Infinity,
  87260. max: -Infinity
  87261. });
  87262. }
  87263. for(let measure of measures){
  87264. let group = groups.get(measure.name);
  87265. group.measures.push(measure);
  87266. group.sum += measure.duration;
  87267. group.n++;
  87268. group.min = Math.min(group.min, measure.duration);
  87269. group.max = Math.max(group.max, measure.duration);
  87270. }
  87271. let glQueries = Potree.resolveQueries(this.renderer.getContext());
  87272. for(let [key, value] of glQueries){
  87273. let group = {
  87274. measures: value.map(v => {return {duration: v}}),
  87275. sum: value.reduce( (a, i) => a + i, 0),
  87276. n: value.length,
  87277. min: Math.min(...value),
  87278. max: Math.max(...value)
  87279. };
  87280. let groupname = `[tq] ${key}`;
  87281. groups.set(groupname, group);
  87282. names.add(groupname);
  87283. }
  87284. for(let [name, group] of groups){
  87285. group.mean = group.sum / group.n;
  87286. group.measures.sort( (a, b) => a.duration - b.duration );
  87287. if(group.n === 1){
  87288. group.median = group.measures[0].duration;
  87289. }else if(group.n > 1){
  87290. group.median = group.measures[parseInt(group.n / 2)].duration;
  87291. }
  87292. }
  87293. let cn = Array.from(names).reduce( (a, i) => Math.max(a, i.length), 0) + 5;
  87294. let cmin = 10;
  87295. let cmed = 10;
  87296. let cmax = 10;
  87297. let csam = 6;
  87298. let message = ` ${"NAME".padEnd(cn)} |`
  87299. + ` ${"MIN".padStart(cmin)} |`
  87300. + ` ${"MEDIAN".padStart(cmed)} |`
  87301. + ` ${"MAX".padStart(cmax)} |`
  87302. + ` ${"SAMPLES".padStart(csam)} \n`;
  87303. message += ` ${"-".repeat(message.length) }\n`;
  87304. names = Array.from(names).sort();
  87305. for(let name of names){
  87306. let group = groups.get(name);
  87307. let min = group.min.toFixed(3);
  87308. let median = group.median.toFixed(3);
  87309. let max = group.max.toFixed(3);
  87310. let n = group.n;
  87311. message += ` ${name.padEnd(cn)} |`
  87312. + ` ${min.padStart(cmin)} |`
  87313. + ` ${median.padStart(cmed)} |`
  87314. + ` ${max.padStart(cmax)} |`
  87315. + ` ${n.toString().padStart(csam)}\n`;
  87316. }
  87317. message += `\n`;
  87318. console.log(message);
  87319. performance.clearMarks();
  87320. performance.clearMeasures();
  87321. this.toggle = timestamp;
  87322. }
  87323. }
  87324. }
  87325. loop(timestamp){
  87326. if(this.stats){
  87327. this.stats.begin();
  87328. }
  87329. if(Potree.measureTimings){
  87330. performance.mark("loop-start");
  87331. }
  87332. this.update(this.clock.getDelta(), timestamp);
  87333. this.magnifier.render();
  87334. this.render();
  87335. // let vrActive = viewer.renderer.xr.isPresenting;
  87336. // if(vrActive){
  87337. // this.update(this.clock.getDelta(), timestamp);
  87338. // this.render();
  87339. // }else{
  87340. // this.update(this.clock.getDelta(), timestamp);
  87341. // this.render();
  87342. // }
  87343. if(Potree.measureTimings){
  87344. performance.mark("loop-end");
  87345. performance.measure("loop", "loop-start", "loop-end");
  87346. }
  87347. this.resolveTimings(timestamp);
  87348. Potree.framenumber++;
  87349. if(this.stats){
  87350. this.stats.end();
  87351. }
  87352. }
  87353. postError(content, params = {}){
  87354. let message = this.postMessage(content, params);
  87355. message.element.addClass("potree_message_error");
  87356. return message;
  87357. }
  87358. postMessage(content, params = {}){
  87359. let message = new Message(content);
  87360. let animationDuration = 100;
  87361. message.element.css("display", "none");
  87362. message.elClose.click( () => {
  87363. message.element.slideToggle(animationDuration);
  87364. let index = this.messages.indexOf(message);
  87365. if(index >= 0){
  87366. this.messages.splice(index, 1);
  87367. }
  87368. });
  87369. this.elMessages.prepend(message.element);
  87370. message.element.slideToggle(animationDuration);
  87371. this.messages.push(message);
  87372. if(params.duration !== undefined){
  87373. let fadeDuration = 500;
  87374. let slideOutDuration = 200;
  87375. setTimeout(() => {
  87376. message.element.animate({
  87377. opacity: 0
  87378. }, fadeDuration);
  87379. message.element.slideToggle(slideOutDuration);
  87380. }, params.duration);
  87381. }
  87382. return message;
  87383. }
  87384. getBoundingBox (pointclouds) {
  87385. //可以直接返回viewer.bound
  87386. if(!this.bound){
  87387. this.updateModelBound();
  87388. }
  87389. return this.bound.boundingBox.clone()//this.scene.getBoundingBox(pointclouds);
  87390. };
  87391. updateModelBound(){
  87392. this.bound = Utils.computePointcloudsBound(this.scene.pointclouds);
  87393. if(Potree.settings.boundAddObjs){//加上obj的bound
  87394. this.objs.children.forEach(e=>{
  87395. this.bound.boundingBox.union(e.boundingBox.clone().applyMatrix4(e.matrixWorld));
  87396. });
  87397. this.bound.boundingBox.getSize(this.bound.boundSize);
  87398. this.bound.boundingBox.getCenter(this.bound.center);
  87399. }
  87400. viewer.farWhenShowPano = this.bound.boundSize.length() * 10;//全景漫游时要能看到整个skybox 原本*2的但对于距离特远的数据集需要乘大一些否则会黑面
  87401. let boundPlane = new Box3();
  87402. boundPlane.expandByPoint(this.bound.boundingBox.min.clone());//最低高度为bound的最低
  87403. boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z));//最高高度为bound的中心高度
  87404. FirstPersonControls.boundPlane = boundPlane;
  87405. FirstPersonControls.standardSpeed = MathUtils.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 , 0.02,0.5); //在这个boundPlane中的速度
  87406. viewer.scene.pointclouds.forEach(e=>{//海拔范围
  87407. e.material.heightMin = this.bound.boundingBox.min.z;
  87408. e.material.heightMax = this.bound.boundingBox.max.z;
  87409. });
  87410. this.dispatchEvent({type:'updateModelBound'});
  87411. }
  87412. waitForLoad(object, isLoadedCallback){//等待加载时显示loading。主要是贴图
  87413. this.waitQueue.push({
  87414. object,
  87415. isLoadedCallback,
  87416. });
  87417. 1 === this.waitQueue.length && this.dispatchEvent({type:"loading", show:true});
  87418. }
  87419. ifAllLoaded(object){
  87420. if(this.waitQueue.length>0){
  87421. this.waitQueue = this.waitQueue.filter(function(e) {
  87422. return !e.isLoadedCallback()
  87423. });
  87424. }
  87425. 0 === this.waitQueue.length && this.dispatchEvent({type:"loading", show:false});
  87426. }
  87427. setView(o={}){
  87428. let callback = ()=>{
  87429. if(o.displayMode){
  87430. Potree.settings.displayMode = o.displayMode;
  87431. }
  87432. o.callback && o.callback();
  87433. };
  87434. if(o.pano != void 0){//pano 权重高于 position
  87435. this.images360.flyToPano(o);
  87436. }else {
  87437. this.scene.view.setView($.extend({},o, {callback}));
  87438. }
  87439. }
  87440. //设置点云为标准模式
  87441. setPointStandardMat(state, pointDensity, fitPointsize){
  87442. console.log('setPointStandardMat',state);
  87443. if(state){
  87444. if(this.pointStatesBefore){
  87445. return console.error('已设置过pointStatesBefore!')
  87446. }
  87447. this.pointStatesBefore = {
  87448. opacity : new Map(),
  87449. size: new Map(),
  87450. density:Potree.settings.pointDensity,
  87451. useEDL:this.getEDLEnabled(),
  87452. shape: viewer.scene.pointclouds[0].material.shape
  87453. };
  87454. viewer.scene.pointclouds.forEach(e=>{
  87455. this.pointStatesBefore.opacity.set(e, e.temp.pointOpacity); //因为更改pointDensity时会自动变opacity,所以这项最先获取
  87456. this.pointStatesBefore.colorType = e.material.activeAttributeName;
  87457. fitPointsize && this.pointStatesBefore.size.set(e,e.temp.pointSize); //这项不一定有用,因为会被后期覆盖
  87458. });
  87459. if(pointDensity)Potree.settings.pointDensity = pointDensity; //万一之后切换到全景模式怎么办
  87460. if(fitPointsize)Potree.settings.sizeFitToLevel = true;
  87461. viewer.scene.pointclouds.forEach(e=>{
  87462. e.material.activeAttributeName = 'rgba';
  87463. e.material.shape = Potree.PointShape['SQUARE'];
  87464. fitPointsize && e.changePointSize(Potree.config.material.realPointSize, true);
  87465. e.changePointOpacity(1);
  87466. });
  87467. viewer.setEDLEnabled(false);
  87468. }else {
  87469. if(!this.pointStatesBefore){
  87470. return console.error('未设置过pointStatesBefore!')
  87471. }
  87472. Potree.settings.sizeFitToLevel = false;
  87473. if(pointDensity)Potree.settings.pointDensity = this.pointStatesBefore.pointDensity;
  87474. viewer.scene.pointclouds.forEach(e=>{
  87475. e.material.activeAttributeName = this.pointStatesBefore.colorType;
  87476. e.changePointOpacity(this.pointStatesBefore.opacity.get(e));
  87477. e.material.shape = this.pointStatesBefore.shape;
  87478. let size = this.pointStatesBefore.size.get(e);
  87479. if(size) e.changePointSize(size);
  87480. });
  87481. viewer.setEDLEnabled(this.pointStatesBefore.useEDL);
  87482. this.pointStatesBefore = null;
  87483. }
  87484. }
  87485. //调试时显示transformControl来调节object
  87486. transformObject(object){
  87487. let seleted = viewer.inputHandler.selection[0];
  87488. if(!object){//取消
  87489. seleted && viewer.inputHandler.toggleSelection(seleted);
  87490. return
  87491. }
  87492. if(seleted && seleted != object){//要更换,先取消
  87493. return this.transformObject(null)
  87494. }
  87495. if(!object.boundingBox){
  87496. object.boundingBox = new Box3(); //任意大小 只是为了显示黄色外框
  87497. //??? computeBoundingBox
  87498. }
  87499. if(!viewer.inputHandler.selection.includes(object)){
  87500. viewer.inputHandler.toggleSelection(object);
  87501. }
  87502. }
  87503. pointInWhichPointcloud(pos){//选择最接近中心的那个 使用boundSphere
  87504. let result = Common.sortByScore(this.scene.pointclouds,[],[
  87505. (pointcloud)=>{
  87506. var size = pointcloud.pcoGeometry.tightBoundingBox.getSize(new Vector3);
  87507. var center = pointcloud.bound.getCenter(new Vector3);
  87508. var length = size.length() / 2;
  87509. var dis = pos.distanceTo(center);
  87510. return length / dis //到数据集中心的距离占数据集大小越小越好
  87511. }
  87512. ]);
  87513. //若要求更准确的话,可以使用ifContainsPoint判断一下是否在bound中
  87514. let r = result && result[0];
  87515. return r.score > 1 ? result[0].item : null
  87516. }
  87517. /* addObjectTest1(){//加水管
  87518. if(Potree.settings.number == 't-8KbK1JjubE'){
  87519. let boundingBox = new THREE.Box3()
  87520. boundingBox.min.set(-1,-1,-1); boundingBox.max.set(1,1,1)
  87521. let radius = 0.08;
  87522. let radialSegments = 5
  87523. let radSegments = Math.PI*2 / radialSegments
  87524. var circlePts = [];//横截面
  87525. for(let i=0;i<radialSegments;i++){
  87526. let angle = radSegments * i;
  87527. circlePts.push(new THREE.Vector2(radius * Math.cos(angle), radius * Math.sin(angle) ))
  87528. }
  87529. var count = 0
  87530. var addMesh = (color, path, height)=>{//height:在path之上的高度,负数代表在path之下
  87531. var name = 'cylinder'+count
  87532. var mat = new THREE.MeshStandardMaterial({color, depthTest:false, roughness:0.4,metalness:0.5}) 
  87533. let linePath = path.map(e=>new THREE.Vector3().copy(e).setZ(e.z+height))
  87534. let geo = MeshDraw.getExtrudeGeo( circlePts, null,{ extrudePath:linePath, tension:0.2} )
  87535. var mesh = new THREE.Mesh(geo,mat);
  87536. mesh.name = name
  87537. window[name] = mesh
  87538. mesh.boundingBox = boundingBox
  87539. mesh.matrixAutoUpdate = false
  87540. mesh.matrix.copy(viewer.scene.pointclouds[0].transformMatrix)
  87541. mesh.matrixWorldNeedsUpdate = true
  87542. this.scene.scene.add(mesh);
  87543. count ++
  87544. }
  87545. let linePath, height
  87546. //地上管子 黄色
  87547. linePath = [{"x":-109.83,"y":-68.33,"z":-7.52},{"x":-95.17,"y":-59.3,"z":-7.38}, {"x":-38.75,"y":-24.01,"z":-6.01},{"x":0.5,"y":0.19,"z":-3.89},{"x":39.29,"y":24.41,"z":-1.31}
  87548. ,{"x":43.58,"y":27.7,"z":-0.97},{"x":40.22,"y":35.37,"z":-0.67}// 拐弯向右
  87549. , {"x":39.18,"y":36.71,"z":0.35},{"x":38.69,"y":36.04,"z":18.04} // 拐弯向上
  87550. ]
  87551. height = radius + 0.05;
  87552. addMesh('#b86', linePath, height)
  87553. //地下管子 藍色
  87554. linePath = [{"x":-108.24,"y":-70.61,"z":-7.52}, {"x":-57.8,"y":-39.31,"z":-6.72},{"x":-18.8,"y":-15.35,"z":-5.01},{"x":55.87,"y":31.67,"z":-0.04},{"x":110.53,"y":66.48,"z":5.14}
  87555. ]
  87556. height = -0.5;
  87557. addMesh('#48a', linePath, height)
  87558. }
  87559. }
  87560. */
  87561. /* createRoomEv(){
  87562. const environment = new RoomEnvironment();
  87563. const pmremGenerator = new THREE.PMREMGenerator( this.renderer );
  87564. }
  87565. */
  87566. loadModel(fileInfo, done, onProgress_, onError){
  87567. let boundingBox = new Box3();
  87568. if(!Potree.settings.boundAddObjs){
  87569. boundingBox.min.set(-0.5,-0.5,-0.5); boundingBox.max.set(0.5,0.5,0.5);
  87570. }
  87571. let fileType = fileInfo.objurl ? 'obj' : 'glb';
  87572. let loadDone = (object, total)=>{
  87573. //object.scale.set(1,1,1);//先获取原始的大小时的boundingBox
  87574. object.updateMatrixWorld();
  87575. let weight = Math.round((total / 1024 / 1024) * 100) / 100;
  87576. if(fileInfo.id != void 0)object.dataset_id = fileInfo.id;
  87577. console.log( fileInfo.name , fileInfo.id + '加载完毕, 模型数据量:' + weight + 'M');
  87578. object.traverse( ( child )=>{
  87579. if ( child instanceof Mesh ) {
  87580. child.renderOrder = 10;
  87581. if(Potree.settings.boundAddObjs){
  87582. child.geometry.computeBoundingBox();
  87583. //console.log(child.matrixWorld.clone())
  87584. boundingBox.union(child.geometry.boundingBox.clone().applyMatrix4(child.matrixWorld)); //但感觉如果最外层object大小不为1,要还原下scale再乘
  87585. }//获取在scale为1时,表现出的大小
  87586. Common.makeTexDontResize(child.material.map);
  87587. //console.log(child.name, 'roughness',child.material.roughness,'metalness',child.material.metalness)
  87588. child.material.roughness = 0.6;
  87589. child.material.metalness = 0.3;
  87590. /* child.depthMat = child.material.clone()
  87591. child.standardMat = child.material
  87592. child.depthMat.onBeforeCompile = function ( shader ) {
  87593. console.log('vertexShader',shader.vertexShader)
  87594. console.log('fragmentShader',shader.fragmentShader)
  87595. shader.fragmentShader = `
  87596. ${shader.fragmentShader.replace(
  87597. 'gl_FragColor = vec4( outgoingLight, diffuseColor.a );',
  87598. 'diffuseColor.a = log(vViewPosition.z); gl_FragColor = vec4( outgoingLight, diffuseColor.a );'
  87599. )}
  87600. `;
  87601. console.log('fragmentShader1',shader.fragmentShader)
  87602. }; */
  87603. //暂时用这种材质:
  87604. if(fileInfo.unlit){
  87605. let material = new MeshBasicMaterial({map:child.material.map});
  87606. child.material = material;
  87607. }
  87608. }
  87609. } );
  87610. object.name = fileInfo.name != void 0 ? fileInfo.name : 'obj';
  87611. this.objs.add(object);
  87612. object.boundingBox = boundingBox;
  87613. let setTransfrom = (name)=>{
  87614. let value = fileInfo.transform[name];
  87615. if(!value)return
  87616. if(value instanceof Array){
  87617. object[name].fromArray(value);
  87618. }else {
  87619. object[name].copy(value);
  87620. }
  87621. };
  87622. setTransfrom('position');
  87623. setTransfrom('rotation');
  87624. setTransfrom('scale');
  87625. if(fileInfo.moveWithPointcloud){
  87626. object.updateMatrix();
  87627. object.matrixAutoUpdate = false;
  87628. object.matrix.premultiply(viewer.scene.pointclouds[0].transformMatrix); //默认跟随第一个数据集
  87629. object.matrixWorldNeedsUpdate = true;
  87630. }
  87631. done && done(object);
  87632. };
  87633. let onProgress = function ( xhr ) {
  87634. if ( xhr.lengthComputable ) {
  87635. let percentComplete = xhr.loaded / xhr.total * 100;
  87636. //console.log( Math.round(percentComplete, 2) + '% downloaded' );
  87637. onProgress_ && onProgress_(percentComplete);
  87638. }
  87639. };
  87640. if(fileType == 'obj'){
  87641. /* manager.onProgress = function ( item, loaded, total ) {
  87642. console.log( item, loaded, total );
  87643. }; */
  87644. /* let onError = function ( xhr ) {
  87645. }; */
  87646. loaders.mtlLoader.load( fileInfo.mtlurl , (materials)=>{
  87647. materials.preload();
  87648. loaders.objLoader.setMaterials( materials ).load(fileInfo.objurl, (object, total)=>{
  87649. loadDone(object, total);
  87650. });
  87651. } , onProgress, onError );
  87652. }else if(fileType == 'glb'){
  87653. loaders.glbLoader.load(fileInfo.glburl, ( gltf, total )=>{ //.setPath( Potree.resourcePath + '/models/glb/' );
  87654. //console.log('loadGLTF', gltf)
  87655. loadDone(gltf.scene, total);
  87656. }, onProgress, onError);
  87657. }
  87658. /* viewer.onGUILoaded(() => {
  87659. // Add entries to object list in sidebar
  87660. let tree = $(`#jstree_scene`);
  87661. let parentNode = "other";
  87662. let bunnyID = tree.jstree('create_node', parentNode, {
  87663. text: "Bunny Textured",
  87664. icon: `${Potree.resourcePath}/icons/triangle.svg`,
  87665. data: object
  87666. },
  87667. "last", false, false);
  87668. tree.jstree(object.visible ? "check_node" : "uncheck_node", bunnyID);
  87669. //tree.jstree("open_node", parentNode);
  87670. }); */
  87671. }
  87672. removeObj(object){
  87673. this.objs.remove(object);
  87674. if(Potree.settings.boundAddObjs){
  87675. this.updateModelBound();
  87676. }
  87677. }
  87678. loadGLTF(name='87b3a367bc3e4273832cb4fa398782e5.glb'){
  87679. const loader = new GLTFLoader(undefined, this.renderer).setPath( Potree.resourcePath + '/models/glb/' );
  87680. /*
  87681. coffeemat.glb
  87682. ModernJPHouseSofa44216499.glb
  87683. ModernJPHouseSofa44105209.glb
  87684. 87ecd10fb0374ea6b3e0bf24c6459e3c.glb
  87685. 87b3a367bc3e4273832cb4fa398782e5.glb
  87686. */
  87687. loader.load(name, ( gltf )=>{
  87688. console.log('loadGLTF', gltf);
  87689. this.objs.add(gltf.scene);
  87690. });
  87691. }
  87692. addFire(){
  87693. if(Potree.settings.number == 't-CwfhfqJ'){
  87694. let position = Potree.Utils.datasetPosTransform({
  87695. pointcloud:viewer.scene.pointclouds[0],
  87696. position: new Vector3(4.4318,-0.580291847759, -0.78),
  87697. fromDataset:true
  87698. });
  87699. viewer.modules.ParticleEditor.addParticle( {
  87700. type:'fire',
  87701. positions:[position],
  87702. radius:0.42,
  87703. height:10,
  87704. });
  87705. viewer.modules.ParticleEditor.addParticle( {
  87706. type:'smoke',
  87707. positions: [ new Vector3().addVectors(position,new Vector3(0,0,0.3))],
  87708. positionStyle : 'sphere' ,
  87709. positionRadius : 0.3,
  87710. sizeTween: [[0, 0.3, 0.9, 1], [0.05, 0.1, 1, 0.8]],
  87711. opacityBase : 0.2,
  87712. opacityTween :[ [0, 0.3, 0.7, 0.95, 1], [0, 0.2, 1 , 0.1, 0] ],
  87713. velocityBase : new Vector3( 0, 0, 1),
  87714. velocitySpread : new Vector3( 0.2, 0.2, -0.3),
  87715. accelerationBase : 0.2,
  87716. accelerationSpread : 0.7,
  87717. radius:0,
  87718. //particlesPerSecond : 30,
  87719. particleDeathAge : 3.0,
  87720. });
  87721. viewer.modules.ParticleEditor.addParticle( {
  87722. type:'explode',
  87723. name:'fire splash',
  87724. position: new Vector3().addVectors(position,new Vector3(0,0,0.3)),
  87725. size: 0.1,
  87726. sizeRange: 0.3,
  87727. sizeTween:[[0, 0.05, 0.3, 0.45], [0, 0.02, 0.1, 0.05] ],
  87728. opacityTween: [[0, 0.05, 0.3, 0.45], [1, 1, 0.5, 0]] ,
  87729. speed : 1, //sphere
  87730. speedRange : 4,
  87731. radius: 0.1,
  87732. acceleration : 0.3,
  87733. accelerationRange : 1,
  87734. particleSpaceTime:0,
  87735. strength:4,
  87736. });
  87737. }
  87738. }
  87739. addVideo11(){
  87740. if(Potree.settings.number != 'SS-fckI7CClKC')return
  87741. var video = $(`<video controls="controls" loop autoplay x5-playsinline="" webkit-playsinline="true" playsinline="true" controlslist="nodownload"></video>`)[0];
  87742. video.setAttribute("crossOrigin", 'Anonymous');
  87743. //video.src = Potree.resourcePath+'/video/SS-fckI7CClKC/19.mp4'
  87744. var map = new VideoTexture(video);
  87745. var plane = this.videoPlane = new Mesh(new PlaneGeometry(1, 1, 1, 1), new MeshBasicMaterial({
  87746. color:"#ffffff",
  87747. transparent: !0,
  87748. depthTest:false,
  87749. opacity:0.7,
  87750. side:2,
  87751. map
  87752. }));
  87753. plane.visible = false;
  87754. plane.geometry.computeBoundingBox();
  87755. plane.boundingBox = plane.geometry.boundingBox.clone();//.applyMatrix4()
  87756. plane.boundingBox.max.z = 1;
  87757. plane.boundingBox.max.y = -0.4;
  87758. plane.boundingBox.max.x = 1;
  87759. /* plane.position.copy(this.images360.panos[19].position);
  87760. plane.lookAt(plane.position.clone().setX(0))
  87761. 9:
  87762. viewer.videoPlane.rotation.set(-1.432978005954197, 1.2296264545169697, 3.0098547630197667)
  87763. viewer.videoPlane.position.set( 6.532456676287381, -9.806373049095631, -0.024205281024294284)
  87764. //viewer.transformObject(viewer.videoPlane)
  87765. //19:
  87766. viewer.videoPlane.rotation.set( 1.627167773445286, -1.172425902600188, 0.04682299709711613)
  87767. viewer.videoPlane.position.set( -9.558613948539932,-1.042301166581578, 0.08159683876743667) */
  87768. video.addEventListener('loadeddata', function(e) {
  87769. video.play();
  87770. //plane.scale.set(video.videoWidth/1000,video.videoHeight/1000,1) // 1080 * 1920
  87771. console.log('video loadeddata');
  87772. });
  87773. plane.scale.set(1080/1000,1920/1000,1); // 1080 * 1920
  87774. var startPlay = ()=>{
  87775. video.play();
  87776. //video.pause()
  87777. //video.currentTime = 0.1;
  87778. this.removeEventListener('global_mousedown', startPlay);
  87779. };
  87780. this.addEventListener('global_mousedown', startPlay);
  87781. var videoInfo = {
  87782. 9:{
  87783. rotation:[-1.432978005954197, 1.2296264545169697, 3.0098547630197667],
  87784. position:[6.532456676287381, -9.806373049095631, -0.024205281024294284]
  87785. },
  87786. 19:{
  87787. rotation:[1.627167773445286, -1.172425902600188, 0.04682299709711613],
  87788. position:[-9.558613948539932,-1.042301166581578, 0.08159683876743667]
  87789. },
  87790. };
  87791. /* this.images360.addEventListener('cameraMoveDone',(e)=>{
  87792. let info = videoInfo[this.images360.currentPano.id]
  87793. if(info ){
  87794. plane.visible = true;
  87795. plane.material.opacity = 1;
  87796. plane.position.fromArray(info.position)
  87797. plane.rotation.fromArray(info.rotation)
  87798. }
  87799. }) */
  87800. this.images360.addEventListener('flyToPano' ,(e)=>{//飞之前
  87801. if(Potree.settings.displayMode != 'showPanos') return
  87802. let info = videoInfo[e.toPano.pano.id];
  87803. if(info ){ //出现
  87804. setTimeout(()=>{
  87805. plane.visible = true;
  87806. plane.position.fromArray(info.position);
  87807. plane.rotation.fromArray(info.rotation);
  87808. video.src = Potree.resourcePath+`/video/${Potree.settings.number}/${e.toPano.pano.id}.mp4`;
  87809. video.play();
  87810. video.currentTime = 0;
  87811. Potree.settings.zoom.enabled = false;
  87812. transitions.start(lerp.property(plane.material, "opacity", 1/* , (e)=>{console.log('fadeIn',e)} */) , e.toPano.duration*0.4 , ()=>{
  87813. }, 0, easing['easeInOutQuad']);
  87814. }, e.toPano.duration*0.6); //时间上不能和消失的重叠 延迟
  87815. }
  87816. //消失
  87817. transitions.start(lerp.property(plane.material, "opacity", 0, /* (e)=>{console.log('fadeOut',e)} */) , e.toPano.duration*0.4, ()=>{
  87818. if(!info){
  87819. plane.visible = false;
  87820. video.pause();
  87821. Potree.settings.zoom.enabled = true;
  87822. }
  87823. }, 0, easing['easeInOutQuad']);
  87824. });
  87825. this.images360.addEventListener('endChangeMode',(e)=>{ //暂时不处理初始加载时就在有视频的点位上的情况
  87826. if(e.mode == 'showPanos'){
  87827. let info = videoInfo[this.images360.currentPano.id];
  87828. if(info ){ //出现
  87829. plane.visible = true;
  87830. plane.position.fromArray(info.position);
  87831. plane.rotation.fromArray(info.rotation);
  87832. plane.material.opacity = 0;
  87833. video.src = Potree.resourcePath+`/video/${Potree.settings.number}/${this.images360.currentPano.id}.mp4`;
  87834. video.play();
  87835. video.currentTime = 0;
  87836. Potree.settings.zoom.enabled = false;
  87837. transitions.start(lerp.property(plane.material, "opacity", 1, (e)=>{console.log('fadeIn',e);}) , 300 , ()=>{
  87838. }, 0, easing['easeInOutQuad']);
  87839. }
  87840. }else {
  87841. plane.visible = false;
  87842. Potree.settings.zoom.enabled = true;
  87843. }
  87844. });
  87845. this.scene.scene.add(plane);
  87846. }
  87847. ////////////////////////
  87848. addVideo(){
  87849. if(Potree.settings.number != 'SS-t-P6zBR73Gke')return
  87850. var geo = new PlaneGeometry(1, 1, 1, 1);
  87851. var videoInfo = this.videoInfo = [
  87852. /* {
  87853. id: 45,
  87854. url: 'https://laser-oss.4dkankan.com/testdata/SS-t-P6zBR73Gke/temp/poi/2022/05/09/c02a2c1e-8420-4f34-b951-5f7a07abe932.mp4',
  87855. rotation:[-1.629007730553656, 0.042029565584517974, -3.1345506775116627],
  87856. position:[ 9.467649296794061, -0.7596961214872837, -0.12477576310191862],
  87857. scale:[4.52209111454416,3.3888400031207984,1],
  87858. }, */
  87859. {
  87860. id: '40-2',
  87861. url: 'https://laser-oss.4dkankan.com/testdata/SS-t-P6zBR73Gke/temp/poi/2022/05/10/0aabafee-36b8-455d-9c11-0780bf694786.mp4',
  87862. rotation:[-1.494468618954883, -1.4987317433158989, -3.061254983446741],
  87863. position:[ 19.801820617361624, 2.884673619844108, -0.03362305858221648],
  87864. scale:[3.5741423153151763, 2.8738725275578703, 1],
  87865. },
  87866. {
  87867. id: 40,
  87868. /* rotation:[-1.534692822378723, 0.01083403560862361, 3.141535283661569],
  87869. position:[17.2934294239949861, 2.413510747928117, -0.008057029580231356], */
  87870. url: 'https://laser-oss.4dkankan.com/testdata/SS-t-P6zBR73Gke/temp/poi/2022/05/09/7896d6ef-a2d6-4fd7-949c-768782a5b484.mp4',
  87871. rotation:[-1.5487684197910518, 0.021848470169552752, -3.1387534893955236],
  87872. position:[17.277316608096, 2.0840432922115846, -0.0931149415437065],
  87873. scale:[2.0821757723834047, 0.6129478480765236, 1],
  87874. visibles: [40]
  87875. },
  87876. ];
  87877. let add = (info)=>{
  87878. var video = $(`<video controls="controls" loop autoplay x5-playsinline="" webkit-playsinline="true" playsinline="true" controlslist="nodownload"></video>`)[0];
  87879. video.setAttribute("crossOrigin", 'Anonymous');
  87880. video.src = info.url || Potree.resourcePath+`/video/${Potree.settings.number}/${info.id}.mp4`;
  87881. var map = new VideoTexture(video);
  87882. var plane = this.videoPlane = new Mesh(geo, new MeshBasicMaterial({
  87883. color:"#ffffff",
  87884. transparent: !0,
  87885. depthTest:false,
  87886. opacity:0 ,
  87887. //side:2,
  87888. map
  87889. }));
  87890. plane.position.fromArray(info.position);
  87891. plane.rotation.fromArray(info.rotation);
  87892. info.scale && plane.scale.fromArray(info.scale);
  87893. this.scene.scene.add(plane);
  87894. info.plane = plane;
  87895. plane.boundingBox = new Box3(new Vector3(0,-0.5,0),new Vector3(1,-0.4,0.2));
  87896. video.addEventListener('loadeddata', function(e) {
  87897. video.play();
  87898. if(!info.visibles/* ||!viewer.images360.currentPano || info.visibles.includes(viewer.images360.currentPano.id) */){
  87899. plane.material.opacity = 1;
  87900. }
  87901. info.scale || plane.scale.set(video.videoWidth/1000,video.videoHeight/1000,1); // 1080 * 1920
  87902. console.log('video loadeddata', info.id);
  87903. });
  87904. if(info.visibles){
  87905. this.images360.addEventListener('flyToPano' ,(e)=>{//飞之前
  87906. if(info.visibles.includes(e.toPano.pano.id)){ //出现
  87907. setTimeout(()=>{
  87908. plane.visible = true;
  87909. video.currentTime = 0;
  87910. video.play();
  87911. if(video.paused){
  87912. var startPlay = ()=>{
  87913. plane.visible && video.play();
  87914. this.removeEventListener('global_mousedown', startPlay);
  87915. };
  87916. this.addEventListener('global_mousedown', startPlay);
  87917. }
  87918. Potree.settings.zoom.enabled = false;
  87919. transitions.start(lerp.property(plane.material, "opacity", 1 ) , e.toPano.duration*0.4 , ()=>{
  87920. }, 0, easing['easeInOutQuad']);
  87921. }, e.toPano.duration*0.6); //时间上不能和消失的重叠 延迟
  87922. }else {
  87923. //消失
  87924. transitions.start(lerp.property(plane.material, "opacity", 0, ) , e.toPano.duration*0.4, ()=>{
  87925. if(!info){
  87926. plane.visible = false;
  87927. video.pause();
  87928. Potree.settings.zoom.enabled = true;
  87929. }
  87930. }, 0, easing['easeInOutQuad']);
  87931. }
  87932. });
  87933. }
  87934. var startPlay = ()=>{
  87935. video.play();
  87936. //video.pause()
  87937. //video.currentTime = 0.1;
  87938. this.removeEventListener('global_mousedown', startPlay);
  87939. };
  87940. this.addEventListener('global_mousedown', startPlay);
  87941. Potree.settings.isTest && plane.addEventListener('select',(e)=>{console.log(e);});
  87942. };
  87943. videoInfo.forEach(info=>{
  87944. add(info);
  87945. });
  87946. /* var video = $(`<video controls="controls" loop autoplay x5-playsinline="" webkit-playsinline="true" playsinline="true" controlslist="nodownload"></video>`)[0]
  87947. video.setAttribute("crossOrigin", 'Anonymous')
  87948. video.src = Potree.resourcePath+'/video/SS-t-P6zBR73Gke/40.mp4'
  87949. var map = new THREE.VideoTexture(video);
  87950. var plane = this.videoPlane = new THREE.Mesh(geo, new THREE.MeshBasicMaterial({
  87951. color:"#ffffff",
  87952. transparent: !0,
  87953. depthTest:false,
  87954. opacity:0.7,
  87955. side:2,
  87956. map
  87957. }))
  87958. //plane.visible = false
  87959. this.scene.scene.add(plane)
  87960. plane.geometry.computeBoundingBox();
  87961. plane.boundingBox = plane.geometry.boundingBox.clone()//.applyMatrix4()
  87962. plane.boundingBox.max.z = 0.3
  87963. plane.boundingBox.max.y = -0.4
  87964. plane.boundingBox.max.x = 1
  87965. plane.position.copy(this.images360.panos[40].position);
  87966. plane.lookAt(plane.position.clone().setX(0))
  87967. plane.rotation.set(-1.534692822378723, 0.01083403560862361, 3.141535283661569)
  87968. plane.position.set( 17.2934294239949861, 2.413510747928117, -0.008057029580231356)
  87969. //viewer.transformObject(viewer.videoPlane)
  87970. //19:
  87971. video.addEventListener('loadeddata', function(e) {
  87972. video.play()
  87973. plane.scale.set(video.videoWidth/1000,video.videoHeight/1000,1) // 1080 * 1920
  87974. console.log('video loadeddata')
  87975. })
  87976. //plane.scale.set(1080/1000,1920/1000,1) // 1080 * 1920
  87977. var startPlay = ()=>{
  87978. video.play()
  87979. //video.pause()
  87980. //video.currentTime = 0.1;
  87981. this.removeEventListener('global_mousedown', startPlay)
  87982. }
  87983. this.addEventListener('global_mousedown', startPlay)
  87984. */
  87985. /* this.images360.addEventListener('flyToPano' ,(e)=>{//飞之前
  87986. if(Potree.settings.displayMode != 'showPanos') return
  87987. let info = videoInfo[e.toPano.pano.id]
  87988. if(info ){ //出现
  87989. setTimeout(()=>{
  87990. plane.visible = true;
  87991. plane.position.fromArray(info.position)
  87992. plane.rotation.fromArray(info.rotation)
  87993. video.src = Potree.resourcePath+`/video/${Potree.settings.number}/${e.toPano.pano.id}.mp4`
  87994. video.play();
  87995. video.currentTime = 0
  87996. Potree.settings.zoom.enabled = false
  87997. transitions.start(lerp.property(plane.material, "opacity", 1 ) , e.toPano.duration*0.4 , ()=>{
  87998. }, 0, easing['easeInOutQuad'])
  87999. }, e.toPano.duration*0.6) //时间上不能和消失的重叠 延迟
  88000. }
  88001. //消失
  88002. transitions.start(lerp.property(plane.material, "opacity", 0, ) , e.toPano.duration*0.4, ()=>{
  88003. if(!info){
  88004. plane.visible = false
  88005. video.pause()
  88006. Potree.settings.zoom.enabled = true
  88007. }
  88008. }, 0, easing['easeInOutQuad'])
  88009. })
  88010. this.images360.addEventListener('endChangeMode',(e)=>{ //暂时不处理初始加载时就在有视频的点位上的情况
  88011. if(e.mode == 'showPanos'){
  88012. let info = videoInfo[this.images360.currentPano.id]
  88013. if(info ){ //出现
  88014. plane.visible = true;
  88015. plane.position.fromArray(info.position)
  88016. plane.rotation.fromArray(info.rotation)
  88017. plane.material.opacity = 0
  88018. video.src = Potree.resourcePath+`/video/${Potree.settings.number}/${this.images360.currentPano.id}.mp4`
  88019. video.play();
  88020. video.currentTime = 0
  88021. Potree.settings.zoom.enabled = false
  88022. transitions.start(lerp.property(plane.material, "opacity", 1, (e)=>{console.log('fadeIn',e)}) , 300 , ()=>{
  88023. }, 0, easing['easeInOutQuad'])
  88024. }
  88025. }else{
  88026. plane.visible = false;
  88027. Potree.settings.zoom.enabled = true
  88028. }
  88029. })
  88030. */
  88031. }
  88032. };
  88033. //------ CLIP 默认clipTask都是clipInside ----------------------
  88034. /*
  88035. 并集相当于加法,交集相当于加法。 所有结果都能展开成多个乘积相加。
  88036. 假设有4个clipBoxes,ABCD, 如果是 A*B + C*D ,那么这是最终结果。 如果是 (A+B)*(C+D) = A*C+A*D+B*C+B*D
  88037. */
  88038. let Clips = {
  88039. boxes : [],
  88040. unionGroups : [], //二维数组。最外层要求并集,里层要求交集(如果只有一个元素就是本身)。总结起来就是要求一堆交集的并集
  88041. shaderParams:{},
  88042. needsUpdate : true,
  88043. addClip(box, clipMethod){
  88044. //不允许重复
  88045. if(this.boxes.includes(box)){
  88046. return console.warn('addClip重复添加了box',box)
  88047. }
  88048. boxes.push(box);
  88049. if(clipMethod == 'any'){//并
  88050. this.unionGroups.push([box]);
  88051. }else if(clipMethod == 'all'){//交
  88052. this.unionGroups.forEach(mixGroup=>mixGroup.push(box));
  88053. }
  88054. this.needsUpdate = true;
  88055. },
  88056. removeClip(box){
  88057. if(!this.boxes.includes(box)){
  88058. return console.warn('removeClip没有找到该box',box)
  88059. }
  88060. var newGroups = [];
  88061. this.unionGroups.forEach(mixGroup=>{
  88062. if(mixGroup.length == 1 && mixGroup[0] == box)return;//直接删除
  88063. newGroups.push(mixGroup.filter(e=>e!=box));
  88064. });
  88065. this.unionGroups = newGroups;
  88066. this.needsUpdate = true;
  88067. }
  88068. ,
  88069. clearClip(){
  88070. this.boxes = [];
  88071. this.unionGroups = [];
  88072. this.needsUpdate = true;
  88073. }
  88074. ,
  88075. updateShaderParams(){//没写完 - - 见 pointcloud clip.vs
  88076. /*
  88077. uniform mat4 clipBoxes[num_clipboxes];
  88078. uniform int clipBoxGroupCount;
  88079. uniform int mixClipIndices[clipboxGroupItemCount]; //把所有的要求都直接放到数组内
  88080. */
  88081. //这里需要转为Float32Array..? 参考material.setClipBoxes
  88082. let everyClipGroupCount = this.unionGroups.map(e=>e.length);
  88083. let mixClipIndices = [];
  88084. this.unionGroups.forEach(e=>{
  88085. mixClipIndices.push(...e);
  88086. });
  88087. this.shaderParams = {
  88088. num_clipboxes : this.boxes.length,
  88089. clipBoxGroupCount : this.unionGroups.length,
  88090. everyClipGroupCount,
  88091. clipBoxIndexCount: mixClipIndices.length,
  88092. mixClipIndices
  88093. };
  88094. }
  88095. ,
  88096. getShaderParams(){//每次要传递参数到shader中,执行这个就好
  88097. if(this.needsUpdate){
  88098. this.updateShaderParams();
  88099. }
  88100. return this.shaderParams
  88101. }
  88102. };
  88103. /* setTimeout(()=>{
  88104. if( Potree.settings.number == 't-YLZ5XAALl7' || 't-e2Kb2iU' ){
  88105. let transform = {
  88106. 't-YLZ5XAALl7' : {
  88107. rotation : [0, 0, 0.002326740152215126],
  88108. position : [0.421017820930033, -0.22730084679456727, 0.0068952417582]
  88109. },
  88110. 't-e2Kb2iU' : {
  88111. rotation : [0.06595546058095993, -0.026986798620029413, 0.8429662590573239],
  88112. position : [ -502.6216232179794, 1051.5690392495885, 15.48490744053752]
  88113. },
  88114. }
  88115. var path = `${Potree.resourcePath}/models/${Potree.settings.number}/`
  88116. viewer.loadObj({
  88117. objurl: path+'pipe.obj',
  88118. mtlurl: path+'pipe.mtl',
  88119. transform : transform[Potree.settings.number]
  88120. })
  88121. }
  88122. },1000)
  88123. //if(!Potree.settings.isOfficial){
  88124. if(number == 't-e2Kb2iU') {
  88125. setTimeout(//暂时延迟,等focus第一个点之后
  88126. ()=>{
  88127. viewer.loadProject(Potree.scriptPath + "/data/"+ number +"/potree.json5", ()=>{
  88128. viewer.scene.cameraAnimations[0].play()
  88129. })
  88130. },
  88131. 3000)
  88132. }
  88133. */
  88134. OrthographicCamera.prototype.zoomTo = function( node, factor = 1){
  88135. if ( !node.geometry && !node.boundingBox) {
  88136. return;
  88137. }
  88138. // TODO
  88139. //let minWS = new THREE.Vector4(node.boundingBox.min.x, node.boundingBox.min.y, node.boundingBox.min.z, 1);
  88140. //let minVS = minWS.applyMatrix4(this.matrixWorldInverse);
  88141. //let right = node.boundingBox.max.x;
  88142. //let bottom = node.boundingBox.min.y;
  88143. //let top = node.boundingBox.max.y;
  88144. this.updateProjectionMatrix();
  88145. };
  88146. PerspectiveCamera.prototype.zoomTo = function (node, factor) {
  88147. if (!node.geometry && !node.boundingSphere && !node.boundingBox) {
  88148. return;
  88149. }
  88150. if (node.geometry && node.geometry.boundingSphere === null) {
  88151. node.geometry.computeBoundingSphere();
  88152. }
  88153. node.updateMatrixWorld();
  88154. let bs;
  88155. if (node.boundingSphere) {
  88156. bs = node.boundingSphere;
  88157. } else if (node.geometry && node.geometry.boundingSphere) {
  88158. bs = node.geometry.boundingSphere;
  88159. } else {
  88160. bs = node.boundingBox.getBoundingSphere(new Sphere());
  88161. }
  88162. let _factor = factor || 1;
  88163. bs = bs.clone().applyMatrix4(node.matrixWorld);
  88164. let radius = bs.radius;
  88165. let fovr = this.fov * Math.PI / 180;
  88166. if (this.aspect < 1) {
  88167. fovr = fovr * this.aspect;
  88168. }
  88169. let distanceFactor = Math.abs(radius / Math.sin(fovr / 2)) * _factor;
  88170. let offset = this.getWorldDirection(new Vector3()).multiplyScalar(-distanceFactor);
  88171. this.position.copy(bs.center.clone().add(offset));
  88172. };
  88173. Ray.prototype.distanceToPlaneWithNegative = function (plane) {
  88174. let denominator = plane.normal.dot(this.direction);
  88175. if (denominator === 0) {
  88176. // line is coplanar, return origin
  88177. if (plane.distanceToPoint(this.origin) === 0) {
  88178. return 0;
  88179. }
  88180. // Null is preferable to undefined since undefined means.... it is undefined
  88181. return null;
  88182. }
  88183. let t = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
  88184. return t;
  88185. };
  88186. const workerPool = new WorkerPool();
  88187. const version = {
  88188. major: 1,
  88189. minor: 8,
  88190. suffix: '.0'
  88191. };
  88192. let lru = new LRU();
  88193. //console.log('Potree ' + version.major + '.' + version.minor + version.suffix);
  88194. let pointBudget = 1 * 1000 * 1000;
  88195. let framenumber = 0;
  88196. let numNodesLoading = 0;
  88197. let maxNodesLoading = 4;
  88198. const debug = {};
  88199. exports.scriptPath = "";
  88200. if (document.currentScript && document.currentScript.src) {
  88201. exports.scriptPath = new URL(document.currentScript.src + '/..').href;
  88202. if (exports.scriptPath.slice(-1) === '/') {
  88203. exports.scriptPath = exports.scriptPath.slice(0, -1);
  88204. }
  88205. } else if(({ url: (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('potree.js', document.baseURI).href)) })){
  88206. exports.scriptPath = new URL((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('potree.js', document.baseURI).href)) + "/..").href;
  88207. if (exports.scriptPath.slice(-1) === '/') {
  88208. exports.scriptPath = exports.scriptPath.slice(0, -1);
  88209. }
  88210. }else {
  88211. console.error('Potree was unable to find its script path using document.currentScript. Is Potree included with a script tag? Does your browser support this function?');
  88212. }
  88213. let resourcePath = exports.scriptPath + '/resources';
  88214. //add:
  88215. async function loadFile(path, callback, onError){
  88216. if(Potree.fileServer){
  88217. Potree.fileServer.get(path).then(data=>{
  88218. callback && callback(data);
  88219. }).catch(onError);
  88220. }else {
  88221. try{
  88222. let response = await fetch(path);
  88223. let text = await response.text();
  88224. var data = JSON.parse(text);
  88225. if(data.data) data = data.data;
  88226. callback && callback(data);
  88227. return data
  88228. }catch(e){
  88229. onError && onError(e);
  88230. }
  88231. }
  88232. //查询: http://192.168.0.26:8080/doc.html#/default/filter-%E6%BC%AB%E6%B8%B8%E7%82%B9/filterUsingGET
  88233. }
  88234. async function loadDatasets(callback,sceneCode,onError){//之后直接把path写进来
  88235. let path;
  88236. sceneCode = sceneCode || Potree.settings.number;
  88237. if(Potree.fileServer){
  88238. path = `/laser/dataset/${sceneCode}/getDataSet`;
  88239. }else {
  88240. //path = `${Potree.settings.urls.prefix2}/indoor/${Potree.settings.number}/api/datasets`
  88241. //现在只能加载得了本地的了
  88242. path = `${Potree.settings.urls.prefix4}laser/dataset/${sceneCode}/getDataSet`;
  88243. //path = `${Potree.scriptPath}/data/${sceneCode}/getDataSet.json`
  88244. }
  88245. return loadFile(path, callback,onError)
  88246. }
  88247. //目前上传平面图后如果不点击保存按钮,数据还是旧的不生效
  88248. async function loadMapEntity(datasetId, force){
  88249. if(!Potree.settings.floorplanEnable && !force && Potree.fileServer )return /* 等待平面图类型定义好会加载 */
  88250. let loaded = 0;
  88251. let needLoads = datasetId == 'all' ? viewer.scene.pointclouds.map(e=>e.dataset_id) : [datasetId];
  88252. let callback = (dataset_id, floorplanType, data )=>{
  88253. //要防止旧的比新的先获取到导致覆盖新的,因为两种type随时可能切换
  88254. if(floorplanType != Potree.settings.floorplanType[dataset_id]) return //如果请求的floorplanType不是当前最新的floorplanType就返回
  88255. var map = viewer.mapViewer.mapLayer.maps.find(e => e.name == 'floorplan_'+ dataset_id);
  88256. if(map){
  88257. viewer.mapViewer.mapLayer.removeMap(map);
  88258. }
  88259. var mapNew = viewer.mapViewer.mapLayer.addMapEntity(data.data || data, dataset_id);
  88260. if(map){
  88261. mapNew.visibleReasons = map.visibleReasons;
  88262. mapNew.unvisibleReasons = map.unvisibleReasons;
  88263. }
  88264. loaded ++;
  88265. };
  88266. needLoads.forEach(dataset_id=>{
  88267. let floorplanType = Potree.settings.floorplanType[dataset_id];
  88268. if(!floorplanType)return
  88269. var path;
  88270. if(Potree.fileServer){
  88271. path = `/laser/tiledMap/${Potree.settings.number}/tiledMap/${floorplanType}/${dataset_id}`;
  88272. }else {
  88273. path = `${Potree.settings.urls.prefix2}/indoor/${Potree.settings.number}/api/tiled_maps`;
  88274. }
  88275. Potree.settings.floorplanRequests[dataset_id] = true; //开始加载了
  88276. return loadFile(path, callback.bind(this, dataset_id, floorplanType) )
  88277. });
  88278. }
  88279. async function loadPanos(datasetId, callback){
  88280. var path;
  88281. let query = `?datasetId=${datasetId}`; //`?lat=${center.lat}&lon=${center.lon}&radius=200000`
  88282. if(Potree.fileServer){
  88283. path = `/laser/filter/${Potree.settings.number}/query` + query;
  88284. }else {
  88285. //path = `${Potree.settings.urls.prefix2}/indoor/${Potree.settings.number}/api/images/filter` + query
  88286. //path = `${Potree.scriptPath}/data/${Potree.settings.number}/panos-${datasetId}.json`
  88287. path = `${Potree.settings.urls.prefix4}laser/filter/${Potree.settings.number}/query` + query;
  88288. }
  88289. return loadFile(path, callback)
  88290. }
  88291. async function loadPanosInfo(callback){
  88292. var path;
  88293. if(Potree.fileServer){
  88294. }else {
  88295. path = `${Potree.scriptPath}/data/panoEdit/vision_edit.txt`;
  88296. }
  88297. return loadFile(path, callback)
  88298. }
  88299. //site_model
  88300. /* {
  88301. "area": 2503.30551910935,
  88302. "attributes": {},
  88303. "center": [
  88304. 113.59568277455075,
  88305. 22.366566635195288,
  88306. 12.78751625
  88307. ],
  88308. "children": [],
  88309. "geometry_hash": 1891071345,
  88310. "id": 10,
  88311. "name": "港湾一号",
  88312. "parentId": null,
  88313. "polygon": {
  88314. "coordinates": [
  88315. [
  88316. [
  88317. 113.59590810534583,
  88318. 22.36679132753878
  88319. ],
  88320. [
  88321. 113.59590810534583,
  88322. 22.366807172528629
  88323. ],
  88324. [
  88325. 113.59545610274934,
  88326. 22.366807172528629
  88327. ],
  88328. [
  88329. 113.59545610274934,
  88330. 22.36679132753878
  88331. ]
  88332. ]
  88333. ],
  88334. "type": "Polygon"
  88335. },
  88336. "type": "BUILDING",
  88337. "volume": null,
  88338. "z_max": null,
  88339. "z_min": null
  88340. }
  88341. */
  88342. function Log(value, color, fontSize){
  88343. color = color || '#13f';
  88344. fontSize = fontSize || 14;
  88345. console.warn(`%c${value}`, `color:${color};font-size:${fontSize}px`);
  88346. }
  88347. function loadPointCloud$1(path, name, sceneCode, timeStamp, callback, onError){
  88348. let loaded = function(e){
  88349. e.pointcloud.name = name;
  88350. e.pointcloud.sceneCode = sceneCode; //对应4dkk的场景码
  88351. callback(e);
  88352. };
  88353. let promise = new Promise( resolve => {
  88354. // load pointcloud
  88355. if (!path){
  88356. // TODO: callback? comment? Hello? Bueller? Anyone?
  88357. } else if (path.indexOf('ept.json') > 0) {
  88358. EptLoader.load(path, function(geometry) {
  88359. if (!geometry) {
  88360. console.error(new Error(`failed to load point cloud from URL: ${path}`));
  88361. }
  88362. else {
  88363. let pointcloud = new PointCloudOctree(geometry);
  88364. //loaded(pointcloud);
  88365. resolve({type: 'pointcloud_loaded', pointcloud: pointcloud});
  88366. }
  88367. });
  88368. } else if (path.indexOf('cloud.js') > 0) {
  88369. POCLoader.load(path, timeStamp, function (geometry) {
  88370. if (!geometry) {
  88371. //callback({type: 'loading_failed'});
  88372. console.error(new Error(`failed to load point cloud from URL: ${path}`));
  88373. onError && onError();
  88374. } else {
  88375. let pointcloud = new PointCloudOctree(geometry);
  88376. // loaded(pointcloud);
  88377. resolve({type: 'pointcloud_loaded', pointcloud: pointcloud});
  88378. }
  88379. });
  88380. }/* else if (path.indexOf('metadata.json') > 0) { //部分浏览器(如uc)不支持NodeLoader中的1n的大数据写法
  88381. Potree.OctreeLoader.load(path).then(e => {
  88382. let geometry = e.geometry;
  88383. if(!geometry){
  88384. console.error(new Error(`failed to load point cloud from URL: ${path}`));
  88385. }else{
  88386. let pointcloud = new PointCloudOctree(geometry);
  88387. let aPosition = pointcloud.getAttribute("position");
  88388. let material = pointcloud.material;
  88389. material.elevationRange = [
  88390. aPosition.range[0][2],
  88391. aPosition.range[1][2],
  88392. ];
  88393. // loaded(pointcloud);
  88394. resolve({type: 'pointcloud_loaded', pointcloud: pointcloud});
  88395. }
  88396. });
  88397. OctreeLoader.load(path, function (geometry) {
  88398. if (!geometry) {
  88399. //callback({type: 'loading_failed'});
  88400. console.error(new Error(`failed to load point cloud from URL: ${path}`));
  88401. } else {
  88402. let pointcloud = new PointCloudOctree(geometry);
  88403. // loaded(pointcloud);
  88404. resolve({type: 'pointcloud_loaded', pointcloud: pointcloud});
  88405. }
  88406. });
  88407. } */else if (path.indexOf('.vpc') > 0) {
  88408. PointCloudArena4DGeometry.load(path, function (geometry) {
  88409. if (!geometry) {
  88410. //callback({type: 'loading_failed'});
  88411. console.error(new Error(`failed to load point cloud from URL: ${path}`));
  88412. } else {
  88413. let pointcloud = new PointCloudArena4D(geometry);
  88414. // loaded(pointcloud);
  88415. resolve({type: 'pointcloud_loaded', pointcloud: pointcloud});
  88416. }
  88417. });
  88418. } else {
  88419. //callback({'type': 'loading_failed'});
  88420. console.error(new Error(`failed to load point cloud from URL: ${path}`));
  88421. }
  88422. });
  88423. if(callback){
  88424. promise.then(pointcloud => {
  88425. loaded(pointcloud);
  88426. });
  88427. }else {
  88428. return promise;
  88429. }
  88430. };
  88431. // add selectgroup
  88432. (function($){
  88433. $.fn.extend({
  88434. selectgroup: function(args = {}){
  88435. let elGroup = $(this);
  88436. let rootID = elGroup.prop("id");
  88437. let groupID = `${rootID}`;
  88438. let groupTitle = (args.title !== undefined) ? args.title : "";
  88439. let elButtons = [];
  88440. elGroup.find("option").each((index, value) => {
  88441. let buttonID = $(value).prop("id");
  88442. let label = $(value).html();
  88443. let optionValue = $(value).prop("value");
  88444. let elButton = $(`
  88445. <span style="flex-grow: 1; display: inherit">
  88446. <label for="${buttonID}" class="ui-button" style="width: 100%; padding: .4em .1em">${label}</label>
  88447. <input type="radio" name="${groupID}" id="${buttonID}" value="${optionValue}" style="display: none"/>
  88448. </span>
  88449. `);
  88450. let elLabel = elButton.find("label");
  88451. let elInput = elButton.find("input");
  88452. elInput.change( () => {
  88453. elGroup.find("label").removeClass("ui-state-active");
  88454. elGroup.find("label").addClass("ui-state-default");
  88455. if(elInput.is(":checked")){
  88456. elLabel.addClass("ui-state-active");
  88457. }else {
  88458. //elLabel.addClass("ui-state-default");
  88459. }
  88460. });
  88461. elButtons.push(elButton);
  88462. });
  88463. let elFieldset = $(`
  88464. <fieldset style="border: none; margin: 0px; padding: 0px">
  88465. <legend>${groupTitle}</legend>
  88466. <span style="display: flex">
  88467. </span>
  88468. </fieldset>
  88469. `);
  88470. let elButtonContainer = elFieldset.find("span");
  88471. for(let elButton of elButtons){
  88472. elButtonContainer.append(elButton);
  88473. }
  88474. elButtonContainer.find("label").each( (index, value) => {
  88475. $(value).css("margin", "0px");
  88476. $(value).css("border-radius", "0px");
  88477. $(value).css("border", "1px solid black");
  88478. $(value).css("border-left", "none");
  88479. });
  88480. elButtonContainer.find("label:first").each( (index, value) => {
  88481. $(value).css("border-radius", "4px 0px 0px 4px");
  88482. });
  88483. elButtonContainer.find("label:last").each( (index, value) => {
  88484. $(value).css("border-radius", "0px 4px 4px 0px");
  88485. $(value).css("border-left", "none");
  88486. });
  88487. elGroup.empty();
  88488. elGroup.append(elFieldset);
  88489. }
  88490. });
  88491. })(jQuery);
  88492. exports.Action = Action;
  88493. exports.Alignment = Alignment;
  88494. exports.AnimationPath = AnimationPath;
  88495. exports.Annotation = Annotation;
  88496. exports.Box3Helper = Box3Helper$1;
  88497. exports.BoxVolume = BoxVolume;
  88498. exports.Buttons = Buttons;
  88499. exports.CameraAnimation = CameraAnimation;
  88500. exports.CameraMode = CameraMode;
  88501. exports.ClassificationScheme = ClassificationScheme;
  88502. exports.ClipMethod = ClipMethod;
  88503. exports.ClipTask = ClipTask;
  88504. exports.ClipVolume = ClipVolume;
  88505. exports.ClippingTool = ClippingTool;
  88506. exports.Compass = Compass;
  88507. exports.DeviceOrientationControls = DeviceOrientationControls;
  88508. exports.DownloadStatus = DownloadStatus;
  88509. exports.EarthControls = EarthControls;
  88510. exports.ElevationGradientRepeat = ElevationGradientRepeat;
  88511. exports.Enum = Enum;
  88512. exports.EnumItem = EnumItem;
  88513. exports.EptBinaryLoader = EptBinaryLoader;
  88514. exports.EptKey = EptKey;
  88515. exports.EptLaszipLoader = EptLaszipLoader;
  88516. exports.EptLazBatcher = EptLazBatcher;
  88517. exports.EptLoader = EptLoader;
  88518. exports.EptZstandardLoader = EptZstandardLoader;
  88519. exports.EventDispatcher = EventDispatcher$1;
  88520. exports.EyeDomeLightingMaterial = EyeDomeLightingMaterial;
  88521. exports.Features = Features;
  88522. exports.FirstPersonControls = FirstPersonControls;
  88523. exports.GLCubeFaces = GLCubeFaces$1;
  88524. exports.GeoPackageLoader = GeoPackageLoader;
  88525. exports.Geopackage = Geopackage$1;
  88526. exports.Gradients = Gradients;
  88527. exports.HierarchicalSlider = HierarchicalSlider;
  88528. exports.Images360 = Images360;
  88529. exports.KeyCodes = KeyCodes;
  88530. exports.LRU = LRU;
  88531. exports.LRUItem = LRUItem;
  88532. exports.LengthUnits = LengthUnits;
  88533. exports.Log = Log;
  88534. exports.Measure = Measure;
  88535. exports.MeasuringTool = MeasuringTool;
  88536. exports.Message = Message;
  88537. exports.ModelManagerEvents = ModelManagerEvents;
  88538. exports.NormalizationEDLMaterial = NormalizationEDLMaterial;
  88539. exports.NormalizationMaterial = NormalizationMaterial;
  88540. exports.OrbitControls = OrbitControls;
  88541. exports.OrientedImage = OrientedImage;
  88542. exports.OrientedImageLoader = OrientedImageLoader;
  88543. exports.OrientedImages = OrientedImages;
  88544. exports.POCLoader = POCLoader;
  88545. exports.PanoRendererEvents = PanoRendererEvents;
  88546. exports.PanoSizeClass = PanoSizeClass;
  88547. exports.PanoramaEvents = PanoramaEvents;
  88548. exports.PathAnimation = PathAnimation;
  88549. exports.PointAttribute = PointAttribute;
  88550. exports.PointAttributeTypes = PointAttributeTypes;
  88551. exports.PointAttributes = PointAttributes;
  88552. exports.PointCloudEptGeometry = PointCloudEptGeometry;
  88553. exports.PointCloudEptGeometryNode = PointCloudEptGeometryNode;
  88554. exports.PointCloudMaterial = PointCloudMaterial$1;
  88555. exports.PointCloudOctree = PointCloudOctree;
  88556. exports.PointCloudOctreeGeometry = PointCloudOctreeGeometry;
  88557. exports.PointCloudOctreeGeometryNode = PointCloudOctreeGeometryNode;
  88558. exports.PointCloudOctreeNode = PointCloudOctreeNode;
  88559. exports.PointCloudSM = PointCloudSM;
  88560. exports.PointCloudTree = PointCloudTree;
  88561. exports.PointCloudTreeNode = PointCloudTreeNode;
  88562. exports.PointShape = PointShape;
  88563. exports.PointSizeType = PointSizeType;
  88564. exports.Points = Points$1;
  88565. exports.PolygonClipVolume = PolygonClipVolume;
  88566. exports.Profile = Profile;
  88567. exports.ProfileData = ProfileData;
  88568. exports.ProfileRequest = ProfileRequest;
  88569. exports.ProfileTool = ProfileTool;
  88570. exports.Renderer = Renderer;
  88571. exports.Scene = Scene$1;
  88572. exports.SceneRendererEvents = SceneRendererEvents;
  88573. exports.ScreenBoxSelectTool = ScreenBoxSelectTool;
  88574. exports.ShapefileLoader = ShapefileLoader;
  88575. exports.SphereVolume = SphereVolume;
  88576. exports.SpotLightHelper = SpotLightHelper$1;
  88577. exports.TileDownloaderEvents = TileDownloaderEvents;
  88578. exports.TransformationTool = TransformationTool;
  88579. exports.TreeType = TreeType;
  88580. exports.Utils = Utils;
  88581. exports.VRControls = VRControls;
  88582. exports.Vectors = Vectors;
  88583. exports.Vectors2 = Vectors2;
  88584. exports.Version = Version;
  88585. exports.Viewer = Viewer;
  88586. exports.Volume = Volume;
  88587. exports.VolumeTool = VolumeTool;
  88588. exports.WorkerPool = WorkerPool;
  88589. exports.XHRFactory = XHRFactory;
  88590. exports.config = config$1;
  88591. exports.debug = debug;
  88592. exports.framenumber = framenumber;
  88593. exports.loadDatasets = loadDatasets;
  88594. exports.loadFile = loadFile;
  88595. exports.loadMapEntity = loadMapEntity;
  88596. exports.loadPanos = loadPanos;
  88597. exports.loadPanosInfo = loadPanosInfo;
  88598. exports.loadPointCloud = loadPointCloud$1;
  88599. exports.loadProject = loadProject;
  88600. exports.lru = lru;
  88601. exports.maxNodesLoading = maxNodesLoading;
  88602. exports.mergeEditStart = mergeEditStart;
  88603. exports.numNodesLoading = numNodesLoading;
  88604. exports.panoEditStart = panoEditStart;
  88605. exports.pointBudget = pointBudget;
  88606. exports.resourcePath = resourcePath;
  88607. exports.saveProject = saveProject;
  88608. exports.settings = settings;
  88609. exports.start = start;
  88610. exports.updatePointClouds = updatePointClouds;
  88611. exports.updateVisibility = updateVisibility;
  88612. exports.updateVisibilityStructures = updateVisibilityStructures;
  88613. exports.version = version;
  88614. exports.workerPool = workerPool;
  88615. Object.defineProperty(exports, '__esModule', { value: true });
  88616. })));
  88617. //# sourceMappingURL=potree.js.map